""" Examples for a feature class and its view provider. (c) 2009 Werner Mayer LGPL """ __author__ = "Werner Mayer " import FreeCAD, Part, math from FreeCAD import Base from pivy import coin class PartFeature: def __init__(self, obj): obj.Proxy = self class Box(PartFeature): def __init__(self, obj): PartFeature.__init__(self, obj) ''' Add some custom properties to our box feature ''' obj.addProperty("App::PropertyLength","Length","Box","Length of the box").Length=1.0 obj.addProperty("App::PropertyLength","Width","Box","Width of the box").Width=1.0 obj.addProperty("App::PropertyLength","Height","Box", "Height of the box").Height=1.0 def onChanged(self, fp, prop): ''' Print the name of the property that has changed ''' FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n") if prop == "Length" or prop == "Width" or prop == "Height": fp.Shape = Part.makeBox(fp.Length,fp.Width,fp.Height) def execute(self, fp): ''' Print a short message when doing a recomputation, this method is mandatory ''' FreeCAD.Console.PrintMessage("Recompute Python Box feature\n") fp.Shape = Part.makeBox(fp.Length,fp.Width,fp.Height) class ViewProviderBox: def __init__(self, obj): ''' Set this object to the proxy object of the actual view provider ''' obj.Proxy = self def attach(self, obj): ''' Setup the scene sub-graph of the view provider, this method is mandatory ''' return def updateData(self, fp, prop): ''' If a property of the handled feature has changed we have the chance to handle this here ''' return def getDisplayModes(self,obj): ''' Return a list of display modes. ''' modes=[] return modes def getDefaultDisplayMode(self): ''' Return the name of the default display mode. It must be defined in getDisplayModes. ''' return "Shaded" def setDisplayMode(self,mode): ''' Map the display mode defined in attach with those defined in getDisplayModes. Since they have the same names nothing needs to be done. This method is optinal. ''' return mode def onChanged(self, vp, prop): ''' Print the name of the property that has changed ''' FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n") def getIcon(self): ''' Return the icon in XMP format which will appear in the tree view. This method is optional and if not defined a default icon is shown. ''' return """ /* XPM */ static const char * ViewProviderBox_xpm[] = { "16 16 6 1", " c None", ". c #141010", "+ c #615BD2", "@ c #C39D55", "# c #000000", "$ c #57C355", " ........", " ......++..+..", " .@@@@.++..++.", " .@@@@.++..++.", " .@@ .++++++.", " ..@@ .++..++.", "###@@@@ .++..++.", "##$.@@$#.++++++.", "#$#$.$$$........", "#$$####### ", "#$$#$$$$$# ", "#$$#$$$$$# ", "#$$#$$$$$# ", " #$#$$$$$# ", " ##$$$$$# ", " ####### "}; """ def __getstate__(self): ''' When saving the document this object gets stored using Python's cPickle module. Since we have some un-pickable here -- the Coin stuff -- we must define this method to return a tuple of all pickable objects or None. ''' return None def __setstate__(self,state): ''' When restoring the pickled object from document we have the chance to set some internals here. Since no data were pickled nothing needs to be done here. ''' return None def makeBox(): FreeCAD.newDocument() a=FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Box") Box(a) ViewProviderBox(a.ViewObject) # ----------------------------------------------------------------------------- class Line: def __init__(self, obj): ''' Add two point properties ''' obj.addProperty("App::PropertyVector","p1","Line","Start point") obj.addProperty("App::PropertyVector","p2","Line","End point").p2=FreeCAD.Vector(1,0,0) obj.Proxy = self def execute(self, fp): ''' Print a short message when doing a recomputation, this method is mandatory ''' fp.Shape = Part.makeLine(fp.p1,fp.p2) class ViewProviderLine: def __init__(self, obj): ''' Set this object to the proxy object of the actual view provider ''' obj.Proxy = self def getDefaultDisplayMode(self): ''' Return the name of the default display mode. It must be defined in getDisplayModes. ''' return "Flat Lines" def makeLine(): FreeCAD.newDocument() a=FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Line") Line(a) #ViewProviderLine(a.ViewObject) a.ViewObject.Proxy=0 # just set it to something different from None # ----------------------------------------------------------------------------- class Octahedron: def __init__(self, obj): "Add some custom properties to our box feature" obj.addProperty("App::PropertyLength","Length","Octahedron","Length of the octahedron").Length=1.0 obj.addProperty("App::PropertyLength","Width","Octahedron","Width of the octahedron").Width=1.0 obj.addProperty("App::PropertyLength","Height","Octahedron", "Height of the octahedron").Height=1.0 obj.addProperty("Part::PropertyPartShape","Shape","Octahedron", "Shape of the octahedron") obj.Proxy = self def execute(self, fp): # Define six vetices for the shape v1 = FreeCAD.Vector(0,0,0) v2 = FreeCAD.Vector(fp.Length,0,0) v3 = FreeCAD.Vector(0,fp.Width,0) v4 = FreeCAD.Vector(fp.Length,fp.Width,0) v5 = FreeCAD.Vector(fp.Length/2,fp.Width/2,fp.Height/2) v6 = FreeCAD.Vector(fp.Length/2,fp.Width/2,-fp.Height/2) # Make the wires/faces f1 = self.make_face(v2,v1,v5) f2 = self.make_face(v4,v2,v5) f3 = self.make_face(v3,v4,v5) f4 = self.make_face(v1,v3,v5) f5 = self.make_face(v1,v2,v6) f6 = self.make_face(v2,v4,v6) f7 = self.make_face(v4,v3,v6) f8 = self.make_face(v3,v1,v6) shell=Part.makeShell([f1,f2,f3,f4,f5,f6,f7,f8]) solid=Part.makeSolid(shell) fp.Shape = solid # helper mehod to create the faces def make_face(self,v1,v2,v3): wire = Part.makePolygon([v1,v2,v3,v1]) face = Part.Face(wire) return face class ViewProviderOctahedron: def __init__(self, obj): "Set this object to the proxy object of the actual view provider" obj.addProperty("App::PropertyColor","Color","Octahedron","Color of the octahedron").Color=(1.0,0.0,0.0) obj.Proxy = self def attach(self, obj): "Setup the scene sub-graph of the view provider, this method is mandatory" self.shaded = coin.SoGroup() self.wireframe = coin.SoGroup() self.color = coin.SoBaseColor() self.data=coin.SoCoordinate3() self.face=coin.SoIndexedFaceSet() self.shaded.addChild(self.color) self.shaded.addChild(self.data) self.shaded.addChild(self.face) obj.addDisplayMode(self.shaded,"Shaded"); style=coin.SoDrawStyle() style.style = coin.SoDrawStyle.LINES self.wireframe.addChild(style) self.wireframe.addChild(self.color) self.wireframe.addChild(self.data) self.wireframe.addChild(self.face) obj.addDisplayMode(self.wireframe,"Wireframe"); self.onChanged(obj,"Color") def updateData(self, fp, prop): "If a property of the handled feature has changed we have the chance to handle this here" # fp is the handled feature, prop is the name of the property that has changed if prop == "Shape": s = fp.getPropertyByName("Shape") self.data.point.setNum(6) cnt=0 for i in s.Vertexes: self.data.point.set1Value(cnt,i.X,i.Y,i.Z) cnt=cnt+1 self.face.coordIndex.set1Value(0,0) self.face.coordIndex.set1Value(1,2) self.face.coordIndex.set1Value(2,1) self.face.coordIndex.set1Value(3,-1) self.face.coordIndex.set1Value(4,3) self.face.coordIndex.set1Value(5,2) self.face.coordIndex.set1Value(6,0) self.face.coordIndex.set1Value(7,-1) self.face.coordIndex.set1Value(8,4) self.face.coordIndex.set1Value(9,2) self.face.coordIndex.set1Value(10,3) self.face.coordIndex.set1Value(11,-1) self.face.coordIndex.set1Value(12,1) self.face.coordIndex.set1Value(13,2) self.face.coordIndex.set1Value(14,4) self.face.coordIndex.set1Value(15,-1) self.face.coordIndex.set1Value(16,1) self.face.coordIndex.set1Value(17,5) self.face.coordIndex.set1Value(18,0) self.face.coordIndex.set1Value(19,-1) self.face.coordIndex.set1Value(20,0) self.face.coordIndex.set1Value(21,5) self.face.coordIndex.set1Value(22,3) self.face.coordIndex.set1Value(23,-1) self.face.coordIndex.set1Value(24,3) self.face.coordIndex.set1Value(25,5) self.face.coordIndex.set1Value(26,4) self.face.coordIndex.set1Value(27,-1) self.face.coordIndex.set1Value(28,4) self.face.coordIndex.set1Value(29,5) self.face.coordIndex.set1Value(30,1) self.face.coordIndex.set1Value(31,-1) def getDisplayModes(self,obj): "Return a list of display modes." modes=[] modes.append("Shaded") modes.append("Wireframe") return modes def getDefaultDisplayMode(self): "Return the name of the default display mode. It must be defined in getDisplayModes." return "Shaded" def setDisplayMode(self,mode): return mode def onChanged(self, vp, prop): "Here we can do something when a single property got changed" FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n") if prop == "Color": c = vp.getPropertyByName("Color") self.color.rgb.setValue(c[0],c[1],c[2]) def getIcon(self): return """ /* XPM */ static const char * ViewProviderBox_xpm[] = { "16 16 6 1", " c None", ". c #141010", "+ c #615BD2", "@ c #C39D55", "# c #000000", "$ c #57C355", " ........", " ......++..+..", " .@@@@.++..++.", " .@@@@.++..++.", " .@@ .++++++.", " ..@@ .++..++.", "###@@@@ .++..++.", "##$.@@$#.++++++.", "#$#$.$$$........", "#$$####### ", "#$$#$$$$$# ", "#$$#$$$$$# ", "#$$#$$$$$# ", " #$#$$$$$# ", " ##$$$$$# ", " ####### "}; """ def __getstate__(self): return None def __setstate__(self,state): return None def makeOctahedron(): FreeCAD.newDocument() a=FreeCAD.ActiveDocument.addObject("App::FeaturePython","Octahedron") Octahedron(a) ViewProviderOctahedron(a.ViewObject) # ----------------------------------------------------------------------------- class PointFeature: def __init__(self, obj): obj.Proxy = self def onChanged(self, fp, prop): ''' Print the name of the property that has changed ''' return def execute(self, fp): ''' Print a short message when doing a recomputation, this method is mandatory ''' return class ViewProviderPoints: def __init__(self, obj): ''' Set this object to the proxy object of the actual view provider ''' obj.Proxy = self def attach(self, obj): ''' Setup the scene sub-graph of the view provider, this method is mandatory ''' return def updateData(self, fp, prop): ''' If a property of the handled feature has changed we have the chance to handle this here ''' return def getDisplayModes(self,obj): ''' Return a list of display modes. ''' modes=[] return modes def getDefaultDisplayMode(self): ''' Return the name of the default display mode. It must be defined in getDisplayModes. ''' return "Points" def setDisplayMode(self,mode): ''' Map the display mode defined in attach with those defined in getDisplayModes. Since they have the same names nothing needs to be done. This method is optinal. ''' return mode def onChanged(self, vp, prop): ''' Print the name of the property that has changed ''' return def getIcon(self): ''' Return the icon in XMP format which will appear in the tree view. This method is optional and if not defined a default icon is shown. ''' return """ /* XPM */ static const char * ViewProviderBox_xpm[] = { "16 16 6 1", " c None", ". c #141010", "+ c #615BD2", "@ c #C39D55", "# c #000000", "$ c #57C355", " ........", " ......++..+..", " .@@@@.++..++.", " .@@@@.++..++.", " .@@ .++++++.", " ..@@ .++..++.", "###@@@@ .++..++.", "##$.@@$#.++++++.", "#$#$.$$$........", "#$$####### ", "#$$#$$$$$# ", "#$$#$$$$$# ", "#$$#$$$$$# ", " #$#$$$$$# ", " ##$$$$$# ", " ####### "}; """ def __getstate__(self): ''' When saving the document this object gets stored using Python's cPickle module. Since we have some un-pickable here -- the Coin stuff -- we must define this method to return a tuple of all pickable objects or None. ''' return None def __setstate__(self,state): ''' When restoring the pickled object from document we have the chance to set some internals here. Since no data were pickled nothing needs to be done here. ''' return None def makePoints(): FreeCAD.newDocument() import Mesh m=Mesh.createSphere(5.0).Points import Points p=Points.Points() l=[] for s in m: l.append(s.Vector) p.addPoints(l) a=FreeCAD.ActiveDocument.addObject("Points::FeaturePython","Points") a.Points=p PointFeature(a) ViewProviderPoints(a.ViewObject) # ----------------------------------------------------------------------------- class MeshFeature: def __init__(self, obj): obj.Proxy = self def onChanged(self, fp, prop): ''' Print the name of the property that has changed ''' return def execute(self, fp): ''' Print a short message when doing a recomputation, this method is mandatory ''' return class ViewProviderMesh: def __init__(self, obj): ''' Set this object to the proxy object of the actual view provider ''' obj.Proxy = self def attach(self, obj): ''' Setup the scene sub-graph of the view provider, this method is mandatory ''' return def getDefaultDisplayMode(self): ''' Return the name of the default display mode. It must be defined in getDisplayModes. ''' return "Shaded" def getIcon(self): ''' Return the icon in XMP format which will appear in the tree view. This method is optional and if not defined a default icon is shown. ''' return """ /* XPM */ static const char * ViewProviderBox_xpm[] = { "16 16 6 1", " c None", ". c #141010", "+ c #615BD2", "@ c #C39D55", "# c #000000", "$ c #57C355", " ........", " ......++..+..", " .@@@@.++..++.", " .@@@@.++..++.", " .@@ .++++++.", " ..@@ .++..++.", "###@@@@ .++..++.", "##$.@@$#.++++++.", "#$#$.$$$........", "#$$####### ", "#$$#$$$$$# ", "#$$#$$$$$# ", "#$$#$$$$$# ", " #$#$$$$$# ", " ##$$$$$# ", " ####### "}; """ def __getstate__(self): ''' When saving the document this object gets stored using Python's cPickle module. Since we have some un-pickable here -- the Coin stuff -- we must define this method to return a tuple of all pickable objects or None. ''' return None def __setstate__(self,state): ''' When restoring the pickled object from document we have the chance to set some internals here. Since no data were pickled nothing needs to be done here. ''' return None def makeMesh(): FreeCAD.newDocument() import Mesh a=FreeCAD.ActiveDocument.addObject("Mesh::FeaturePython","Mesh") a.Mesh=Mesh.createSphere(5.0) MeshFeature(a) ViewProviderMesh(a.ViewObject) # ----------------------------------------------------------------------------- class Molecule: def __init__(self, obj): ''' Add two point properties ''' obj.addProperty("App::PropertyVector","p1","Line","Start point") obj.addProperty("App::PropertyVector","p2","Line","End point").p2=FreeCAD.Vector(1,0,0) obj.Proxy = self def onChanged(self, fp, prop): if prop == "p1" or prop == "p2": ''' Print the name of the property that has changed ''' fp.Shape = Part.makeLine(fp.p1,fp.p2) def execute(self, fp): ''' Print a short message when doing a recomputation, this method is mandatory ''' fp.Shape = Part.makeLine(fp.p1,fp.p2) class ViewProviderMolecule: def __init__(self, obj): ''' Set this object to the proxy object of the actual view provider ''' obj.Proxy = self sep1=coin.SoSeparator() self.trl1=coin.SoTranslation() sep1.addChild(self.trl1) sep1.addChild(coin.SoSphere()) sep2=coin.SoSeparator() self.trl2=coin.SoTranslation() sep2.addChild(self.trl2) sep2.addChild(coin.SoSphere()) obj.RootNode.addChild(sep1) obj.RootNode.addChild(sep2) def updateData(self, fp, prop): "If a property of the handled feature has changed we have the chance to handle this here" # fp is the handled feature, prop is the name of the property that has changed if prop == "p1": p = fp.getPropertyByName("p1") self.trl1.translation=(p.x,p.y,p.z) elif prop == "p2": p = fp.getPropertyByName("p2") self.trl2.translation=(p.x,p.y,p.z) def __getstate__(self): return None def __setstate__(self,state): return None def makeMolecule(): FreeCAD.newDocument() a=FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Molecule") Molecule(a) ViewProviderMolecule(a.ViewObject) # ----------------------------------------------------------------------------- class CircleSet: def __init__(self, obj): obj.addProperty("Part::PropertyPartShape","Shape","Circle","Shape") obj.Proxy = self def execute(self, fp): pass class ViewProviderCircleSet: def __init__(self, obj): ''' Set this object to the proxy object of the actual view provider ''' obj.Proxy = self def attach(self, obj): self.coords=coin.SoCoordinate3() self.lines=coin.SoLineSet() obj.RootNode.addChild(self.coords) obj.RootNode.addChild(self.lines) def updateData(self, fp, prop): if prop == "Shape": edges=p = fp.getPropertyByName("Shape").Edges pts=[] ver=[] for i in edges: length=i.Length ver.append(10) for j in range(10): v=i.valueAt(j/9.0*length) pts.append((v.x,v.y,v.z)) self.coords.point.setValues(pts) self.lines.numVertices.setValues(ver) def __getstate__(self): return None def __setstate__(self,state): return None def makeCircleSet(): x=0.5 comp=Part.Compound([]) for j in range (630): y=0.5 for i in range (630): c = Part.makeCircle(0.1, Base.Vector(x,y,0), Base.Vector(0,0,1)) #Part.show(c) comp.add(c) y=y+0.5 x=x+0.5 FreeCAD.newDocument() a=FreeCAD.ActiveDocument.addObject("App::FeaturePython","Circles") c=CircleSet(a) v=ViewProviderCircleSet(a.ViewObject) a.Shape=comp # ----------------------------------------------------------------------------- class EnumTest: def __init__(self, obj): ''' Add enum properties ''' obj.addProperty("App::PropertyEnumeration","Enum","","Enumeration").Enum=["One","Two","Three"] obj.addProperty("App::PropertyEnumeration","Enum2","","Enumeration2").Enum2=["One","Two","Three"] obj.Proxy = self def execute(self, fp): return class ViewProviderEnumTest: def __init__(self, obj): ''' Set this object to the proxy object of the actual view provider ''' obj.addProperty("App::PropertyEnumeration","Enum3","","Enumeration3").Enum3=["One","Two","Three"] obj.addProperty("App::PropertyEnumeration","Enum4","","Enumeration4").Enum4=["One","Two","Three"] obj.Proxy = self def updateData(self, fp, prop): print "prop updated:",prop def __getstate__(self): return None def __setstate__(self,state): return None def makeEnumTest(): FreeCAD.newDocument() a=FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Enum") EnumTest(a) ViewProviderEnumTest(a.ViewObject) # ----------------------------------------------------------------------------- class DistanceBolt: def __init__(self, obj): ''' Add the properties: Length, Edges, Radius, Height ''' obj.addProperty("App::PropertyInteger","Edges","Bolt","Number of edges of the outline").Edges=6 obj.addProperty("App::PropertyLength","Length","Bolt","Length of the edges of the outline").Length=10.0 obj.addProperty("App::PropertyLength","Radius","Bolt","Radius of the inner circle").Radius=4.0 obj.addProperty("App::PropertyLength","Height","Bolt","Height of the extrusion").Height=20.0 obj.Proxy = self def onChanged(self, fp, prop): if prop == "Edges" or prop == "Length" or prop == "Radius" or prop == "Height": self.execute(fp) def execute(self, fp): edges = fp.Edges if edges < 3: edges = 3 length = fp.Length radius = fp.Radius height = fp.Height m=Base.Matrix() m.rotateZ(math.radians(360.0/edges)) # create polygon polygon = [] v=Base.Vector(length,0,0) for i in range(edges): polygon.append(v) v = m.multiply(v) polygon.append(v) wire = Part.makePolygon(polygon) # create circle circ=Part.makeCircle(radius) # Create the face with the polygon as outline and the circle as hole face=Part.Face([wire,Part.Wire(circ)]) # Extrude in z to create the final solid extrude=face.extrude(Base.Vector(0,0,height)) fp.Shape = extrude def makeDistanceBolt(): FreeCAD.newDocument() bolt=FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Distance_Bolt") bolt.Label = "Distance bolt" DistanceBolt(bolt) bolt.ViewObject.Proxy=0