mirror of
https://github.com/gumyr/build123d.git
synced 2025-12-05 18:20:46 -08:00
Convert intersect to use _bool_op and split Wire after intersect
This commit is contained in:
parent
3877fd5876
commit
68f6ef2125
2 changed files with 78 additions and 98 deletions
|
|
@ -52,12 +52,11 @@ license:
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import numpy as np
|
|
||||||
import warnings
|
import warnings
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable, Sequence
|
||||||
from itertools import combinations
|
from itertools import combinations
|
||||||
from math import atan2, ceil, copysign, cos, floor, inf, isclose, pi, radians
|
from math import atan2, ceil, copysign, cos, floor, inf, isclose, pi, radians
|
||||||
from typing import TYPE_CHECKING, Literal, TypeAlias, overload
|
from typing import TYPE_CHECKING, Literal, overload
|
||||||
from typing import cast as tcast
|
from typing import cast as tcast
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
@ -729,122 +728,103 @@ class Mixin1D(Shape):
|
||||||
def to_vertex(objs: Iterable) -> ShapeList:
|
def to_vertex(objs: Iterable) -> ShapeList:
|
||||||
return ShapeList([Vertex(v) if isinstance(v, Vector) else v for v in objs])
|
return ShapeList([Vertex(v) if isinstance(v, Vector) else v for v in objs])
|
||||||
|
|
||||||
common_set: ShapeList[Vertex | Edge] = ShapeList(self.edges())
|
def bool_op(
|
||||||
target: ShapeList | Shape | Plane
|
args: Sequence,
|
||||||
|
tools: Sequence,
|
||||||
|
operation: BRepAlgoAPI_Section | BRepAlgoAPI_Common,
|
||||||
|
) -> ShapeList:
|
||||||
|
# Wrap Shape._bool_op for corrected output
|
||||||
|
intersections: Shape | ShapeList = Shape()._bool_op(args, tools, operation)
|
||||||
|
if isinstance(intersections, ShapeList):
|
||||||
|
return intersections or ShapeList()
|
||||||
|
if isinstance(intersections, Shape) and not intersections.is_null:
|
||||||
|
return ShapeList([intersections])
|
||||||
|
return ShapeList()
|
||||||
|
|
||||||
|
def filter_shapes_by_order(shapes: ShapeList, orders: list) -> ShapeList:
|
||||||
|
# Remove lower order shapes from list which *appear* to be part of
|
||||||
|
# a higher order shape using a lazy distance check
|
||||||
|
# (sufficient for vertices, may be an issue for higher orders)
|
||||||
|
order_groups = []
|
||||||
|
for order in orders:
|
||||||
|
order_groups.append(
|
||||||
|
ShapeList([s for s in shapes if isinstance(s, order)])
|
||||||
|
)
|
||||||
|
|
||||||
|
filtered_shapes = order_groups[-1]
|
||||||
|
for i in range(len(order_groups) - 1):
|
||||||
|
los = order_groups[i]
|
||||||
|
his: list = sum(order_groups[i + 1 :], [])
|
||||||
|
filtered_shapes.extend(
|
||||||
|
ShapeList(
|
||||||
|
lo
|
||||||
|
for lo in los
|
||||||
|
if all(lo.distance_to(hi) > TOLERANCE for hi in his)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return filtered_shapes
|
||||||
|
|
||||||
|
common_set: ShapeList[Vertex | Edge | Wire] = ShapeList([self])
|
||||||
|
target: Shape | Plane
|
||||||
for other in to_intersect:
|
for other in to_intersect:
|
||||||
# Conform target type
|
# Conform target type
|
||||||
# Vertices need to be Vector for set()
|
|
||||||
match other:
|
match other:
|
||||||
case Axis():
|
case Axis():
|
||||||
target = ShapeList([Edge(other)])
|
# BRepAlgoAPI_Section seems happier if Edge isnt infinite
|
||||||
|
bbox = self.bounding_box()
|
||||||
|
dist = self.distance_to(other.position)
|
||||||
|
dist = dist if dist >= 1 else 1
|
||||||
|
target = Edge.make_line(
|
||||||
|
other.position - other.direction * bbox.diagonal * dist,
|
||||||
|
other.position + other.direction * bbox.diagonal * dist,
|
||||||
|
)
|
||||||
case Plane():
|
case Plane():
|
||||||
target = other
|
target = other
|
||||||
case Vector():
|
case Vector():
|
||||||
target = Vertex(other)
|
target = Vertex(other)
|
||||||
case Location():
|
case Location():
|
||||||
target = Vertex(other.position)
|
target = Vertex(other.position)
|
||||||
case Edge():
|
|
||||||
target = ShapeList([other])
|
|
||||||
case Wire():
|
|
||||||
target = ShapeList(other.edges())
|
|
||||||
case _ if issubclass(type(other), Shape):
|
case _ if issubclass(type(other), Shape):
|
||||||
target = other
|
target = other
|
||||||
case _:
|
case _:
|
||||||
raise ValueError(f"Unsupported type to_intersect: {type(other)}")
|
raise ValueError(f"Unsupported type to_intersect: {type(other)}")
|
||||||
|
|
||||||
# Find common matches
|
# Find common matches
|
||||||
common: list[Vector | Edge] = []
|
common: list[Vertex | Edge | Wire] = []
|
||||||
result: ShapeList | Shape | None
|
result: ShapeList | None
|
||||||
for obj in common_set:
|
for obj in common_set:
|
||||||
match (obj, target):
|
match (obj, target):
|
||||||
case obj, Shape() as target:
|
case (_, Plane()):
|
||||||
# Find Shape with Edge/Wire
|
target = Shape(BRepBuilderAPI_MakeFace(other.wrapped).Face())
|
||||||
if isinstance(target, Vertex):
|
operation = BRepAlgoAPI_Section()
|
||||||
result = Shape.intersect(obj, target)
|
result = bool_op((obj,), (target,), operation)
|
||||||
else:
|
operation = BRepAlgoAPI_Common()
|
||||||
result = target.intersect(obj)
|
result.extend(bool_op((obj,), (target,), operation))
|
||||||
|
|
||||||
if result:
|
case (_, Vertex() | Edge() | Wire()):
|
||||||
if not isinstance(result, list):
|
operation = BRepAlgoAPI_Section()
|
||||||
result = ShapeList([result])
|
section = bool_op((obj,), (target,), operation)
|
||||||
common.extend(to_vector(result))
|
result = section
|
||||||
|
if not section:
|
||||||
|
operation = BRepAlgoAPI_Common()
|
||||||
|
result.extend(bool_op((obj,), (target,), operation))
|
||||||
|
|
||||||
case Vertex() as obj, target:
|
case _ if issubclass(type(target), Shape):
|
||||||
if not isinstance(target, ShapeList):
|
result = target.intersect(obj)
|
||||||
target = ShapeList([target])
|
|
||||||
|
|
||||||
for tar in target:
|
if result:
|
||||||
if isinstance(tar, Edge):
|
common.extend(result)
|
||||||
result = Shape.intersect(obj, tar)
|
|
||||||
else:
|
|
||||||
result = obj.intersect(tar)
|
|
||||||
|
|
||||||
if result:
|
|
||||||
if not isinstance(result, list):
|
|
||||||
result = ShapeList([result])
|
|
||||||
common.extend(to_vector(result))
|
|
||||||
|
|
||||||
case Edge() as obj, ShapeList() as targets:
|
|
||||||
# Find any edge / edge intersection points
|
|
||||||
for tar in targets:
|
|
||||||
# Find crossing points
|
|
||||||
try:
|
|
||||||
intersection_points = obj.find_intersection_points(tar)
|
|
||||||
common.extend(intersection_points)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Find common end points
|
|
||||||
obj_end_points = set(Vector(v) for v in obj.vertices())
|
|
||||||
tar_end_points = set(Vector(v) for v in tar.vertices())
|
|
||||||
points = set.intersection(obj_end_points, tar_end_points)
|
|
||||||
common.extend(points)
|
|
||||||
|
|
||||||
# Find Edge/Edge overlaps
|
|
||||||
result = obj._bool_op(
|
|
||||||
(obj,), targets, BRepAlgoAPI_Common()
|
|
||||||
).edges()
|
|
||||||
common.extend(result if isinstance(result, list) else [result])
|
|
||||||
|
|
||||||
case Edge() as obj, Plane() as plane:
|
|
||||||
# Find any edge / plane intersection points & edges
|
|
||||||
# Find point intersections
|
|
||||||
if obj.wrapped is None:
|
|
||||||
continue
|
|
||||||
geom_line = BRep_Tool.Curve_s(
|
|
||||||
obj.wrapped, obj.param_at(0), obj.param_at(1)
|
|
||||||
)
|
|
||||||
geom_plane = Geom_Plane(plane.local_coord_system)
|
|
||||||
intersection_calculator = GeomAPI_IntCS(geom_line, geom_plane)
|
|
||||||
plane_intersection_points: list[Vector] = []
|
|
||||||
if intersection_calculator.IsDone():
|
|
||||||
plane_intersection_points = [
|
|
||||||
Vector(intersection_calculator.Point(i + 1))
|
|
||||||
for i in range(intersection_calculator.NbPoints())
|
|
||||||
]
|
|
||||||
common.extend(plane_intersection_points)
|
|
||||||
|
|
||||||
# Find edge intersections
|
|
||||||
if all(
|
|
||||||
plane.contains(v)
|
|
||||||
for v in obj.positions(i / 7 for i in range(8))
|
|
||||||
): # is a 2D edge
|
|
||||||
common.append(obj)
|
|
||||||
|
|
||||||
if common:
|
if common:
|
||||||
common_set = to_vertex(set(common))
|
common_set = ShapeList()
|
||||||
# Remove Vertex intersections coincident to Edge intersections
|
for shape in common:
|
||||||
vts = common_set.vertices()
|
if isinstance(shape, Wire):
|
||||||
eds = common_set.edges()
|
common_set.extend(shape.edges())
|
||||||
if vts and eds:
|
else:
|
||||||
filtered_vts = ShapeList(
|
common_set.append(shape)
|
||||||
[
|
common_set = to_vertex(set(to_vector(common_set)))
|
||||||
v
|
common_set = filter_shapes_by_order(common_set, [Vertex, Edge])
|
||||||
for v in vts
|
|
||||||
if all(v.distance_to(e) > TOLERANCE for e in eds)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
common_set = filtered_vts + eds
|
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -296,7 +296,7 @@ sl1 = Box(2, 2, 2).solid()
|
||||||
sl2 = Pos(Z=5) * Box(2, 2, 2).solid()
|
sl2 = Pos(Z=5) * Box(2, 2, 2).solid()
|
||||||
sl3 = Cylinder(2, 1).solid() - Cylinder(1.5, 1).solid()
|
sl3 = Cylinder(2, 1).solid() - Cylinder(1.5, 1).solid()
|
||||||
|
|
||||||
wi7 = Wire([l1 := sl3.faces().sort_by(Axis.Z)[-1].edge().trim(.3, .4),
|
wi7 = Wire([l1 := sl3.faces().sort_by(Axis.Z)[-1].edges()[0].trim(.3, .4),
|
||||||
l2 := l1.trim(2, 3),
|
l2 := l1.trim(2, 3),
|
||||||
RadiusArc(l1 @ 1, l2 @ 0, 1, short_sagitta=False)
|
RadiusArc(l1 @ 1, l2 @ 0, 1, short_sagitta=False)
|
||||||
])
|
])
|
||||||
|
|
@ -430,7 +430,7 @@ freecad_matrix = [
|
||||||
Case(vert, e1, [Vertex], "vertical, ellipse, tangent", None),
|
Case(vert, e1, [Vertex], "vertical, ellipse, tangent", None),
|
||||||
Case(horz, e1, [Vertex], "horizontal, ellipse, tangent", None),
|
Case(horz, e1, [Vertex], "horizontal, ellipse, tangent", None),
|
||||||
|
|
||||||
Case(c1, c2, [Vertex, Vertex], "circle, skew, intersect", "Should return 2 Vertices"),
|
Case(c1, c2, [Vertex, Vertex], "circle, skew, intersect", None),
|
||||||
Case(c1, horz, [Vertex], "circle, horiz, tangent", None),
|
Case(c1, horz, [Vertex], "circle, horiz, tangent", None),
|
||||||
Case(c2, horz, [Vertex], "circle, horiz, tangent", None),
|
Case(c2, horz, [Vertex], "circle, horiz, tangent", None),
|
||||||
Case(c1, vert, [Vertex], "circle, vert, tangent", None),
|
Case(c1, vert, [Vertex], "circle, vert, tangent", None),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue