Fixed typing problems
Some checks failed
benchmarks / benchmarks (macos-13, 3.12) (push) Has been cancelled
benchmarks / benchmarks (macos-14, 3.12) (push) Has been cancelled
benchmarks / benchmarks (ubuntu-latest, 3.12) (push) Has been cancelled
benchmarks / benchmarks (windows-latest, 3.12) (push) Has been cancelled
Upload coverage reports to Codecov / run (push) Has been cancelled
pylint / lint (3.10) (push) Has been cancelled
Run type checker / typecheck (3.10) (push) Has been cancelled
Run type checker / typecheck (3.13) (push) Has been cancelled
Wheel building and publishing / Build wheel on ubuntu-latest (push) Has been cancelled
tests / tests (macos-13, 3.10) (push) Has been cancelled
tests / tests (macos-13, 3.13) (push) Has been cancelled
tests / tests (macos-14, 3.10) (push) Has been cancelled
tests / tests (macos-14, 3.13) (push) Has been cancelled
tests / tests (ubuntu-latest, 3.10) (push) Has been cancelled
tests / tests (ubuntu-latest, 3.13) (push) Has been cancelled
tests / tests (windows-latest, 3.10) (push) Has been cancelled
tests / tests (windows-latest, 3.13) (push) Has been cancelled
Wheel building and publishing / upload_pypi (push) Has been cancelled

This commit is contained in:
gumyr 2025-10-01 19:13:51 -04:00
parent 59a6e3623f
commit 6ac2e67a2e
2 changed files with 57 additions and 21 deletions

View file

@ -30,12 +30,12 @@ license:
from __future__ import annotations from __future__ import annotations
from math import atan2, cos, sin 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 typing import cast as tcast
from OCP.BRep import BRep_Tool from OCP.BRep import BRep_Tool
from OCP.BRepAdaptor import BRepAdaptor_Curve 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.GCPnts import GCPnts_AbscissaPoint
from OCP.Geom import Geom_Curve, Geom_Plane from OCP.Geom import Geom_Curve, Geom_Plane
from OCP.Geom2d import ( from OCP.Geom2d import (
@ -71,7 +71,7 @@ from OCP.gp import (
) )
from OCP.IntAna2d import IntAna2d_AnaIntersection from OCP.IntAna2d import IntAna2d_AnaIntersection
from OCP.Standard import Standard_ConstructionError, Standard_Failure 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.build_enums import Sagitta, Tangency
from build123d.geometry import Axis, TOLERANCE, Vector, VectorLike from build123d.geometry import Axis, TOLERANCE, Vector, VectorLike
@ -154,6 +154,18 @@ def _param_in_trim(
return (u >= first - TOLERANCE) and (u <= last + TOLERANCE) 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[ def _as_gcc_arg(obj: Edge | Vector, constaint: Tangency) -> tuple[
Geom2dGcc_QualifiedCurve | Geom2d_CartesianPoint, Geom2dGcc_QualifiedCurve | Geom2d_CartesianPoint,
Geom2d_Curve | None, Geom2d_Curve | None,
@ -221,9 +233,10 @@ def _edge_from_line(
TopoDS_Edge TopoDS_Edge
Finite line segment between the two points. Finite line segment between the two points.
""" """
mk_edge = BRepBuilderAPI_MakeEdge( v1 = BRepBuilderAPI_MakeVertex(gp_Pnt(p1.X(), p1.Y(), 0)).Vertex()
Vertex(p1.X(), p1.Y()).wrapped, Vertex(p2.X(), p2.Y()).wrapped v2 = BRepBuilderAPI_MakeVertex(gp_Pnt(p2.X(), p2.Y(), 0)).Vertex()
)
mk_edge = BRepBuilderAPI_MakeEdge(v1, v2)
if not mk_edge.IsDone(): if not mk_edge.IsDone():
raise RuntimeError("Failed to build edge from line contacts") raise RuntimeError("Failed to build edge from line contacts")
return mk_edge.Edge() return mk_edge.Edge()
@ -689,8 +702,8 @@ def _make_tan_on_rad_arcs(
def _make_2tan_lines( def _make_2tan_lines(
curve1: Edge, tangency1: tuple[Edge, Tangency] | Edge,
curve2: Edge | Vector, tangency2: tuple[Edge, Tangency] | Edge | Vector,
*, *,
edge_factory: Callable[[TopoDS_Edge], Edge], edge_factory: Callable[[TopoDS_Edge], Edge],
) -> ShapeList[Edge]: ) -> ShapeList[Edge]:
@ -707,19 +720,27 @@ def _make_2tan_lines(
ShapeList[Edge] ShapeList[Edge]
Finite tangent line(s). 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): if isinstance(tangency2, Vector):
pnt_2d = gp_Pnt2d(curve2.X, curve2.Y) pnt_2d = gp_Pnt2d(tangency2.X, tangency2.Y)
gcc = Geom2dGcc_Lin2d2Tan(q1, pnt_2d, TOLERANCE) gcc = Geom2dGcc_Lin2d2Tan(q1, pnt_2d, TOLERANCE)
else: 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) gcc = Geom2dGcc_Lin2d2Tan(q1, q2, TOLERANCE)
if not gcc.IsDone() or gcc.NbSolutions() == 0: if not gcc.IsDone() or gcc.NbSolutions() == 0:
raise RuntimeError("Unable to find common tangent line(s)") 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): for i in range(1, gcc.NbSolutions() + 1):
# Two tangency points # Two tangency points
p1, p2 = gp_Pnt2d(), gp_Pnt2d() p1, p2 = gp_Pnt2d(), gp_Pnt2d()
@ -732,9 +753,9 @@ def _make_2tan_lines(
def _make_tan_oriented_lines( def _make_tan_oriented_lines(
curve: Edge, tangency: tuple[Edge, Tangency] | Edge,
reference: Axis, 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], edge_factory: Callable[[TopoDS_Edge], Edge],
) -> ShapeList[Edge]: ) -> ShapeList[Edge]:
@ -744,7 +765,11 @@ def _make_tan_oriented_lines(
- the tangency point on the curve, and - the tangency point on the curve, and
- the intersection with the reference line. - 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) # reference axis direction (2D angle in radians)
ref_dir = reference.direction ref_dir = reference.direction

View file

@ -1871,7 +1871,7 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]):
@classmethod @classmethod
def make_constrained_lines( def make_constrained_lines(
cls, cls,
tangency_one: Edge, tangency_one: tuple[Axis | Edge, Tangency] | Axis | Edge,
tangency_two: Axis, tangency_two: Axis,
*, *,
angle: float | None = None, angle: float | None = None,
@ -1913,6 +1913,7 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]):
angle = kwargs.pop("angle", None) angle = kwargs.pop("angle", None)
direction = kwargs.pop("direction", None) direction = kwargs.pop("direction", None)
is_ref = angle is not None or direction is not None
# Handle unexpected kwargs # Handle unexpected kwargs
if kwargs: if kwargs:
raise TypeError(f"Unexpected argument(s): {', '.join(kwargs.keys())}") raise TypeError(f"Unexpected argument(s): {', '.join(kwargs.keys())}")
@ -1921,10 +1922,13 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]):
if len(tangency_args) != 2: if len(tangency_args) != 2:
raise TypeError("Provide exactly 2 tangency targets.") raise TypeError("Provide exactly 2 tangency targets.")
tangencies: list[tuple[Edge, Tangency] | Edge | Vector] = [] tangencies: list[tuple[Edge, Tangency] | Axis | Edge | Vector] = []
for tangency_arg in tangency_args: for i, tangency_arg in enumerate(tangency_args):
if isinstance(tangency_arg, Axis): 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 continue
elif isinstance(tangency_arg, Edge): elif isinstance(tangency_arg, Edge):
tangencies.append(tangency_arg) tangencies.append(tangency_arg)
@ -1942,11 +1946,14 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]):
except Exception as exc: except Exception as exc:
raise TypeError(f"Invalid tangency: {tangency_arg!r}") from 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))) tangencies = sorted(tangencies, key=lambda x: isinstance(x, (Axis, Vector)))
# --- decide problem kind --- # --- decide problem kind ---
if isinstance(tangencies[1], Axis): if isinstance(tangencies[1], Axis):
assert isinstance(
tangencies[0], Edge
), "Internal error - 1st tangency must be Edge"
if angle is not None: if angle is not None:
ang_rad = radians(angle) ang_rad = radians(angle)
elif direction is not None: elif direction is not None:
@ -1957,6 +1964,10 @@ class Edge(Mixin1D, Shape[TopoDS_Edge]):
tangencies[0], tangencies[1], ang_rad, edge_factory=cls tangencies[0], tangencies[1], ang_rad, edge_factory=cls
) )
else: 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) return _make_2tan_lines(tangencies[0], tangencies[1], edge_factory=cls)
@classmethod @classmethod