From 8317d81d107ff06b74b7ac52112bafb6d2a396f8 Mon Sep 17 00:00:00 2001 From: deuxcents Date: Mon, 15 Dec 2025 19:35:40 +0100 Subject: [PATCH 1/3] Update cq_utils.py build123d support Add flexible build123d shapes and builders support. You can pass directly the builder, even incomplete, or the shape within it. Or just a standalone shape (algebra mode). --- cq_editor/cq_utils.py | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/cq_editor/cq_utils.py b/cq_editor/cq_utils.py index 0439c7d3..a19984c1 100644 --- a/cq_editor/cq_utils.py +++ b/cq_editor/cq_utils.py @@ -17,6 +17,8 @@ from PyQt5.QtGui import QColor +#for builder123d Builder classes support +import gc DEFAULT_FACE_COLOR = Quantity_Color(GOLD) DEFAULT_MATERIAL = Graphic3d_MaterialAspect(Graphic3d_NOM_JADE) @@ -42,25 +44,46 @@ def to_compound( ): vals = [] - - if isinstance(obj, cq.Workplane): + + if isinstance(obj, TopoDS_Shape): + vals.append(cq.Shape.cast(obj)) + elif isinstance(obj, cq.Workplane): vals.extend(obj.vals()) elif isinstance(obj, cq.Shape): vals.append(obj) + elif isinstance(obj, cq.Sketch): + if obj._faces: + vals.append(obj._faces) + else: + vals.extend(obj._edges) + #builder123d Shape for instance BuildLine.line or Box, wrapped is the TopoDS_Shape + elif "topology" in type(obj).__module__ and hasattr(obj, "wrapped"): + vals.extend(cq.Shape.cast(obj.wrapped)) + #builder123d Builder classes + elif "Build" in type(obj).__name__: + #if builder is complete (builder._obj defined: for instance when a part has a 3D Shape, a part with one line has builder._obj to None for instance) + if hasattr(obj, "_obj") and obj._obj is not None: + vals.extend(cq.Shape.cast(obj._obj.wrapped)) + else: + #get all objects and find the children of obj + for obj2 in gc.get_objects(): + if "Build" in type(obj2).__name__: + #select complete builders + if hasattr(obj2, "_obj") and obj2._obj is not None and hasattr(obj2, "builder_parent"): + #is it a child ? + if obj2.builder_parent is obj: + vals.extend(cq.Shape.cast(obj2._obj.wrapped)) + #is it a grandchild (BuildPart has BuildSketche(s) that have BuildLine(s)) ? + elif hasattr(obj2.builder_parent, "builder_parent") and obj2.builder_parent.builder_parent is obj: + vals.extend(cq.Shape.cast(obj2._obj.wrapped)) + #we consider we had an empty builder: no error elif isinstance(obj, list) and isinstance(obj[0], cq.Workplane): for o in obj: vals.extend(o.vals()) elif isinstance(obj, list) and isinstance(obj[0], cq.Shape): vals.extend(obj) - elif isinstance(obj, TopoDS_Shape): - vals.append(cq.Shape.cast(obj)) elif isinstance(obj, list) and isinstance(obj[0], TopoDS_Shape): vals.extend(cq.Shape.cast(o) for o in obj) - elif isinstance(obj, cq.Sketch): - if obj._faces: - vals.append(obj._faces) - else: - vals.extend(obj._edges) else: raise ValueError(f"Invalid type {type(obj)}") From 2a2b511fba45bcb71858491104bd3c64aab94a50 Mon Sep 17 00:00:00 2001 From: deuxcents Date: Mon, 15 Dec 2025 20:33:10 +0100 Subject: [PATCH 2/3] Update cq_utils.py Fix duplicates issue when parent is complete --- cq_editor/cq_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cq_editor/cq_utils.py b/cq_editor/cq_utils.py index a19984c1..88e2ac96 100644 --- a/cq_editor/cq_utils.py +++ b/cq_editor/cq_utils.py @@ -73,8 +73,8 @@ def to_compound( #is it a child ? if obj2.builder_parent is obj: vals.extend(cq.Shape.cast(obj2._obj.wrapped)) - #is it a grandchild (BuildPart has BuildSketche(s) that have BuildLine(s)) ? - elif hasattr(obj2.builder_parent, "builder_parent") and obj2.builder_parent.builder_parent is obj: + #is it a grandchild (BuildPart has BuildSketche(s) that have BuildLine(s)) with incomplete parent ? + elif obj2.builder_parent._obj is None and hasattr(obj2.builder_parent, "builder_parent") and obj2.builder_parent.builder_parent is obj: vals.extend(cq.Shape.cast(obj2._obj.wrapped)) #we consider we had an empty builder: no error elif isinstance(obj, list) and isinstance(obj[0], cq.Workplane): From e0dbef1187b1d5e04e6d4bb4d6285cf0ed4946b9 Mon Sep 17 00:00:00 2001 From: deuxcents Date: Wed, 17 Dec 2025 17:53:00 +0100 Subject: [PATCH 3/3] Update cq_utils.py add subclasses support --- cq_editor/cq_utils.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cq_editor/cq_utils.py b/cq_editor/cq_utils.py index 88e2ac96..4c6f4db7 100644 --- a/cq_editor/cq_utils.py +++ b/cq_editor/cq_utils.py @@ -56,18 +56,18 @@ def to_compound( vals.append(obj._faces) else: vals.extend(obj._edges) - #builder123d Shape for instance BuildLine.line or Box, wrapped is the TopoDS_Shape - elif "topology" in type(obj).__module__ and hasattr(obj, "wrapped"): + #builder123d Shape for instance BuildLine.line or Box, wrapped is the TopoDS_Shape + elif "topology" in "".join([str(full_classes.__module__)+full_classes.__qualname__ for full_classes in (type(obj),*type(obj).__mro__)]) and hasattr(obj, "wrapped"): vals.extend(cq.Shape.cast(obj.wrapped)) #builder123d Builder classes - elif "Build" in type(obj).__name__: + elif "Builder" in "".join([str(full_classes.__module__)+full_classes.__qualname__ for full_classes in (type(obj),*type(obj).__mro__)]): #if builder is complete (builder._obj defined: for instance when a part has a 3D Shape, a part with one line has builder._obj to None for instance) if hasattr(obj, "_obj") and obj._obj is not None: vals.extend(cq.Shape.cast(obj._obj.wrapped)) else: #get all objects and find the children of obj for obj2 in gc.get_objects(): - if "Build" in type(obj2).__name__: + if "Builder" in "".join([str(full_classes.__module__)+full_classes.__qualname__ for full_classes in (type(obj2),*type(obj2).__mro__)]): #select complete builders if hasattr(obj2, "_obj") and obj2._obj is not None and hasattr(obj2, "builder_parent"): #is it a child ? @@ -76,7 +76,7 @@ def to_compound( #is it a grandchild (BuildPart has BuildSketche(s) that have BuildLine(s)) with incomplete parent ? elif obj2.builder_parent._obj is None and hasattr(obj2.builder_parent, "builder_parent") and obj2.builder_parent.builder_parent is obj: vals.extend(cq.Shape.cast(obj2._obj.wrapped)) - #we consider we had an empty builder: no error + #we consider we had an empty builder: no error elif isinstance(obj, list) and isinstance(obj[0], cq.Workplane): for o in obj: vals.extend(o.vals())