Added Compound constructor and deprecated make_compound Issue #523

This commit is contained in:
gumyr 2024-02-02 09:22:52 -05:00
parent e6b9ca6e66
commit d520fc40da
15 changed files with 182 additions and 83 deletions

View file

@ -421,7 +421,7 @@ class Builder(ABC):
raise RuntimeError("Nothing to intersect with") raise RuntimeError("Nothing to intersect with")
self._obj = self._obj.intersect(*typed[self._shape]) self._obj = self._obj.intersect(*typed[self._shape])
elif mode == Mode.REPLACE: elif mode == Mode.REPLACE:
self._obj = Compound.make_compound(list(typed[self._shape])) self._obj = Compound(list(typed[self._shape]))
if self._obj is not None and clean: if self._obj is not None and clean:
self._obj = self._obj.clean() self._obj = self._obj.clean()
@ -452,9 +452,7 @@ class Builder(ABC):
if isinstance(self._obj, Compound): if isinstance(self._obj, Compound):
self._obj = self._sub_class(self._obj.wrapped) self._obj = self._sub_class(self._obj.wrapped)
else: else:
self._obj = self._sub_class( self._obj = self._sub_class(Compound(self._shapes()).wrapped)
Compound.make_compound(self._shapes()).wrapped
)
# Add to pending # Add to pending
if self._tag == "BuildPart": if self._tag == "BuildPart":

View file

@ -82,7 +82,7 @@ class BuildSketch(Builder):
global_objs = [] global_objs = []
for plane in workplanes: for plane in workplanes:
global_objs.append(plane.from_local_coords(self._obj)) global_objs.append(plane.from_local_coords(self._obj))
return Sketch(Compound.make_compound(global_objs).wrapped) return Sketch(Compound(global_objs).wrapped)
def __init__( def __init__(
self, self,

View file

@ -139,8 +139,8 @@ class Drawing:
BRepLib.BuildCurves3d_s(el, TOLERANCE) BRepLib.BuildCurves3d_s(el, TOLERANCE)
# Convert and store the results. # Convert and store the results.
self.visible_lines = Compound.make_compound(map(Shape, visible)) self.visible_lines = Compound(map(Shape, visible))
self.hidden_lines = Compound.make_compound(map(Shape, hidden)) self.hidden_lines = Compound(map(Shape, hidden))
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@ -149,6 +149,7 @@ class Drawing:
class AutoNameEnum(Enum): class AutoNameEnum(Enum):
"""An enum class that automatically sets members' value to their name.""" """An enum class that automatically sets members' value to their name."""
@staticmethod @staticmethod
def _generate_next_value_(name, start, count, last_values): def _generate_next_value_(name, start, count, last_values):
return name return name
@ -865,6 +866,7 @@ class ExportSVG(Export2D):
ValueError: Invalid unit. ValueError: Invalid unit.
""" """
# pylint: disable=too-many-instance-attributes # pylint: disable=too-many-instance-attributes
_Converter = Callable[[Edge], ET.Element] _Converter = Callable[[Edge], ET.Element]
@ -1375,7 +1377,11 @@ class ExportSVG(Export2D):
ltname = layer.line_type.value ltname = layer.line_type.value
_, pattern = Export2D.LINETYPE_DEFS[ltname] _, pattern = Export2D.LINETYPE_DEFS[ltname]
d = self.dot_length.value if isinstance(self.dot_length, DotLength) else self.dot_length d = (
self.dot_length.value
if isinstance(self.dot_length, DotLength)
else self.dot_length
)
pattern = copy(pattern) pattern = copy(pattern)
plen = len(pattern) plen = len(pattern)
for i in range(0, plen): for i in range(0, plen):

View file

@ -45,6 +45,7 @@ from svgpathtools import svg2paths
from build123d.geometry import Color from build123d.geometry import Color
from build123d.topology import Compound, Face, Shape, ShapeList, Wire from build123d.topology import Compound, Face, Shape, ShapeList, Wire
def import_brep(file_name: str) -> Shape: def import_brep(file_name: str) -> Shape:
"""Import shape from a BREP file """Import shape from a BREP file
@ -100,7 +101,7 @@ def import_step(file_name: str) -> Compound:
for shape in occ_shapes: for shape in occ_shapes:
solids.append(Shape.cast(shape)) solids.append(Shape.cast(shape))
return Compound.make_compound(solids) return Compound(solids)
def import_stl(file_name: str) -> Face: def import_stl(file_name: str) -> Face:

View file

@ -221,7 +221,7 @@ class RevoluteJoint(Joint):
"""A CAD symbol representing the axis of rotation as bound to part""" """A CAD symbol representing the axis of rotation as bound to part"""
radius = self.parent.bounding_box().diagonal / 30 radius = self.parent.bounding_box().diagonal / 30
return Compound.make_compound( return Compound(
[ [
Edge.make_line((0, 0, 0), (0, 0, radius * 10)), Edge.make_line((0, 0, 0), (0, 0, radius * 10)),
Edge.make_circle(radius), Edge.make_circle(radius),
@ -328,7 +328,7 @@ class LinearJoint(Joint):
def symbol(self) -> Compound: def symbol(self) -> Compound:
"""A CAD symbol of the linear axis positioned relative to_part""" """A CAD symbol of the linear axis positioned relative to_part"""
radius = (self.linear_range[1] - self.linear_range[0]) / 15 radius = (self.linear_range[1] - self.linear_range[0]) / 15
return Compound.make_compound( return Compound(
[ [
Edge.make_line( Edge.make_line(
(0, 0, self.linear_range[0]), (0, 0, self.linear_range[1]) (0, 0, self.linear_range[0]), (0, 0, self.linear_range[1])
@ -492,13 +492,14 @@ class CylindricalJoint(Joint):
Raises: Raises:
ValueError: angle_reference must be normal to axis ValueError: angle_reference must be normal to axis
""" """
# pylint: disable=too-many-instance-attributes # pylint: disable=too-many-instance-attributes
@property @property
def symbol(self) -> Compound: def symbol(self) -> Compound:
"""A CAD symbol representing the cylindrical axis as bound to part""" """A CAD symbol representing the cylindrical axis as bound to part"""
radius = (self.linear_range[1] - self.linear_range[0]) / 15 radius = (self.linear_range[1] - self.linear_range[0]) / 15
return Compound.make_compound( return Compound(
[ [
Edge.make_line( Edge.make_line(
(0, 0, self.linear_range[0]), (0, 0, self.linear_range[1]) (0, 0, self.linear_range[0]), (0, 0, self.linear_range[1])
@ -640,7 +641,7 @@ class BallJoint(Joint):
circle_y = Edge.make_circle(radius, self.angle_reference.rotated((90, 0, 0))) circle_y = Edge.make_circle(radius, self.angle_reference.rotated((90, 0, 0)))
circle_z = Edge.make_circle(radius, self.angle_reference.rotated((0, 90, 0))) circle_z = Edge.make_circle(radius, self.angle_reference.rotated((0, 90, 0)))
return Compound.make_compound( return Compound(
[ [
circle_x, circle_x,
circle_y, circle_y,

View file

@ -92,15 +92,15 @@ class BasePartObject(Part):
context._add_to_context(*new_solids, mode=mode) context._add_to_context(*new_solids, mode=mode)
if len(new_solids) > 1: if len(new_solids) > 1:
new_part = Compound.make_compound(new_solids).wrapped new_part = Compound(new_solids).wrapped
elif isinstance(new_solids[0], Compound): # Don't add extra layers elif isinstance(new_solids[0], Compound): # Don't add extra layers
new_part = new_solids[0].wrapped new_part = new_solids[0].wrapped
else: else:
new_part = Compound.make_compound(new_solids).wrapped new_part = Compound(new_solids).wrapped
super().__init__( super().__init__(
obj=new_part, obj=new_part,
# obj=Compound.make_compound(new_solids).wrapped, # obj=Compound(new_solids).wrapped,
label=part.label, label=part.label,
material=part.material, material=part.material,
joints=part.joints, joints=part.joints,

View file

@ -83,7 +83,7 @@ class BaseSketchObject(Sketch):
if isinstance(context, BuildSketch): if isinstance(context, BuildSketch):
context._add_to_context(*new_faces, mode=mode) context._add_to_context(*new_faces, mode=mode)
super().__init__(Compound.make_compound(new_faces).wrapped) super().__init__(Compound(new_faces).wrapped)
class Circle(BaseSketchObject): class Circle(BaseSketchObject):

View file

@ -188,7 +188,7 @@ def add(
else: else:
raise RuntimeError(f"Builder {context.__class__.__name__} is unsupported") raise RuntimeError(f"Builder {context.__class__.__name__} is unsupported")
return Compound.make_compound(new_objects) return Compound(new_objects)
def bounding_box( def bounding_box(
@ -234,7 +234,7 @@ def bounding_box(
) )
if context is not None: if context is not None:
context._add_to_context(*new_faces, mode=mode) context._add_to_context(*new_faces, mode=mode)
return Sketch(Compound.make_compound(new_faces).wrapped) return Sketch(Compound(new_faces).wrapped)
new_objects = [] new_objects = []
for obj in object_list: for obj in object_list:
@ -251,7 +251,7 @@ def bounding_box(
) )
if context is not None: if context is not None:
context._add_to_context(*new_objects, mode=mode) context._add_to_context(*new_objects, mode=mode)
return Part(Compound.make_compound(new_objects).wrapped) return Part(Compound(new_objects).wrapped)
#:TypeVar("ChamferFilletType"): Type of objects which can be chamfered or filleted #:TypeVar("ChamferFilletType"): Type of objects which can be chamfered or filleted
@ -326,7 +326,7 @@ def chamfer(
if context is not None: if context is not None:
context._add_to_context(new_part, mode=Mode.REPLACE) context._add_to_context(new_part, mode=Mode.REPLACE)
return Part(Compound.make_compound([new_part]).wrapped) return Part(Compound([new_part]).wrapped)
if target._dim == 2: if target._dim == 2:
# Convert BaseSketchObject into Sketch so casting into Sketch during construction works # Convert BaseSketchObject into Sketch so casting into Sketch during construction works
@ -344,7 +344,7 @@ def chamfer(
) )
else: else:
new_faces.append(face) new_faces.append(face)
new_sketch = Sketch(Compound.make_compound(new_faces).wrapped) new_sketch = Sketch(Compound(new_faces).wrapped)
if context is not None: if context is not None:
context._add_to_context(new_sketch, mode=Mode.REPLACE) context._add_to_context(new_sketch, mode=Mode.REPLACE)
@ -428,7 +428,7 @@ def fillet(
if context is not None: if context is not None:
context._add_to_context(new_part, mode=Mode.REPLACE) context._add_to_context(new_part, mode=Mode.REPLACE)
return Part(Compound.make_compound([new_part]).wrapped) return Part(Compound([new_part]).wrapped)
if target._dim == 2: if target._dim == 2:
# Convert BaseSketchObject into Sketch so casting into Sketch during construction works # Convert BaseSketchObject into Sketch so casting into Sketch during construction works
@ -445,7 +445,7 @@ def fillet(
new_faces.append(face.fillet_2d(radius, vertices_in_face)) new_faces.append(face.fillet_2d(radius, vertices_in_face))
else: else:
new_faces.append(face) new_faces.append(face)
new_sketch = Sketch(Compound.make_compound(new_faces).wrapped) new_sketch = Sketch(Compound(new_faces).wrapped)
if context is not None: if context is not None:
context._add_to_context(new_sketch, mode=Mode.REPLACE) context._add_to_context(new_sketch, mode=Mode.REPLACE)
@ -522,7 +522,7 @@ def mirror(
if context is not None: if context is not None:
context._add_to_context(*mirrored, mode=mode) context._add_to_context(*mirrored, mode=mode)
mirrored_compound = Compound.make_compound(mirrored) mirrored_compound = Compound(mirrored)
if all([obj._dim == 3 for obj in object_list]): if all([obj._dim == 3 for obj in object_list]):
return Part(mirrored_compound.wrapped) return Part(mirrored_compound.wrapped)
if all([obj._dim == 2 for obj in object_list]): if all([obj._dim == 2 for obj in object_list]):
@ -656,7 +656,7 @@ def offset(
if context is not None: if context is not None:
context._add_to_context(*new_objects, mode=mode) context._add_to_context(*new_objects, mode=mode)
offset_compound = Compound.make_compound(new_objects) offset_compound = Compound(new_objects)
if all([obj._dim == 3 for obj in object_list]): if all([obj._dim == 3 for obj in object_list]):
return Part(offset_compound.wrapped) return Part(offset_compound.wrapped)
if all([obj._dim == 2 for obj in object_list]): if all([obj._dim == 2 for obj in object_list]):
@ -806,7 +806,7 @@ def project(
if projected_points: if projected_points:
result = ShapeList(projected_points) result = ShapeList(projected_points)
else: else:
result = Compound.make_compound(projected_shapes) result = Compound(projected_shapes)
if all([obj._dim == 2 for obj in object_list]): if all([obj._dim == 2 for obj in object_list]):
result = Sketch(result.wrapped) result = Sketch(result.wrapped)
elif all([obj._dim == 1 for obj in object_list]): elif all([obj._dim == 1 for obj in object_list]):
@ -881,7 +881,7 @@ def scale(
if context is not None: if context is not None:
context._add_to_context(*new_objects, mode=mode) context._add_to_context(*new_objects, mode=mode)
scale_compound = Compound.make_compound(new_objects) scale_compound = Compound(new_objects)
if all([obj._dim == 3 for obj in object_list]): if all([obj._dim == 3 for obj in object_list]):
return Part(scale_compound.wrapped) return Part(scale_compound.wrapped)
if all([obj._dim == 2 for obj in object_list]): if all([obj._dim == 2 for obj in object_list]):
@ -934,7 +934,7 @@ def split(
if context is not None: if context is not None:
context._add_to_context(*new_objects, mode=mode) context._add_to_context(*new_objects, mode=mode)
split_compound = Compound.make_compound(new_objects) split_compound = Compound(new_objects)
if all([obj._dim == 3 for obj in object_list]): if all([obj._dim == 3 for obj in object_list]):
return Part(split_compound.wrapped) return Part(split_compound.wrapped)
if all([obj._dim == 2 for obj in object_list]): if all([obj._dim == 2 for obj in object_list]):
@ -1059,5 +1059,5 @@ def sweep(
new_faces = [face.clean() for face in new_faces] new_faces = [face.clean() for face in new_faces]
if new_solids: if new_solids:
return Part(Compound.make_compound(new_solids).wrapped) return Part(Compound(new_solids).wrapped)
return Sketch(Compound.make_compound(new_faces).wrapped) return Sketch(Compound(new_faces).wrapped)

View file

@ -176,7 +176,7 @@ def extrude(
if clean: if clean:
new_solids = [solid.clean() for solid in new_solids] new_solids = [solid.clean() for solid in new_solids]
return Part(Compound.make_compound(new_solids).wrapped) return Part(Compound(new_solids).wrapped)
def loft( def loft(
@ -250,7 +250,7 @@ def loft(
elif clean: elif clean:
new_solid = new_solid.clean() new_solid = new_solid.clean()
return Part(Compound.make_compound([new_solid]).wrapped) return Part(Compound([new_solid]).wrapped)
def make_brake_formed( def make_brake_formed(
@ -356,7 +356,7 @@ def make_brake_formed(
elif clean: elif clean:
new_solid = new_solid.clean() new_solid = new_solid.clean()
return Part(Compound.make_compound([new_solid]).wrapped) return Part(Compound([new_solid]).wrapped)
def project_workplane( def project_workplane(
@ -472,7 +472,7 @@ def revolve(
new_solids.append(Solid.revolve(profile, angle, axis)) new_solids.append(Solid.revolve(profile, angle, axis))
new_solid = Compound.make_compound(new_solids) new_solid = Compound(new_solids)
if context is not None: if context is not None:
context._add_to_context(*new_solids, clean=clean, mode=mode) context._add_to_context(*new_solids, clean=clean, mode=mode)
elif clean: elif clean:
@ -541,7 +541,7 @@ def section(
if clean: if clean:
new_objects = [r.clean() for r in new_objects] new_objects = [r.clean() for r in new_objects]
return Sketch(Compound.make_compound(new_objects).wrapped) return Sketch(Compound(new_objects).wrapped)
def thicken( def thicken(
@ -616,4 +616,4 @@ def thicken(
if clean: if clean:
new_solids = [solid.clean() for solid in new_solids] new_solids = [solid.clean() for solid in new_solids]
return Part(Compound.make_compound(new_solids).wrapped) return Part(Compound(new_solids).wrapped)

View file

@ -66,7 +66,7 @@ def make_face(
context._add_to_context(pending_face, mode=mode) context._add_to_context(pending_face, mode=mode)
context.pending_edges = ShapeList() context.pending_edges = ShapeList()
return Sketch(Compound.make_compound([pending_face]).wrapped) return Sketch(Compound([pending_face]).wrapped)
def make_hull( def make_hull(
@ -104,7 +104,7 @@ def make_hull(
context._add_to_context(pending_face, mode=mode) context._add_to_context(pending_face, mode=mode)
context.pending_edges = ShapeList() context.pending_edges = ShapeList()
return Sketch(Compound.make_compound([pending_face]).wrapped) return Sketch(Compound([pending_face]).wrapped)
def trace( def trace(

View file

@ -1417,7 +1417,6 @@ class Shape(NodeMixin):
material: str = "", material: str = "",
joints: dict[str, Joint] = None, joints: dict[str, Joint] = None,
parent: Compound = None, parent: Compound = None,
children: list[Shape] = None,
): ):
self.wrapped = downcast(obj) if obj is not None else None self.wrapped = downcast(obj) if obj is not None else None
self.for_construction = False self.for_construction = False
@ -1429,11 +1428,6 @@ class Shape(NodeMixin):
if isinstance(self, Solid): if isinstance(self, Solid):
self.joints = joints if joints else {} self.joints = joints if joints else {}
# Bind joints and children to Compounds (other Shapes can't have children)
if isinstance(self, Compound):
self.joints = joints if joints else {}
self.children = children if children else []
# parent must be set following children as post install accesses children # parent must be set following children as post install accesses children
self.parent = parent self.parent = parent
@ -1695,7 +1689,7 @@ class Shape(NodeMixin):
elif isinstance(self, Sketch): elif isinstance(self, Sketch):
new_shape = Sketch(new_shape.wrapped) new_shape = Sketch(new_shape.wrapped)
elif isinstance(self, (Wire, Curve)): elif isinstance(self, (Wire, Curve)):
new_shape = Curve(Compound.make_compound(new_shape.edges()).wrapped) new_shape = Curve(Compound(new_shape.edges()).wrapped)
return new_shape return new_shape
@ -1727,7 +1721,7 @@ class Shape(NodeMixin):
elif isinstance(self, Sketch): elif isinstance(self, Sketch):
new_shape = Sketch(new_shape.wrapped) new_shape = Sketch(new_shape.wrapped)
elif isinstance(self, (Wire, Curve)): elif isinstance(self, (Wire, Curve)):
new_shape = Curve(Compound.make_compound(new_shape.edges()).wrapped) new_shape = Curve(Compound(new_shape.edges()).wrapped)
return new_shape return new_shape
@ -1747,7 +1741,7 @@ class Shape(NodeMixin):
elif isinstance(self, Sketch): elif isinstance(self, Sketch):
new_shape = Sketch(new_shape.wrapped) new_shape = Sketch(new_shape.wrapped)
elif isinstance(self, (Wire, Curve)): elif isinstance(self, (Wire, Curve)):
new_shape = Curve(Compound.make_compound(new_shape.edges()).wrapped) new_shape = Curve(Compound(new_shape.edges()).wrapped)
return new_shape return new_shape
@ -2760,12 +2754,12 @@ class Shape(NodeMixin):
if len(tops) == 1: if len(tops) == 1:
result = tops[0] result = tops[0]
else: else:
result = Compound.make_compound(tops) result = Compound(tops)
elif keep == Keep.BOTTOM: elif keep == Keep.BOTTOM:
if len(bottoms) == 1: if len(bottoms) == 1:
result = bottoms[0] result = bottoms[0]
else: else:
result = Compound.make_compound(bottoms) result = Compound(bottoms)
return result return result
def distance(self, other: Shape) -> float: def distance(self, other: Shape) -> float:
@ -3093,7 +3087,7 @@ class Shape(NodeMixin):
logger.debug("finished projecting '%d' faces", len(faces)) logger.debug("finished projecting '%d' faces", len(faces))
return Compound.make_compound(projected_faces) return Compound(projected_faces)
def _extrude( def _extrude(
self, direction: VectorLike self, direction: VectorLike
@ -3136,7 +3130,7 @@ class Shape(NodeMixin):
topods_solid = downcast(explorer.Current()) topods_solid = downcast(explorer.Current())
solids.append(Solid(topods_solid)) solids.append(Solid(topods_solid))
explorer.Next() explorer.Next()
result = Compound.make_compound(solids) result = Compound(solids)
else: else:
raise RuntimeError("extrude produced an unexpected result") raise RuntimeError("extrude produced an unexpected result")
return result return result
@ -3791,6 +3785,105 @@ class Compound(Mixin3D, Shape):
_dim = None _dim = None
@overload
def __init__(
self,
obj: TopoDS_Shape = None,
label: str = "",
color: Color = None,
material: str = "",
joints: dict[str, Joint] = None,
parent: Compound = None,
children: Iterable[Shape] = None,
):
"""Build a Compound from an OCCT TopoDS_Shape/TopoDS_Compound
Args:
obj (TopoDS_Shape, optional): OCCT Compound. Defaults to None.
label (str, optional): Defaults to ''.
color (Color, optional): Defaults to None.
material (str, optional): tag for external tools. Defaults to ''.
joints (dict[str, Joint], optional): names joints. Defaults to None.
parent (Compound, optional): assembly parent. Defaults to None.
children (Iterable[Shape], optional): assembly children. Defaults to None.
"""
@overload
def __init__(
self,
shapes: Iterable[Shape],
label: str = "",
color: Color = None,
material: str = "",
joints: dict[str, Joint] = None,
parent: Compound = None,
children: Iterable[Shape] = None,
):
"""Build a Compound from Shapes
Args:
shapes (Iterable[Shape]): shapes within the compound
label (str, optional): Defaults to ''.
color (Color, optional): Defaults to None.
material (str, optional): tag for external tools. Defaults to ''.
joints (dict[str, Joint], optional): names joints. Defaults to None.
parent (Compound, optional): assembly parent. Defaults to None.
children (Iterable[Shape], optional): assembly children. Defaults to None.
"""
def __init__(self, *args, **kwargs):
shapes, obj, label, color, material, joints, parent, children = (None,) * 8
if args:
l_a = len(args)
if isinstance(args[0], TopoDS_Shape):
obj, label, color, material, joints, parent, children = args[:7] + (
None,
) * (7 - l_a)
elif isinstance(args[0], Iterable):
shapes, label, color, material, joints, parent, children = args[:7] + (
None,
) * (7 - l_a)
unknown_args = ", ".join(
set(kwargs.keys()).difference(
[
"shapes",
"obj",
"label",
"material",
"color",
"joints",
"parent",
"children",
]
)
)
if unknown_args:
raise ValueError(f"Unexpected argument(s) {unknown_args}")
obj = kwargs.get("obj", obj)
shapes = kwargs.get("shapes", shapes)
material = kwargs.get("material", material)
joints = kwargs.get("joints", joints)
label = kwargs.get("label", label)
color = kwargs.get("color", color)
parent = kwargs.get("parent", parent)
children = kwargs.get("children", children)
if shapes:
obj = Compound._make_compound([s.wrapped for s in shapes])
super().__init__(
obj=obj,
label="" if label is None else label,
color=color,
material="" if material is None else material,
parent=parent,
)
self.joints = {} if joints is None else joints
self.children = [] if children is None else children
def __repr__(self): def __repr__(self):
"""Return Compound info as string""" """Return Compound info as string"""
if hasattr(self, "label") and hasattr(self, "children"): if hasattr(self, "label") and hasattr(self, "children"):
@ -3865,6 +3958,12 @@ class Compound(Mixin3D, Shape):
shapes: Iterable[Shape]: shapes: Iterable[Shape]:
Returns: Returns:
""" """
warnings.warn(
"make_compound() will be deprecated - use the Compound constructor instead",
DeprecationWarning,
stacklevel=2,
)
return cls(Compound._make_compound([s.wrapped for s in shapes])) return cls(Compound._make_compound([s.wrapped for s in shapes]))
def _remove(self, shape: Shape) -> Compound: def _remove(self, shape: Shape) -> Compound:
@ -4079,9 +4178,7 @@ class Compound(Mixin3D, Shape):
if text_path is not None: if text_path is not None:
path_length = text_path.length path_length = text_path.length
text_flat = Compound.make_compound( text_flat = Compound([position_face(f) for f in text_flat.faces()])
[position_face(f) for f in text_flat.faces()]
)
return text_flat return text_flat
@ -5322,7 +5419,7 @@ class Face(Shape):
inner_wires = inner_wires if inner_wires else [] inner_wires = inner_wires if inner_wires else []
# check if wires are coplanar # check if wires are coplanar
verification_compound = Compound.make_compound([outer_wire] + inner_wires) verification_compound = Compound([outer_wire] + inner_wires)
if not BRepLib_FindSurface( if not BRepLib_FindSurface(
verification_compound.wrapped, OnlyPlane=True verification_compound.wrapped, OnlyPlane=True
).Found(): ).Found():
@ -5739,9 +5836,7 @@ class Face(Shape):
Returns: Returns:
ShapeList[Face]: Face(s) projected on target object ordered by distance ShapeList[Face]: Face(s) projected on target object ordered by distance
""" """
max_dimension = ( max_dimension = Compound([self, target_object]).bounding_box().diagonal
Compound.make_compound([self, target_object]).bounding_box().diagonal
)
if taper == 0: if taper == 0:
face_extruded = Solid.extrude(self, Vector(direction) * max_dimension) face_extruded = Solid.extrude(self, Vector(direction) * max_dimension)
else: else:
@ -5823,7 +5918,7 @@ class Face(Shape):
bool: indicating whether or not point is within Face bool: indicating whether or not point is within Face
""" """
return Compound.make_compound([self]).is_inside(point, tolerance) return Compound([self]).is_inside(point, tolerance)
class Shell(Shape): class Shell(Shape):
@ -6244,11 +6339,7 @@ class Solid(Mixin3D, Shape):
# make straight spine # make straight spine
straight_spine_e = Edge.make_line(center, center.add(normal)) straight_spine_e = Edge.make_line(center, center.add(normal))
straight_spine_w = Wire.combine( straight_spine_w = Wire.combine([straight_spine_e])[0].wrapped
[
straight_spine_e,
]
)[0].wrapped
# make an auxiliary spine # make an auxiliary spine
pitch = 360.0 / angle * normal.length pitch = 360.0 / angle * normal.length
@ -6268,7 +6359,7 @@ class Solid(Mixin3D, Shape):
] ]
# combine the inner solids into compound # combine the inner solids into compound
inner_comp = Compound.make_compound(inner_solids).wrapped inner_comp = Compound._make_compound(inner_solids)
# subtract from the outer solid # subtract from the outer solid
return Solid(BRepAlgoAPI_Cut(outer_solid, inner_comp).Shape()) return Solid(BRepAlgoAPI_Cut(outer_solid, inner_comp).Shape())
@ -6304,9 +6395,7 @@ class Solid(Mixin3D, Shape):
direction *= -1 direction *= -1
until = Until.NEXT if until == Until.PREVIOUS else Until.LAST until = Until.NEXT if until == Until.PREVIOUS else Until.LAST
max_dimension = ( max_dimension = Compound([section, target_object]).bounding_box().diagonal
Compound.make_compound([section, target_object]).bounding_box().diagonal
)
clipping_direction = ( clipping_direction = (
direction * max_dimension direction * max_dimension
if until == Until.NEXT if until == Until.NEXT
@ -6866,7 +6955,7 @@ class Wire(Mixin1D, Shape):
edges_in = TopTools_HSequenceOfShape() edges_in = TopTools_HSequenceOfShape()
wires_out = TopTools_HSequenceOfShape() wires_out = TopTools_HSequenceOfShape()
for edge in Compound.make_compound(wires).edges(): for edge in Compound(wires).edges():
edges_in.Append(edge.wrapped) edges_in.Append(edge.wrapped)
ShapeAnalysis_FreeBounds.ConnectEdgesToWires_s(edges_in, tol, False, wires_out) ShapeAnalysis_FreeBounds.ConnectEdgesToWires_s(edges_in, tol, False, wires_out)

View file

@ -107,7 +107,7 @@ class AddTests(unittest.TestCase):
# Add Compound # Add Compound
with BuildPart() as test: with BuildPart() as test:
add( add(
Compound.make_compound( Compound(
[ [
Solid.make_box(10, 10, 10), Solid.make_box(10, 10, 10),
Solid.make_box(5, 5, 5, Plane((20, 20, 20))), Solid.make_box(5, 5, 5, Plane((20, 20, 20))),
@ -116,7 +116,7 @@ class AddTests(unittest.TestCase):
) )
self.assertAlmostEqual(test.part.volume, 1125, 5) self.assertAlmostEqual(test.part.volume, 1125, 5)
with BuildPart() as test: with BuildPart() as test:
add(Compound.make_compound([Edge.make_line((0, 0), (1, 1))])) add(Compound([Edge.make_line((0, 0), (1, 1))]))
self.assertEqual(len(test.pending_edges), 1) self.assertEqual(len(test.pending_edges), 1)
# Add Wire # Add Wire
@ -435,7 +435,7 @@ class MirrorTests(unittest.TestCase):
edge = Edge.make_line((1, 0), (2, 0)) edge = Edge.make_line((1, 0), (2, 0))
wire = Wire.make_circle(1, Plane((5, 0, 0))) wire = Wire.make_circle(1, Plane((5, 0, 0)))
face = Face.make_rect(2, 2, Plane((8, 0))) face = Face.make_rect(2, 2, Plane((8, 0)))
compound = Compound.make_compound( compound = Compound(
[ [
Face.make_rect(2, 2, Plane((8, 8))), Face.make_rect(2, 2, Plane((8, 8))),
Face.make_rect(2, 2, Plane((8, -8))), Face.make_rect(2, 2, Plane((8, -8))),

View file

@ -740,32 +740,32 @@ class TestCompound(DirectApiTestCase):
def test_fuse(self): def test_fuse(self):
box1 = Solid.make_box(1, 1, 1) box1 = Solid.make_box(1, 1, 1)
box2 = Solid.make_box(1, 1, 1, Plane((1, 0, 0))) box2 = Solid.make_box(1, 1, 1, Plane((1, 0, 0)))
combined = Compound.make_compound([box1]).fuse(box2, glue=True) combined = Compound([box1]).fuse(box2, glue=True)
self.assertTrue(combined.is_valid()) self.assertTrue(combined.is_valid())
self.assertAlmostEqual(combined.volume, 2, 5) self.assertAlmostEqual(combined.volume, 2, 5)
fuzzy = Compound.make_compound([box1]).fuse(box2, tol=1e-6) fuzzy = Compound([box1]).fuse(box2, tol=1e-6)
self.assertTrue(fuzzy.is_valid()) self.assertTrue(fuzzy.is_valid())
self.assertAlmostEqual(fuzzy.volume, 2, 5) self.assertAlmostEqual(fuzzy.volume, 2, 5)
def test_remove(self): def test_remove(self):
box1 = Solid.make_box(1, 1, 1) box1 = Solid.make_box(1, 1, 1)
box2 = Solid.make_box(1, 1, 1, Plane((2, 0, 0))) box2 = Solid.make_box(1, 1, 1, Plane((2, 0, 0)))
combined = Compound.make_compound([box1, box2]) combined = Compound([box1, box2])
self.assertTrue(len(combined._remove(box2).solids()), 1) self.assertTrue(len(combined._remove(box2).solids()), 1)
def test_repr(self): def test_repr(self):
simple = Compound.make_compound([Solid.make_box(1, 1, 1)]) simple = Compound([Solid.make_box(1, 1, 1)])
simple_str = repr(simple).split("0x")[0] + repr(simple).split(", ")[1] simple_str = repr(simple).split("0x")[0] + repr(simple).split(", ")[1]
self.assertEqual(simple_str, "Compound at label()") self.assertEqual(simple_str, "Compound at label()")
assembly = Compound.make_compound([Solid.make_box(1, 1, 1)]) assembly = Compound([Solid.make_box(1, 1, 1)])
assembly.children = [Solid.make_box(1, 1, 1)] assembly.children = [Solid.make_box(1, 1, 1)]
assembly.label = "test" assembly.label = "test"
assembly_str = repr(assembly).split("0x")[0] + repr(assembly).split(", l")[1] assembly_str = repr(assembly).split("0x")[0] + repr(assembly).split(", l")[1]
self.assertEqual(assembly_str, "Compound at abel(test), #children(1)") self.assertEqual(assembly_str, "Compound at abel(test), #children(1)")
def test_center(self): def test_center(self):
test_compound = Compound.make_compound( test_compound = Compound(
[ [
Solid.make_box(2, 2, 2).locate(Location((-1, -1, -1))), Solid.make_box(2, 2, 2).locate(Location((-1, -1, -1))),
Solid.make_box(1, 1, 1).locate(Location((8.5, -0.5, -0.5))), Solid.make_box(1, 1, 1).locate(Location((8.5, -0.5, -0.5))),
@ -807,6 +807,10 @@ class TestCompound(DirectApiTestCase):
self.assertAlmostEqual(c.volume, 3, 5) self.assertAlmostEqual(c.volume, 3, 5)
# N.B. b and bb overlap but still add to Compound volume # N.B. b and bb overlap but still add to Compound volume
def test_constructor(self):
with self.assertRaises(ValueError):
Compound(bob="fred")
class TestEdge(DirectApiTestCase): class TestEdge(DirectApiTestCase):
def test_close(self): def test_close(self):
@ -3666,4 +3670,4 @@ class TestWire(DirectApiTestCase):
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main(failfast=True)

View file

@ -148,7 +148,7 @@ class TestAddShape(DirectApiTestCase):
exporter = Mesher() exporter = Mesher()
box = Solid.make_box(1, 1, 1) box = Solid.make_box(1, 1, 1)
cone = Solid.make_cone(1, 0, 2).locate(Location((0, -1, 0))) cone = Solid.make_cone(1, 0, 2).locate(Location((0, -1, 0)))
shape_assembly = Compound.make_compound([box, cone]) shape_assembly = Compound([box, cone])
exporter.add_shape(shape_assembly) exporter.add_shape(shape_assembly)
exporter.write("test.3mf") exporter.write("test.3mf")
importer = Mesher() importer = Mesher()

View file

@ -17,7 +17,7 @@ class TestPersistence(unittest.TestCase):
wire = Wire.make_circle(10) wire = Wire.make_circle(10)
face = Face.make_rect(10, 5) face = Face.make_rect(10, 5)
solid = Solid.make_box(10, 5, 2) solid = Solid.make_box(10, 5, 2)
compound = Compound.make_compound([edge, wire, face, solid]) compound = Compound([edge, wire, face, solid])
buffer = serialize_shape(edge.wrapped) buffer = serialize_shape(edge.wrapped)
retrived_edge = deserialize_shape(buffer) retrived_edge = deserialize_shape(buffer)