From 2d82b2ca5cde5b1ad50e23ac2eb9ededd388f2fe Mon Sep 17 00:00:00 2001 From: gumyr Date: Tue, 25 Nov 2025 11:27:17 -0500 Subject: [PATCH] Adding tests for positions with deflection --- src/build123d/topology/one_d.py | 9 +++- tests/test_direct_api/test_mixin1_d.py | 63 +++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/src/build123d/topology/one_d.py b/src/build123d/topology/one_d.py index d416be0..231b844 100644 --- a/src/build123d/topology/one_d.py +++ b/src/build123d/topology/one_d.py @@ -373,7 +373,10 @@ class Mixin1D(Shape[TOPODS]): def _to_param(edge_wire: Mixin1D, value: float | VectorLike, name: str) -> float: """Convert a float or VectorLike into a curve parameter.""" if isinstance(value, (int, float)): - return float(value) + if edge_wire.is_forward: + return float(value) + else: + return 1.0 - float(value) try: point = Vector(value) except TypeError as exc: @@ -1209,7 +1212,9 @@ class Mixin1D(Shape[TOPODS]): curve: BRepAdaptor_Curve | BRepAdaptor_CompCurve = self.geom_adaptor() # GCPnts_UniformDeflection provides the best results but is limited if curve.Continuity() in (GeomAbs_C2, GeomAbs_C3, GeomAbs_CN): - discretizer = GCPnts_UniformDeflection() + discretizer: ( + GCPnts_UniformDeflection | GCPnts_QuasiUniformDeflection + ) = GCPnts_UniformDeflection() else: discretizer = GCPnts_QuasiUniformDeflection() diff --git a/tests/test_direct_api/test_mixin1_d.py b/tests/test_direct_api/test_mixin1_d.py index 1d7791b..efd4989 100644 --- a/tests/test_direct_api/test_mixin1_d.py +++ b/tests/test_direct_api/test_mixin1_d.py @@ -28,6 +28,7 @@ license: import math import unittest +from unittest.mock import patch from build123d.build_enums import ( CenterOf, @@ -106,13 +107,73 @@ class TestMixin1D(unittest.TestCase): 5, ) - def test_positions(self): + def test_positions_with_distances(self): e = Edge.make_line((0, 0, 0), (1, 1, 1)) distances = [i / 4 for i in range(3)] pts = e.positions(distances) for i, position in enumerate(pts): self.assertAlmostEqual(position, (i / 4, i / 4, i / 4), 5) + def test_positions_deflection_line(self): + """Deflection sampling on a straight line should yield exactly 2 points.""" + e = Edge.make_line((0, 0, 0), (10, 0, 0)) + pts = e.positions(deflection=0.1) + + self.assertEqual(len(pts), 2) + self.assertAlmostEqual(pts[0], (0, 0, 0), 7) + self.assertAlmostEqual(pts[1], (10, 0, 0), 7) + + def test_positions_deflection_circle(self): + """Deflection on a C2 curve (circle) should produce multiple points.""" + radius = 5 + e = Edge.make_circle(radius) + + pts = e.positions(deflection=0.1) + + # Should produce more than just two points + self.assertGreater(len(pts), 2) + + # Endpoints should match curve endpoints + first, last = pts[0], pts[-1] + curve = e.geom_adaptor() + p0 = Vector(curve.Value(curve.FirstParameter())) + p1 = Vector(curve.Value(curve.LastParameter())) + + self.assertAlmostEqual(first, p0, 7) + self.assertAlmostEqual(last, p1, 7) + + def test_positions_deflection_resolution(self): + """Smaller deflection tolerance should produce more points.""" + e = Edge.make_circle(10) + + pts_coarse = e.positions(deflection=0.5) + pts_fine = e.positions(deflection=0.05) + + self.assertGreater(len(pts_fine), len(pts_coarse)) + + def test_positions_deflection_C0_curve(self): + """C0 spline should use QuasiUniformDeflection and still succeed.""" + e = Polyline((0, 0), (1, 2), (2, 0))._to_bspline() # C0 + pts = e.positions(deflection=0.1) + + self.assertGreater(len(pts), 2) + + def test_positions_missing_arguments(self): + e = Edge.make_line((0, 0, 0), (1, 0, 0)) + with self.assertRaises(ValueError): + e.positions() + + def test_positions_deflection_failure(self): + e = Edge.make_circle(1.0) + + with patch("build123d.edge.GCPnts_UniformDeflection") as MockDefl: + instance = MockDefl.return_value + instance.IsDone.return_value = False + instance.NbPoints.return_value = 0 + + with self.assertRaises(RuntimeError): + e.positions(deflection=0.1) + def test_tangent_at(self): self.assertAlmostEqual( Edge.make_circle(1, start_angle=0, end_angle=90).tangent_at(1.0),