From 6ac2e67a2eed74bca1c397bd61332c139cbbbb8f Mon Sep 17 00:00:00 2001 From: gumyr Date: Wed, 1 Oct 2025 19:13:51 -0400 Subject: [PATCH] Fixed typing problems --- src/build123d/topology/constrained_lines.py | 57 +++++++++++++++------ src/build123d/topology/one_d.py | 21 ++++++-- 2 files changed, 57 insertions(+), 21 deletions(-) diff --git a/src/build123d/topology/constrained_lines.py b/src/build123d/topology/constrained_lines.py index 914eed7..12329da 100644 --- a/src/build123d/topology/constrained_lines.py +++ b/src/build123d/topology/constrained_lines.py @@ -30,12 +30,12 @@ license: from __future__ import annotations from math import atan2, cos, sin -from typing import TYPE_CHECKING, Callable, TypeVar +from typing import overload, TYPE_CHECKING, Callable, TypeVar from typing import cast as tcast from OCP.BRep import BRep_Tool from OCP.BRepAdaptor import BRepAdaptor_Curve -from OCP.BRepBuilderAPI import BRepBuilderAPI_MakeEdge +from OCP.BRepBuilderAPI import BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeVertex from OCP.GCPnts import GCPnts_AbscissaPoint from OCP.Geom import Geom_Curve, Geom_Plane from OCP.Geom2d import ( @@ -71,7 +71,7 @@ from OCP.gp import ( ) from OCP.IntAna2d import IntAna2d_AnaIntersection from OCP.Standard import Standard_ConstructionError, Standard_Failure -from OCP.TopoDS import TopoDS_Edge +from OCP.TopoDS import TopoDS_Edge, TopoDS_Vertex from build123d.build_enums import Sagitta, Tangency from build123d.geometry import Axis, TOLERANCE, Vector, VectorLike @@ -154,6 +154,18 @@ def _param_in_trim( return (u >= first - TOLERANCE) and (u <= last + TOLERANCE) +@overload +def _as_gcc_arg( + obj: Edge, constaint: Tangency +) -> tuple[ + Geom2dGcc_QualifiedCurve, Geom2d_Curve | None, float | None, float | None, bool +]: ... +@overload +def _as_gcc_arg( + obj: Vector, constaint: Tangency +) -> tuple[Geom2d_CartesianPoint, None, None, None, bool]: ... + + def _as_gcc_arg(obj: Edge | Vector, constaint: Tangency) -> tuple[ Geom2dGcc_QualifiedCurve | Geom2d_CartesianPoint, Geom2d_Curve | None, @@ -221,9 +233,10 @@ def _edge_from_line( TopoDS_Edge Finite line segment between the two points. """ - mk_edge = BRepBuilderAPI_MakeEdge( - Vertex(p1.X(), p1.Y()).wrapped, Vertex(p2.X(), p2.Y()).wrapped - ) + v1 = BRepBuilderAPI_MakeVertex(gp_Pnt(p1.X(), p1.Y(), 0)).Vertex() + v2 = BRepBuilderAPI_MakeVertex(gp_Pnt(p2.X(), p2.Y(), 0)).Vertex() + + mk_edge = BRepBuilderAPI_MakeEdge(v1, v2) if not mk_edge.IsDone(): raise RuntimeError("Failed to build edge from line contacts") return mk_edge.Edge() @@ -689,8 +702,8 @@ def _make_tan_on_rad_arcs( def _make_2tan_lines( - curve1: Edge, - curve2: Edge | Vector, + tangency1: tuple[Edge, Tangency] | Edge, + tangency2: tuple[Edge, Tangency] | Edge | Vector, *, edge_factory: Callable[[TopoDS_Edge], Edge], ) -> ShapeList[Edge]: @@ -707,19 +720,27 @@ def _make_2tan_lines( ShapeList[Edge] Finite tangent line(s). """ - q1, _, _, _, _ = _as_gcc_arg(curve1, Tangency.UNQUALIFIED) + if isinstance(tangency1, tuple): + object_one, obj1_qual = tangency1 + else: + object_one, obj1_qual = tangency1, Tangency.UNQUALIFIED + q1, _, _, _, _ = _as_gcc_arg(object_one, obj1_qual) - if isinstance(curve2, Vector): - pnt_2d = gp_Pnt2d(curve2.X, curve2.Y) + if isinstance(tangency2, Vector): + pnt_2d = gp_Pnt2d(tangency2.X, tangency2.Y) gcc = Geom2dGcc_Lin2d2Tan(q1, pnt_2d, TOLERANCE) else: - q2, _, _, _, _ = _as_gcc_arg(curve2, Tangency.UNQUALIFIED) + if isinstance(tangency2, tuple): + object_two, obj2_qual = tangency2 + else: + object_two, obj2_qual = tangency2, Tangency.UNQUALIFIED + q2, _, _, _, _ = _as_gcc_arg(object_two, obj2_qual) gcc = Geom2dGcc_Lin2d2Tan(q1, q2, TOLERANCE) if not gcc.IsDone() or gcc.NbSolutions() == 0: raise RuntimeError("Unable to find common tangent line(s)") - out_edges: list[Edge] = [] + out_edges: list[TopoDS_Edge] = [] for i in range(1, gcc.NbSolutions() + 1): # Two tangency points p1, p2 = gp_Pnt2d(), gp_Pnt2d() @@ -732,9 +753,9 @@ def _make_2tan_lines( def _make_tan_oriented_lines( - curve: Edge, + tangency: tuple[Edge, Tangency] | Edge, reference: Axis, - angle: float | None = None, # radians; absolute angle offset from `reference` + angle: float, # radians; absolute angle offset from `reference` *, edge_factory: Callable[[TopoDS_Edge], Edge], ) -> ShapeList[Edge]: @@ -744,7 +765,11 @@ def _make_tan_oriented_lines( - the tangency point on the curve, and - the intersection with the reference line. """ - q_curve, _, _, _, _ = _as_gcc_arg(curve, Tangency.UNQUALIFIED) + if isinstance(tangency, tuple): + object_one, obj1_qual = tangency + else: + object_one, obj1_qual = tangency, Tangency.UNQUALIFIED + q_curve, _, _, _, _ = _as_gcc_arg(object_one, obj1_qual) # reference axis direction (2D angle in radians) ref_dir = reference.direction diff --git a/src/build123d/topology/one_d.py b/src/build123d/topology/one_d.py index e5847a4..2018474 100644 --- a/src/build123d/topology/one_d.py +++ b/src/build123d/topology/one_d.py @@ -1871,7 +1871,7 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]): @classmethod def make_constrained_lines( cls, - tangency_one: Edge, + tangency_one: tuple[Axis | Edge, Tangency] | Axis | Edge, tangency_two: Axis, *, angle: float | None = None, @@ -1913,6 +1913,7 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]): angle = kwargs.pop("angle", None) direction = kwargs.pop("direction", None) + is_ref = angle is not None or direction is not None # Handle unexpected kwargs if kwargs: raise TypeError(f"Unexpected argument(s): {', '.join(kwargs.keys())}") @@ -1921,10 +1922,13 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]): if len(tangency_args) != 2: raise TypeError("Provide exactly 2 tangency targets.") - tangencies: list[tuple[Edge, Tangency] | Edge | Vector] = [] - for tangency_arg in tangency_args: + tangencies: list[tuple[Edge, Tangency] | Axis | Edge | Vector] = [] + for i, tangency_arg in enumerate(tangency_args): if isinstance(tangency_arg, Axis): - tangencies.append(tangency_arg) + if i == 1 and is_ref: + tangencies.append(tangency_arg) + else: + tangencies.append(Edge(tangency_arg)) continue elif isinstance(tangency_arg, Edge): tangencies.append(tangency_arg) @@ -1942,11 +1946,14 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]): except Exception as exc: raise TypeError(f"Invalid tangency: {tangency_arg!r}") from exc - # Sort so Vector (point) is always last + # Sort so Vector (point) | Axis is always last tangencies = sorted(tangencies, key=lambda x: isinstance(x, (Axis, Vector))) # --- decide problem kind --- if isinstance(tangencies[1], Axis): + assert isinstance( + tangencies[0], Edge + ), "Internal error - 1st tangency must be Edge" if angle is not None: ang_rad = radians(angle) elif direction is not None: @@ -1957,6 +1964,10 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]): tangencies[0], tangencies[1], ang_rad, edge_factory=cls ) else: + assert not isinstance( + tangencies[0], (Axis, Vector) + ), "Internal error - 1st tangency can't be an Axis | Vector" + return _make_2tan_lines(tangencies[0], tangencies[1], edge_factory=cls) @classmethod