FreeCAD/src/Mod/TemplatePyMod/FeaturePython.py
2013-08-09 17:26:57 +02:00

723 lines
21 KiB
Python

"""
Examples for a feature class and its view provider.
(c) 2009 Werner Mayer LGPL
"""
__author__ = "Werner Mayer <wmayer@users.sourceforge.net>"
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