From 5eeaeed104753e0e120f3ef1a45921f05780e39b Mon Sep 17 00:00:00 2001 From: Roy-043 Date: Sun, 26 May 2024 17:44:45 +0200 Subject: [PATCH] Draft: update fuse behavior in facebinder.py Fixes #14242. In the current dev fusing an empty shape with a face or solid no longer works (probably introduced with #14169). The reason for starting with an empty shape was the assumption that the end result would then always have a default placement. But that is only correct if multiple objects are fused. In the new version of the code fusing no longer starts with an empty shape. The default placement issue is solved by always returning a compound. Additionally the value for the Area property is now taken after offsetting and fusing the faces. --- src/Mod/Draft/draftobjects/facebinder.py | 117 ++++++++++++----------- 1 file changed, 62 insertions(+), 55 deletions(-) diff --git a/src/Mod/Draft/draftobjects/facebinder.py b/src/Mod/Draft/draftobjects/facebinder.py index cad541c98d..255e60f3ee 100644 --- a/src/Mod/Draft/draftobjects/facebinder.py +++ b/src/Mod/Draft/draftobjects/facebinder.py @@ -57,73 +57,80 @@ class Facebinder(DraftObject): _tip = QT_TRANSLATE_NOOP("App::Property","The area of the faces of this Facebinder") obj.addProperty("App::PropertyArea","Area", "Draft", _tip) - obj.setEditorMode("Area",1) + obj.setEditorMode("Area", 1) def execute(self, obj): if self.props_changed_placement_only(obj): self.props_changed_clear() return - import Part - pl = obj.Placement if not obj.Faces: return + + import Part faces = [] - area = 0 - offs_val = obj.Offset.Value if hasattr(obj, "Offset") else 0 - extr_val = obj.Extrusion.Value if hasattr(obj, "Extrusion") else 0 - for sel in obj.Faces: - for sub in sel[1]: - if "Face" in sub: - try: - face = Part.getShape(sel[0], sub, needSubElement=True, retType=0) - area += face.Area - if offs_val: - if face.Surface.isPlanar(): - norm = face.normalAt(0, 0) - dist = norm.multiply(offs_val) - face.translate(dist) - faces.append(face) - else: - offs = face.makeOffsetShape(offs_val, 1e-7) - faces.extend(offs.Faces) - else: - faces.append(face) - except Part.OCCError: - print("Draft: error building facebinder") - return - if not faces: - return try: - if extr_val: - extrs = [] - for face in faces: - if face.Surface.isPlanar(): - extr = face.extrude(face.normalAt(0, 0).multiply(extr_val)) - extrs.append(extr) - else: - extr = face.makeOffsetShape(extr_val, 1e-7, fill=True) - extrs.extend(extr.Solids) - shp = Part.Shape() # create empty shape to ensure default Placement - shp = shp.fuse(extrs.pop()) # add 1st shape, multiFuse does not work otherwise - if extrs: - shp = shp.multiFuse(extrs) # multiFuse is more reliable than serial fuse - else: - shp = Part.Shape() - shp = shp.fuse(faces.pop()) - if faces: - shp = shp.multiFuse(faces) - if len(faces) > 1: - if hasattr(obj, "Sew") and obj.Sew: - shp.sewShape() - if not hasattr(obj, "RemoveSplitter"): - shp = shp.removeSplitter() - elif obj.RemoveSplitter: - shp = shp.removeSplitter() - except Part.OCCError: + for sel in obj.Faces: + for sub in sel[1]: + if "Face" in sub: + face = Part.getShape(sel[0], sub, needSubElement=True, retType=0) + faces.append(face) + except Exception: print("Draft: error building facebinder") return - obj.Shape = shp + + if not faces: + return + + offset_val = obj.Offset.Value if hasattr(obj, "Offset") else 0 + extrusion_val = obj.Extrusion.Value if hasattr(obj, "Extrusion") else 0 + + try: + if offset_val: + offsets = [] + for face in faces: + if face.Surface.isPlanar(): + norm = face.normalAt(0, 0) + dist = norm.multiply(offset_val) + face.translate(dist) + offsets.append(face) + else: + offset = face.makeOffsetShape(offset_val, 1e-7) + offsets.extend(offset.Faces) + faces = offsets + + shp = faces.pop() + if faces: + shp = shp.fuse(faces) + area = shp.Area # take area after offsetting and fusing, but before extruding + + if extrusion_val: + extrusions = [] + for face in shp.Faces: + if face.Surface.isPlanar(): + extrusion = face.extrude(face.normalAt(0, 0).multiply(extrusion_val)) + extrusions.append(extrusion) + else: + extrusion = face.makeOffsetShape(extrusion_val, 1e-7, fill=True) + extrusions.extend(extrusion.Solids) + shp = extrusions.pop() + if extrusions: + shp = shp.fuse(extrusions) + + if len(shp.Faces) > 1: + if getattr(obj, "Sew", True): + shp.sewShape() + if getattr(obj, "RemoveSplitter", True): + shp = shp.removeSplitter() + + except Exception: + print("Draft: error building facebinder") + return + + if shp.__class__.__name__ == "Compound": + obj.Shape = shp + else: + obj.Shape = Part.Compound([shp]) # nest in compound to ensure default Placement obj.Area = area self.props_changed_clear()