# -*- coding: utf-8 -*- __title__ = "MultiLoft" __author__ = "Christophe Grellier (Chris_G)" __license__ = "LGPL 2.1" __doc__ = """Loft profile objects made of multiple faces in parallel""" import os import FreeCAD import FreeCADGui import Part from freecad.Curves import _utils from freecad.Curves import ICONPATH TOOL_ICON = os.path.join( ICONPATH, 'multiLoft.svg') #debug = _utils.debug #debug = _utils.doNothing props = """ App::PropertyBool App::PropertyBoolList App::PropertyFloat App::PropertyFloatList App::PropertyFloatConstraint App::PropertyQuantity App::PropertyQuantityConstraint App::PropertyAngle App::PropertyDistance App::PropertyLength App::PropertySpeed App::PropertyAcceleration App::PropertyForce App::PropertyPressure App::PropertyInteger App::PropertyIntegerConstraint App::PropertyPercent App::PropertyEnumeration App::PropertyIntegerList App::PropertyIntegerSet App::PropertyMap App::PropertyString App::PropertyUUID App::PropertyFont App::PropertyStringList App::PropertyLink App::PropertyLinkSub App::PropertyLinkList App::PropertyLinkSubList App::PropertyMatrix App::PropertyVector App::PropertyVectorList App::PropertyPlacement App::PropertyPlacementLink App::PropertyColor App::PropertyColorList App::PropertyMaterial App::PropertyPath App::PropertyFile App::PropertyFileIncluded App::PropertyPythonObject Part::PropertyPartShape Part::PropertyGeometryList Part::PropertyShapeHistory Part::PropertyFilletEdges Sketcher::PropertyConstraintList """ class MultiLoftFP: """Creates a ...""" def __init__(self, obj): """Add the properties""" obj.addProperty("App::PropertyLinkList", "Sources", "Multiloft", "Objects to loft") obj.addProperty("App::PropertyBool", "Ruled", "Multiloft", "Ruled Loft").Ruled = False obj.addProperty("App::PropertyBool", "Closed", "Multiloft", "Close loft").Closed = False obj.addProperty("App::PropertyInteger", "MaxDegree", "Multiloft", "Max Bspline degree").MaxDegree = 5 obj.Proxy = self def execute(self, obj): if not hasattr(obj, "Sources"): return src_shapes = [] for o in obj.Sources: sh = o.Shape.copy() #pl = sh.Placement sh.Placement = o.getGlobalPlacement() #.multiply(pl) src_shapes.append(sh) solids = [] num_faces = len(src_shapes[0].Faces) for i in range(num_faces): faces = [src_shapes[0].Faces[i], src_shapes[-1].Faces[i]] loft = [] num_wires = len(faces[0].Wires) for j in range(num_wires): wires = [] for o in src_shapes: wires.append(o.Faces[i].Wires[j]) loft = Part.makeLoft(wires, False, obj.Ruled, obj.Closed, obj.MaxDegree) faces.extend(loft.Faces) shell = Part.Shell(faces) solids.append(Part.Solid(shell)) obj.Shape = Part.Compound(solids) def onChanged(self, obj, prop): if prop == "MaxDegree": if obj.MaxDegree < 1: obj.MaxDegree = 1 if obj.MaxDegree > 25: obj.MaxDegree = 25 if prop in ["Ruled","Closed","MaxDegree"]: self.execute(obj) return class MultiLoftVP: def __init__(self,vobj): vobj.Proxy = self def getIcon(self): return TOOL_ICON def attach(self, vobj): self.Object = vobj.Object def __getstate__(self): return {"name": self.Object.Name} def __setstate__(self,state): self.Object = FreeCAD.ActiveDocument.getObject(state["name"]) return None def claimChildren(self): return self.Object.Sources def onDelete(self, feature, subelements): # subelements is a tuple of strings for c in self.Object.Sources: if hasattr(c,"ViewObject"): c.ViewObject.Visibility = True return True class MultiLoftCommand: """Creates a MultiLoft""" def makeFeature(self, sel): fp = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","MultiLoft") MultiLoftFP(fp) MultiLoftVP(fp.ViewObject) fp.Sources = sel for c in sel: if hasattr(c,"ViewObject"): c.ViewObject.Visibility = False FreeCAD.ActiveDocument.recompute() def Activated(self): sel = FreeCADGui.Selection.getSelection() if sel == []: FreeCAD.Console.PrintError("Select something first !\n") else: self.makeFeature(sel) def IsActive(self): if FreeCAD.ActiveDocument: return True else: return False def GetResources(self): return {'Pixmap' : TOOL_ICON, 'MenuText': __title__, 'ToolTip': __doc__} FreeCADGui.addCommand('MultiLoft', MultiLoftCommand())