From ffeda1970403dedeae27886959b8271fb0a5cdda Mon Sep 17 00:00:00 2001 From: gumyr Date: Thu, 26 Jun 2025 10:46:36 -0400 Subject: [PATCH] Added support for copying _base_wrapped, ensure _base_wrapped is not None --- src/build123d/topology/composite.py | 39 ++++++++++++---------------- src/build123d/topology/shape_core.py | 9 +++++++ 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/build123d/topology/composite.py b/src/build123d/topology/composite.py index 7f58596..fb746b0 100644 --- a/src/build123d/topology/composite.py +++ b/src/build123d/topology/composite.py @@ -174,7 +174,7 @@ class MixinComposite(NodeMixin): - If no children or only one shape is present, the node is collapsed to a single wrapped shape. - This method should be called whenever child geometry or hierarchy changes. """ - where_am_i_called_from() + # where_am_i_called_from(3) # print(f"{self=}, {self.location=}") for node in PostOrderIter(self): # print(f"{node=}, {node.location=}, {node.location_relative_to_parent=}") @@ -800,41 +800,34 @@ class Compound(Mixin3D, MixinComposite, Shape[TopoDS_Compound]): children (Sequence[Shape], optional): assembly children. Defaults to None. """ if isinstance(obj, TopoDS_Shape): - print("Making a Compound 1") - where_am_i_called_from(3) - self._base_wrapped = downcast(obj) + topods_compound = downcast(obj) elif isinstance(obj, Iterable): - print("Making a Compound 2") - where_am_i_called_from(3) - self._base_wrapped = _make_topods_compound_from_shapes( + topods_compound = _make_topods_compound_from_shapes( [s.wrapped for s in obj] ) elif obj is None: - print("Making a Compound 3") - self._base_wrapped = None + # When used in a Part/Sketch etc. context an empty Compound must + # have a wrapped attribute of None + topods_compound = None elif isinstance(obj, Assembly): - print("Making a Compound 4") - self._base_wrapped = obj.wrapped + topods_compound = obj.wrapped else: raise ValueError(f"Invalid obj of type {type(obj)}") - # if isinstance(obj, Iterable): - # print("Making a Compound 1") - # topods_compound = _make_topods_compound_from_shapes( - # [s.wrapped for s in obj] - # ) - # else: - # print("Making a Compound 2") - # topods_compound = obj - # self._base_wrapped = topods_compound - super().__init__( - obj=self._base_wrapped, + obj=topods_compound, label=label, color=color, parent=parent, ) - self.location = Location() + # When used in an assembly context the base shape must be a valid + # compound in order to add children or set a parent + self._base_wrapped = ( + _make_topods_compound_from_shapes([]) + if topods_compound is None + else topods_compound + ) + self.material = "" if material is None else material self.joints = {} if joints is None else joints diff --git a/src/build123d/topology/shape_core.py b/src/build123d/topology/shape_core.py index 67d7593..eee15a6 100644 --- a/src/build123d/topology/shape_core.py +++ b/src/build123d/topology/shape_core.py @@ -908,6 +908,11 @@ class Shape(NodeMixin, Generic[TOPODS]): reference.wrapped is not None ) # Ensure mypy knows reference.wrapped is not None reference.wrapped.TShape(self.wrapped.TShape()) + if hasattr(self, "_base_wrapped") and self.wrapped is not None: + assert ( + reference._base_wrapped is not None + ) # Ensure mypy knows reference.wrapped is not None + reference._base_wrapped.TShape(self._base_wrapped.TShape()) return reference def __deepcopy__(self, memo) -> Self: @@ -920,6 +925,10 @@ class Shape(NodeMixin, Generic[TOPODS]): memo[id(self)] = result if self.wrapped is not None: memo[id(self.wrapped)] = downcast(BRepBuilderAPI_Copy(self.wrapped).Shape()) + if hasattr(self, "_base_wrapped") and self._base_wrapped is not None: + memo[id(self._base_wrapped)] = downcast( + BRepBuilderAPI_Copy(self._base_wrapped).Shape() + ) for key, value in self.__dict__.items(): if key == "topo_parent": result.topo_parent = value