mirror of
https://github.com/gumyr/build123d.git
synced 2025-12-06 02:30:55 -08:00
Replaced Axis.as_infinite_edge with Edge __init__ method Issue #648
This commit is contained in:
parent
b40bcf9a24
commit
ce20991745
3 changed files with 107 additions and 107 deletions
|
|
@ -37,6 +37,8 @@ from __future__ import annotations
|
|||
import copy
|
||||
import json
|
||||
import logging
|
||||
import numpy as np
|
||||
|
||||
from math import degrees, pi, radians
|
||||
from typing import (
|
||||
Any,
|
||||
|
|
@ -798,9 +800,31 @@ class Axis(metaclass=AxisMeta):
|
|||
if self.is_coaxial(axis):
|
||||
return self
|
||||
else:
|
||||
pnt = self.as_infinite_edge().intersect(axis.as_infinite_edge())
|
||||
if pnt is not None:
|
||||
return Vector(pnt)
|
||||
# Extract points and directions to numpy arrays
|
||||
p1 = np.array([*self.position])
|
||||
d1 = np.array([*self.direction])
|
||||
p2 = np.array([*axis.position])
|
||||
d2 = np.array([*axis.direction])
|
||||
|
||||
# Compute the cross product of directions
|
||||
cross_d1_d2 = np.cross(d1, d2)
|
||||
cross_d1_d2_norm = np.linalg.norm(cross_d1_d2)
|
||||
|
||||
if cross_d1_d2_norm < TOLERANCE:
|
||||
# The directions are parallel
|
||||
return None
|
||||
|
||||
# Solve the system of equations to find the intersection
|
||||
system_of_equations = np.array([d1, -d2, cross_d1_d2]).T
|
||||
origin_diff = p2 - p1
|
||||
try:
|
||||
t1, t2, _ = np.linalg.solve(system_of_equations, origin_diff)
|
||||
except np.linalg.LinAlgError:
|
||||
return None # The lines do not intersect
|
||||
|
||||
# Calculate the intersection point
|
||||
intersection_point = p1 + t1 * d1
|
||||
return Vector(*intersection_point)
|
||||
|
||||
elif plane is not None:
|
||||
return plane.intersect(self)
|
||||
|
|
|
|||
|
|
@ -2570,7 +2570,7 @@ class Shape(NodeMixin):
|
|||
return return_value
|
||||
|
||||
def _intersect_with_axis(self, *axes: Axis) -> Shape:
|
||||
lines = [a.as_infinite_edge() for a in axes]
|
||||
lines = [Edge(a) for a in axes]
|
||||
return self.intersect(*lines)
|
||||
|
||||
def _intersect_with_plane(self, *planes: Plane) -> Shape:
|
||||
|
|
@ -2594,7 +2594,7 @@ class Shape(NodeMixin):
|
|||
if isinstance(obj, Vector):
|
||||
objs.append(Vertex(obj))
|
||||
elif isinstance(obj, Axis):
|
||||
objs.append(obj.as_infinite_edge())
|
||||
objs.append(Edge(obj))
|
||||
elif isinstance(obj, Plane):
|
||||
objs.append(Face.make_plane(obj))
|
||||
elif isinstance(obj, Location):
|
||||
|
|
@ -4401,6 +4401,77 @@ class Edge(Mixin1D, Shape):
|
|||
|
||||
_dim = 1
|
||||
|
||||
@overload
|
||||
def __init__(
|
||||
self,
|
||||
obj: TopoDS_Shape,
|
||||
label: str = "",
|
||||
color: Color = None,
|
||||
parent: Compound = None,
|
||||
):
|
||||
"""Build an Edge from an OCCT TopoDS_Shape/TopoDS_Edge
|
||||
|
||||
Args:
|
||||
obj (TopoDS_Shape, optional): OCCT Face.
|
||||
label (str, optional): Defaults to ''.
|
||||
color (Color, optional): Defaults to None.
|
||||
parent (Compound, optional): assembly parent. Defaults to None.
|
||||
"""
|
||||
|
||||
@overload
|
||||
def __init__(
|
||||
self,
|
||||
axis: Axis,
|
||||
label: str = "",
|
||||
color: Color = None,
|
||||
parent: Compound = None,
|
||||
):
|
||||
"""Build an infinite Edge from an Axis
|
||||
|
||||
Args:
|
||||
axis (Axis): Axis to be converted to an infinite Edge
|
||||
label (str, optional): Defaults to ''.
|
||||
color (Color, optional): Defaults to None.
|
||||
parent (Compound, optional): assembly parent. Defaults to None.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
axis, obj, label, color, parent = (None,) * 5
|
||||
|
||||
if args:
|
||||
l_a = len(args)
|
||||
if isinstance(args[0], TopoDS_Shape):
|
||||
obj, label, color, parent = args[:4] + (None,) * (4 - l_a)
|
||||
elif isinstance(args[0], Axis):
|
||||
axis, label, color, parent = args[:4] + (None,) * (4 - l_a)
|
||||
|
||||
unknown_args = ", ".join(
|
||||
set(kwargs.keys()).difference(["axis", "obj", "label", "color", "parent"])
|
||||
)
|
||||
if unknown_args:
|
||||
raise ValueError(f"Unexpected argument(s) {unknown_args}")
|
||||
|
||||
obj = kwargs.get("obj", obj)
|
||||
axis = kwargs.get("axis", axis)
|
||||
label = kwargs.get("label", label)
|
||||
color = kwargs.get("color", color)
|
||||
parent = kwargs.get("parent", parent)
|
||||
|
||||
if axis is not None:
|
||||
obj = BRepBuilderAPI_MakeEdge(
|
||||
Geom_Line(
|
||||
axis.position.to_pnt(),
|
||||
axis.direction.to_dir(),
|
||||
)
|
||||
).Edge()
|
||||
|
||||
super().__init__(
|
||||
obj=obj,
|
||||
label="" if label is None else label,
|
||||
color=color,
|
||||
parent=parent,
|
||||
)
|
||||
|
||||
def _geom_adaptor(self) -> BRepAdaptor_Curve:
|
||||
""" """
|
||||
return BRepAdaptor_Curve(self.wrapped)
|
||||
|
|
@ -4513,14 +4584,10 @@ class Edge(Mixin1D, Shape):
|
|||
|
||||
# Find Edge/Edge overlaps
|
||||
intersect_op = BRepAlgoAPI_Common()
|
||||
edge_intersections = self._bool_op(
|
||||
(self,), (axis.as_infinite_edge(),), intersect_op
|
||||
).edges()
|
||||
edge_intersections = self._bool_op((self,), (Edge(axis),), intersect_op).edges()
|
||||
|
||||
return Compound(vertex_intersections + edge_intersections)
|
||||
|
||||
# return self._intersect_with_edge(axis.as_infinite_edge())
|
||||
|
||||
def find_intersection_points(
|
||||
self, edge: Union[Axis, Edge] = None, tolerance: float = TOLERANCE
|
||||
) -> ShapeList[Vector]:
|
||||
|
|
@ -8665,98 +8732,3 @@ class SkipClean:
|
|||
|
||||
def __exit__(self, exception_type, exception_value, traceback):
|
||||
SkipClean.clean = True
|
||||
|
||||
|
||||
# Monkey-patched Axis and Plane methods that take Shapes as arguments
|
||||
def _axis_as_infinite_edge(self: Axis) -> Edge:
|
||||
"""return an edge with infinite length along self"""
|
||||
return Edge(
|
||||
BRepBuilderAPI_MakeEdge(
|
||||
Geom_Line(
|
||||
self.position.to_pnt(),
|
||||
self.direction.to_dir(),
|
||||
)
|
||||
).Edge()
|
||||
)
|
||||
|
||||
|
||||
Axis.as_infinite_edge = _axis_as_infinite_edge
|
||||
|
||||
|
||||
# def _axis_intersect(self: Axis, *to_intersect: Union[Shape, Axis, Plane]) -> Shape:
|
||||
# """axis intersect
|
||||
|
||||
# Args:
|
||||
# to_intersect (sequence of Union[Shape, Axis, Plane]): objects to intersect
|
||||
# with Axis.
|
||||
|
||||
# Returns:
|
||||
# Shape: result of intersection
|
||||
# """
|
||||
# self_i_edge: Edge = self.as_infinite_edge()
|
||||
# self_as_curve = Geom_Line(self.position.to_pnt(), self.direction.to_dir())
|
||||
|
||||
# intersections = []
|
||||
# for intersector in to_intersect:
|
||||
# if isinstance(intersector, Axis):
|
||||
# intersector_as_edge: Edge = intersector.as_infinite_edge()
|
||||
# distance, point1, _point2 = self_i_edge.distance_to_with_closest_points(
|
||||
# intersector_as_edge
|
||||
# )
|
||||
# if distance <= TOLERANCE:
|
||||
# intersections.append(Vertex(*point1.to_tuple()))
|
||||
# elif isinstance(intersector, Plane):
|
||||
# geom_plane: Geom_Surface = Face.make_plane(intersector)._geom_adaptor()
|
||||
|
||||
# # Create a GeomAPI_IntCS object and compute the intersection
|
||||
# int_cs = GeomAPI_IntCS(self_as_curve, geom_plane)
|
||||
# # Check if there is an intersection point
|
||||
# if int_cs.NbPoints() > 0:
|
||||
# intersections.append(Vertex(*Vector(int_cs.Point(1)).to_tuple()))
|
||||
# elif isinstance(intersector, Shape):
|
||||
# intersections.extend(self_i_edge.intersect(intersector))
|
||||
|
||||
# return (
|
||||
# intersections[0]
|
||||
# if len(intersections) == 1
|
||||
# else Compound(children=intersections)
|
||||
# )
|
||||
|
||||
|
||||
# Axis.intersect = _axis_intersect
|
||||
|
||||
|
||||
# def _axis_and(self: Axis, other: Union[Shape, Axis, Plane]) -> Shape:
|
||||
# """intersect shape with self operator &"""
|
||||
# return self.intersect(other)
|
||||
|
||||
|
||||
# Axis.__and__ = _axis_and
|
||||
|
||||
|
||||
# def _plane_intersect(self: Plane, *to_intersect: Union[Shape, Axis, Plane]) -> Shape:
|
||||
# """plane intersect
|
||||
|
||||
# Args:
|
||||
# to_intersect (sequence of Union[Shape, Axis, Plane]): objects to intersect
|
||||
# with Plane.
|
||||
|
||||
# Returns:
|
||||
# Shape: result of intersection
|
||||
# """
|
||||
# self_as_face: Face = Face.make_plane(self)
|
||||
# intersections = [
|
||||
# self_as_face.intersect(intersector) for intersector in to_intersect
|
||||
# ]
|
||||
# return Compound(children=intersections)
|
||||
|
||||
|
||||
# Plane.intersect = _plane_intersect
|
||||
|
||||
|
||||
# def _plane_and(self: Plane, other: Union[Shape, Axis, Plane]) -> Shape:
|
||||
# """intersect shape with self operator &"""
|
||||
# return self.intersect(other)
|
||||
|
||||
|
||||
# Plane.__and__ = _plane_and
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ class TestAxis(DirectApiTestCase):
|
|||
self.assertVectorAlmostEquals(axis.direction, (-1, 0, 0), 5)
|
||||
|
||||
def test_axis_as_edge(self):
|
||||
edge = Axis.X.as_infinite_edge()
|
||||
edge = Edge(Axis.X)
|
||||
self.assertTrue(isinstance(edge, Edge))
|
||||
common = (edge & Edge.make_line((0, 0, 0), (1, 0, 0))).edge()
|
||||
self.assertAlmostEqual(common.length, 1, 5)
|
||||
|
|
@ -994,7 +994,7 @@ class TestEdge(DirectApiTestCase):
|
|||
self.assertAlmostEqual(e3_trim.length, 7, 5)
|
||||
|
||||
a4 = Axis((0, 0, 0), (1, 1, 1))
|
||||
e4_trim = a4.as_infinite_edge().trim_to_length(0.5, 2)
|
||||
e4_trim = Edge(a4).trim_to_length(0.5, 2)
|
||||
self.assertAlmostEqual(e4_trim.length, 2, 5)
|
||||
|
||||
def test_bezier(self):
|
||||
|
|
@ -1068,6 +1068,10 @@ class TestEdge(DirectApiTestCase):
|
|||
e2r = e2.reversed()
|
||||
self.assertAlmostEqual((e2 @ 0.1).X, -(e2r @ 0.1).X, 5)
|
||||
|
||||
def test_init(self):
|
||||
with self.assertRaises(ValueError):
|
||||
Edge(direction=(1, 0, 0))
|
||||
|
||||
|
||||
class TestFace(DirectApiTestCase):
|
||||
def test_make_surface_from_curves(self):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue