Moved edge/point ordering to make_constrained_arcs
Some checks are pending
benchmarks / benchmarks (macos-13, 3.12) (push) Waiting to run
benchmarks / benchmarks (macos-14, 3.12) (push) Waiting to run
benchmarks / benchmarks (ubuntu-latest, 3.12) (push) Waiting to run
benchmarks / benchmarks (windows-latest, 3.12) (push) Waiting to run
Upload coverage reports to Codecov / run (push) Waiting to run
pylint / lint (3.10) (push) Waiting to run
Run type checker / typecheck (3.10) (push) Waiting to run
Run type checker / typecheck (3.13) (push) Waiting to run
Wheel building and publishing / Build wheel on ubuntu-latest (push) Waiting to run
Wheel building and publishing / upload_pypi (push) Blocked by required conditions
tests / tests (macos-13, 3.10) (push) Waiting to run
tests / tests (macos-13, 3.13) (push) Waiting to run
tests / tests (macos-14, 3.10) (push) Waiting to run
tests / tests (macos-14, 3.13) (push) Waiting to run
tests / tests (ubuntu-latest, 3.10) (push) Waiting to run
tests / tests (ubuntu-latest, 3.13) (push) Waiting to run
tests / tests (windows-latest, 3.10) (push) Waiting to run
tests / tests (windows-latest, 3.13) (push) Waiting to run

This commit is contained in:
gumyr 2025-09-11 10:09:56 -04:00
parent 76ec798d21
commit 3b11f40d9d
2 changed files with 43 additions and 49 deletions

View file

@ -264,11 +264,11 @@ def _make_2tan_rad_arcs(
if isinstance(object_1, tuple):
object_one, object_one_constraint = object_1
else:
object_one, object_one_constraint = object_1, None
object_one, object_one_constraint = object_1, PositionConstraint.UNQUALIFIED
if isinstance(object_2, tuple):
object_two, object_two_constraint = object_2
else:
object_two, object_two_constraint = object_2, None
object_two, object_two_constraint = object_2, PositionConstraint.UNQUALIFIED
# ---------------------------
# Build inputs and GCC
@ -280,10 +280,6 @@ def _make_2tan_rad_arcs(
object_two, object_two_constraint
)
# Put the Edge arg first when exactly one is an Edge (improves robustness)
if is_edge1 ^ is_edge2:
q_o1, q_o2 = (q_o1, q_o2) if is_edge1 else (q_o2, q_o1)
gcc = Geom2dGcc_Circ2d2TanRad(q_o1, q_o2, radius, TOLERANCE)
if not gcc.IsDone() or gcc.NbSolutions() == 0:
raise RuntimeError("Unable to find a tangent arc")
@ -349,25 +345,18 @@ def _make_2tan_on_arcs(
Notes
-----
- `center_on` is treated as a **center locus** (not a tangency target). For a line
locus this uses Geom2dGcc_Circ2d2TanOn; for other 2D curves it uses the *Geo variant*.
- A point is NOT a valid center locus for the 2TanOn solver; use the TanCen variant
(fixed center) for that case.
- `center_on` is treated as a **center locus** (not a tangency target).
"""
# Unpack optional qualifiers on the two tangency args
object_one_constraint = PositionConstraint.UNQUALIFIED
object_two_constraint = PositionConstraint.UNQUALIFIED
if isinstance(object_1, tuple):
object_one, object_one_constraint = object_1
else:
object_one = object_1
object_one, object_one_constraint = object_1, PositionConstraint.UNQUALIFIED
if isinstance(object_2, tuple):
object_two, object_two_constraint = object_2
else:
object_two = object_2
object_two, object_two_constraint = object_2, PositionConstraint.UNQUALIFIED
# ---------------------------
# Build tangency inputs
@ -379,17 +368,6 @@ def _make_2tan_on_arcs(
object_two, object_two_constraint
)
# Prefer "edge-first" ordering when exactly one arg is an Edge
if is_edge1 ^ is_edge2:
q_o1, q_o2 = (q_o1, q_o2) if is_edge1 else (q_o2, q_o1)
h_e1, h_e2 = (h_e1, h_e2) if is_edge1 else (h_e2, h_e1)
e1_first, e1_last, e2_first, e2_last = (
(e1_first, e1_last, e2_first, e2_last)
if is_edge1
else (e2_first, e2_last, e1_first, e1_last)
)
is_edge1, is_edge2 = (True, False) if is_edge1 else (False, True)
# ---------------------------
# Build center locus ("On") input
# ---------------------------
@ -404,7 +382,10 @@ def _make_2tan_on_arcs(
guesses.append((e2_last - e2_first) / 2 + e2_first)
guesses.append((on_last - on_first) / 2 + on_first)
if is_edge1 or is_edge2:
gcc = Geom2dGcc_Circ2d2TanOn(q_o1, q_o2, adapt_on, TOLERANCE, *guesses)
else:
gcc = Geom2dGcc_Circ2d2TanOn(q_o1, q_o2, adapt_on, TOLERANCE)
if not gcc.IsDone() or gcc.NbSolutions() == 0:
raise RuntimeError("Unable to find a tangent arc with center_on constraint")
@ -510,10 +491,15 @@ def _make_3tan_arcs(
q_o2, h_e2, e2_first, e2_last, is_edge2 = _as_gcc_arg(object_two, obj2_qual)
q_o3, h_e3, e3_first, e3_last, is_edge3 = _as_gcc_arg(object_three, obj3_qual)
guesses = [
(l - f) / 2 + f
for f, l in [(e1_first, e1_last), (e2_first, e2_last), (e3_first, e3_last)]
]
# Provide initial guess parameters for all of the lines
guesses = []
if is_edge1:
guesses.append((e1_last - e1_first) / 2 + e1_first)
if is_edge2:
guesses.append((e2_last - e2_first) / 2 + e2_first)
if is_edge3:
guesses.append((e3_last - e3_first) / 2 + e3_first)
# For 3Tan we keep the user-given order so the arc endpoints remain (arg1,arg2)
gcc = Geom2dGcc_Circ2d3Tan(q_o1, q_o2, q_o3, TOLERANCE, *guesses)
if not gcc.IsDone() or gcc.NbSolutions() == 0:

View file

@ -1588,8 +1588,8 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]):
@classmethod
def make_constrained_arcs(
cls,
tangency_one: tuple[Edge, PositionConstraint] | Vertex | VectorLike,
tangency_two: tuple[Edge, PositionConstraint] | Vertex | VectorLike,
tangency_one: tuple[Edge, PositionConstraint] | Edge | Vertex | VectorLike,
tangency_two: tuple[Edge, PositionConstraint] | Edge | Vertex | VectorLike,
*,
radius: float,
sagitta_constraint: LengthConstraint = LengthConstraint.SHORT,
@ -1598,8 +1598,8 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]):
Create all planar circular arcs of a given radius that are tangent/contacting
the two provided objects on the XY plane.
Args:
tangency_one (tuple[Edge, PositionConstraint] | Vertex | VectorLike):
tangency_two (tuple[Edge, PositionConstraint] | Vertex | VectorLike):
tangency_one (tuple[Edge, PositionConstraint] | Edge | Vertex | VectorLike):
tangency_two (tuple[Edge, PositionConstraint] | Edge | Vertex | VectorLike):
Geometric entities to be contacted/touched by the circle(s)
radius (float): arc radius
sagitta_constraint (LengthConstraint, optional): returned arc selector
@ -1614,8 +1614,8 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]):
@classmethod
def make_constrained_arcs(
cls,
tangency_one: tuple[Edge, PositionConstraint] | Vertex | VectorLike,
tangency_two: tuple[Edge, PositionConstraint] | Vertex | VectorLike,
tangency_one: tuple[Edge, PositionConstraint] | Edge | Vertex | VectorLike,
tangency_two: tuple[Edge, PositionConstraint] | Edge | Vertex | VectorLike,
*,
center_on: Edge,
sagitta_constraint: LengthConstraint = LengthConstraint.SHORT,
@ -1625,8 +1625,8 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]):
CENTER lies on a given locus (line/circle/curve) on the XY plane.
Args:
tangency_one (tuple[Edge, PositionConstraint] | Vertex | VectorLike):
tangency_two (tuple[Edge, PositionConstraint] | Vertex | VectorLike):
tangency_one (tuple[Edge, PositionConstraint] | Edge | Vertex | VectorLike):
tangency_two (tuple[Edge, PositionConstraint] | Edge | Vertex | VectorLike):
Geometric entities to be contacted/touched by the circle(s)
center_on (Edge): center must lie on this edge
sagitta_constraint (LengthConstraint, optional): returned arc selector
@ -1641,9 +1641,9 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]):
@classmethod
def make_constrained_arcs(
cls,
tangency_one: tuple[Edge, PositionConstraint] | Vertex | VectorLike,
tangency_two: tuple[Edge, PositionConstraint] | Vertex | VectorLike,
tangency_three: tuple[Edge, PositionConstraint] | Vertex | VectorLike,
tangency_one: tuple[Edge, PositionConstraint] | Edge | Vertex | VectorLike,
tangency_two: tuple[Edge, PositionConstraint] | Edge | Vertex | VectorLike,
tangency_three: tuple[Edge, PositionConstraint] | Edge | Vertex | VectorLike,
*,
sagitta_constraint: LengthConstraint = LengthConstraint.SHORT,
) -> ShapeList[Edge]:
@ -1651,9 +1651,9 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]):
Create planar circular arc(s) on XY tangent to three provided objects.
Args:
tangency_one (tuple[Edge, PositionConstraint] | Vertex | VectorLike):
tangency_two (tuple[Edge, PositionConstraint] | Vertex | VectorLike):
tangency_three (tuple[Edge, PositionConstraint] | Vertex | VectorLike):
tangency_one (tuple[Edge, PositionConstraint] | Edge | Vertex | VectorLike):
tangency_two (tuple[Edge, PositionConstraint] | Edge | Vertex | VectorLike):
tangency_three (tuple[Edge, PositionConstraint] | Edge | Vertex | VectorLike):
Geometric entities to be contacted/touched by the circle(s)
sagitta_constraint (LengthConstraint, optional): returned arc selector
(i.e. either the short, long or both arcs). Defaults to
@ -1667,7 +1667,7 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]):
@classmethod
def make_constrained_arcs(
cls,
tangency_one: tuple[Edge, PositionConstraint] | Vertex | VectorLike,
tangency_one: tuple[Edge, PositionConstraint] | Edge | Vertex | VectorLike,
*,
center: VectorLike,
) -> ShapeList[Edge]:
@ -1677,7 +1677,7 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]):
a single object.
Args:
tangency_one (tuple[Edge, PositionConstraint] | Vertex | VectorLike):
tangency_one (tuple[Edge, PositionConstraint] | Edge | Vertex | VectorLike):
Geometric entity to be contacted/touched by the circle(s)
center (VectorLike): center position
@ -1689,7 +1689,7 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]):
@classmethod
def make_constrained_arcs(
cls,
tangency_one: tuple[Edge, PositionConstraint] | Vertex | VectorLike,
tangency_one: tuple[Edge, PositionConstraint] | Edge | Vertex | VectorLike,
*,
radius: float,
center_on: Edge,
@ -1742,6 +1742,14 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]):
tangencies = [
t for t in (tangency_one, tangency_two, tangency_three) if t is not None
]
# Sort the tangency inputs so points are always last
tangent_tuples = [t if isinstance(t, tuple) else (t, None) for t in tangencies]
tangent_tuples = sorted(
tangent_tuples, key=lambda t: not issubclass(type(t[0]), Edge)
)
tangencies = [t[0] if t[1] is None else t for t in tangent_tuples]
tan_count = len(tangencies)
if not (1 <= tan_count <= 3):
raise TypeError("Provide 1 to 3 tangency targets.")