From 80326986761fa5915832e0ad622e18cca9555ba5 Mon Sep 17 00:00:00 2001 From: Roy-043 Date: Tue, 19 Sep 2023 16:02:59 +0200 Subject: [PATCH] Draft: Add distance_to_plane and project_point_on_plane to geometry.py The functions have been copied from the WorkingPlane class. It makes sense to also have them available outside that class. The WorkingPlane class will later be updated to use these functions so that duplicate code is avoided. Note that the default tolerance of the project_point_on_plane function is 1e-7. In the original projectPoint function it is sys.float_info.epsilon (too small for FreeCAD IMO). --- src/Mod/Draft/DraftGeomUtils.py | 4 +- src/Mod/Draft/draftgeoutils/geometry.py | 89 ++++++++++++++++++++++--- 2 files changed, 84 insertions(+), 9 deletions(-) diff --git a/src/Mod/Draft/DraftGeomUtils.py b/src/Mod/Draft/DraftGeomUtils.py index 4df2d73818..314ed82b95 100644 --- a/src/Mod/Draft/DraftGeomUtils.py +++ b/src/Mod/Draft/DraftGeomUtils.py @@ -81,7 +81,9 @@ from draftgeoutils.geometry import (findPerpendicular, mirror_matrix, uv_vectors_from_face, placement_from_face, - placement_from_points) + placement_from_points, + distance_to_plane, + project_point_on_plane) from draftgeoutils.edges import (findEdge, orientEdge, diff --git a/src/Mod/Draft/draftgeoutils/geometry.py b/src/Mod/Draft/draftgeoutils/geometry.py index f25f1eb62e..329e819e5f 100644 --- a/src/Mod/Draft/draftgeoutils/geometry.py +++ b/src/Mod/Draft/draftgeoutils/geometry.py @@ -529,8 +529,8 @@ def mirror_matrix(mtx, pos, nor): nor: Base::Vector3 Normal of mirror plane. - Return - ------ + Returns + ------- Base::Matrix """ # Code by Jolbas: @@ -563,8 +563,8 @@ def uv_vectors_from_face(face, vec_z=App.Vector(0, 0, 1), tol=-1): Defaults to -1. Internal tolerance. 1e-7 is used if tol <=0. - Return - ------ + Returns + ------- tuple U and v vector (Base::Vector3). """ @@ -608,8 +608,8 @@ def placement_from_face(face, vec_z=App.Vector(0, 0, 1), rotated=False, tol=-1): Defaults to -1. Internal tolerance. 1e-7 is used if tol <=0. - Return - ------ + Returns + ------- Base::Placement See also @@ -645,8 +645,8 @@ def placement_from_points(pt_pos, pt_x, pt_y, as_vectors=False, tol=-1): Defaults to -1. Internal tolerance. 1e-7 is used if tol <=0. - Return - ------ + Returns + ------- Base::Placement See also @@ -675,6 +675,79 @@ def placement_from_points(pt_pos, pt_x, pt_y, as_vectors=False, tol=-1): return App.Placement(pt_pos, rot) +# Code separated from WorkingPlane.py (offsetToPoint function). +# Note that the return value of this function has the opposite sign. +def distance_to_plane(point, base, normal): + """Return the signed distance from a plane to a point. + + The distance is positive if the point lies on the +normal side of the plane. + + Parameters + ---------- + point: Base::Vector3 + Point to project. + base: Base::Vector3 + Point on plane. + normal: Base::Vector3 + Normal of plane. + + Returns + ------- + float + """ + return (point - base).dot(normal) + + +# Code separated from WorkingPlane.py (projectPoint function). +# See: https://github.com/FreeCAD/FreeCAD/pull/5307 +def project_point_on_plane(point, base, normal, direction=None, force_projection=False, tol=-1): + """Project a point onto a plane. + + Parameters + ---------- + point: Base::Vector3 + Point to project. + base: Base::Vector3 + Point on plane. + normal: Base::Vector3 + Normal of plane. + direction: Base::Vector3, optional + Defaults to `None` in which case the normal is used. + Direction of projection. + force_projection: Bool, optional + Defaults to `False`. + If `True` forces the projection if the deviation between the direction + and the normal is less than tol from the orthogonality. The direction + of projection is then modified to a tol deviation between the direction + and the orthogonal. + tol: float, optional + Defaults to -1. + Internal tolerance. 1e-7 is used if tol <=0. + + Returns + ------- + Base::Vector3 or `None` + """ + err = 1e-7 if tol <= 0 else tol + normal = App.Vector(normal).normalize() + if direction is None: + direction = normal + else: + direction = App.Vector(direction).normalize() + + cos = direction.dot(normal) + delta_ax_proj = (point - base).dot(normal) + # check the only conflicting case: direction orthogonal to normal + if abs(cos) < err: + if force_projection: + cos = math.copysign(err, delta_ax_proj) + direction = normal.cross(direction).cross(normal) - cos * normal + else: + return None + + return point - delta_ax_proj / cos * direction + + #compatibility layer getSplineNormal = get_spline_normal