From 1317927131660d1cf4b813ce678bed1125e1c077 Mon Sep 17 00:00:00 2001 From: shai Date: Sun, 20 Oct 2024 14:58:22 +0300 Subject: [PATCH] revert buggy ondsel changes --- README.md | 1 + Resources/panels/UnfoldOptions.ui | 368 +++++++++++++++++--------- SheetMetalBaseCmd.py | 11 +- SheetMetalBend.py | 10 +- SheetMetalCmd.py | 10 +- SheetMetalCornerReliefCmd.py | 15 +- SheetMetalExtendCmd.py | 10 +- SheetMetalFoldCmd.py | 17 +- SheetMetalFormingCmd.py | 18 +- SheetMetalJunction.py | 12 +- SheetMetalRelief.py | 2 +- SheetMetalTools.py | 12 + SheetMetalUnfoldCmd.py | 351 ++++--------------------- SheetMetalUnfolder.py | 413 ++++++++++++++++-------------- SketchOnSheetMetalCmd.py | 18 +- UnfoldGUI.py | 330 ++++++++++++++++++++++++ package.xml | 4 +- 17 files changed, 905 insertions(+), 697 deletions(-) create mode 100644 UnfoldGUI.py diff --git a/README.md b/README.md index 4b01ae3..210b50f 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,7 @@ Starting from FreeCAD 0.17 it can be installed via the [Addon Manager](https://g * FreeCAD Forum announcement/discussion [thread](https://forum.freecadweb.org/viewtopic.php?f=3&t=60818) #### Release notes: +* V0.5.02 21 Oct 2024: Fix many small bugs after Ondsel merge. * V0.5.01 20 Oct 2024: Fix bug in base shape creating double model. - Fix typos by [@luzpaz][luzpaz]. * V0.5.00 19 Oct 2024: Merge Ondsel changes made by [@adrianinsaval][adrianinsaval]. diff --git a/Resources/panels/UnfoldOptions.ui b/Resources/panels/UnfoldOptions.ui index 3f64309..b8e361f 100644 --- a/Resources/panels/UnfoldOptions.ui +++ b/Resources/panels/UnfoldOptions.ui @@ -6,8 +6,8 @@ 0 0 - 277 - 231 + 676 + 565 @@ -15,132 +15,242 @@ - + + + + + Generate projection sketch + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 66 + 203 + 105 + + + + + + + + - Select Face - - - true + Separate projection layers - - - Material Settings + + + + + Bend lines color + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + Internal lines color + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 - - - - - - - Material Definition Sheet - - - - - - - - 0 - 0 - - - - - - - - - - QLayout::SetDefaultConstraint - - - - - - 0 - 0 - - - - Manual K-Factor - - - - - - - true - - - - 0 - 0 - - - - - 100 - 16777215 - - - - 5 - - - 2.000000000000000 - - - 0.001000000000000 - - - 0.500000000000000 - - - - - - - - - 0 - - - - - Standard - - - - - - - ANSI - - - true - - - kFactorStandardGroup - - - - - - - DIN - - - kFactorStandardGroup - - - - - - - + + + + Export sketch + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + DXF + + + true + + + exportGroup + + + + + + + SVG + + + exportGroup + + + + + + + + + + + Material Definition Sheet + + + + + + + + + + + + QLayout::SetDefaultConstraint + + + + + Manual K-Factor + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + true + + + + 0 + 0 + + + + + 100 + 16777215 + + + + 3 + + + 2.000000000000000 + + + 0.100000000000000 + + + 0.500000000000000 + + + + + + + ANSI + + + kFactorGroup + + + + + + + DIN + + + kFactorGroup + + + + @@ -159,7 +269,7 @@ - Unfold Transparency + Unfold object transparency @@ -198,16 +308,24 @@ 20 - 40 + 272 + + + Gui::ColorButton + QPushButton +
Gui/Widgets.h
+
+
- + + diff --git a/SheetMetalBaseCmd.py b/SheetMetalBaseCmd.py index 0340be9..349f94e 100644 --- a/SheetMetalBaseCmd.py +++ b/SheetMetalBaseCmd.py @@ -108,7 +108,7 @@ def smBase( return wallSolid class SMBaseBend: - def __init__(self, obj): + def __init__(self, obj, sketch): '''"Add wall or Wall with radius bend"''' _tip_ = translate("App::Property", "Bend Radius") obj.addProperty( @@ -129,7 +129,7 @@ def __init__(self, obj): _tip_ = translate("App::Property", "Wall Sketch object") obj.addProperty( "App::PropertyLink", "BendSketch", "Parameters", _tip_ - ).BendSketch = None + ).BendSketch = sketch _tip_ = translate("App::Property", "Extrude Symmetric to Plane") obj.addProperty( "App::PropertyBool", "MidPlane", "Parameters", _tip_ @@ -162,6 +162,7 @@ def execute(self, fp): ) fp.Shape = s + SheetMetalTools.HideObjects(fp.BendSketch) ########################################################################################################## @@ -260,15 +261,13 @@ def Activated(self): doc.openTransaction("BaseBend") if activeBody is None: a = doc.addObject("Part::FeaturePython", "BaseBend") - SMBaseBend(a) + SMBaseBend(a, selobj) SMBaseViewProvider(a.ViewObject) - a.BendSketch = selobj else: # FreeCAD.Console.PrintLog("found active body: " + activeBody.Name) a = doc.addObject("PartDesign::FeaturePython", "BaseBend") - SMBaseBend(a) + SMBaseBend(a, selobj) SMBaseViewProvider(a.ViewObject) - a.BendSketch = selobj activeBody.addObject(a) doc.recompute() doc.commitTransaction() diff --git a/SheetMetalBend.py b/SheetMetalBend.py index cfb39d4..ca05d0a 100644 --- a/SheetMetalBend.py +++ b/SheetMetalBend.py @@ -102,14 +102,15 @@ def smSolidBend(radius = 1.0, selEdgeNames = '', MainObject = None): class SMSolidBend: - def __init__(self, obj): + def __init__(self, obj, selobj, sel_elements): '''"Add Bend to Solid" ''' _tip_ = FreeCAD.Qt.translate("App::Property","Bend Radius") obj.addProperty("App::PropertyLength","radius","Parameters", _tip_).radius = 1.0 _tip_ = FreeCAD.Qt.translate("App::Property","Base object") - obj.addProperty("App::PropertyLinkSub", "baseObject", "Parameters", _tip_) + obj.addProperty("App::PropertyLinkSub", "baseObject", "Parameters", _tip_).baseObject = (selobj, sel_elements) + obj.Proxy = self def getElementMapVersion(self, _fp, ver, _prop, restored): if not restored: @@ -390,13 +391,12 @@ def Activated(self): doc.openTransaction("Add Bend") if activeBody is None or not SheetMetalTools.smIsPartDesign(selobj): a = doc.addObject("Part::FeaturePython","SolidBend") - SMSolidBend(a) - a.baseObject = (selobj, sel.SubElementNames) + SMSolidBend(a, selobj, sel.SubElementNames) SMBendViewProviderTree(a.ViewObject) else: #FreeCAD.Console.PrintLog("found active body: " + activeBody.Name) a = doc.addObject("PartDesign::FeaturePython","SolidBend") - SMSolidBend(a) + SMSolidBend(a, selobj, sel.SubElementNames) SMBendViewProviderFlat(a.ViewObject) activeBody.addObject(a) SheetMetalTools.SetViewConfig(a, viewConf) diff --git a/SheetMetalCmd.py b/SheetMetalCmd.py index 7bbcf16..a3a5938 100644 --- a/SheetMetalCmd.py +++ b/SheetMetalCmd.py @@ -1367,14 +1367,14 @@ def smBend( class SMBendWall: - def __init__(self, obj): + def __init__(self, obj, selobj, sel_items): '''"Add Wall with radius bend"''' self._addProperties(obj) _tip_ = translate("App::Property", "Base Object") obj.addProperty( "App::PropertyLinkSub", "baseObject", "Parameters", _tip_ - ) + ).baseObject = (selobj, sel_items) obj.Proxy = self def _addProperties(self, obj): @@ -2066,14 +2066,12 @@ def Activated(self): doc.openTransaction("Bend") if activeBody is None or not SheetMetalTools.smIsPartDesign(selobj): a = doc.addObject("Part::FeaturePython", "Bend") - SMBendWall(a) - a.baseObject = (selobj, sel.SubElementNames) + SMBendWall(a, selobj, sel.SubElementNames) SMViewProviderTree(a.ViewObject) else: # FreeCAD.Console.PrintLog("found active body: " + activeBody.Name) a = doc.addObject("PartDesign::FeaturePython", "Bend") - SMBendWall(a) - a.baseObject = (selobj, sel.SubElementNames) + SMBendWall(a, selobj, sel.SubElementNames) SMViewProviderFlat(a.ViewObject) activeBody.addObject(a) SheetMetalTools.SetViewConfig(a, viewConf) diff --git a/SheetMetalCornerReliefCmd.py b/SheetMetalCornerReliefCmd.py index 2d6bf63..674ea62 100644 --- a/SheetMetalCornerReliefCmd.py +++ b/SheetMetalCornerReliefCmd.py @@ -433,9 +433,8 @@ def smCornerR( class SMCornerRelief: - def __init__(self, obj): + def __init__(self, obj, selobj, sel_items): '''"Add Corner Relief to Sheetmetal Bends"''' - selobj = Gui.Selection.getSelectionEx() _tip_ = FreeCAD.Qt.translate("App::Property", "Corner Relief Type") obj.addProperty( "App::PropertyEnumeration", "ReliefSketch", "Parameters", _tip_ @@ -449,7 +448,7 @@ def __init__(self, obj): _tip_ = FreeCAD.Qt.translate("App::Property", "Base object") obj.addProperty( "App::PropertyLinkSub", "baseObject", "Parameters", _tip_ - ).baseObject = (selobj[0].Object, selobj[0].SubElementNames) + ).baseObject = (selobj, sel_items) _tip_ = FreeCAD.Qt.translate("App::Property", "Size of Shape") obj.addProperty("App::PropertyLength", "Size", "Parameters", _tip_).Size = 3.0 _tip_ = FreeCAD.Qt.translate("App::Property", "Size Ratio of Shape") @@ -487,10 +486,7 @@ def execute(self, fp): MainObject=fp.baseObject[0], ) fp.Shape = s - - Gui.ActiveDocument.getObject(fp.baseObject[0].Name).Visibility = False - if fp.Sketch: - Gui.ActiveDocument.getObject(fp.Sketch.Name).Visibility = False + SheetMetalTools.HideObjects(fp.baseObject[0], fp.Sketch) ########################################################################################################## # Gui code @@ -640,13 +636,12 @@ def Activated(self): doc.openTransaction("Corner Relief") if activeBody is None or not SheetMetalTools.smIsPartDesign(selobj): a = doc.addObject("Part::FeaturePython", "CornerRelief") - SMCornerRelief(a) - a.baseObject = (selobj, sel.SubElementNames) + SMCornerRelief(a, selobj, sel.SubElementNames) SMCornerReliefVP(a.ViewObject) else: # FreeCAD.Console.PrintLog("found active body: " + activeBody.Name) a = doc.addObject("PartDesign::FeaturePython", "CornerRelief") - SMCornerRelief(a) + SMCornerRelief(a, selobj, sel.SubElementNames) SMCornerReliefPDVP(a.ViewObject) activeBody.addObject(a) SheetMetalTools.SetViewConfig(a, viewConf) diff --git a/SheetMetalExtendCmd.py b/SheetMetalExtendCmd.py index 49a3d6e..9d6a812 100644 --- a/SheetMetalExtendCmd.py +++ b/SheetMetalExtendCmd.py @@ -263,7 +263,7 @@ def smExtrude(extLength = 10.0, gap1 = 0.0, gap2 = 0.0, subtraction = False, off return finalShape class SMExtrudeWall: - def __init__(self, obj): + def __init__(self, obj, selobj, sel_items): '''"Add Sheetmetal Wall by Extending" ''' _tip_ = FreeCAD.Qt.translate("App::Property","Length of Wall") @@ -273,7 +273,7 @@ def __init__(self, obj): _tip_ = FreeCAD.Qt.translate("App::Property","Gap from right side") obj.addProperty("App::PropertyDistance","gap2","Parameters",_tip_).gap2 = 0.0 _tip_ = FreeCAD.Qt.translate("App::Property","Base object") - obj.addProperty("App::PropertyLinkSub", "baseObject", "Parameters",_tip_).baseObject + obj.addProperty("App::PropertyLinkSub", "baseObject", "Parameters",_tip_).baseObject = (selobj, sel_items) _tip_ = FreeCAD.Qt.translate("App::Property","Wall Sketch") obj.addProperty("App::PropertyLink","Sketch","ParametersExt",_tip_) _tip_ = FreeCAD.Qt.translate("App::Property","Use Subtraction") @@ -579,13 +579,11 @@ def Activated(self): doc.openTransaction("Extend") if (activeBody is None): a = doc.addObject("Part::FeaturePython","Extend") - SMExtrudeWall(a) - a.baseObject = (selobj, sel.SubElementNames) + SMExtrudeWall(a, selobj, sel.SubElementNames) SMViewProviderTree(a.ViewObject) else: a = doc.addObject("PartDesign::FeaturePython","Extend") - SMExtrudeWall(a) - a.baseObject = (selobj, sel.SubElementNames) + SMExtrudeWall(a, selobj, sel.SubElementNames) SMViewProviderFlat(a.ViewObject) activeBody.addObject(a) SheetMetalTools.SetViewConfig(a, viewConf) diff --git a/SheetMetalFoldCmd.py b/SheetMetalFoldCmd.py index 6c8f7ec..2de90b2 100644 --- a/SheetMetalFoldCmd.py +++ b/SheetMetalFoldCmd.py @@ -121,7 +121,7 @@ def smFold( facenormal = cutFaceDir.Faces[0].normalAt(0, 0) # print(facenormal) - if position == "middle": + if position == "middle" or position == "intersection of planes": tool.translate(facenormal * -unfoldLength / 2.0) toolFaces = tool.extrude(normal * -thk) elif position == "backward": @@ -243,11 +243,12 @@ def smFold( else: if bendlinesketch and bendA > 0.0: resultsolid = FoldShape + SheetMetalTools.HideObjects(MainObject, bendlinesketch) return resultsolid class SMFoldWall: - def __init__(self, obj): + def __init__(self, obj, selobj, sel_items, sel_sketch): '''"Fold / Bend a Sheetmetal with given Bend Radius"''' _tip_ = FreeCAD.Qt.translate("App::Property", "Bend Radius") @@ -259,11 +260,11 @@ def __init__(self, obj): _tip_ = FreeCAD.Qt.translate("App::Property", "Base Object") obj.addProperty( "App::PropertyLinkSub", "baseObject", "Parameters", _tip_ - ) + ).baseObject = (selobj, sel_items) _tip_ = FreeCAD.Qt.translate("App::Property", "Bend Reference Line List") obj.addProperty( "App::PropertyLink", "BendLine", "Parameters", _tip_ - ) + ).BendLine = sel_sketch _tip_ = FreeCAD.Qt.translate("App::Property", "Invert Solid Bend Direction") obj.addProperty( "App::PropertyBool", "invertbend", "Parameters", _tip_ @@ -458,16 +459,12 @@ def Activated(self): doc.openTransaction("Bend") if activeBody is None or not SheetMetalTools.smIsPartDesign(selobj): a = doc.addObject("Part::FeaturePython", "Fold") - SMFoldWall(a) - a.baseObject = (selobj, sel[0].SubElementNames) - a.BendLine = sel[1].Object + SMFoldWall(a, selobj, sel[0].SubElementNames, sel[1].Object) SMFoldViewProvider(a.ViewObject) else: # FreeCAD.Console.PrintLog("found active body: " + activeBody.Name) a = doc.addObject("PartDesign::FeaturePython", "Fold") - SMFoldWall(a) - a.baseObject = (selobj, sel[0].SubElementNames) - a.BendLine = sel[1].Object + SMFoldWall(a, selobj, sel[0].SubElementNames, sel[1].Object) SMFoldPDViewProvider(a.ViewObject) activeBody.addObject(a) SheetMetalTools.SetViewConfig(a, viewConf) diff --git a/SheetMetalFormingCmd.py b/SheetMetalFormingCmd.py index f7e7398..cf4a811 100644 --- a/SheetMetalFormingCmd.py +++ b/SheetMetalFormingCmd.py @@ -105,7 +105,7 @@ def makeforming(tool, base, base_face, thk, tool_faces = None, point = FreeCAD.V return base class SMBendWall: - def __init__(self, obj): + def __init__(self, obj, selobj, selobj_items, seltool, seltool_items): '''"Add Forming Wall" ''' _tip_ = FreeCAD.Qt.translate("App::Property","Offset from Center of Face") @@ -117,9 +117,11 @@ def __init__(self, obj): _tip_ = FreeCAD.Qt.translate("App::Property","Thickness of Sheetmetal") obj.addProperty("App::PropertyDistance","thickness","Parameters",_tip_) _tip_ = FreeCAD.Qt.translate("App::Property","Base Object") - obj.addProperty("App::PropertyLinkSub", "baseObject", "Parameters",_tip_) + obj.addProperty("App::PropertyLinkSub", "baseObject", "Parameters", + _tip_).baseObject = (selobj, selobj_items) _tip_ = FreeCAD.Qt.translate("App::Property","Forming Tool Object") - obj.addProperty("App::PropertyLinkSub", "toolObject", "Parameters",_tip_) + obj.addProperty("App::PropertyLinkSub", "toolObject", "Parameters", + _tip_).toolObject = (seltool, seltool_items) _tip_ = FreeCAD.Qt.translate("App::Property","Point Sketch on Sheetmetal") obj.addProperty("App::PropertyLink","Sketch","Parameters1",_tip_) obj.Proxy = self @@ -155,7 +157,7 @@ def execute(self, fp): else : a = base fp.Shape = a - + SheetMetalTools.HideObjects(fp.baseObject[0], fp.toolObject[0].Name, fp.Sketch) ########################################################################################################## # Gui code @@ -472,16 +474,12 @@ def Activated(self): doc.openTransaction("WallForming") if activeBody is None or not SheetMetalTools.smIsPartDesign(selobj): a = doc.addObject("Part::FeaturePython","WallForming") - SMBendWall(a) - a.baseObject = (selobj, sel[0].SubElementNames) - a.toolObject = (sel[1].Object, sel[1].SubElementNames) + SMBendWall(a, selobj, sel[0].SubElementNames, sel[1].Object, sel[1].SubElementNames) SMFormingVP(a.ViewObject) else: #FreeCAD.Console.PrintLog("found active body: " + activeBody.Name) a = doc.addObject("PartDesign::FeaturePython","WallForming") - SMBendWall(a) - a.baseObject = (selobj, sel[0].SubElementNames) - a.toolObject = (sel[1].Object, sel[1].SubElementNames) + SMBendWall(a, selobj, sel[0].SubElementNames, sel[1].Object, sel[1].SubElementNames) SMFormingPDVP(a.ViewObject) activeBody.addObject(a) SheetMetalTools.SetViewConfig(a, viewConf) diff --git a/SheetMetalJunction.py b/SheetMetalJunction.py index 4b357b7..f2138ba 100644 --- a/SheetMetalJunction.py +++ b/SheetMetalJunction.py @@ -62,13 +62,14 @@ def smJunction(gap = 2.0, selEdgeNames = '', MainObject = None): return resultSolid class SMJunction: - def __init__(self, obj): + def __init__(self, obj, selobj, sel_items): '''"Add Gap to Solid" ''' _tip_ = FreeCAD.Qt.translate("App::Property","Junction Gap") obj.addProperty("App::PropertyLength","gap","Parameters",_tip_).gap = 2.0 _tip_ = FreeCAD.Qt.translate("App::Property","Base Object") - obj.addProperty("App::PropertyLinkSub", "baseObject", "Parameters",_tip_) + obj.addProperty("App::PropertyLinkSub", "baseObject", "Parameters", + _tip_).baseObject = (selobj, sel_items) obj.Proxy = self def getElementMapVersion(self, _fp, ver, _prop, restored): @@ -81,6 +82,7 @@ def execute(self, fp): Main_Object = fp.baseObject[0].Shape.copy() s = smJunction(gap = fp.gap.Value, selEdgeNames = fp.baseObject[1], MainObject = Main_Object) fp.Shape = s + SheetMetalTools.HideObjects(fp.baseObject[0]) ########################################################################################################## @@ -351,14 +353,12 @@ def Activated(self): doc.openTransaction("Add Junction") if activeBody is None or not SheetMetalTools.smIsPartDesign(selobj): a = doc.addObject("Part::FeaturePython","Junction") - SMJunction(a) - a.baseObject = (selobj, sel.SubElementNames) + SMJunction(a, selobj, sel.SubElementNames) SMJViewProviderTree(a.ViewObject) else: #FreeCAD.Console.PrintLog("found active body: " + activeBody.Name) a = doc.addObject("PartDesign::FeaturePython","Junction") - SMJunction(a) - a.baseObject = (selobj, sel.SubElementNames) + SMJunction(a, selobj, sel.SubElementNames) SMJViewProviderFlat(a.ViewObject) activeBody.addObject(a) SheetMetalTools.SetViewConfig(a, viewConf) diff --git a/SheetMetalRelief.py b/SheetMetalRelief.py index cd73144..afa787a 100644 --- a/SheetMetalRelief.py +++ b/SheetMetalRelief.py @@ -129,7 +129,7 @@ def execute(self, fp): Main_Object = fp.baseObject[0].Shape.copy() s = smRelief(relief = fp.relief.Value, selVertexNames = fp.baseObject[1], MainObject = Main_Object) fp.Shape = s - fp.baseObject[0].ViewObject.Visibility = False + SheetMetalTools.HideObjects(fp.baseObject[0]) ########################################################################################################## diff --git a/SheetMetalTools.py b/SheetMetalTools.py index d7e544d..ed57a49 100644 --- a/SheetMetalTools.py +++ b/SheetMetalTools.py @@ -26,10 +26,22 @@ def smWarnDialog(msg): ) diag.setWindowModality(QtCore.Qt.ApplicationModal) diag.exec_() + + def HideObjects(*args): + from FreeCAD import Gui + for arg in args: + if arg: + obj = Gui.ActiveDocument.getObject(arg.Name) + if obj: + obj.Visibility = False + else: def smWarnDialog(msg): SMLogger.warning(msg) + def HideObjects(*args): + pass + def smBelongToBody(item, body): if body is None: return False diff --git a/SheetMetalUnfoldCmd.py b/SheetMetalUnfoldCmd.py index 5f28fbb..4057e91 100644 --- a/SheetMetalUnfoldCmd.py +++ b/SheetMetalUnfoldCmd.py @@ -24,289 +24,29 @@ # ############################################################################### -import FreeCAD, Part, os, SheetMetalTools, SheetMetalKfactor -from PySide import QtCore, QtGui +import Part, FreeCAD, FreeCADGui, os +from PySide import QtGui, QtCore from FreeCAD import Gui -from engineering_mode import engineering_mode_enabled -from SheetMetalUnfolder import SMUnfold, processUnfoldSketches -from SheetMetalLogger import SMLogger - -GENSKETCHCOLOR = "#000080" -BENDSKETCHCOLOR = "#c00000" -INTSKETCHCOLOR = "#ff5733" -KFACTOR = 0.40 -panels_path = SheetMetalTools.panels_path -icons_path = SheetMetalTools.icons_path -mds_help_url = "https://github.com/shaise/FreeCAD_SheetMetal#material-definition-sheet" - -######## ViewProvider ######## - - -class SMUnfoldVP: - "A View provider that places objects flat under base object" - - def __init__(self, obj): - obj.Proxy = self - self.Object = obj.Object - - def attach(self, obj): - self.Object = obj.Object - return - - def setupContextMenu(self, viewObject, menu): - action = menu.addAction( - FreeCAD.Qt.translate("QObject", "Edit %1").replace( - "%1", viewObject.Object.Label - ) - ) - action.triggered.connect(lambda: self.startDefaultEditMode(viewObject)) - return False - - def startDefaultEditMode(self, viewObject): - document = viewObject.Document.Document - if not document.HasPendingTransaction: - text = FreeCAD.Qt.translate("QObject", "Edit %1").replace( - "%1", viewObject.Object.Label - ) - document.openTransaction(text) - viewObject.Document.setEdit(viewObject.Object, 0) - - def updateData(self, fp, prop): - return - - def getDisplayModes(self, obj): - modes = [] - return modes - - def setDisplayMode(self, mode): - return mode - - def onChanged(self, vp, prop): - return - - def __getstate__(self): - # return {'ObjectName' : self.Object.Name} - return None - - def __setstate__(self, state): - self.loads(state) - - # dumps and loads replace __getstate__ and __setstate__ post v. 0.21.2 - def dumps(self): - return None - - def loads(self, state): - if state is not None: - import FreeCAD - - doc = FreeCAD.ActiveDocument # crap - self.Object = doc.getObject(state["ObjectName"]) - - def getIcon(self): - return os.path.join(icons_path, "SheetMetal_Unfold.svg") - - def setEdit(self, vobj, mode): - vobj.Object.Document.openTransaction("Unfold") - taskd = SMUnfoldTaskPanel(vobj.Object) - taskd.form[1].chkSketch.setChecked(False) - Gui.Control.showDialog(taskd) - return True - - def unsetEdit(self, vobj, mode): - Gui.Control.closeDialog() - self.Object.ViewObject.Visibility = True - return False - - -######## TaskPanel ######## +from UnfoldGUI import SMUnfoldTaskPanel +try: + from TechDraw import projectEx +except: + from Drawing import projectEx -class SMUnfoldTaskPanel: - def __init__(self, object): - path = os.path.join(panels_path,"UnfoldOptions.ui") - path2 = os.path.join(panels_path,"UnfoldSketchOptions.ui") - self.form = [] - self.form.append(Gui.PySideUic.loadUi(path)) - self.form.append(Gui.PySideUic.loadUi(path2)) - self.pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/SheetMetal") - self.object = object - self.SelModeActive = False - self.setupUi() - - def _boolToState(self, bool): - return QtCore.Qt.Checked if bool else QtCore.Qt.Unchecked - - def _isManualKSelected(self): - return self.form[0].availableMds.currentIndex() == ( - self.form[0].availableMds.count() - 1 - ) - - def _isNoMdsSelected(self): - return self.form[0].availableMds.currentIndex() == 0 - - def _getMdsIndex(self, label): - for i in range(self.form[0].availableMds.count()): - if self.form[0].availableMds.itemText(i) == label: - return i - return -1 - - def setupUi(self): - self.form[0].availableMds.currentIndexChanged.connect(self.availableMdsChange) - self.form[0].selectFaceButton.toggled.connect(self.toggleSelectionMode) - - self.form[0].kfactorAnsi.setChecked(self.object.kFactorStandard == "ansi") - self.form[0].kfactorDin.setChecked(self.object.kFactorStandard == "din") - self.form[0].kFactSpin.setValue(self.object.kfactor) - self.form[0].transSpin.setValue(self.object.ViewObject.Transparency) - - self.populateMdsList() - self.availableMdsChange() - - self.form[0].update() - self.form[1].chkSketch.stateChanged.connect(self.chkSketchChange) - self.form[1].chkSeparate.stateChanged.connect(self.chkSketchChange) - self.form[1].chkSketch.setCheckState( - self._boolToState(self.pg.GetBool("genSketch")) - ) - self.form[1].chkSeparate.setCheckState( - self._boolToState(self.pg.GetBool("separateSketches")) - ) - self.form[1].genColor.setProperty( - "color", self.pg.GetString("genColor", GENSKETCHCOLOR) - ) - self.form[1].bendColor.setProperty( - "color", self.pg.GetString("bendColor", BENDSKETCHCOLOR) - ) - self.form[1].internalColor.setProperty( - "color", self.pg.GetString("internalColor", INTSKETCHCOLOR) - ) - - - def accept(self): - if self.SelModeActive: - self.toggleSelectionMode() - self.object.kFactorStandard = "din" if self.form[0].kfactorDin.isChecked() else "ansi" - self.object.kfactor = self.form[0].kFactSpin.value() - if self._isManualKSelected(): - self.object.useManualKFactor = True - self.object.materialSheet = None - elif self._isNoMdsSelected(): - msg = FreeCAD.Qt.translate( - "Logger", "Unfold operation needs to know K-factor value(s) to be used." - ) - SMLogger.warning(msg) - msg += FreeCAD.Qt.translate( - "QMessageBox", - "
    \n" - "
  1. Either select 'Manual K-factor'
  2. \n" - "
  3. Or use a Material Definition Sheet
  4. \n" - "
", - ).format(mds_help_url) - QtGui.QMessageBox.warning( - None, FreeCAD.Qt.translate("QMessageBox", "Warning"), msg - ) - return None - else: - self.object.useManualKFactor = False - self.object.materialSheet = FreeCAD.ActiveDocument.getObjectsByLabel( - self.form[0].availableMds.currentText() - )[0] - self.object.ViewObject.Transparency = self.form[0].transSpin.value() - FreeCAD.ActiveDocument.commitTransaction() - FreeCAD.ActiveDocument.recompute() - if self.form[1].chkSketch.isChecked() and self.object.foldComp: - FreeCAD.ActiveDocument.openTransaction("Unfold sketch projection") - shape = self.object.Shape - foldLines = self.object.foldComp.Edges - norm = self.object.baseObject[0].getSubObject(self.object.baseObject[1][0]).normalAt(0,0) - splitSketches = self.form[1].chkSeparate.isChecked() - genSketchColor = self.form[1].genColor.property("color").name() - bendSketchColor = self.form[1].bendColor.property("color").name() - intSketchColor = self.form[1].internalColor.property("color").name() - processUnfoldSketches(shape, foldLines, norm, splitSketches, genSketchColor, bendSketchColor, intSketchColor) - FreeCAD.ActiveDocument.commitTransaction() - FreeCAD.ActiveDocument.recompute() - Gui.Control.closeDialog() - Gui.ActiveDocument.resetEdit() - - def reject(self): - FreeCAD.ActiveDocument.abortTransaction() - Gui.Control.closeDialog() - Gui.ActiveDocument.resetEdit() - FreeCAD.ActiveDocument.recompute() - - def populateMdsList(self): - sheetnames = SheetMetalKfactor.getSpreadSheetNames() - self.form[0].availableMds.clear() - - self.form[0].availableMds.addItem("Please select") - for mds in sheetnames: - if mds.Label.startswith("material_"): - self.form[0].availableMds.addItem(mds.Label) - self.form[0].availableMds.addItem("Manual K-Factor") - - selMdsIndex = -1 - if self.object.materialSheet: - selMdsIndex = self._getMdsIndex(self.object.materialSheet.Label) - elif self.object.useManualKFactor: - selMdsIndex = self.form[0].availableMds.count()-1 - - if selMdsIndex >= 0: - self.form[0].availableMds.setCurrentIndex(selMdsIndex) - elif len(sheetnames) == 1: - self.form[0].availableMds.setCurrentIndex(1) - elif engineering_mode_enabled(): - self.form[0].availableMds.setCurrentIndex(0) - elif len(sheetnames) == 0: - self.form[0].availableMds.setCurrentIndex(1) - - def chkSketchChange(self): - self.form[1].genColor.setEnabled(self.form[1].chkSketch.isChecked()) - self.form[1].chkSeparate.setEnabled(self.form[1].chkSketch.isChecked()) - enabled = self.form[1].chkSketch.isChecked() and self.form[1].chkSeparate.isChecked() - self.form[1].bendColor.setEnabled(enabled) - self.form[1].internalColor.setEnabled(enabled) - - def availableMdsChange(self): - isManualK = self._isManualKSelected() - self.form[0].kfactorAnsi.setEnabled(isManualK) - self.form[0].kfactorDin.setEnabled(isManualK) - self.form[0].kFactSpin.setEnabled(isManualK) - self.object.useManualKFactor = isManualK - if not isManualK: - self.object.materialSheet = FreeCAD.ActiveDocument.getObjectsByLabel( - self.form[0].availableMds.currentText() - )[0] - self.object.recompute() - - def toggleSelectionMode(self): - if not self.SelModeActive: - self.object.Visibility=False - self.object.baseObject[0].Visibility=True - Gui.Selection.clearSelection() - Gui.Selection.addSelection(self.object.baseObject[0],self.object.baseObject[1]) - self.SelModeActive=True - self.form[0].selectFaceButton.setText('Preview') - else: - sel = Gui.Selection.getSelectionEx()[0] - self.object.baseObject = [ sel.Object, sel.SubElementNames[0] ] - Gui.Selection.clearSelection() - self.object.Document.recompute() - self.object.Visibility=True - self.SelModeActive=False - self.form[0].selectFaceButton.setText('Select Face') - -######## Commands ######## +from engineering_mode import engineering_mode_enabled +from SheetMetalLogger import SMLogger, UnfoldException, BendException, TreeException class SMUnfoldUnattendedCommandClass: """Unfold object""" def GetResources(self): - icons_path = SheetMetalTools.icons_path + __dir__ = os.path.dirname(__file__) + iconPath = os.path.join(__dir__, "Resources", "icons") return { "Pixmap": os.path.join( - icons_path, "SheetMetal_UnfoldUnattended.svg" + iconPath, "SheetMetal_UnfoldUnattended.svg" ), # the name of a svg file available in the resources "MenuText": FreeCAD.Qt.translate("SheetMetal", "Unattended Unfold"), "Accel": "U", @@ -320,21 +60,26 @@ def GetResources(self): def Activated(self): SMLogger.message(FreeCAD.Qt.translate("Logger", "Running unattended unfold...")) - doc = FreeCAD.ActiveDocument - sel = Gui.Selection.getSelectionEx()[0] - doc.openTransaction("Unattended Unfold") - obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Unfold") - SMUnfold(obj) - SMUnfoldVP(obj.ViewObject) - obj.baseObject = [ sel.Object, sel.SubElementNames[0] ] + try: + taskd = SMUnfoldTaskPanel() + except ValueError as e: + SMLogger.error(e.args[0]) + return + pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/SheetMetal") - obj.kFactorStandard = pg.GetString("kFactorStandard", "ansi") - obj.ViewObject.Transparency = pg.GetInt("genObjTransparency", 50) - obj.kfactor = pg.GetFloat("manualKFactor", KFACTOR) - Gui.Selection.clearSelection() - doc.recompute() - dialog = SMUnfoldTaskPanel(obj) - dialog.accept() + if pg.GetBool("separateSketches"): + taskd.form.chkSeparate.setCheckState(QtCore.Qt.CheckState.Checked) + else: + taskd.form.chkSeparate.setCheckState(QtCore.Qt.CheckState.Unchecked) + if pg.GetBool("genSketch"): + taskd.form.chkSketch.setCheckState(QtCore.Qt.CheckState.Checked) + else: + taskd.form.chkSketch.setCheckState(QtCore.Qt.CheckState.Unchecked) + taskd.form.bendColor.setProperty("color", pg.GetString("bendColor")) + taskd.form.genColor.setProperty("color", pg.GetString("genColor")) + taskd.form.internalColor.setProperty("color", pg.GetString("intColor")) + # taskd.new_mds_name = taskd.material_sheet_name + taskd.accept() return def IsActive(self): @@ -355,13 +100,15 @@ class SMUnfoldCommandClass: """Unfold object""" def GetResources(self): - icons_path = SheetMetalTools.icons_path + __dir__ = os.path.dirname(__file__) + iconPath = os.path.join(__dir__, "Resources", "icons") # add translations path - Gui.addLanguagePath(SheetMetalTools.language_path) + LanguagePath = os.path.join(__dir__, "translations") + Gui.addLanguagePath(LanguagePath) Gui.updateLocale() return { "Pixmap": os.path.join( - icons_path, "SheetMetal_Unfold.svg" + iconPath, "SheetMetal_Unfold.svg" ), # the name of a svg file available in the resources "MenuText": FreeCAD.Qt.translate("SheetMetal", "Unfold"), "Accel": "U", @@ -374,21 +121,17 @@ def GetResources(self): } def Activated(self): - doc = FreeCAD.ActiveDocument - sel = Gui.Selection.getSelectionEx()[0] - doc.openTransaction("Unfold") - obj = doc.addObject("Part::FeaturePython", "Unfold") - SMUnfold(obj) - SMUnfoldVP(obj.ViewObject) - obj.baseObject = [ sel.Object, sel.SubElementNames[0] ] - pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/SheetMetal") - obj.kFactorStandard = pg.GetString("kFactorStandard", "ansi") - obj.ViewObject.Transparency = pg.GetInt("genObjTransparency", 50) - obj.kfactor = pg.GetFloat("manualKFactor", KFACTOR) - Gui.Selection.clearSelection() - doc.recompute() - dialog = SMUnfoldTaskPanel(obj) - Gui.Control.showDialog(dialog) + dialog = SMUnfoldTaskPanel() + FreeCADGui.Control.showDialog(dialog) + + # try: + # taskd = SMUnfoldTaskPanel() + # except ValueError as e: + # SMErrorBox(e.args[0]) + # return + + # FreeCADGui.Control.showDialog(taskd) + # return def IsActive(self): if ( diff --git a/SheetMetalUnfolder.py b/SheetMetalUnfolder.py index b0b148e..e5ffdbe 100644 --- a/SheetMetalUnfolder.py +++ b/SheetMetalUnfolder.py @@ -103,14 +103,20 @@ def main(): """ -import FreeCAD, Part, sys, SheetMetalTools, SheetMetalKfactor +import Part, FreeCAD, FreeCADGui, os, sys from FreeCAD import Base -import math, time +import DraftVecUtils, math, time +import Draft # import traceback # traceback.print_exc() +try: + from TechDraw import projectEx +except ImportError: + from Drawing import projectEx + from lookup import get_val_from_range import tempfile @@ -119,14 +125,8 @@ def main(): from SheetMetalLogger import SMLogger, UnfoldException, BendException, TreeException -# IMPORTANT: please remember to change the element map version in case of any -# changes in modeling logic -smElementMapVersion = "sm1." - KFACTORSTANDARD = None -translate = FreeCAD.Qt.translate - # TODO: Error Codes # - Put error numbers into the text # - Put user help into more texts @@ -422,7 +422,7 @@ def k_Factor(self): @k_Factor.setter def k_Factor(self, val): SMLogger.error( - translate( + FreeCAD.Qt.translate( "Logger", "k_Factor is a readonly property! Won't set to:" ), val, @@ -465,12 +465,11 @@ def dump(self): print("index Unfold list:") print(self.index_unfold_list) - def __init__(self, TheShape, f_idx, k_factor_lookup, obj): + def __init__(self, TheShape, f_idx, k_factor_lookup): self.cFaceTol = 0.002 # tolerance to detect counter-face vertices # this high tolerance was needed for more real parts self.root = None # make_new_face_node adds the root node if parent_node == None self.__Shape = TheShape.copy() - self.obj = obj self.error_code = None self.failed_face_idx = None self.k_factor_lookup = k_factor_lookup @@ -1153,8 +1152,8 @@ def make_new_face_node(self, face_idx, P_node, P_edge, wires_e_lists): counter_found = False if counter_found: - if hasattr(self.obj, "Refine"): - if self.obj.Refine is True: + if hasattr(FreeCADGui.Selection.getSelection()[0], "Refine"): + if FreeCADGui.Selection.getSelection()[0].Refine is True: distance = self.__Shape.Faces[i].distToShape( self.__Shape.Faces[face_idx] )[0] @@ -1573,8 +1572,8 @@ def Bend_analysis(self, face_idx, parent_node=None, parent_edge=None): if not self.handle_hole( parent_node, face_idx, edge, child_face, child_index ): - if hasattr(self.obj, "Refine"): - if self.obj.Refine is True: + if hasattr(FreeCADGui.Selection.getSelection()[0], "Refine"): + if FreeCADGui.Selection.getSelection()[0].Refine is True: if not self.handle_chamfer( face_idx, edge, child_face, child_face_idx ): @@ -2496,7 +2495,7 @@ def unbendPoint(poi): # theFace = Part.makeFilledFace(wires) theFace = faces[0] SMLogger.error( - translate("Logger", "at line {} got exception: ").format( + FreeCAD.Qt.translate("Logger", "at line {} got exception: ").format( str(exc_tb.tb_lineno), ), str(e), @@ -2881,19 +2880,71 @@ def build_new_wire(self, wire, face_idx, wire_idx): return wire.copy(), False -def sew_Shape(obj): +# from Defeaturing WB: Export to Step +def sew_Shape(): """checking Shape""" - if hasattr(obj, "Shape"): - sh = obj.Shape.copy() - sh.sewShape() - sl = Part.Solid(sh) - return sl + doc = FreeCAD.ActiveDocument + docG = FreeCADGui.ActiveDocument + + sel = FreeCADGui.Selection.getSelection() + if len(sel) == 1: + o = sel[0] + if hasattr(o, "Shape"): + sh = o.Shape.copy() + sh.sewShape() + sl = Part.Solid(sh) + docG.getObject(o.Name).Visibility = False + Part.show(sl) + ao = FreeCAD.ActiveDocument.ActiveObject + ao.Label = "Solid" + docG.ActiveObject.ShapeColor = docG.getObject(o.Name).ShapeColor + docG.ActiveObject.LineColor = docG.getObject(o.Name).LineColor + docG.ActiveObject.PointColor = docG.getObject(o.Name).PointColor + docG.ActiveObject.DiffuseColor = docG.getObject(o.Name).DiffuseColor + docG.ActiveObject.Transparency = docG.getObject(o.Name).Transparency + else: + FreeCAD.Console.PrintError("select only one object") + + +def makeSolidExpSTEP(): + doc = FreeCAD.ActiveDocument + docG = FreeCADGui.ActiveDocument + if doc is not None: + fname = doc.FileName + if len(fname) == 0: + fileNm = "untitled" + else: + fileNm = os.path.basename(fname) + fileNm = os.path.splitext(fileNm)[0] + tempdir = tempfile.gettempdir() # get the current temporary directory + # print(tempdir) + # fileNm = os.path.basename(fname) + # tempfilepath = os.path.join(tempdir,fname.rstrip(".fcstd").rstrip(".FCStd") + u'_cp.stp') + tempfilepath = os.path.join(tempdir, fileNm + "_cp.stp") + print(tempfilepath) + sel = FreeCADGui.Selection.getSelection() + if len(sel) == 1: + __objs__ = [] + __objs__.append(sel[0]) + import ImportGui + + stop + ImportGui.export(__objs__, tempfilepath) + del __objs__ + # docG.getObject(sel[0].Name).Visibility = False + ImportGui.insert(tempfilepath, doc.Name) + FreeCADGui.SendMsgToActiveView("ViewFit") + else: + FreeCAD.Console.PrintError("Select only one object") + else: + FreeCAD.Console.PrintError("Select only one object") -def getUnfold(k_factor_lookup, solid, subelement, facename, kFactorStandard): - global KFACTORSTANDARD - KFACTORSTANDARD = kFactorStandard +## + + +def getUnfold(k_factor_lookup, solid, subelement, facename): resPart = None normalVect = None folds = None @@ -2909,7 +2960,7 @@ def getUnfold(k_factor_lookup, solid, subelement, facename, kFactorStandard): startzeit = time.process_time() TheTree = SheetTree( - solid.Shape, f_number, k_factor_lookup, solid + solid.Shape, f_number, k_factor_lookup ) # initializes the tree-structure if TheTree.error_code is None: TheTree.Bend_analysis( @@ -2987,18 +3038,11 @@ def getUnfold(k_factor_lookup, solid, subelement, facename, kFactorStandard): "Trying to repeat the unfold process again with the Sewed copied Shape\n" ) FreeCAD.ActiveDocument.openTransaction("sanitize") - sewedShape = sew_Shape(solid) - solid.Visibility = False - ob = Part.show(sewedShape,"Solid") - ob.Label = solid.Label + "_copy" - if SheetMetalTools.isGuiLoaded(): - ob.ViewObject.ShapeColor = solid.ViewObject.ShapeColor - ob.ViewObject.LineColor = solid.ViewObject.LineColor - ob.ViewObject.PointColor = solid.ViewObject.PointColor - ob.ViewObject.DiffuseColor = solid.ViewObject.DiffuseColor - ob.ViewObject.Transparency = solid.ViewObject.Transparency + sew_Shape() FreeCAD.ActiveDocument.commitTransaction() + ob = FreeCAD.ActiveDocument.ActiveObject ob_Name = ob.Name + ob.Label = solid.Label + "_copy" faceSel = facename err_code = TheTree.error_code else: @@ -3058,8 +3102,144 @@ def SMmakeSketchfromEdges(edges, name): return usk +def processUnfold( + k_factor_lookup, + object, + referenceFace, + faceName, + genSketch=True, + splitSketches=False, + sketchColor="#000080", + bendSketchColor="#c00000", + internalSketchColor="#ff5733", + transparency=0.7, + kFactorStandard="ansi", +): + global KFACTORSTANDARD + KFACTORSTANDARD = kFactorStandard + + unfoldShape = None + unfold_sketch = None + unfold_sketch_outline = None + unfold_sketch_bend = None + unfold_sketch_internal = None + + try: + shape, foldComp, norm, thename, err_cd, fSel, obN = getUnfold( + k_factor_lookup, object, referenceFace, faceName + ) + foldLines = foldComp.Edges + except Exception as e: + exc_type, exc_obj, exc_tb = sys.exc_info() + SMLogger.error( + FreeCAD.Qt.translate("Logger", "exception at line ") + + str(exc_tb.tb_lineno), + e.args, + ) + SMLogger.error(e.args) + raise UnfoldException() + + if shape is None: + raise UnfoldException() + + unfoldShape = FreeCAD.ActiveDocument.addObject("Part::Feature", "Unfold") + unfoldShape.Shape = shape + + if genSketch: + # locate the projection face + unfoldobj = shape + for face in shape.Faces: + fnorm = face.normalAt(0, 0) + isSameDir = abs(fnorm.dot(norm) - 1.0) < 0.00001 + if isSameDir: + unfoldobj = face + break + edges = [] + perimEdges = projectEx(unfoldobj, norm)[0] + edges.append(perimEdges) + if len(foldLines) > 0: + co = Part.makeCompound(foldLines) + foldEdges = projectEx(co, norm)[0] + + if not splitSketches: + edges.append(foldEdges) + unfold_sketch = generateSketch(edges, "Unfold_Sketch", sketchColor) + FreeCAD.ActiveDocument.recompute() + + if splitSketches: + tidy = False + try: + newface = Part.makeFace(unfold_sketch.Shape, "Part::FaceMakerBullseye") + + try: + owEdgs = newface.OuterWire.Edges + faceEdgs = newface.Edges + except: + exc_type, exc_obj, exc_tb = sys.exc_info() + SMLogger.error( + FreeCAD.Qt.translate( + "Logger", + "Exception at line {}" + ": Outline Sketch failed, re-trying after tidying up", + ).format(str(exc_tb.tb_lineno)) + ) + tidy = True + owEdgs = unfold_sketch.Shape.Edges + faceEdgs = unfold_sketch.Shape.Edges + FreeCAD.ActiveDocument.recompute() + + unfold_sketch_outline = generateSketch( + owEdgs, "Unfold_Sketch_Outline", sketchColor + ) + + if tidy: + SMLogger.error( + FreeCAD.Qt.translate( + "Logger", "tidying up Unfold_Sketch_Outline" + ) + ) + intEdgs = [] + idx = [] + for i, e in enumerate(faceEdgs): + for oe in owEdgs: + if oe.hashCode() == e.hashCode(): + idx.append(i) + for i, e in enumerate(faceEdgs): + if i not in idx: + intEdgs.append(e) + if len(intEdgs) > 0: + unfold_sketch_internal = generateSketch( + intEdgs, "Unfold_Sketch_Internal", internalSketchColor + ) + + except Exception as e: + print(e) + exc_type, exc_obj, exc_tb = sys.exc_info() + SMLogger.error( + FreeCAD.Qt.translate( + "Logger", + "Exception at line {}: Outline Sketch not created", + ).format(str(exc_tb.tb_lineno)) + ) + + if len(foldLines) > 0 and splitSketches: + unfold_sketch_bend = generateSketch( + foldEdges, "Unfold_Sketch_bends", bendSketchColor + ) + + if FreeCAD.GuiUp: + unfoldShape.ViewObject.Transparency = transparency + + return ( + unfoldShape, + unfold_sketch, + unfold_sketch_outline, + unfold_sketch_bend, + unfold_sketch_internal, + ) + + def generateSketch(edges, name, color): - import Draft p = Part.makeCompound(edges) try: sk = Draft.makeSketch( @@ -3073,166 +3253,9 @@ def generateSketch(edges, name, color): SMLogger.warning(FreeCAD.Qt.translate("Logger", "discretizing Sketch")) sk = SMmakeSketchfromEdges(p.Edges, name) - if SheetMetalTools.isGuiLoaded(): + if FreeCAD.GuiUp: rgb_color = tuple(int(color[i : i + 2], 16) for i in (1, 3, 5)) - v = FreeCAD.Version() - if v[0] == '0' and int(v[1]) < 21: - rgb_color = tuple(i / 255 for i in rgb_color) sk.ViewObject.LineColor = rgb_color sk.ViewObject.PointColor = rgb_color return sk - -def processUnfoldSketches(shape, foldLines, norm, splitSketches, genSketchColor, bendSketchColor, intSketchColor): - try: - from TechDraw import projectEx - except ImportError: - from Drawing import projectEx - - # locate the projection face - unfoldobj = shape - for face in shape.Faces: - fnorm = face.normalAt(0, 0) - isSameDir = abs(fnorm.dot(norm) - 1.0) < 0.00001 - if isSameDir: - unfoldobj = face - break - edges = [] - perimEdges = projectEx(unfoldobj, norm)[0] - edges.append(perimEdges) - if len(foldLines) > 0: - co = Part.makeCompound(foldLines) - foldEdges = projectEx(co, norm)[0] - if not splitSketches: - edges.append(foldEdges) - unfold_sketch = generateSketch(edges, "Unfold_Sketch", genSketchColor) - FreeCAD.ActiveDocument.recompute() - if splitSketches: - tidy = False - try: - newface = Part.makeFace(unfold_sketch.Shape, "Part::FaceMakerBullseye") - try: - owEdgs = newface.OuterWire.Edges - faceEdgs = newface.Edges - except: - exc_type, exc_obj, exc_tb = sys.exc_info() - SMLogger.error( - FreeCAD.Qt.translate( - "Logger", - "Exception at line {}" - ": Outline Sketch failed, re-trying after tidying up", - ).format(str(exc_tb.tb_lineno)) - ) - tidy = True - owEdgs = unfold_sketch.Shape.Edges - faceEdgs = unfold_sketch.Shape.Edges - FreeCAD.ActiveDocument.recompute() - unfold_sketch_outline = generateSketch( - owEdgs, "Unfold_Sketch_Outline", genSketchColor - ) - if tidy: - SMLogger.error( - FreeCAD.Qt.translate( - "Logger", "tidying up Unfold_Sketch_Outline" - ) - ) - intEdgs = [] - idx = [] - for i, e in enumerate(faceEdgs): - for oe in owEdgs: - if oe.hashCode() == e.hashCode(): - idx.append(i) - for i, e in enumerate(faceEdgs): - if i not in idx: - intEdgs.append(e) - if len(intEdgs) > 0: - unfold_sketch_internal = generateSketch( - intEdgs, "Unfold_Sketch_Internal", intSketchColor - ) - except Exception as e: - print(e) - exc_type, exc_obj, exc_tb = sys.exc_info() - SMLogger.error( - FreeCAD.Qt.translate( - "Logger", - "Exception at line {}: Outline Sketch not created", - ).format(str(exc_tb.tb_lineno)) - ) - if len(foldLines) > 0 and splitSketches: - unfold_sketch_bend = generateSketch( - foldEdges, "Unfold_Sketch_bends", bendSketchColor - ) - -class SMUnfold: - def __init__(self, obj): - '''"Add wall or Wall with radius bend"''' - SheetMetalTools.smAddProperty( - obj, - "App::PropertyFloatConstraint", - "kfactor", - translate( "App::Property", "Manual K-Factor value" ), - (0.4, 0.0, 2.0, 0.01), - "Unfold" - ) - SheetMetalTools.smAddEnumProperty( - obj, - "kFactorStandard", - translate( "App::Property", "K-Factor standard" ), - ["ansi","din"], - None, - "Unfold" - ) - SheetMetalTools.smAddProperty( - obj, - "App::PropertyLinkSub", - "baseObject", - translate( "App::Property", "Base Object" ), - None, - "Unfold", - ) - SheetMetalTools.smAddProperty( - obj, - "App::PropertyLink", - "materialSheet", - translate( "App::Property", "Material definition sheet" ), - None, - "Unfold", - ) - SheetMetalTools.smAddBoolProperty( - obj, - "useManualKFactor", - translate("App::Property", - "Enable manually defining K-Factor value, otherwise the lookup table is used"), - False, - "Unfold", - ) - obj.addProperty( - "Part::PropertyPartShape", - "foldComp", - translate("App::Property", - "Fold lines compound"), - "Unfold", - read_only=True, - hidden=True - ) - obj.Proxy = self - - def getElementMapVersion(self, _fp, ver, _prop, restored): - if not restored: - return smElementMapVersion + ver - - def execute(self, fp): - '''"Print a short message when doing a recomputation, this method is mandatory"''' - kf_lookup = {1: fp.kfactor} - if fp.materialSheet and fp.useManualKFactor: - lookupTable = SheetMetalKfactor.KFactorLookupTable(fp.materialSheet) - kf_lookup = lookupTable.k_factor_lookup - shape, foldComp, norm, thename, err_cd, fSel, obN = getUnfold( - k_factor_lookup=kf_lookup, - solid=fp.baseObject[0], - subelement=fp.baseObject[0].getSubObject(fp.baseObject[1][0]), - facename=fp.baseObject[1][0], - kFactorStandard=fp.kFactorStandard) - fp.Shape = shape - fp.foldComp = foldComp - diff --git a/SketchOnSheetMetalCmd.py b/SketchOnSheetMetalCmd.py index 57a50cd..60d5ece 100644 --- a/SketchOnSheetMetalCmd.py +++ b/SketchOnSheetMetalCmd.py @@ -255,21 +255,21 @@ def smSketchOnSheetMetal( SMSolid = solidlist[0] # Part.show(SMSolid,"SMSolid") resultSolid = resultSolid.cut(SMSolid) - + SheetMetalTools.HideObjects(MainObject, sketch) return resultSolid class SMSketchOnSheet: - def __init__(self, obj): + def __init__(self, obj, selobj, sel_items, selsketch): '''"Add Sketch based cut On Sheet metal"''' _tip_ = FreeCAD.Qt.translate("App::Property", "Base Object") obj.addProperty( "App::PropertyLinkSub", "baseObject", "Parameters", _tip_ - ).baseObject + ).baseObject = (selobj, sel_items) _tip_ = FreeCAD.Qt.translate("App::Property", "Sketch on Sheetmetal") obj.addProperty( "App::PropertyLink", "Sketch", "Parameters", _tip_ - ) + ).Sketch = selsketch _tip_ = FreeCAD.Qt.translate("App::Property", "Gap from Left Side") obj.addProperty( "App::PropertyFloatConstraint", "kfactor", "Parameters", _tip_ @@ -427,7 +427,7 @@ def Activated(self): view = Gui.ActiveDocument.ActiveView activeBody = None sel = Gui.Selection.getSelectionEx() - selobj = Gui.Selection.getSelectionEx()[0].Object + selobj = sel[0].Object viewConf = SheetMetalTools.GetViewConfig(selobj) if hasattr(view, "getActiveObject"): activeBody = view.getActiveObject("pdbody") @@ -436,16 +436,12 @@ def Activated(self): doc.openTransaction("SketchOnSheet") if activeBody is None or not SheetMetalTools.smIsPartDesign(selobj): a = doc.addObject("Part::FeaturePython", "SketchOnSheet") - SMSketchOnSheet(a) - a.baseObject = (selobj, sel[0].SubElementNames) - a.Sketch = sel[1].Object + SMSketchOnSheet(a, selobj, sel[0].SubElementNames, sel[1].Object) SMSketchOnSheetVP(a.ViewObject) else: # FreeCAD.Console.PrintLog("found active body: " + activeBody.Name) a = doc.addObject("PartDesign::FeaturePython", "SketchOnSheet") - SMSketchOnSheet(a) - a.baseObject = (selobj, sel[0].SubElementNames) - a.Sketch = sel[1].Object + SMSketchOnSheet(a, selobj, sel[0].SubElementNames, sel[1].Object) SMSketchOnSheetPDVP(a.ViewObject) activeBody.addObject(a) SheetMetalTools.SetViewConfig(a, viewConf) diff --git a/UnfoldGUI.py b/UnfoldGUI.py new file mode 100644 index 0000000..994c3c5 --- /dev/null +++ b/UnfoldGUI.py @@ -0,0 +1,330 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# UnfoldGUI.py +# +# Copyright 2014, 2018 Ulrich Brammer +# Copyright 2023 Ondsel Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +# +# +############################################################################## + +from PySide import QtCore, QtGui +from SheetMetalLogger import SMLogger, UnfoldException +from engineering_mode import engineering_mode_enabled +import FreeCAD +import FreeCADGui +import SheetMetalKfactor +import importDXF +import importSVG +import os +import SheetMetalUnfolder as smu + +modPath = os.path.dirname(__file__).replace("\\", "/") + +GENSKETCHCOLOR = "#000080" +BENDSKETCHCOLOR = "#c00000" +INTSKETCHCOLOR = "#ff5733" +KFACTOR = 0.40 + +last_selected_mds = "none" +mds_help_url = "https://github.com/shaise/FreeCAD_SheetMetal#material-definition-sheet" + +mw = FreeCADGui.getMainWindow() + + +class SMUnfoldTaskPanel: + def __init__(self): + path = f"{modPath}/Resources/panels/UnfoldOptions.ui" + self.form = FreeCADGui.PySideUic.loadUi(path) + self.pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/SheetMetal") + + # Technical Debt. + # The command that gets us here is defined in SheetMetalUnfoldCmd.py. + # It limits the selection to planar faces. + # However, once the dialog is open, the user can change the selection + # and select any kind of geometry. This is wrong. + + # if it is desirable to allow user to change the selection with the + # dialog open, then a selectiongate should be written to limit + # what the user can select. + # If we want to prevent changing selection, then something else has to + # happen. + # For now, we are setting the reference plane when the user activates + # the command. Any change by the user is ignored. + + self.referenceFace = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0] + self.facename = FreeCADGui.Selection.getSelectionEx()[0].SubElementNames[0] + self.object = FreeCADGui.Selection.getSelectionEx()[0].Object + + # End Technical debt + + self.setupUi() + + def _boolToState(self, bool): + return QtCore.Qt.Checked if bool else QtCore.Qt.Unchecked + + def _getExportType(self, typeonly=False): + if not typeonly and not self.form.chkExport.isChecked(): + return None + if self.form.svgExport.isChecked(): + return "svg" + else: + return "dxf" + + def _isManualKSelected(self): + return self.form.availableMds.currentIndex() == ( + self.form.availableMds.count() - 1 + ) + + def _isNoMdsSelected(self): + return self.form.availableMds.currentIndex() == 0 + + def _updateSelectedMds(self): + global last_selected_mds + last_selected_mds = self.form.availableMds.currentText() + + def _getLastSelectedMdsIndex(self): + global last_selected_mds + for i in range(self.form.availableMds.count()): + if self.form.availableMds.itemText(i) == last_selected_mds: + return i + return -1 + + def _getData(self): + kFactorStandard = "din" if self.form.kfactorDin.isChecked() else "ansi" + + results = { + "exportType": self._getExportType(), + "genObjTransparency": self.form.transSpin.value(), + "genSketchColor": self.form.genColor.property("color").name(), + "bendSketchColor": self.form.bendColor.property("color").name(), + "intSketchColor": self.form.internalColor.property("color").name(), + "separateSketches": self.form.chkSeparate.isChecked(), + "genSketch": self.form.chkSketch.isChecked(), + "kFactorStandard": kFactorStandard, + } + + if self._isManualKSelected(): + results["lookupTable"] = {1: self.form.kFactSpin.value()} + elif self._isNoMdsSelected(): + msg = FreeCAD.Qt.translate( + "Logger", "Unfold operation needs to know K-factor value(s) to be used." + ) + SMLogger.warning(msg) + msg += FreeCAD.Qt.translate( + "QMessageBox", + "
    \n" + "
  1. Either select 'Manual K-factor'
  2. \n" + "
  3. Or use a Material Definition Sheet
  4. \n" + "
", + ).format(mds_help_url) + QtGui.QMessageBox.warning( + None, FreeCAD.Qt.translate("QMessageBox", "Warning"), msg + ) + return None + else: + lookupTable = SheetMetalKfactor.KFactorLookupTable( + self.form.availableMds.currentText() + ) + results["lookupTable"] = lookupTable.k_factor_lookup + + self.pg.SetString("kFactorStandard", str(results["kFactorStandard"])) + self.pg.SetFloat("manualKFactor", float(self.form.kFactSpin.value())) + self.pg.SetBool("genSketch", results["genSketch"]) + + self.pg.SetString("genColor", results["genSketchColor"]) + self.pg.SetString("bendColor", results["bendSketchColor"]) + self.pg.SetString("internalColor", results["intSketchColor"]) + self.pg.SetBool("separateSketches", results["separateSketches"]) + self.pg.SetBool("exportEn", self.form.chkExport.isChecked()) + self.pg.SetString("exportType", self._getExportType(True)) + + return results + + def setupUi(self): + kFactorStandard = self.pg.GetString("kFactorStandard", "ansi") + if kFactorStandard == "ansi": + self.form.kfactorAnsi.setChecked(True) + else: + self.form.kfactorDin.setChecked(True) + + self.form.chkSketch.stateChanged.connect(self.chkSketchChange) + self.form.chkSeparate.stateChanged.connect(self.chkSketchChange) + self.form.availableMds.currentIndexChanged.connect(self.availableMdsChacnge) + + self.form.chkSeparate.setCheckState( + self._boolToState(self.pg.GetBool("separateSketches")) + ) + self.form.chkSketch.setCheckState( + self._boolToState(self.pg.GetBool("genSketch")) + ) + + self.form.genColor.setProperty( + "color", self.pg.GetString("genColor", GENSKETCHCOLOR) + ) + self.form.bendColor.setProperty( + "color", self.pg.GetString("bendColor", BENDSKETCHCOLOR) + ) + self.form.internalColor.setProperty( + "color", self.pg.GetString("internalColor", INTSKETCHCOLOR) + ) + + self.form.transSpin.setValue(self.pg.GetInt("genObjTransparency", 50)) + self.form.kFactSpin.setValue(self.pg.GetFloat("manualKFactor", KFACTOR)) + + self.form.chkSeparate.setEnabled(self.pg.GetBool("separateSketches", False)) + + self.form.chkExport.setCheckState( + self._boolToState(self.pg.GetBool("exportEn", False)) + ) + if self.pg.GetString("exportType", "dxf") == "dxf": + self.form.dxfExport.setChecked(True) + else: + self.form.svgExport.setChecked(True) + + self.chkSketchChange() + self.populateMdsList() + self.availableMdsChacnge() + + self.form.update() + FreeCAD.ActiveDocument.openTransaction("Unfold") + + def accept(self): + self._updateSelectedMds() + params = self._getData() + if params is None: + return + + try: + result = smu.processUnfold( + params["lookupTable"], + self.object, + self.referenceFace, + self.facename, + genSketch=self.form.chkSketch.isChecked(), + splitSketches=self.form.chkSeparate.isChecked(), + sketchColor=params["genSketchColor"], + bendSketchColor=params["bendSketchColor"], + internalSketchColor=params["intSketchColor"], + transparency=params["genObjTransparency"], + kFactorStandard=params["kFactorStandard"], + ) + if result: + self.doExport(result[1]) + + FreeCAD.ActiveDocument.commitTransaction() + FreeCADGui.ActiveDocument.resetEdit() + FreeCADGui.Control.closeDialog() + FreeCAD.ActiveDocument.recompute() + else: + FreeCAD.ActiveDocument.abortTransaction() + FreeCADGui.Control.closeDialog() + FreeCAD.ActiveDocument.recompute() + + except UnfoldException: + msg = ( + FreeCAD.Qt.translate( + "QMessageBox", + "Unfold is failing.\n" + "Please try to select a different face to unfold your object\n\n" + "If the opposite face also fails then switch Refine to false on feature ", + ) + + FreeCADGui.Selection.getSelection()[0].Name + ) + QtGui.QMessageBox.question( + None, + FreeCAD.Qt.translate("QMessageBox", "Warning"), + msg, + QtGui.QMessageBox.Ok, + ) + + except Exception as e: + raise e + + def reject(self): + FreeCAD.ActiveDocument.abortTransaction() + FreeCADGui.Control.closeDialog() + FreeCAD.ActiveDocument.recompute() + + def doExport(self, obj): + # Not sure we should be doing export in this dialog but if we want to, + # it should be handled here and not in the unfold function. + + # This implementation of export is limited because it doesn't export + # split sketches. More reason to potentially remove it entirely and + # let the user use the standard export functions + + if obj is None: + return + + if self._getExportType() is None: + return + + __objs__ = [] + __objs__.append(obj) + filename = f"{FreeCAD.ActiveDocument.FileName[0:-6]}-{obj.Name}.{self._getExportType()}" + print("Exporting to " + filename) + + if self._getExportType() == "dxf": + importDXF.export(__objs__, filename) + else: + importSVG.export(__objs__, filename) + del __objs__ + + def populateMdsList(self): + sheetnames = SheetMetalKfactor.getSpreadSheetNames() + self.form.availableMds.clear() + + self.form.availableMds.addItem("Please select") + for mds in sheetnames: + if mds.Label.startswith("material_"): + self.form.availableMds.addItem(mds.Label) + self.form.availableMds.addItem("Manual K-Factor") + + selMdsIndex = self._getLastSelectedMdsIndex() + + if selMdsIndex >= 0: + self.form.availableMds.setCurrentIndex(selMdsIndex) + elif len(sheetnames) == 1: + self.form.availableMds.setCurrentIndex(1) + elif engineering_mode_enabled(): + self.form.availableMds.setCurrentIndex(0) + elif len(sheetnames) == 0: + self.form.availableMds.setCurrentIndex(1) + + def chkSketchChange(self): + self.form.chkSeparate.setEnabled(self.form.chkSketch.isChecked()) + if self.form.chkSketch.isChecked(): + self.form.dxfExport.show() + self.form.svgExport.show() + self.form.genColor.setEnabled(True) + else: + self.form.dxfExport.hide() + self.form.svgExport.hide() + self.form.genColor.setEnabled(False) + + enabled = self.form.chkSketch.isChecked() and self.form.chkSeparate.isChecked() + self.form.bendColor.setEnabled(enabled) + self.form.internalColor.setEnabled(enabled) + + def availableMdsChacnge(self): + isManualK = self._isManualKSelected() + self.form.kfactorAnsi.setEnabled(isManualK) + self.form.kfactorDin.setEnabled(isManualK) + self.form.kFactSpin.setEnabled(isManualK) diff --git a/package.xml b/package.xml index 962fc58..c9ce4a9 100644 --- a/package.xml +++ b/package.xml @@ -2,8 +2,8 @@ SheetMetal Workbench A simple sheet metal tools workbench for FreeCAD. - 0.5.01 - 2024-10-20 + 0.5.02 + 2024-10-21 Shai Seger LGPL-2.1-or-later https://github.com/shaise/FreeCAD_SheetMetal