diff --git a/InitGui.py b/InitGui.py index 2ebffa0..958af11 100644 --- a/InitGui.py +++ b/InitGui.py @@ -68,7 +68,7 @@ class Lattice2Workbench (Workbench): import lattice2Resample as mod cmdsArrayTools = cmdsArrayTools + mod.exportedCommands - import lattice2Apply as mod + import lattice2PopulateCopies as mod cmdsArrayTools = cmdsArrayTools + mod.exportedCommands import lattice2Compose as mod cmdsArrayTools = cmdsArrayTools + mod.exportedCommands diff --git a/lattice2Apply.py b/lattice2Apply.py deleted file mode 100644 index 513dfa7..0000000 --- a/lattice2Apply.py +++ /dev/null @@ -1,169 +0,0 @@ -#*************************************************************************** -#* * -#* Copyright (c) 2015 - Victor Titov (DeepSOIC) * -#* * -#* * -#* 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 * -#* * -#*************************************************************************** - -__title__="Lattice Apply object: puts a copy of an object at every placement in a lattice object (makes the array real)." -__author__ = "DeepSOIC" -__url__ = "" - -import math - -import FreeCAD as App -import Part - -from lattice2Common import * -import lattice2BaseFeature -import lattice2CompoundExplorer as LCE -import lattice2Executer - -# -------------------------- document object -------------------------------------------------- - -def makeLatticeApply(name): - '''makeLatticeApply(name): makes a LatticeApply object.''' - return lattice2BaseFeature.makeLatticeFeature(name, LatticeApply, ViewProviderLatticeApply) - -class LatticeApply(lattice2BaseFeature.LatticeFeature): - "The Lattice Apply object" - - def derivedInit(self,obj): - self.Type = "LatticeApply" - - obj.addProperty("App::PropertyLink","Base","Lattice Apply","Base object. Can be any generic shape, as well as another lattice object.") - - obj.addProperty("App::PropertyBool","KeepBaseFirstItemPos","Lattice Apply","Apply extra transform, so that first item doesn't move.") - obj.KeepBaseFirstItemPos = False - - obj.addProperty("App::PropertyLink","Tool","Lattice Apply","Tool object. Must be a lattice object. Contains placements to be applied.") - - obj.addProperty("App::PropertyBool","FlattenToolHierarchy","Lattice Apply","Unpack subcompounds, to use all shapes, not just direct children.") - obj.FlattenToolHierarchy = True - - - def derivedExecute(self,obj): - # cache stuff - base = obj.Base.Shape - - tool = obj.Tool.Shape - if tool.ShapeType != 'Compound': - tool = Part.makeCompound([tool]) - if obj.FlattenToolHierarchy: - toolChildren = LCE.AllLeaves(tool) - else: - toolChildren = tool.childShapes() - - # validity logic - if not lattice2BaseFeature.isObjectLattice(obj.Tool): - lattice2Executer.warning(obj, 'Tool is not a lattice object. Results may be unexpected.\n') - outputIsLattice = lattice2BaseFeature.isObjectLattice(obj.Base) - - plmMatcher = App.Placement() #extra placement, that makes first item to preserve its original placement - if obj.KeepBaseFirstItemPos: - plmMatcher = toolChildren[0].Placement.inverse() - - # Pre-collect base placement list, if base is a lattice. For speed. - if outputIsLattice: - baseLeaves = LCE.AllLeaves(base) - basePlms = [] - for leaf in baseLeaves: - basePlms.append(plmMatcher.multiply(leaf.Placement)) - baseLeaves = None #free memory - - # initialize output containers and loop variables - outputShapes = [] #output list of shapes - outputPlms = [] #list of placements - - # the essence - for toolChild in toolChildren: - #cache some stuff - toolPlm = toolChild.Placement - - if outputIsLattice: - for basePlm in basePlms: - outputPlms.append(toolPlm.multiply(basePlm)) - else: - outputShape = base.copy() - outputShape.Placement = toolPlm.multiply(plmMatcher.multiply(outputShape.Placement)) - outputShapes.append(outputShape) - - if outputIsLattice: - return outputPlms - else: - obj.Shape = Part.makeCompound(outputShapes) - return None - -class ViewProviderLatticeApply(lattice2BaseFeature.ViewProviderLatticeFeature): - - def getIcon(self): - return getIconPath("Lattice2_Apply.svg") - - def claimChildren(self): - return [self.Object.Base, self.Object.Tool] - -# -------------------------- /document object -------------------------------------------------- - -# -------------------------- Gui command -------------------------------------------------- - -def CreateLatticeApply(name): - sel = FreeCADGui.Selection.getSelectionEx() - FreeCAD.ActiveDocument.openTransaction("Create LatticeApply") - FreeCADGui.addModule("lattice2Apply") - FreeCADGui.addModule("lattice2Executer") - FreeCADGui.doCommand("f = lattice2Apply.makeLatticeApply(name='"+name+"')") - FreeCADGui.doCommand("f.Base = App.ActiveDocument."+sel[0].ObjectName) - FreeCADGui.doCommand("f.Tool = App.ActiveDocument."+sel[1].ObjectName) - FreeCADGui.doCommand("for child in f.ViewObject.Proxy.claimChildren():\n"+ - " child.ViewObject.hide()") - FreeCADGui.doCommand("lattice2Executer.executeFeature(f)") - FreeCADGui.doCommand("f = None") - FreeCAD.ActiveDocument.commitTransaction() - - -class _CommandLatticeApply: - "Command to create LatticeApply feature" - def GetResources(self): - return {'Pixmap' : getIconPath("Lattice2_Apply.svg"), - 'MenuText': QtCore.QT_TRANSLATE_NOOP("Lattice2_Apply","Apply array"), - 'Accel': "", - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Lattice2_Apply","Lattice Apply: put copies of an object at every placement in an array.")} - - def Activated(self): - if len(FreeCADGui.Selection.getSelection()) == 2 : - CreateLatticeApply(name = "Apply") - else: - mb = QtGui.QMessageBox() - mb.setIcon(mb.Icon.Warning) - mb.setText(translate("Lattice2_Apply", "Please select two objects, first. The fist object is Base, second is Tool. Base can be a lattice or any shape, that is to be arrayed. Tool must be a lattice object.", None)) - mb.setWindowTitle(translate("Lattice2_Apply","Bad selection", None)) - mb.exec_() - - def IsActive(self): - if FreeCAD.ActiveDocument: - return True - else: - return False - -FreeCADGui.addCommand('Lattice2_Apply', _CommandLatticeApply()) - -exportedCommands = ['Lattice2_Apply'] - -# -------------------------- /Gui command -------------------------------------------------- - diff --git a/lattice2ArrayFilter.py b/lattice2ArrayFilter.py index 6640de4..d6222e4 100644 --- a/lattice2ArrayFilter.py +++ b/lattice2ArrayFilter.py @@ -204,7 +204,7 @@ def CreateLatticeArrayFilter(name,mode): if mode == 'specific items': FreeCADGui.doCommand("f.items = lattice2ArrayFilter.makeItemListFromSelection(sel["+str(iLtc)+"])") if len(sel[0].SubElementNames) == 1: - FreeCADGui.doCommand("f.SingleByDesign = True") + FreeCADGui.doCommand("f.ExposePlacement = True") else: FreeCADGui.doCommand("f.Stencil = App.ActiveDocument."+sel[iStc].ObjectName) FreeCADGui.doCommand("for child in f.ViewObject.Proxy.claimChildren():\n"+ @@ -330,7 +330,7 @@ class _CommandExplodeArray: af.Base = obj af.FilterType = 'specific items' af.items = str(i) - af.SingleByDesign = True + af.ExposePlacement = True af.ViewObject.DontUnhideOnDelete = True FreeCAD.ActiveDocument.recompute() obj.ViewObject.hide() diff --git a/lattice2ArrayFromShape.py b/lattice2ArrayFromShape.py index af6f7ec..ab541e2 100644 --- a/lattice2ArrayFromShape.py +++ b/lattice2ArrayFromShape.py @@ -197,7 +197,7 @@ def CreateLatticeArrayFromShape(name, nonArray = False): FreeCADGui.doCommand("f.Base = App.ActiveDocument."+sel[0].ObjectName) if nonArray: FreeCADGui.doCommand("f.WholeObject = True") - FreeCADGui.doCommand("f.SingleByDesign = True") + FreeCADGui.doCommand("f.ExposePlacement = True") FreeCADGui.doCommand("f.Label = 'Placement of ' + f.Base.Label") else: FreeCADGui.doCommand("f.Label = 'Array from ' + f.Base.Label") diff --git a/lattice2BaseFeature.py b/lattice2BaseFeature.py index 537595c..f6d8af1 100644 --- a/lattice2BaseFeature.py +++ b/lattice2BaseFeature.py @@ -33,6 +33,7 @@ import lattice2CompoundExplorer as LCE import lattice2Markers import lattice2Executer + def getDefLatticeFaceColor(): return (1.0, 0.7019608020782471, 0.0, 0.0) #orange def getDefShapeColor(): @@ -104,10 +105,8 @@ class LatticeFeature(): obj.isLattice = ['Auto-Off','Auto-On','Force-Off','Force-On'] # Auto-On an Auto-Off can be modified when recomputing. Force values are going to stay. - #Hidden properties affecting some standard behaviours - prop = "SingleByDesign" - obj.addProperty("App::PropertyBool",prop,"Lattice","Makes the element be populated into object's Placement property") - obj.setEditorMode(prop, 2) # set hidden + prop = "ExposePlacement" + obj.addProperty("App::PropertyBool",prop,"Lattice","Makes the placement syncronized to Placement property. This will oftem make this object unmoveable. Not applicable to arrays.") self.derivedInit(obj) @@ -130,10 +129,16 @@ class LatticeFeature(): if markerSize < DistConfusion: markerSize = getMarkerSizeEstimate(plms) marker = lattice2Markers.getPlacementMarker(scale= markerSize, markerID= obj.MarkerShape) - #FIXME: make hierarchy-aware - if obj.SingleByDesign: - if len(plms) != 1: - lattice2Executer.warning(obj,"Multiple placements are being fed, but object is single by design. Only fisrt placement will be used...") + + bExposing = False + if obj.ExposePlacement: + if len(plms) == 1: + bExposing = True + else: + lattice2Executer.warning(obj,"Multiple placements are being fed, can't expose placements. Placement property will be forced to zero.") + obj.Placement = App.Placement() + + if bExposing: obj.Shape = marker.copy() obj.Placement = plms[0] else: @@ -158,8 +163,18 @@ class LatticeFeature(): # Moreover, we assume that it is no longer a lattice object, so: if obj.isLattice == 'Auto-On': obj.isLattice = 'Auto-Off' - obj.NumElements = len(obj.Shape.childShapes(False,False)) - + + if obj.ExposePlacement: + if obj.Shape.ShapeType == "Compound": + children = obj.Shape.childShapes() + if len(children) == 1: + obj.Placement = children[0].Placement + obj.Shape = children[0] + else: + obj.Placement = App.Placement() + else: + #nothing to do - FreeCAD will take care to make obj.Placement and obj.Shape.Placement synchronized. + pass return def derivedExecute(self,obj): @@ -258,4 +273,34 @@ class ViewProviderLatticeFeature: FreeCAD.Console.PrintError("Error in onDelete: " + err.message) return True - \ No newline at end of file + + # ----------------------utility functions ------------------------------------- + +def makeMoveFromTo(plmFrom, plmTo): + '''makeMoveFromTo(plmFrom, plmTo): construct a placement that moves something + from one placement to another placement''' + return plmTo.multiply(plmFrom.inverse()) + +def getPlacementsList(documentObject, context = None): + '''getPlacementsList(documentObject, context = None): extract list of placements + from an array object. Context is an object to report as context, when displaying + a warning if the documentObject happens to be a non-lattice.''' + if not isObjectLattice(documentObject): + lattice2Executer.warning(context, documentObject.Name + " is not a placement or an array of placements. Results may be unexpected.") + leaves = LCE.AllLeaves(documentObject.Shape) + return [leaf.Placement for leaf in leaves] + +def splitSelection(sel): + '''splitSelection(sel): splits sel (use getSelectionEx()) into lattices and non-lattices. + returns a tuple: (lattices, shapes). lattices is a list, containing all objects + that are lattices (placements of arrays of placements). shapes contains all + the rest. The lists conain SelectionObjects, not the actual document objects.''' + lattices = [] + shapes = [] + for selobj in sel: + if isObjectLattice(selobj.Object): + lattices.append(selobj) + else: + shapes.append(selobj) + return (lattices, shapes) + diff --git a/lattice2Common.py b/lattice2Common.py index a337ae2..3730c57 100644 --- a/lattice2Common.py +++ b/lattice2Common.py @@ -50,6 +50,33 @@ def getParamRefine(): def getIconPath(icon_dot_svg): return ":/icons/" + icon_dot_svg +class SelectionError(FreeCAD.Base.FreeCADError): + '''Error that isused inside Gui command code''' + def __init__(self, title, message): + self.message = message + self.title = title + +def msgError(err): + mb = QtGui.QMessageBox() + mb.setIcon(mb.Icon.Warning) + mb.setText(err.message) + if type(err) is SelectionError: + mb.setWindowTitle(err.title) + else: + mb.setWindowTitle("Error") + mb.exec_() + +def infoMessage(title, message): + mb = QtGui.QMessageBox() + mb.setIcon(mb.Icon.Information) + mb.setText(message) + mb.setWindowTitle(title) + mb.exec_() + +def deselect(sel): + '''deselect(sel): remove objects in sel from selection''' + for selobj in sel: + FreeCADGui.Selection.removeSelection(selobj.Object) # OCC's Precision::Confusion; should have taken this from FreeCAD but haven't found; unlikely to ever change. DistConfusion = 1e-7 diff --git a/lattice2Placement.py b/lattice2Placement.py index 987020b..f594258 100644 --- a/lattice2Placement.py +++ b/lattice2Placement.py @@ -54,7 +54,7 @@ class LatticePlacement(lattice2BaseFeature.LatticeFeature): obj.addProperty("App::PropertyBool","Invert","Lattice Placement","Invert the placement") - obj.SingleByDesign = True + obj.ExposePlacement = True def updateReadOnlyness(self, obj): m = obj.PlacementChoice diff --git a/lattice2PopulateCopies.py b/lattice2PopulateCopies.py new file mode 100644 index 0000000..de99d0d --- /dev/null +++ b/lattice2PopulateCopies.py @@ -0,0 +1,327 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2015 - Victor Titov (DeepSOIC) * +#* * +#* * +#* 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 * +#* * +#*************************************************************************** + +__title__="Lattice PopulateWithCopies object: puts a copy of an object at every placement in a lattice object (makes the array real)." +__author__ = "DeepSOIC" +__url__ = "" + +import math + +import FreeCAD as App +import Part + +from lattice2Common import * +import lattice2BaseFeature +import lattice2CompoundExplorer as LCE +import lattice2Executer + +# -------------------------- document object -------------------------------------------------- + +def makeLatticePopulateCopies(name): + '''makeLatticePopulateCopies(name): makes a LatticePopulateCopies object.''' + return lattice2BaseFeature.makeLatticeFeature(name, LatticePopulateCopies, ViewProviderLatticePopulateCopies) + +class LatticePopulateCopies(lattice2BaseFeature.LatticeFeature): + "The Lattice PopulateCopies object" + + def derivedInit(self,obj): + self.Type = "LatticePopulateCopies" + + obj.addProperty("App::PropertyLink","Object","Lattice PopulateCopies","Base object. Can be any generic shape, as well as another lattice object.") + + obj.addProperty("App::PropertyEnumeration","Referencing","Lattice PopulateCopies","Reference for array of placements.") + obj.Referencing = ["Origin","First item", "Last item", "Use PlacementsFrom"] + + + obj.addProperty("App::PropertyLink","PlacementsTo","Lattice PopulateCopies", "Placement or array of placements, containing target locations.") + obj.addProperty("App::PropertyLink","PlacementsFrom", "Lattice PopulateCopies","Placement or array of placements to be treated as origins for PlacementsTo.") + + + def derivedExecute(self,obj): + # cache stuff + objectShape = obj.Object.Shape + placements = lattice2BaseFeature.getPlacementsList(obj.PlacementsTo, obj) + + outputIsLattice = lattice2BaseFeature.isObjectLattice(obj.Object) + + # Pre-collect base placement list, if base is a lattice. For speed. + if outputIsLattice: + objectPlms = lattice2BaseFeature.getPlacementsList(obj.Object,obj) + + # Precompute referencing + plmDeref = App.Placement() #inverse placement of reference (reference is a substitute of origin) + if obj.PlacementsFrom is not None and obj.Referencing != "Use PlacementsFrom": + lattice2Executer.warning(obj,"Referencing mode is '"+obj.Referencing+"', doesn't need PlacementsFrom link to be set. The link is set, but it will be ignored.") + if obj.Referencing == "Origin": + pass + elif obj.Referencing == "First item": + plmDeref = placements[0].inverse() + elif obj.Referencing == "Last item": + plmDeref = placements[0].inverse() + elif obj.Referencing == "Use PlacementsFrom": + if obj.PlacementsFrom is None: + raise ValueError("Referencing mode is 'Move from to', but PlacementsFrom link is not set.") + placementsFrom = lattice2BaseFeature.getPlacementsList(obj.PlacementsFrom, obj) + if len(placementsFrom) == 1: + plmDeref = placementsFrom[0].inverse() + elif len(placementsFrom) == len(placements): + for i in range(0, len(placements)): + placements[i] = lattice2BaseFeature.makeMoveFromTo(placementsFrom[i],placements[i]) + else: + latticeExecuter.warning(obj,"Lengths of arrays linked as PlacementsTo and PlacementsFrom must equal, or PlacementsFrom can be one placement. Violation: lengths are "+str(len(placements))+ " and "+str(len(placementsFrom))) + else: + raise ValueError("Referencing mode not implemented: "+obj.Referencing) + + + # initialize output containers and loop variables + outputShapes = [] #output list of shapes + outputPlms = [] #list of placements + + # the essence + for plm in placements: + refdPlm = plm.multiply(plmDeref) + + if outputIsLattice: + for objectPlm in objectPlms: + outputPlms.append(refdPlm.multiply(objectPlm)) + else: + outputShape = objectShape.copy() + outputShape.Placement = refdPlm.multiply(outputShape.Placement) + outputShapes.append(outputShape) + + if outputIsLattice: + return outputPlms + else: + obj.Shape = Part.makeCompound(outputShapes) + return None + +class ViewProviderLatticePopulateCopies(lattice2BaseFeature.ViewProviderLatticeFeature): + + def getIcon(self): + if lattice2BaseFeature.isObjectLattice(self.Object): + return getIconPath( + {"Origin":"Lattice2_PopulateCopies_Plms_Normal.svg", + "First item":"Lattice2_PopulateCopies_Plms_Array.svg", + "Last item":"Lattice2_PopulateCopies_Plms_Array.svg", + "Use PlacementsFrom":"Lattice2_PopulateCopies_Plms_Move.svg", + }[self.Object.Referencing] + ) + else: + return getIconPath( + {"Origin":"Lattice2_PopulateCopies_Normal.svg", + "First item":"Lattice2_PopulateCopies_Array.svg", + "Last item":"Lattice2_PopulateCopies_Array.svg", + "Use PlacementsFrom":"Lattice2_PopulateCopies_Move.svg", + }[self.Object.Referencing] + ) + + def claimChildren(self): + children = [self.Object.Object, self.Object.PlacementsTo] + if self.Object.Referencing == "Use PlacementsFrom": + children.append(self.Object.PlacementsFrom) + return children + +# -------------------------- /document object -------------------------------------------------- + +# -------------------------- Gui command -------------------------------------------------- + + + +def CreateLatticePopulateCopies(name, label, shapeObj, latticeObjFrom, latticeObjTo, refmode): + '''utility function; sharing common code for all populate-copies commands''' + FreeCADGui.addModule("lattice2PopulateCopies") + FreeCADGui.addModule("lattice2Executer") + + #fill in properties + FreeCADGui.doCommand("f = lattice2PopulateCopies.makeLatticePopulateCopies(name='"+name+"')") + FreeCADGui.doCommand("f.Object = App.ActiveDocument."+shapeObj.Name) + FreeCADGui.doCommand("f.PlacementsTo = App.ActiveDocument."+latticeObjTo.Name) + if latticeObjFrom is not None: + FreeCADGui.doCommand("f.PlacementsFrom = App.ActiveDocument."+latticeObjFrom.Name) + FreeCADGui.doCommand("f.Referencing = "+repr(refmode)) + FreeCADGui.doCommand("f.Label = " + repr(label)) + + #execute + FreeCADGui.doCommand("lattice2Executer.executeFeature(f)") + + #hide something + if (refmode != "Origin" and refmode != "Use PlacementsFrom") or lattice2BaseFeature.isObjectLattice(shapeObj): + FreeCADGui.doCommand("f.Object.ViewObject.hide()") + FreeCADGui.doCommand("f.PlacementsTo.ViewObject.hide()") + if latticeObjFrom is not None: + FreeCADGui.doCommand("f.PlacementsFrom.ViewObject.hide()") + + #finalize + FreeCADGui.doCommand("Gui.Selection.addSelection(f)") + FreeCADGui.doCommand("f = None") + +def cmdPopulate_shapes_nonFromTo(refmode): + sel = FreeCADGui.Selection.getSelectionEx() + (lattices, shapes) = lattice2BaseFeature.splitSelection(sel) + if len(shapes) > 0 and len(lattices) == 1: + FreeCAD.ActiveDocument.openTransaction("Populate with copies") + lattice = lattices[0] + for shape in shapes: + CreateLatticePopulateCopies("Populate",u"Populate "+lattice.Object.Label+u" with "+shape.Object.Label,shape.Object,None,lattice.Object,refmode) + deselect(sel) + FreeCAD.ActiveDocument.commitTransaction() + elif len(shapes) == 1 and len(lattices) > 1: + shape = shapes[0] + FreeCAD.ActiveDocument.openTransaction("Populate with copies") + for lattice in lattices: + CreateLatticePopulateCopies("Populate",u"Populate "+lattice.Object.Label+u" with "+shape.Object.Label,shape.Object,None,lattice.Object,refmode) + deselect(sel) + FreeCAD.ActiveDocument.commitTransaction() + elif len(shapes) == 0 and len(lattices) == 2: + shape = lattices[0] + lattice = lattices[1] + FreeCAD.ActiveDocument.openTransaction("Populate with copies") + CreateLatticePopulateCopies("Populate",u"Populate "+lattice.Object.Label+u" with "+shape.Object.Label,shape.Object,None,lattice.Object,refmode) + deselect(sel) + FreeCAD.ActiveDocument.commitTransaction() + else: + raise SelectionError("Bad selection","Please select some shapes and some arrays, first. You can select multiple shapes and one array, or multiple arrays and one shape.") + +def cmdPopulate_shapes_FromTo(): + sel = FreeCADGui.Selection.getSelectionEx() + (lattices, shapes) = lattice2BaseFeature.splitSelection(sel) + if len(shapes) == 0 and len(sel) >= 3: + shapes = sel[:-2] + lattices = sel[-2:] + if len(shapes) > 0 and len(lattices) == 2: + FreeCAD.ActiveDocument.openTransaction("Populate with copies") + latticeFrom = lattices[0] + latticeTo = lattices[1] + for shape in shapes: + CreateLatticePopulateCopies("Populate",u"Moved "+shape.Object.Label, shape.Object, latticeFrom.Object, latticeTo.Object,"Use PlacementsFrom") + deselect(sel) + FreeCAD.ActiveDocument.commitTransaction() + else: + raise SelectionError("Bad selection","Please select either:\n one or more shapes, and two placements/arrays \nor\nthree placements/arrays") + + +class _CommandLatticePopulateCopies_Normal: + "Command to create LatticePopulateCopies feature" + def GetResources(self): + return {'Pixmap' : getIconPath("Lattice2_PopulateCopies_Normal.svg"), + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Lattice2_PopulateCopies","Populate with copies"), + 'Accel': "", + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Lattice2_PopulateCopies","Populate with copies: put copies of an object at every placement in an array. Select the object(s) to be copied, and the placement/array.")} + + def Activated(self): + try: + if len(FreeCADGui.Selection.getSelection())==0: + infoMessage("Populate with copies", + "Populate with copies command. Places a copy of a selected object placed under selected placement.\n\n"+ + "Please select some objects, and a placement/an array of placements. Then invoke the command.\n\n"+ + "A copy of object will pe made and placed in local coordinate system of each placement in an array. Placement of the object is taken into account, and becomes a placement in local coordinates of a placement of the array item.") + return + cmdPopulate_shapes_nonFromTo("Origin") + except Exception as err: + msgError(err) + + def IsActive(self): + if FreeCAD.ActiveDocument: + return True + else: + return False + +FreeCADGui.addCommand('Lattice2_PopulateCopies_Normal', _CommandLatticePopulateCopies_Normal()) + +class _CommandLatticePopulateCopies_Array: + "Command to create LatticePopulateCopies feature" + def GetResources(self): + return {'Pixmap' : getIconPath("Lattice2_PopulateCopies_Array.svg"), + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Lattice2_PopulateCopies","Populate with copies: Build Array"), + 'Accel': "", + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Lattice2_PopulateCopies","Populate with copies: Build Array: poplate placements with copies so that the array passes through original shape. Select the object(s) to be copied, and the placement/array.")} + + def Activated(self): + try: + if len(FreeCADGui.Selection.getSelection())==0: + infoMessage("Populate with copies: Build Array", + "Populate with copies: Build Array command. Creates an array of shapes.\n\n"+ + "Please select some objects, and the array of placements. Then invoke the command. Object can also be a placement/array.\n\n"+ + "Compared to plain 'Populate With copies' command, the placements are treated as being relative to the first placement in the array. As a result, the array built always includes the original object as-is.") + return + cmdPopulate_shapes_nonFromTo("First item") + except Exception as err: + msgError(err) + + def IsActive(self): + if FreeCAD.ActiveDocument: + return True + else: + return False + +FreeCADGui.addCommand('Lattice2_PopulateCopies_Array', _CommandLatticePopulateCopies_Array()) + +class _CommandLatticePopulateCopies_Move: + "Command to create LatticePopulateCopies feature" + def GetResources(self): + return {'Pixmap' : getIconPath("Lattice2_PopulateCopies.svg"), + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Lattice2_PopulateCopies","Moved object"), + 'Accel': "", + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Lattice2_PopulateCopies","Moved object: move object from one placement to another placement. Select the object, placement to move from, and placement to move to. Arrays of placements are accepted.")} + + def Activated(self): + try: + if len(FreeCADGui.Selection.getSelection())==0: + infoMessage("Moved Object", + "Moved Object command. Creates a moved copy of a shape.\n\n"+ + "The shape is moved from one placement to another placement. Please select some shapes, then placement to move from, and placement to move to (order matters).\n"+ + "Placement 'to' can be an array of placements; the array of objects will be created in this case. If 'to' is an array, 'from' can be either a single placement, or an array of matching length.\n\n"+ + "Object can itself be an array of placements.") + return + cmdPopulate_shapes_FromTo() + except Exception as err: + msgError(err) + + def IsActive(self): + if FreeCAD.ActiveDocument: + return True + else: + return False + +FreeCADGui.addCommand('Lattice2_PopulateCopies_Move', _CommandLatticePopulateCopies_Move()) + +class _CommandLatticePopulateCopiesGroup: + def GetCommands(self): + return ("Lattice2_PopulateCopies_Normal","Lattice2_PopulateCopies_Array","Lattice2_PopulateCopies_Move") + + def GetDefaultCommand(self): # return the index of the tuple of the default command. + return 0 + + def GetResources(self): + return { 'MenuText': 'Populate with copies:', + 'ToolTip': 'Populate with copies: put a copy of an object at every placement in an array of placements.'} + + def IsActive(self): # optional + return True + +FreeCADGui.addCommand('Lattice2_PopulateCopiesGroupCommand',_CommandLatticePopulateCopiesGroup()) + +exportedCommands = ['Lattice2_PopulateCopiesGroupCommand'] + +# -------------------------- /Gui command -------------------------------------------------- +