diff --git a/src/build123d/topology/shape_core.py b/src/build123d/topology/shape_core.py index 11a7216..a57fda5 100644 --- a/src/build123d/topology/shape_core.py +++ b/src/build123d/topology/shape_core.py @@ -448,6 +448,12 @@ class Shape(NodeMixin, Generic[TOPODS]): @property def is_planar_face(self) -> bool: """Is the shape a planar face even though its geom_type may not be PLANE""" + warnings.warn( + "The ``is_planar_face`` property is deprecated and will be removed in a future version." + "Use ``Face.is_planar`` instead", + DeprecationWarning, + stacklevel=2, + ) if self._wrapped is None or not isinstance(self.wrapped, TopoDS_Face): return False surface = BRep_Tool.Surface_s(self.wrapped) @@ -2773,10 +2779,12 @@ class ShapeList(list[T]): # could be moved out maybe? def axis_parallel_predicate(axis: Axis, tolerance: float): def pred(shape: Shape): - if shape.is_planar_face: - assert shape.wrapped is not None and isinstance( - shape.wrapped, TopoDS_Face - ) + if ( + isinstance(shape.wrapped, TopoDS_Face) + and GeomLib_IsPlanarSurface( + BRep_Tool.Surface_s(shape.wrapped), TOLERANCE + ).IsPlanar() + ): gp_pnt = gp_Pnt() surface_normal = gp_Vec() u_val, _, v_val, _ = BRepTools.UVBounds_s(shape.wrapped) @@ -2810,10 +2818,12 @@ class ShapeList(list[T]): def pred(shape: Shape): - if shape.is_planar_face: - assert shape.wrapped is not None and isinstance( - shape.wrapped, TopoDS_Face - ) + if ( + isinstance(shape.wrapped, TopoDS_Face) + and GeomLib_IsPlanarSurface( + BRep_Tool.Surface_s(shape.wrapped), TOLERANCE + ).IsPlanar() + ): gp_pnt: gp_Pnt = gp_Pnt() surface_normal: gp_Vec = gp_Vec() u_val, _, v_val, _ = BRepTools.UVBounds_s(shape.wrapped) diff --git a/src/build123d/topology/two_d.py b/src/build123d/topology/two_d.py index 0559486..3175047 100644 --- a/src/build123d/topology/two_d.py +++ b/src/build123d/topology/two_d.py @@ -100,6 +100,7 @@ from OCP.GeomAPI import ( GeomAPI_PointsToBSplineSurface, GeomAPI_ProjectPointOnSurf, ) +from OCP.GeomLib import GeomLib_IsPlanarSurface from OCP.GeomProjLib import GeomProjLib from OCP.gp import gp_Ax1, gp_Pnt, gp_Vec from OCP.GProp import GProp_GProps @@ -872,7 +873,7 @@ class Face(Mixin2D[TopoDS_Face]): if self._wrapped is None: raise ValueError("Can't determine axes_of_symmetry of empty face") - if not self.is_planar_face: + if not self.is_planar: raise ValueError("axes_of_symmetry only supports for planar faces") cog = self.center() @@ -1062,9 +1063,11 @@ class Face(Mixin2D[TopoDS_Face]): return self._curvature_sign < -TOLERANCE @property - def is_planar(self) -> bool: - """Is the face planar even though its geom_type may not be PLANE""" - return self.is_planar_face + def is_planar(self) -> Plane | None: + """Is the face planar even though its geom_type may not be PLANE - if so return Plane""" + surface = BRep_Tool.Surface_s(self.wrapped) + planar_searcher = GeomLib_IsPlanarSurface(surface, TOLERANCE) + return Plane(planar_searcher.Plan()) if planar_searcher.IsPlanar() else None @property def length(self) -> None | float: diff --git a/tests/test_direct_api/test_face.py b/tests/test_direct_api/test_face.py index 96c93bb..fa60acf 100644 --- a/tests/test_direct_api/test_face.py +++ b/tests/test_direct_api/test_face.py @@ -1213,7 +1213,7 @@ class TestFace(unittest.TestCase): wrapped_face: Face = surface.wrap(star, target) self.assertTrue(isinstance(wrapped_face, Face)) - self.assertFalse(wrapped_face.is_planar_face) + self.assertFalse(wrapped_face.is_planar) self.assertTrue(wrapped_face.inner_wires()) wrapped_edge = surface.wrap(planar_edge, target) @@ -1266,7 +1266,7 @@ class TestFace(unittest.TestCase): text = Text(txt="ei", font_size=15, align=(Align.MIN, Align.CENTER)) wrapped_faces = surface.wrap_faces(text.faces(), path, 0.2) self.assertEqual(len(wrapped_faces), 3) - self.assertTrue(all(not f.is_planar_face for f in wrapped_faces)) + self.assertTrue(all(not f.is_planar for f in wrapped_faces)) def test_revolve(self): l1 = Edge.make_line((3, 0), (3, 2))