# -*- coding: utf-8 -*- # *************************************************************************** # * Copyright (c) 2017 LTS under LGPL * # * Copyright (c) 2020 Schildkroet * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * # * as published by the Free Software Foundation; either version 2 of * # * the License, or (at your option) any later version. * # * for detail see the LICENCE text file. * # * * # * 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 Library General Public License for more details. * # * * # * You should have received a copy of the GNU Library General Public * # * License along with this program; if not, write to the Free Software * # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * # * USA * # * * # *************************************************************************** from __future__ import print_function import FreeCAD import FreeCADGui import Path import PathScripts.PathDressup as PathDressup import PathScripts.PathGeom as PathGeom import PathScripts.PathLog as PathLog import PathScripts.PathUtils as PathUtils import math import copy from PySide import QtCore, QtGui __doc__ = """LeadInOut Dressup MASHIN-CRC USE ROLL-ON ROLL-OFF to profile""" if FreeCAD.GuiUp: import FreeCADGui # Qt translation handling def translate(text, context="Path_DressupLeadInOut", disambig=None): return QtCore.QCoreApplication.translate(context, text, disambig) PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) movecommands = ['G1', 'G01', 'G2', 'G02', 'G3', 'G03'] rapidcommands = ['G0', 'G00'] arccommands = ['G2', 'G3', 'G02', 'G03'] currLocation = {} class ObjectDressup: def __init__(self, obj): self.obj = obj obj.addProperty("App::PropertyLink", "Base", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "The base path to modify")) obj.addProperty("App::PropertyBool", "LeadIn", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Calculate roll-on to path")) obj.addProperty("App::PropertyBool", "LeadOut", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Calculate roll-off from path")) obj.addProperty("App::PropertyBool", "KeepToolDown", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Keep the Tool Down in Path")) obj.addProperty("App::PropertyBool", "UseMachineCRC", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Use Machine Cutter Radius Compensation /Tool Path Offset G41/G42")) obj.addProperty("App::PropertyDistance", "Length", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Length or Radius of the approach")) obj.addProperty("App::PropertyEnumeration", "StyleOn", "Path", QtCore.QT_TRANSLATE_NOOP("Path_DressupLeadInOut", "The Style of LeadIn the Path")) obj.StyleOn = ["Arc", "Tangent", "Perpendicular"] obj.addProperty("App::PropertyEnumeration", "StyleOff", "Path", QtCore.QT_TRANSLATE_NOOP("Path_DressupLeadInOut", "The Style of LeadOut the Path")) obj.StyleOff = ["Arc", "Tangent", "Perpendicular"] obj.addProperty("App::PropertyEnumeration", "RadiusCenter", "Path", QtCore.QT_TRANSLATE_NOOP("Path_DressupLeadInOut", "The Mode of Point Radiusoffset or Center")) obj.RadiusCenter = ["Radius", "Center"] obj.Proxy = self obj.addProperty("App::PropertyDistance", "ExtendLeadIn", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Extends LeadIn distance")) obj.addProperty("App::PropertyDistance", "ExtendLeadOut", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Extends LeadOut distance")) obj.addProperty("App::PropertyBool", "RapidPlunge", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Perform plunges with G0")) obj.addProperty("App::PropertyBool", "IncludeLayers", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Apply LeadInOut to layers within an operation")) self.wire = None self.rapids = None def __getstate__(self): return None def __setstate__(self, state): # pylint: disable=unused-argument return None def setup(self, obj): obj.Length = obj.Base.ToolController.Tool.Diameter * 0.75 obj.LeadIn = True obj.LeadOut = True obj.KeepToolDown = False obj.UseMachineCRC = False obj.StyleOn = 'Arc' obj.StyleOff = 'Arc' obj.RadiusCenter = 'Radius' obj.ExtendLeadIn = 0 obj.ExtendLeadOut = 0 obj.RapidPlunge = False obj.IncludeLayers = True def execute(self, obj): if not obj.Base: return if not obj.Base.isDerivedFrom("Path::Feature"): return if not obj.Base.Path: return if obj.Length < 0: PathLog.error(translate("Length/Radius positive not Null")+"\n") obj.Length = 0.1 self.wire, self.rapids = PathGeom.wireForPath(obj.Base.Path) obj.Path = self.generateLeadInOutCurve(obj) def getDirectionOfPath(self, obj): op = PathDressup.baseOp(obj.Base) if hasattr(op, 'Side') and op.Side == 'Outside': if hasattr(op, 'Direction') and op.Direction == 'CW': return 'left' else: return 'right' else: if hasattr(op, 'Direction') and op.Direction == 'CW': return 'right' return 'left' def getSideOfPath(self, obj): op = PathDressup.baseOp(obj.Base) if hasattr(op, 'Side'): return op.Side return '' def normalize(self, Vector): x = Vector.x y = Vector.y length = math.sqrt(x*x + y*y) if((math.fabs(length)) > 0.0000000000001): vx = round(x / length, 3) vy = round(y / length, 3) return FreeCAD.Vector(vx, vy, 0) def invert(self, Vector): x = Vector.x * -1 y = Vector.y * -1 z = Vector.z * -1 return FreeCAD.Vector(x, y, z) def multiply(self, Vector, len): x = Vector.x * len y = Vector.y * len z = Vector.z * len return FreeCAD.Vector(x, y, z) def rotate(self, Vector, angle): s = math.sin(math.radians(angle)) c = math.cos(math.radians(angle)) xnew = Vector.x * c - Vector.y * s; ynew = Vector.x * s + Vector.y * c; return FreeCAD.Vector(xnew, ynew, Vector.z) def getLeadStart(self, obj, queue, action): '''returns Lead In G-code.''' results = [] op = PathDressup.baseOp(obj.Base) tc = PathDressup.toolController(obj.Base) horizFeed = tc.HorizFeed.Value vertFeed = tc.VertFeed.Value toolnummer = tc.ToolNumber arcs_identical = False # Set the correct twist command if self.getDirectionOfPath(obj) == 'left': arcdir = "G3" else: arcdir = "G2" R = obj.Length.Value # Radius of roll or length if queue[1].Name == "G1": # line p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base v = self.normalize(p1.sub(p0)) # PathLog.debug(" CURRENT_IN : P0 Z:{} p1 Z:{}".format(p0.z,p1.z)) else: p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base v = self.normalize(p1.sub(p0)) # PathLog.debug(" CURRENT_IN ARC : P0 X:{} Y:{} P1 X:{} Y:{} ".format(p0.x,p0.y,p1.x,p1.y)) # Calculate offset vector (will be overwritten for arcs) if self.getDirectionOfPath(obj) == 'right': off_v = FreeCAD.Vector(v.y*R, -v.x*R, 0.0) else: off_v = FreeCAD.Vector(-v.y*R, v.x*R, 0.0) # Check if we enter at line or arc command if queue[1].Name in movecommands and queue[1].Name not in arccommands: # We have a line move vec = p1.sub(p0) vec_n = self.normalize(vec) vec_inv = self.invert(vec_n) vec_off = self.multiply(vec_inv, obj.ExtendLeadIn) #PathLog.debug("LineCMD: {}, Vxinv: {}, Vyinv: {}, Vxoff: {}, Vyoff: {}".format(queue[0].Name, vec_inv.x, vec_inv.y, vec_off.x, vec_off.y)) else: # We have an arc move # Calculate coordinates for middle of circle pij = copy.deepcopy(p0) pij.x += queue[1].Parameters['I'] pij.y += queue[1].Parameters['J'] # Check if lead in and operation go in same direction (usually for inner circles) if arcdir == queue[1].Name: arcs_identical = True # Calculate vector circle start -> circle middle vec_circ = pij.sub(p0) # Rotate vector to get direction for lead in if arcdir == "G2": vec_rot = self.rotate(vec_circ, 90) else: vec_rot = self.rotate(vec_circ, -90) # Normalize and invert vector vec_n = self.normalize(vec_rot) v = self.invert(vec_n) # Calculate offset of lead in if arcdir == "G3": off_v = FreeCAD.Vector(-v.y*R, v.x*R, 0.0) else: off_v = FreeCAD.Vector(v.y*R, -v.x*R, 0.0) # Multiply offset by LeadIn length vec_off = self.multiply(vec_n, obj.ExtendLeadIn) offsetvector = FreeCAD.Vector(v.x*R-vec_off.x, v.y*R-vec_off.y, 0) # IJ if obj.RadiusCenter == 'Radius': leadstart = (p0.add(off_v)).sub(offsetvector) # Rmode if arcs_identical: t = p0.sub(leadstart) t = p0.add(t) leadstart = t offsetvector = self.multiply(offsetvector, -1) else: leadstart = p0.add(off_v) # Dmode if action == 'start': #extendcommand = Path.Command('G0', {"X": 0.0, "Y": 0.0, "Z": op.ClearanceHeight.Value}) #results.append(extendcommand) extendcommand = Path.Command('G0', {"X": leadstart.x, "Y": leadstart.y, "Z": op.ClearanceHeight.Value}) results.append(extendcommand) extendcommand = Path.Command('G0', {"Z": op.SafeHeight.Value}) results.append(extendcommand) if action == 'layer': if not obj.KeepToolDown: extendcommand = Path.Command('G0', {"Z": op.SafeHeight.Value}) results.append(extendcommand) extendcommand = Path.Command('G0', {"X": leadstart.x, "Y": leadstart.y}) results.append(extendcommand) if not obj.RapidPlunge: extendcommand = Path.Command('G1', {"X": leadstart.x, "Y": leadstart.y, "Z": p1.z, "F": vertFeed}) else: extendcommand = Path.Command('G0', {"X": leadstart.x, "Y": leadstart.y, "Z": p1.z,}) results.append(extendcommand) if obj.UseMachineCRC: if self.getDirectionOfPath(obj) == 'right': results.append(Path.Command('G42', {'D': toolnummer})) else: results.append(Path.Command('G41', {'D': toolnummer})) if obj.StyleOn == 'Arc': arcmove = Path.Command(arcdir, {"X": p0.x+vec_off.x, "Y": p0.y+vec_off.y, "I": offsetvector.x+vec_off.x, "J": offsetvector.y+vec_off.y, "F": horizFeed}) # add G2/G3 move results.append(arcmove) if obj.ExtendLeadIn != 0: extendcommand = Path.Command('G1', {"X": p0.x, "Y": p0.y, "F": horizFeed}) results.append(extendcommand) elif obj.StyleOn == 'Tangent': extendcommand = Path.Command('G1', {"X": p0.x, "Y": p0.y, "F": horizFeed}) results.append(extendcommand) else: PathLog.debug(" CURRENT_IN Perp") currLocation.update(results[-1].Parameters) currLocation['Z'] = p1.z return results def getLeadEnd(self, obj, queue, action): '''returns the Gcode of LeadOut.''' # pylint: disable=unused-argument results = [] horizFeed = PathDressup.toolController(obj.Base).HorizFeed.Value R = obj.Length.Value # Radius of roll or length arcs_identical = False # Set the correct twist command if self.getDirectionOfPath(obj) == 'right': arcdir = "G2" else: arcdir = "G3" if queue[1].Name == "G1": # line p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base v = self.normalize(p1.sub(p0)) else: # dealing with a circle p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base v = self.normalize(p1.sub(p0)) if self.getDirectionOfPath(obj) == 'right': off_v = FreeCAD.Vector(v.y*R, -v.x*R, 0.0) else: off_v = FreeCAD.Vector(-v.y*R, v.x*R, 0.0) # Check if we leave at line or arc command if queue[1].Name in movecommands and queue[1].Name not in arccommands: # We have a line move vec = p1.sub(p0) vec_n = self.normalize(vec) vec_inv = self.invert(vec_n) vec_off = self.multiply(vec_inv, obj.ExtendLeadOut) #PathLog.debug("LineCMD: {}, Vxinv: {}, Vyinv: {}, Vxoff: {}, Vyoff: {}".format(queue[0].Name, vec_inv.x, vec_inv.y, vec_off.x, vec_off.y)) else: # We have an arc move pij = copy.deepcopy(p0) pij.x += queue[1].Parameters['I'] pij.y += queue[1].Parameters['J'] ve = pij.sub(p1) if arcdir == queue[1].Name: arcs_identical = True if arcdir == "G2": vec_rot = self.rotate(ve, -90) else: vec_rot = self.rotate(ve, 90) vec_n = self.normalize(vec_rot) v = vec_n if arcdir == "G3": off_v = FreeCAD.Vector(-v.y*R, v.x*R, 0.0) else: off_v = FreeCAD.Vector(v.y*R, -v.x*R, 0.0) vec_inv = self.invert(vec_rot) vec_off = self.multiply(vec_inv, obj.ExtendLeadOut) offsetvector = FreeCAD.Vector(v.x*R-vec_off.x, v.y*R-vec_off.y, 0.0) if obj.RadiusCenter == 'Radius': leadend = (p1.add(off_v)).add(offsetvector) # Rmode if arcs_identical: t = p1.sub(leadend) t = p1.add(t) leadend = t off_v = self.multiply(off_v, -1) else: leadend = p1.add(off_v) # Dmode IJ = off_v # .negative() #results.append(queue[1]) if obj.StyleOff == 'Arc': if obj.ExtendLeadOut != 0: extendcommand = Path.Command('G1', {"X": p1.x-vec_off.x, "Y": p1.y-vec_off.y, "F": horizFeed}) results.append(extendcommand) arcmove = Path.Command(arcdir, {"X": leadend.x, "Y": leadend.y, "I": IJ.x, "J": IJ.y, "F": horizFeed}) # add G2/G3 move results.append(arcmove) elif obj.StyleOff == 'Tangent': extendcommand = Path.Command('G1', {"X": leadend.x, "Y": leadend.y, "F": horizFeed}) results.append(extendcommand) else: PathLog.debug(" CURRENT_IN Perp") if obj.UseMachineCRC: # crc off results.append(Path.Command('G40', {})) return results def generateLeadInOutCurve(self, obj): global currLocation # pylint: disable=global-statement firstmove = Path.Command("G0", {"X": 0, "Y": 0, "Z": 0}) op = PathDressup.baseOp(obj.Base) currLocation.update(firstmove.Parameters) newpath = [] queue = [] action = 'start' prevCmd = '' layers = [] # Read in all commands for curCommand in obj.Base.Path.Commands: #PathLog.debug("CurCMD: {}".format(curCommand)) if curCommand.Name not in movecommands + rapidcommands: # Don't worry about non-move commands, just add to output newpath.append(curCommand) continue if curCommand.Name in rapidcommands: # We don't care about rapid moves prevCmd = curCommand currLocation.update(curCommand.Parameters) continue if curCommand.Name in movecommands: if prevCmd.Name in rapidcommands and curCommand.Name in movecommands and len(queue) > 0: # Layer changed: Save current layer cmds and prepare next layer layers.append(queue) queue = [] if obj.IncludeLayers and curCommand.z < currLocation['Z'] and prevCmd.Name in movecommands: # Layer change within move cmds #PathLog.debug("Layer change in move: {}->{}".format(currLocation['Z'], curCommand.z)) layers.append(queue) queue = [] # Save all move commands queue.append(curCommand) currLocation.update(curCommand.Parameters) prevCmd = curCommand # Add last layer if len(queue) > 0: layers.append(queue) queue = [] # Go through each layer and add leadIn/Out idx = 0 for layer in layers: #PathLog.debug("Layer {}".format(idx)) if obj.LeadIn: temp = self.getLeadStart(obj, layer, action) newpath.extend(temp) for cmd in layer: #PathLog.debug("CurLoc: {}, NewCmd: {}".format(currLocation, cmd)) #if currLocation['X'] == cmd.x and currLocation['Y'] == cmd.y and currLocation['Z'] == cmd.z and cmd.Name in ['G1', 'G01']: #continue newpath.append(cmd) if obj.LeadOut: tmp = [] tmp.append(layer[-2]) tmp.append(layer[-1]) temp = self.getLeadEnd(obj, tmp, action) newpath.extend(temp) if not obj.KeepToolDown or idx == len(layers)-1: extendcommand = Path.Command('G0', {"Z": op.ClearanceHeight.Value}) newpath.append(extendcommand) else: action = 'layer' idx += 1 commands = newpath return Path.Path(commands) class TaskPanel: def __init__(self, obj, view): self.obj = obj self.viewProvider = view self.form = FreeCADGui.PySideUic.loadUi(":/panels/DressUpLeadInOutEdit.ui") self.setupUi() FreeCAD.ActiveDocument.openTransaction(translate("Path_DressupLeadInOut", "Edit LeadInOut Dress-up")) def getStandardButtons(self): return int(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Cancel) def modifyStandardButtons(self, buttonBox): self.buttonBox = buttonBox def setDirty(self): self.isDirty = True self.buttonBox.button(QtGui.QDialogButtonBox.Apply).setEnabled(True) def setClean(self): self.isDirty = False self.buttonBox.button(QtGui.QDialogButtonBox.Apply).setEnabled(False) def clicked(self, button): # callback for standard buttons if button == QtGui.QDialogButtonBox.Apply: self.updateModel() FreeCAD.ActiveDocument.recompute() if button == QtGui.QDialogButtonBox.Cancel: self.abort() def abort(self): FreeCAD.ActiveDocument.abortTransaction() self.cleanup(True) def reject(self): FreeCAD.ActiveDocument.abortTransaction() FreeCADGui.Control.closeDialog() FreeCAD.ActiveDocument.recompute() def accept(self): self.getFields() FreeCAD.ActiveDocument.commitTransaction() FreeCADGui.ActiveDocument.resetEdit() FreeCADGui.Control.closeDialog() FreeCAD.ActiveDocument.recompute() def cleanup(self, gui): self.viewProvider.clearTaskPanel() if gui: #FreeCADGui.ActiveDocument.resetEdit() FreeCADGui.Control.closeDialog() FreeCAD.ActiveDocument.recompute() def getFields(self): self.obj.LeadIn = self.form.chkLeadIn.isChecked() self.obj.LeadOut = self.form.chkLeadOut.isChecked() self.obj.Length = self.form.dsbLen.value() self.obj.ExtendLeadIn = self.form.dsbExtendIn.value() self.obj.ExtendLeadOut = self.form.dsbExtendOut.value() self.obj.StyleOn = str(self.form.cboStyleIn.currentText()) self.obj.StyleOff = str(self.form.cboStyleOut.currentText()) self.obj.RadiusCenter = str(self.form.cboRadius.currentText()) self.obj.RapidPlunge = self.form.chkRapidPlunge.isChecked() self.obj.IncludeLayers = self.form.chkLayers.isChecked() self.obj.KeepToolDown = self.form.chkKeepToolDown.isChecked() self.obj.UseMachineCRC = self.form.chkUseCRC.isChecked() self.updateUI() self.obj.Proxy.execute(self.obj) def updateUI(self): self.form.chkLeadIn.setChecked(self.obj.LeadIn) self.form.chkLeadOut.setChecked(self.obj.LeadOut) self.form.chkRapidPlunge.setChecked(self.obj.RapidPlunge) self.form.chkLayers.setChecked(self.obj.IncludeLayers) self.form.chkKeepToolDown.setChecked(self.obj.KeepToolDown) self.form.chkUseCRC.setChecked(self.obj.UseMachineCRC) self.form.dsbLen.setValue(self.obj.Length) self.form.dsbExtendIn.setValue(self.obj.ExtendLeadIn) #self.form.dsbExtendIn.setEnabled(self.obj.LeadIn) self.form.dsbExtendOut.setValue(self.obj.ExtendLeadOut) #self.form.dsbExtendOut.setEnabled(self.obj.LeadOut) self.form.cboStyleIn.setCurrentIndex(self.form.cboStyleIn.findText(self.obj.StyleOn)) #self.form.cboStyleIn.setEnabled(self.obj.LeadIn) self.form.cboStyleOut.setCurrentIndex(self.form.cboStyleIn.findText(self.obj.StyleOff)) #self.form.cboStyleOut.setEnabled(self.obj.LeadOut) self.form.cboRadius.setCurrentIndex(self.form.cboRadius.findText(self.obj.RadiusCenter)) def updateModel(self): self.getFields() FreeCAD.ActiveDocument.recompute() def setFields(self): self.updateUI() def open(self): pass def setupUi(self): self.setFields() class ViewProviderDressup: def __init__(self, vobj): self.obj = vobj.Object self.setEdit(vobj) def attach(self, vobj): self.obj = vobj.Object self.panel = None def claimChildren(self): if hasattr(self.obj.Base, "InList"): for i in self.obj.Base.InList: if hasattr(i, "Group"): group = i.Group for g in group: if g.Name == self.obj.Base.Name: group.remove(g) i.Group = group print(i.Group) # FreeCADGui.ActiveDocument.getObject(obj.Base.Name).Visibility = False return [self.obj.Base] def setEdit(self, vobj, mode=0): # pylint: disable=unused-argument FreeCADGui.Control.closeDialog() panel = TaskPanel(vobj.Object, self) FreeCADGui.Control.showDialog(panel) panel.setupUi() return True def unsetEdit(self, vobj, mode=0): if self.panel: self.panel.abort() def onDelete(self, arg1=None, arg2=None): '''this makes sure that the base operation is added back to the project and visible''' # pylint: disable=unused-argument PathLog.debug("Deleting Dressup") if arg1.Object and arg1.Object.Base: FreeCADGui.ActiveDocument.getObject(arg1.Object.Base.Name).Visibility = True job = PathUtils.findParentJob(self.obj) if job: job.Proxy.addOperation(arg1.Object.Base, arg1.Object) arg1.Object.Base = None return True def __getstate__(self): return None def __setstate__(self, state): # pylint: disable=unused-argument return None def clearTaskPanel(self): self.panel = None class CommandPathDressupLeadInOut: # pylint: disable=no-init def GetResources(self): return {'Pixmap': 'Path_Dressup', 'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_DressupLeadInOut", "LeadInOut Dressup"), 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_DressupLeadInOut", "Creates a Cutter Radius Compensation G41/G42 Entry Dressup object from a selected path")} def IsActive(self): op = PathDressup.selection() if op: return not PathDressup.hasEntryMethod(op) return False def Activated(self): # check that the selection contains exactly what we want selection = FreeCADGui.Selection.getSelection() if len(selection) != 1: PathLog.error(translate("Please select one path object")+"\n") return baseObject = selection[0] if not baseObject.isDerivedFrom("Path::Feature"): PathLog.error(translate("The selected object is not a path")+"\n") return if baseObject.isDerivedFrom("Path::FeatureCompoundPython"): PathLog.error(translate("Please select a Profile object")) return # everything ok! FreeCAD.ActiveDocument.openTransaction(translate("Create LeadInOut Dressup")) FreeCADGui.addModule("PathScripts.PathDressupLeadInOut") FreeCADGui.addModule("PathScripts.PathUtils") FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", "LeadInOutDressup")') FreeCADGui.doCommand('dbo = PathScripts.PathDressupLeadInOut.ObjectDressup(obj)') FreeCADGui.doCommand('base = FreeCAD.ActiveDocument.' + selection[0].Name) FreeCADGui.doCommand('job = PathScripts.PathUtils.findParentJob(base)') FreeCADGui.doCommand('obj.Base = base') FreeCADGui.doCommand('job.Proxy.addOperation(obj, base)') FreeCADGui.doCommand('dbo.setup(obj)') FreeCADGui.doCommand('obj.ViewObject.Proxy = PathScripts.PathDressupLeadInOut.ViewProviderDressup(obj.ViewObject)') FreeCADGui.doCommand('Gui.ActiveDocument.getObject(base.Name).Visibility = False') FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() if FreeCAD.GuiUp: # register the FreeCAD command FreeCADGui.addCommand('Path_DressupLeadInOut', CommandPathDressupLeadInOut()) PathLog.notice("Loading PathDressupLeadInOut... done\n")