diff --git a/Gui/Resources/icons/Assembly_Add_Origin.svg b/Gui/Resources/icons/Assembly_Add_Origin.svg new file mode 100644 index 0000000..8a9258d --- /dev/null +++ b/Gui/Resources/icons/Assembly_Add_Origin.svg @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + Path-Heights + 2016-05-15 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/Mod/Path/Gui/Resources/icons/Path-Heights.svg + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assembly.py b/assembly.py index f7accaf..587d13d 100644 --- a/assembly.py +++ b/assembly.py @@ -590,7 +590,7 @@ class ViewProviderAsmElementSketch(ViewProviderAsmElement): ElementInfo = namedtuple('AsmElementInfo', ('Parent','SubnameRef','Part', 'PartName','Placement','Object','Subname','Shape')) -def getElementInfo(parent, subname): +def getElementInfo(parent, subname, checkPlacement=False): '''Return a named tuple containing the part object element information Parameters: @@ -723,12 +723,14 @@ def getElementInfo(parent, subname): # object. We trim the subname reference to be relative to the part # object. And obtain the shape before part's Placement by setting # 'transform' to False + if checkPlacement and not hasattr(part,'Placement'): + raise RuntimeError('part has no placement') subname = '.'.join(names[1:]) shape = utils.getElementShape((part,subname)) if not shape: raise RuntimeError('cannot get geometry element from {}.{}'.format( part.Name,subname)) - pla = part.Placement + pla = getattr(part,'Placement',FreeCAD.Placement()) obj = part.getLinkedObject(False) partName = part.Name @@ -1743,6 +1745,13 @@ class ViewProviderAssembly(ViewProviderAsmGroup): self._movingPart = None super(ViewProviderAssembly,self).__init__(vobj) + def onDelete(self,vobj,_subs): + for o in vobj.Object.Proxy.getPartGroup().Group: + if o.TypeId == 'App::Origin': + o.Document.removeObject(o.Name) + break + return True + def _convertSubname(self,owner,subname): sub = subname.split('.') if not sub: @@ -1833,6 +1842,8 @@ class AsmWorkPlane(object): def __init__(self,obj): obj.addProperty("App::PropertyLength","Length","Base") obj.addProperty("App::PropertyLength","Width","Base") + obj.addProperty("App::PropertyBool","Fixed","Base") + obj.Fixed = True obj.Length = 10 obj.Width = 10 obj.Proxy = self @@ -1926,38 +1937,66 @@ class AsmWorkPlane(object): BoundBox = bbox) @staticmethod - def make(sels=None,name='Workplane', tp=0, undo=True): + def make(sels=None,name=None, tp=0, undo=True): info = AsmWorkPlane.getSelection(sels) doc = info.PartGroup.Document if undo: FreeCAD.setActiveTransaction('Assembly create workplane') try: - obj = doc.addObject('Part::FeaturePython',name) - AsmWorkPlane(obj) - ViewProviderAsmWorkPlane(obj.ViewObject) - if tp==1: - pla = FreeCAD.Placement(info.Placement.Base, - FreeCAD.Rotation(FreeCAD.Vector(0,1,0),-90)) - elif tp==2: - pla = FreeCAD.Placement(info.Placement.Base, - FreeCAD.Rotation(FreeCAD.Vector(1,0,0),90)) + logger.debug('make {}'.format(tp)) + if tp == 3: + obj = None + for o in info.PartGroup.Group: + if o.TypeId == 'App::Origin': + obj = o + break + if not obj: + if not name: + name = 'Origin' + obj = doc.addObject('App::Origin',name) + info.PartGroup.setLink({-1:obj}) + + info.PartGroup.recompute(True) + shape = Part.getShape(info.PartGroup) + if not shape.isNull(): + bbox = shape.BoundBox + if bbox.isValid(): + obj.ViewObject.Size = tuple([ + max(abs(a),abs(b)) for a,b in ( + (bbox.XMin,bbox.XMax), + (bbox.YMin,bbox.YMax), + (bbox.ZMin,bbox.ZMax)) ]) else: - pla = info.Placement - if utils.isVertex(info.Shape): - obj.Length = obj.Width = 0 - elif utils.isLinearEdge(info.Shape): - if info.BoundBox.isValid(): - obj.Length = info.BoundBox.DiagonalLength - obj.Width = 0 - pla = FreeCAD.Placement(pla.Base,pla.Rotation.multiply( - FreeCAD.Rotation(FreeCAD.Vector(0,1,0),90))) - elif info.BoundBox.isValid(): - obj.Length = obj.Width = info.BoundBox.DiagonalLength + if not name: + name = 'Workplane' + obj = doc.addObject('Part::FeaturePython',name) + AsmWorkPlane(obj) + ViewProviderAsmWorkPlane(obj.ViewObject) + if tp==1: + pla = FreeCAD.Placement(info.Placement.Base, + FreeCAD.Rotation(FreeCAD.Vector(0,1,0),-90)) + elif tp==2: + pla = FreeCAD.Placement(info.Placement.Base, + FreeCAD.Rotation(FreeCAD.Vector(1,0,0),90)) + else: + pla = info.Placement - obj.Placement = pla + if utils.isVertex(info.Shape): + obj.Length = obj.Width = 0 + elif utils.isLinearEdge(info.Shape): + if info.BoundBox.isValid(): + obj.Length = info.BoundBox.DiagonalLength + obj.Width = 0 + pla = FreeCAD.Placement(pla.Base,pla.Rotation.multiply( + FreeCAD.Rotation(FreeCAD.Vector(0,1,0),90))) + elif info.BoundBox.isValid(): + obj.Length = obj.Width = info.BoundBox.DiagonalLength + + obj.Placement = pla + + obj.recompute(True) + info.PartGroup.setLink({-1:obj}) - obj.recompute(True) - info.PartGroup.setLink({-1:obj}) if undo: FreeCAD.closeActiveTransaction() @@ -1965,6 +2004,7 @@ class AsmWorkPlane(object): FreeCADGui.Selection.addSelection(info.SelObj, info.SelSubname + info.PartGroup.Name + '.' + obj.Name + '.') FreeCADGui.runCommand('Std_TreeSelection') + FreeCADGui.Selection.setVisible(True) return obj except Exception: if undo: diff --git a/constraint.py b/constraint.py index 50d97c3..5ba7ccf 100644 --- a/constraint.py +++ b/constraint.py @@ -469,10 +469,18 @@ class Constraint(ProxyType): return mcs.getProxy(obj).prepare(obj,solver) @classmethod - def getFixedParts(mcs,solver,cstrs): + def getFixedParts(mcs,solver,cstrs,parts): firstInfo = None - found = False ret = set() + + from .assembly import isTypeOf, AsmWorkPlane + for obj in parts: + if not hasattr(obj,'Placement'): + ret.add(obj) + elif isTypeOf(obj,AsmWorkPlane) and getattr(obj,'Fixed',False): + ret.add(obj) + found = len(ret) + for obj in cstrs: cstr = mcs.getProxy(obj) if cstr.hasFixedPart(obj): diff --git a/gui.py b/gui.py index b718aa0..c0da6f2 100644 --- a/gui.py +++ b/gui.py @@ -390,6 +390,8 @@ class AsmCmdAddWorkplane(AsmCmdBase): _menuText = 'Add workplane' _iconName = 'Assembly_Add_Workplane.svg' _toolbarName = None + _accel = 'A, P' + _makeType = 0 @classmethod def checkActive(cls): @@ -405,34 +407,48 @@ class AsmCmdAddWorkplane(AsmCmdBase): cls._active = False @classmethod - def Activated(cls,idx): + def Activated(cls,idx=0): + _ = idx from . import assembly - assembly.AsmWorkPlane.make(tp=idx) + assembly.AsmWorkPlane.make(tp=cls._makeType) class AsmCmdAddWorkplaneXZ(AsmCmdAddWorkplane): _id = 10 _menuText = 'Add XZ workplane' _iconName = 'Assembly_Add_WorkplaneXZ.svg' + _makeType = 1 class AsmCmdAddWorkplaneZY(AsmCmdAddWorkplane): _id = 11 _menuText = 'Add ZY workplane' _iconName = 'Assembly_Add_WorkplaneZY.svg' + _makeType = 2 +class AsmCmdAddOrigin(AsmCmdAddWorkplane): + _id = 14 + _menuText = 'Add Origin' + _iconName = 'Assembly_Add_Origin.svg' + _makeType = 3 + _accel = 'A, O' class AsmCmdAddWorkplaneGroup(AsmCmdAddWorkplane): _id = 12 _toolbarName = AsmCmdBase._toolbarName _cmds = (AsmCmdAddWorkplane.getName(), AsmCmdAddWorkplaneXZ.getName(), - AsmCmdAddWorkplaneZY.getName()) + AsmCmdAddWorkplaneZY.getName(), + AsmCmdAddOrigin.getName()) @classmethod def GetCommands(cls): return cls._cmds + @classmethod + def Activated(cls,idx=0): + FreeCADGui.runCommand(cls._cmds[idx]) + class AsmCmdUp(AsmCmdBase): _id = 6 diff --git a/mover.py b/mover.py index 1acaed3..cbada1d 100644 --- a/mover.py +++ b/mover.py @@ -244,9 +244,8 @@ def getMovingElementInfo(): objName(selObj),selSub)) if len(sels[0].SubElementNames)==1: - info = getElementInfo(ret[0].Assembly,ret[0].Subname) - if not info: - return + info = getElementInfo(ret[0].Assembly, + ret[0].Subname, checkPlacement=True) return MovingPartInfo(SelObj=selObj, SelSubname=selSub, Hierarchy=ret, @@ -270,10 +269,11 @@ def getMovingElementInfo(): assembly = ret[-1].Assembly for r in ret2: if assembly == r.Assembly: + info = getElementInfo(r.Assembly,r.Subname,checkPlacement=True) return MovingPartInfo(SelObj=selObj, SelSubname=selSub, Hierarchy=ret2, - ElementInfo=getElementInfo(r.Assembly,r.Subname)) + ElementInfo=info) raise RuntimeError('not child parent selection') def canMovePart(): diff --git a/solver.py b/solver.py index c725bdc..12feef0 100644 --- a/solver.py +++ b/solver.py @@ -56,7 +56,8 @@ class Solver(object): roty = FreeCAD.Rotation(FreeCAD.Vector(1,0,0),90) self.ny = self.system.addNormal3dV(*utils.getNormal(roty)) - self._fixedParts = Constraint.getFixedParts(self,cstrs) + parts = assembly.Proxy.getPartGroup().Group + self._fixedParts = Constraint.getFixedParts(self,cstrs,parts) for part in self._fixedParts: self._fixedElements.add((part,None))