From bfa8d79afbdf2afaeef7d4f320c6979ba80a6b86 Mon Sep 17 00:00:00 2001 From: Roy-043 <70520633+Roy-043@users.noreply.github.com> Date: Wed, 23 Aug 2023 12:05:34 +0200 Subject: [PATCH] Draft: Add placement_from_face to geometry.py (#10327) Changed getPlacementFromFace function in WorkingPlane.py to a compatibility function that calls placement_from_face. --- src/Mod/Draft/DraftGeomUtils.py | 2 + src/Mod/Draft/WorkingPlane.py | 38 ++-------- src/Mod/Draft/draftgeoutils/geometry.py | 99 +++++++++++++++++++++---- 3 files changed, 92 insertions(+), 47 deletions(-) diff --git a/src/Mod/Draft/DraftGeomUtils.py b/src/Mod/Draft/DraftGeomUtils.py index a54bfad117..725f8e7c11 100644 --- a/src/Mod/Draft/DraftGeomUtils.py +++ b/src/Mod/Draft/DraftGeomUtils.py @@ -78,6 +78,8 @@ from draftgeoutils.geometry import (findPerpendicular, mirror, are_coplanar, is_straight_line, + uv_vectors_from_face, + placement_from_face, placement_from_points) from draftgeoutils.edges import (findEdge, diff --git a/src/Mod/Draft/WorkingPlane.py b/src/Mod/Draft/WorkingPlane.py index 2ee910ef61..0fedbc35a1 100644 --- a/src/Mod/Draft/WorkingPlane.py +++ b/src/Mod/Draft/WorkingPlane.py @@ -1313,7 +1313,7 @@ class Plane: plane = Plane -# Compatibility function: +# Compatibility function (V0.22, 2023): def getPlacementFromPoints(points): """Return a placement from a list of 3 or 4 points. The 4th point is no longer used. @@ -1323,39 +1323,11 @@ def getPlacementFromPoints(points): return DraftGeomUtils.placement_from_points(*points[:3]) +# Compatibility function (V0.22, 2023): def getPlacementFromFace(face, rotated=False): """Return a placement from a face. - It creates a temporary `plane` and uses `alignToFace(face)` - to set its orientation. - - Then it returns the `Base::Placement` returned - from `plane.getPlacement(rotated)`. - - Parameter - --------- - face : Part.Face - A shape of type `'Face'`. - rotated : bool, optional - It defaults to `False`. If it is `True`, the temporary plane - switches `axis` with `-v` to produce a rotated placement. - - Returns - ------- - Base::Placement - A placement obtained from the temporary plane - defined by `face`, - or `None` if it fails to use `face`. - - See Also - -------- - alignToFace, getPlacement + Calls DraftGeomUtils.placement_from_face(). See there. """ - pl = plane() - try: - pl.alignToFace(face) - except Exception: - return None - p = pl.getPlacement(rotated) - del pl - return p + utils.use_instead("DraftGeomUtils.placement_from_face") + return DraftGeomUtils.placement_from_face(face, rotated) diff --git a/src/Mod/Draft/draftgeoutils/geometry.py b/src/Mod/Draft/draftgeoutils/geometry.py index d00f7c49fc..5e46cca410 100644 --- a/src/Mod/Draft/draftgeoutils/geometry.py +++ b/src/Mod/Draft/draftgeoutils/geometry.py @@ -517,6 +517,79 @@ def mirror(point, edge): return None +def uv_vectors_from_face(face, vec_z=App.Vector(0, 0, 1), tol=-1): + """Return the u and v vectors of a planar face. + + It is up to the calling function to ensure the face is planar. + + If the u vector matches +/-vec_z, or the v vector matches -vec_z, the + vectors are rotated to ensure the v vector matches +vec_z. + + face: Part.Face + Face. + vec_z: Base::Vector3, optional + Defaults to Vector(0, 0, 1). + Z axis vector used for reference. + tol: float, optional + Defaults to -1. + Internal tolerance. 1e-7 is used if tol <=0. + + Return + ------ + tuple + U and v vector (Base::Vector3). + """ + err = 1e-7 if tol <= 0 else tol + vec_u, vec_v = face.tangentAt(0, 0) + if face.Orientation == "Reversed": + vec_u, vec_v = vec_v, vec_u + if vec_v.isEqual(vec_z.negative(), err): + vec_u, vec_v = vec_u.negative(), vec_v.negative() + elif vec_u.isEqual(vec_z, err): + vec_u, vec_v = vec_v.negative(), vec_u + elif vec_u.isEqual(vec_z.negative(), err): + vec_u, vec_v = vec_v, vec_u.negative() + return vec_u, vec_v + + +def placement_from_face(face, vec_z=App.Vector(0, 0, 1), rotated=False, tol=-1): + """Return a placement from the center of gravity, and the u and v vectors of a planar face. + + It is up to the calling function to ensure the face is planar. + + Parameters + ---------- + face: Part.Face + Face. + vec_z: Base::Vector3, optional + Defaults to Vector(0, 0, 1). + Z axis vector used for reference. + rotated: bool, optional + Defaults to `False`. + If `False` the v vector of the face defines the Y axis of the placement. + If `True` the -v vector of the face defines the Z axis of the placement + (used by Arch_Window). + The u vector defines the X axis in both cases. + tol: float, optional + Defaults to -1. + Internal tolerance. 1e-7 is used if tol <=0. + + Return + ------ + Base::Placement + + See also + -------- + DraftGeomUtils.uv_vectors_from_face + """ + pt_pos = face.CenterOfGravity + vec_u, vec_v = uv_vectors_from_face(face, vec_z, tol) + if rotated: + return App.Placement(pt_pos, App.Rotation(vec_u, App.Vector(), vec_v.negative(), "XZY")) + else: + return App.Placement(pt_pos, App.Rotation(vec_u, vec_v, App.Vector(), "XYZ")) + + def placement_from_points(pt_pos, pt_x, pt_y, as_vectors=False, tol=-1): """Return a placement from 3 points defining an origin, an X axis and a Y axis. @@ -525,29 +598,27 @@ def placement_from_points(pt_pos, pt_x, pt_y, as_vectors=False, tol=-1): Parameters ---------- - pt_pos : Base::Vector3 + pt_pos: Base::Vector3 Origin (Base of Placement). - - pt_x : Base::Vector3 + pt_x: Base::Vector3 Point on positive X axis. Or X axis vector if as_vectors is `True`. - - pt_y : Base::Vector3 + pt_y: Base::Vector3 Point on positive Y axis. Or Y axis vector if as_vectors is `True`. - - as_vectors : bool + as_vectors: bool, optional + Defaults to `False`. If `True` treat pt_x and pt_y as axis vectors. - - tol : float + tol: float, optional + Defaults to -1. Internal tolerance. 1e-7 is used if tol <=0. - See also: - --------- - DraftVecUtils.getRotation - DraftGeomUtils.getRotation - Return ------ Base::Placement + + See also + -------- + DraftGeomUtils.getRotation + DraftVecUtils.getRotation """ err = 1e-7 if tol <= 0 else tol if as_vectors is False: