From 649dde980896df542441ed9bdfddd18e1aabd55b Mon Sep 17 00:00:00 2001 From: Roy-043 <70520633+Roy-043@users.noreply.github.com> Date: Wed, 23 Aug 2023 11:17:17 +0200 Subject: [PATCH] Draft: Add placement_from_points to geometry.py Changed getPlacementFromPoints function in WorkingPlane.py to a compatibility function that calls placement_from_points. --- src/Mod/Draft/DraftGeomUtils.py | 3 +- src/Mod/Draft/WorkingPlane.py | 50 +++---------------- src/Mod/Draft/draftgeoutils/geometry.py | 54 +++++++++++++++++++++ src/Mod/Draft/draftguitools/gui_trackers.py | 15 +++--- 4 files changed, 70 insertions(+), 52 deletions(-) diff --git a/src/Mod/Draft/DraftGeomUtils.py b/src/Mod/Draft/DraftGeomUtils.py index 62ade87e8a..a54bfad117 100644 --- a/src/Mod/Draft/DraftGeomUtils.py +++ b/src/Mod/Draft/DraftGeomUtils.py @@ -77,7 +77,8 @@ from draftgeoutils.geometry import (findPerpendicular, calculatePlacement, mirror, are_coplanar, - is_straight_line) + is_straight_line, + placement_from_points) from draftgeoutils.edges import (findEdge, orientEdge, diff --git a/src/Mod/Draft/WorkingPlane.py b/src/Mod/Draft/WorkingPlane.py index da0698d7c1..2ee910ef61 100644 --- a/src/Mod/Draft/WorkingPlane.py +++ b/src/Mod/Draft/WorkingPlane.py @@ -40,6 +40,7 @@ import lazy_loader.lazy_loader as lz import FreeCAD import DraftVecUtils from FreeCAD import Vector +from draftutils import utils from draftutils.translate import translate DraftGeomUtils = lz.LazyLoader("DraftGeomUtils", globals(), "DraftGeomUtils") @@ -1312,53 +1313,14 @@ class Plane: plane = Plane +# Compatibility function: def getPlacementFromPoints(points): - """Return a placement from a list of 3 or 4 points. + """Return a placement from a list of 3 or 4 points. The 4th point is no longer used. - With these points a temporary `plane` is defined. - - Then it returns the `Base::Placement` returned from `plane.getPlacement()`. - - Parameters - ---------- - points : list of Base::Vector3 - A list with 3 or 4 points to create a temporary plane - from which to extract the placement. - - The first point is the plane's `position`. - The other two points are used to define the `u` and `v` axes, - as originating from the first point. - - If the fourth point exists, it is used to define the plane's `axis` - as originating from the first point. - If no fourth point is provided, the cross product bewtween - the previously defined `u` and `v` is used as `axis`. - - Return - ------ - Base::Placement - A placement obtained from the temporary plane - defined by `points`, - or `None` is it fails to use the points. - - See Also - -------- - getPlacement + Calls DraftGeomUtils.placement_from_points(). See there. """ - pl = plane() - try: - pl.position = points[0] - pl.u = (points[1].sub(points[0]).normalize()) - pl.v = (points[2].sub(points[0]).normalize()) - if len(points) == 4: - pl.axis = (points[3].sub(points[0]).normalize()) - else: - pl.axis = ((pl.u).cross(pl.v)).normalize() - except Exception: - return None - p = pl.getPlacement() - del pl - return p + utils.use_instead("DraftGeomUtils.placement_from_points") + return DraftGeomUtils.placement_from_points(*points[:3]) def getPlacementFromFace(face, rotated=False): diff --git a/src/Mod/Draft/draftgeoutils/geometry.py b/src/Mod/Draft/draftgeoutils/geometry.py index 0ead657198..d00f7c49fc 100644 --- a/src/Mod/Draft/draftgeoutils/geometry.py +++ b/src/Mod/Draft/draftgeoutils/geometry.py @@ -517,6 +517,60 @@ def mirror(point, edge): return None +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. + + If the vectors calculated from the arguments are too short or parallel, + the returned placement will have a default rotation. + + Parameters + ---------- + pt_pos : Base::Vector3 + Origin (Base of Placement). + + pt_x : Base::Vector3 + Point on positive X axis. Or X axis vector if as_vectors is `True`. + + pt_y : Base::Vector3 + Point on positive Y axis. Or Y axis vector if as_vectors is `True`. + + as_vectors : bool + If `True` treat pt_x and pt_y as axis vectors. + + tol : float + Internal tolerance. 1e-7 is used if tol <=0. + + See also: + --------- + DraftVecUtils.getRotation + DraftGeomUtils.getRotation + + Return + ------ + Base::Placement + """ + err = 1e-7 if tol <= 0 else tol + if as_vectors is False: + vec_u = pt_x - pt_pos + vec_v = pt_y - pt_pos + else: + vec_u = App.Vector(pt_x) + vec_v = App.Vector(pt_y) + + if vec_u.Length < err or vec_v.Length < err: + rot = App.Rotation() + else: + vec_u.normalize() + vec_v.normalize() + if vec_u.isEqual(vec_v, err) \ + or vec_u.isEqual(vec_v.negative(), err): + rot = App.Rotation() + else: + rot = App.Rotation(vec_u, vec_v, App.Vector(), "XYZ") + + return App.Placement(pt_pos, rot) + + #compatibility layer getSplineNormal = get_spline_normal diff --git a/src/Mod/Draft/draftguitools/gui_trackers.py b/src/Mod/Draft/draftguitools/gui_trackers.py index b28be430f8..45d6609a89 100644 --- a/src/Mod/Draft/draftguitools/gui_trackers.py +++ b/src/Mod/Draft/draftguitools/gui_trackers.py @@ -1267,7 +1267,6 @@ class boxTracker(Tracker): def update(self, line=None, normal=None): """Update the tracker.""" - import WorkingPlane import DraftGeomUtils if not normal: normal = FreeCAD.DraftWorkingPlane.axis @@ -1283,16 +1282,18 @@ class boxTracker(Tracker): bp = self.baseline.Shape.Edges[0].Vertexes[0].Point else: return - right = lvec.cross(normal) self.cube.width.setValue(lvec.Length) - p = WorkingPlane.getPlacementFromPoints([bp, - bp.add(lvec), - bp.add(right)]) - if p: - self.trans.rotation.setValue(p.Rotation.Q) bp = bp.add(lvec.multiply(0.5)) bp = bp.add(DraftVecUtils.scaleTo(normal, self.cube.depth.getValue()/2.0)) self.pos(bp) + tol = 1e-6 + if lvec.Length > tol and normal.Length > tol: + lvec.normalize() + normal.normalize() + if not lvec.isEqual(normal, tol) \ + and not lvec.isEqual(normal.negative(), tol): + rot = FreeCAD.Rotation(lvec, FreeCAD.Vector(), normal, "XZY") + self.trans.rotation.setValue(rot.Q) def setRotation(self, rot): """Set the rotation."""