FreeCAD
723 строки · 21.2 Кб
1"""
2Examples for a feature class and its view provider.
3(c) 2009 Werner Mayer LGPL
4"""
5
6__author__ = "Werner Mayer <wmayer@users.sourceforge.net>"7
8import FreeCAD, Part, math9from FreeCAD import Base10from pivy import coin11
12class PartFeature:13def __init__(self, obj):14obj.Proxy = self15
16class Box(PartFeature):17def __init__(self, obj):18PartFeature.__init__(self, obj)19''' Add some custom properties to our box feature '''20obj.addProperty("App::PropertyLength","Length","Box","Length of the box").Length=1.021obj.addProperty("App::PropertyLength","Width","Box","Width of the box").Width=1.022obj.addProperty("App::PropertyLength","Height","Box", "Height of the box").Height=1.023
24def onChanged(self, fp, prop):25''' Print the name of the property that has changed '''26FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n")27
28def execute(self, fp):29''' Print a short message when doing a recomputation, this method is mandatory '''30FreeCAD.Console.PrintMessage("Recompute Python Box feature\n")31fp.Shape = Part.makeBox(fp.Length,fp.Width,fp.Height)32
33class ViewProviderBox:34def __init__(self, obj):35''' Set this object to the proxy object of the actual view provider '''36obj.Proxy = self37
38def attach(self, obj):39''' Setup the scene sub-graph of the view provider, this method is mandatory '''40return41
42def updateData(self, fp, prop):43''' If a property of the handled feature has changed we have the chance to handle this here '''44return45
46def getDisplayModes(self,obj):47''' Return a list of display modes. '''48modes=[]49return modes50
51def getDefaultDisplayMode(self):52''' Return the name of the default display mode. It must be defined in getDisplayModes. '''53return "Shaded"54
55def setDisplayMode(self,mode):56''' Map the display mode defined in attach with those defined in getDisplayModes.57Since they have the same names nothing needs to be done. This method is optional.
58'''
59return mode60
61def onChanged(self, vp, prop):62''' Print the name of the property that has changed '''63FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n")64
65def getIcon(self):66''' Return the icon in XMP format which will appear in the tree view. This method is optional67and if not defined a default icon is shown.
68'''
69return """70/* XPM */
71static const char * ViewProviderBox_xpm[] = {
72"16 16 6 1",
73" c None",
74". c #141010",
75"+ c #615BD2",
76"@ c #C39D55",
77"# c #000000",
78"$ c #57C355",
79" ........",
80" ......++..+..",
81" .@@@@.++..++.",
82" .@@@@.++..++.",
83" .@@ .++++++.",
84" ..@@ .++..++.",
85"###@@@@ .++..++.",
86"##$.@@$#.++++++.",
87"#$#$.$$$........",
88"#$$####### ",
89"#$$#$$$$$# ",
90"#$$#$$$$$# ",
91"#$$#$$$$$# ",
92" #$#$$$$$# ",
93" ##$$$$$# ",
94" ####### "};
95"""
96
97def __getstate__(self):98''' When saving the document this object gets stored using Python's cPickle module.99Since we have some un-pickable here -- the Coin stuff -- we must define this method
100to return a tuple of all pickable objects or None.
101'''
102return None103
104def __setstate__(self,state):105''' When restoring the pickled object from document we have the chance to set some106internals here. Since no data were pickled nothing needs to be done here.
107'''
108return None109
110
111def makeBox():112doc=FreeCAD.newDocument()113a=FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Box")114Box(a)115ViewProviderBox(a.ViewObject)116doc.recompute()117
118# -----------------------------------------------------------------------------
119
120class Line:121def __init__(self, obj):122''' Add two point properties '''123obj.addProperty("App::PropertyVector","p1","Line","Start point")124obj.addProperty("App::PropertyVector","p2","Line","End point").p2=FreeCAD.Vector(1,0,0)125obj.Proxy = self126
127def execute(self, fp):128''' Print a short message when doing a recomputation, this method is mandatory '''129fp.Shape = Part.makeLine(fp.p1,fp.p2)130
131class ViewProviderLine:132def __init__(self, obj):133''' Set this object to the proxy object of the actual view provider '''134obj.Proxy = self135
136def getDefaultDisplayMode(self):137''' Return the name of the default display mode. It must be defined in getDisplayModes. '''138return "Flat Lines"139
140def makeLine():141doc=FreeCAD.newDocument()142a=FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Line")143Line(a)144#ViewProviderLine(a.ViewObject)145a.ViewObject.Proxy=0 # just set it to something different from None146doc.recompute()147
148# -----------------------------------------------------------------------------
149
150class Octahedron:151def __init__(self, obj):152"Add some custom properties to our box feature"153obj.addProperty("App::PropertyLength","Length","Octahedron","Length of the octahedron").Length=1.0154obj.addProperty("App::PropertyLength","Width","Octahedron","Width of the octahedron").Width=1.0155obj.addProperty("App::PropertyLength","Height","Octahedron", "Height of the octahedron").Height=1.0156obj.addProperty("Part::PropertyPartShape","Shape","Octahedron", "Shape of the octahedron")157obj.Proxy = self158
159def execute(self, fp):160# Define six vetices for the shape161v1 = FreeCAD.Vector(0,0,0)162v2 = FreeCAD.Vector(fp.Length,0,0)163v3 = FreeCAD.Vector(0,fp.Width,0)164v4 = FreeCAD.Vector(fp.Length,fp.Width,0)165v5 = FreeCAD.Vector(fp.Length/2,fp.Width/2,fp.Height/2)166v6 = FreeCAD.Vector(fp.Length/2,fp.Width/2,-fp.Height/2)167
168# Make the wires/faces169f1 = self.make_face(v2,v1,v5)170f2 = self.make_face(v4,v2,v5)171f3 = self.make_face(v3,v4,v5)172f4 = self.make_face(v1,v3,v5)173f5 = self.make_face(v1,v2,v6)174f6 = self.make_face(v2,v4,v6)175f7 = self.make_face(v4,v3,v6)176f8 = self.make_face(v3,v1,v6)177shell=Part.makeShell([f1,f2,f3,f4,f5,f6,f7,f8])178solid=Part.makeSolid(shell)179fp.Shape = solid180# helper method to create the faces181def make_face(self,v1,v2,v3):182wire = Part.makePolygon([v1,v2,v3,v1])183face = Part.Face(wire)184return face185
186class ViewProviderOctahedron:187def __init__(self, obj):188"Set this object to the proxy object of the actual view provider"189obj.addProperty("App::PropertyColor","Color","Octahedron","Color of the octahedron").Color=(1.0,0.0,0.0)190obj.Proxy = self191
192def attach(self, obj):193"Setup the scene sub-graph of the view provider, this method is mandatory"194self.shaded = coin.SoGroup()195self.wireframe = coin.SoGroup()196self.color = coin.SoBaseColor()197
198self.data=coin.SoCoordinate3()199self.face=coin.SoIndexedFaceSet()200
201self.shaded.addChild(self.color)202self.shaded.addChild(self.data)203self.shaded.addChild(self.face)204obj.addDisplayMode(self.shaded,"Shaded");205style=coin.SoDrawStyle()206style.style = coin.SoDrawStyle.LINES207self.wireframe.addChild(style)208self.wireframe.addChild(self.color)209self.wireframe.addChild(self.data)210self.wireframe.addChild(self.face)211obj.addDisplayMode(self.wireframe,"Wireframe");212self.onChanged(obj,"Color")213
214def updateData(self, fp, prop):215"If a property of the handled feature has changed we have the chance to handle this here"216# fp is the handled feature, prop is the name of the property that has changed217if prop == "Shape":218s = fp.getPropertyByName("Shape")219self.data.point.setNum(6)220cnt=0221for i in s.Vertexes:222self.data.point.set1Value(cnt,i.X,i.Y,i.Z)223cnt=cnt+1224
225self.face.coordIndex.set1Value(0,0)226self.face.coordIndex.set1Value(1,2)227self.face.coordIndex.set1Value(2,1)228self.face.coordIndex.set1Value(3,-1)229
230self.face.coordIndex.set1Value(4,3)231self.face.coordIndex.set1Value(5,2)232self.face.coordIndex.set1Value(6,0)233self.face.coordIndex.set1Value(7,-1)234
235self.face.coordIndex.set1Value(8,4)236self.face.coordIndex.set1Value(9,2)237self.face.coordIndex.set1Value(10,3)238self.face.coordIndex.set1Value(11,-1)239
240self.face.coordIndex.set1Value(12,1)241self.face.coordIndex.set1Value(13,2)242self.face.coordIndex.set1Value(14,4)243self.face.coordIndex.set1Value(15,-1)244
245self.face.coordIndex.set1Value(16,1)246self.face.coordIndex.set1Value(17,5)247self.face.coordIndex.set1Value(18,0)248self.face.coordIndex.set1Value(19,-1)249
250self.face.coordIndex.set1Value(20,0)251self.face.coordIndex.set1Value(21,5)252self.face.coordIndex.set1Value(22,3)253self.face.coordIndex.set1Value(23,-1)254
255self.face.coordIndex.set1Value(24,3)256self.face.coordIndex.set1Value(25,5)257self.face.coordIndex.set1Value(26,4)258self.face.coordIndex.set1Value(27,-1)259
260self.face.coordIndex.set1Value(28,4)261self.face.coordIndex.set1Value(29,5)262self.face.coordIndex.set1Value(30,1)263self.face.coordIndex.set1Value(31,-1)264
265def getDisplayModes(self,obj):266"Return a list of display modes."267modes=[]268modes.append("Shaded")269modes.append("Wireframe")270return modes271
272def getDefaultDisplayMode(self):273"Return the name of the default display mode. It must be defined in getDisplayModes."274return "Shaded"275
276def setDisplayMode(self,mode):277return mode278
279def onChanged(self, vp, prop):280"Here we can do something when a single property got changed"281FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n")282if prop == "Color":283c = vp.getPropertyByName("Color")284self.color.rgb.setValue(c[0],c[1],c[2])285
286def getIcon(self):287return """288/* XPM */
289static const char * ViewProviderBox_xpm[] = {
290"16 16 6 1",
291" c None",
292". c #141010",
293"+ c #615BD2",
294"@ c #C39D55",
295"# c #000000",
296"$ c #57C355",
297" ........",
298" ......++..+..",
299" .@@@@.++..++.",
300" .@@@@.++..++.",
301" .@@ .++++++.",
302" ..@@ .++..++.",
303"###@@@@ .++..++.",
304"##$.@@$#.++++++.",
305"#$#$.$$$........",
306"#$$####### ",
307"#$$#$$$$$# ",
308"#$$#$$$$$# ",
309"#$$#$$$$$# ",
310" #$#$$$$$# ",
311" ##$$$$$# ",
312" ####### "};
313"""
314
315def __getstate__(self):316return None317
318def __setstate__(self,state):319return None320
321def makeOctahedron():322doc=FreeCAD.newDocument()323a=FreeCAD.ActiveDocument.addObject("App::FeaturePython","Octahedron")324Octahedron(a)325ViewProviderOctahedron(a.ViewObject)326doc.recompute()327
328# -----------------------------------------------------------------------------
329
330class PointFeature:331def __init__(self, obj):332obj.Proxy = self333
334def onChanged(self, fp, prop):335''' Print the name of the property that has changed '''336return337
338def execute(self, fp):339''' Print a short message when doing a recomputation, this method is mandatory '''340return341
342class ViewProviderPoints:343def __init__(self, obj):344''' Set this object to the proxy object of the actual view provider '''345obj.Proxy = self346
347def attach(self, obj):348''' Setup the scene sub-graph of the view provider, this method is mandatory '''349return350
351def updateData(self, fp, prop):352''' If a property of the handled feature has changed we have the chance to handle this here '''353return354
355def getDisplayModes(self,obj):356''' Return a list of display modes. '''357modes=[]358return modes359
360def getDefaultDisplayMode(self):361''' Return the name of the default display mode. It must be defined in getDisplayModes. '''362return "Points"363
364def setDisplayMode(self,mode):365''' Map the display mode defined in attach with those defined in getDisplayModes.366Since they have the same names nothing needs to be done. This method is optional.
367'''
368return mode369
370def onChanged(self, vp, prop):371''' Print the name of the property that has changed '''372return373
374def getIcon(self):375''' Return the icon in XMP format which will appear in the tree view. This method is optional376and if not defined a default icon is shown.
377'''
378return """379/* XPM */
380static const char * ViewProviderBox_xpm[] = {
381"16 16 6 1",
382" c None",
383". c #141010",
384"+ c #615BD2",
385"@ c #C39D55",
386"# c #000000",
387"$ c #57C355",
388" ........",
389" ......++..+..",
390" .@@@@.++..++.",
391" .@@@@.++..++.",
392" .@@ .++++++.",
393" ..@@ .++..++.",
394"###@@@@ .++..++.",
395"##$.@@$#.++++++.",
396"#$#$.$$$........",
397"#$$####### ",
398"#$$#$$$$$# ",
399"#$$#$$$$$# ",
400"#$$#$$$$$# ",
401" #$#$$$$$# ",
402" ##$$$$$# ",
403" ####### "};
404"""
405
406def __getstate__(self):407''' When saving the document this object gets stored using Python's cPickle module.408Since we have some un-pickable here -- the Coin stuff -- we must define this method
409to return a tuple of all pickable objects or None.
410'''
411return None412
413def __setstate__(self,state):414''' When restoring the pickled object from document we have the chance to set some415internals here. Since no data were pickled nothing needs to be done here.
416'''
417return None418
419
420def makePoints():421doc=FreeCAD.newDocument()422import Mesh423m=Mesh.createSphere(5.0).Points424import Points425p=Points.Points()426
427l=[]428for s in m:429l.append(s.Vector)430
431p.addPoints(l)432
433
434a=FreeCAD.ActiveDocument.addObject("Points::FeaturePython","Points")435a.Points=p436PointFeature(a)437ViewProviderPoints(a.ViewObject)438doc.recompute()439
440# -----------------------------------------------------------------------------
441
442class MeshFeature:443def __init__(self, obj):444obj.Proxy = self445
446def onChanged(self, fp, prop):447''' Print the name of the property that has changed '''448return449
450def execute(self, fp):451''' Print a short message when doing a recomputation, this method is mandatory '''452return453
454class ViewProviderMesh:455def __init__(self, obj):456''' Set this object to the proxy object of the actual view provider '''457obj.Proxy = self458
459def attach(self, obj):460''' Setup the scene sub-graph of the view provider, this method is mandatory '''461return462
463def getDefaultDisplayMode(self):464''' Return the name of the default display mode. It must be defined in getDisplayModes. '''465return "Shaded"466
467def getIcon(self):468''' Return the icon in XMP format which will appear in the tree view. This method is optional469and if not defined a default icon is shown.
470'''
471return """472/* XPM */
473static const char * ViewProviderBox_xpm[] = {
474"16 16 6 1",
475" c None",
476". c #141010",
477"+ c #615BD2",
478"@ c #C39D55",
479"# c #000000",
480"$ c #57C355",
481" ........",
482" ......++..+..",
483" .@@@@.++..++.",
484" .@@@@.++..++.",
485" .@@ .++++++.",
486" ..@@ .++..++.",
487"###@@@@ .++..++.",
488"##$.@@$#.++++++.",
489"#$#$.$$$........",
490"#$$####### ",
491"#$$#$$$$$# ",
492"#$$#$$$$$# ",
493"#$$#$$$$$# ",
494" #$#$$$$$# ",
495" ##$$$$$# ",
496" ####### "};
497"""
498
499def __getstate__(self):500''' When saving the document this object gets stored using Python's cPickle module.501Since we have some un-pickable here -- the Coin stuff -- we must define this method
502to return a tuple of all pickable objects or None.
503'''
504return None505
506def __setstate__(self,state):507''' When restoring the pickled object from document we have the chance to set some508internals here. Since no data were pickled nothing needs to be done here.
509'''
510return None511
512
513def makeMesh():514doc=FreeCAD.newDocument()515import Mesh516
517a=FreeCAD.ActiveDocument.addObject("Mesh::FeaturePython","Mesh")518a.Mesh=Mesh.createSphere(5.0)519MeshFeature(a)520ViewProviderMesh(a.ViewObject)521doc.recompute()522
523# -----------------------------------------------------------------------------
524
525class Molecule:526def __init__(self, obj):527''' Add two point properties '''528obj.addProperty("App::PropertyVector","p1","Line","Start point")529obj.addProperty("App::PropertyVector","p2","Line","End point").p2=FreeCAD.Vector(5,0,0)530
531obj.Proxy = self532
533def execute(self, fp):534''' Print a short message when doing a recomputation, this method is mandatory '''535fp.Shape = Part.makeLine(fp.p1,fp.p2)536
537class ViewProviderMolecule:538def __init__(self, obj):539''' Set this object to the proxy object of the actual view provider '''540sep1=coin.SoSeparator()541self.trl1=coin.SoTranslation()542sep1.addChild(self.trl1)543sep1.addChild(coin.SoSphere())544sep2=coin.SoSeparator()545self.trl2=coin.SoTranslation()546sep2.addChild(self.trl2)547sep2.addChild(coin.SoSphere())548obj.RootNode.addChild(sep1)549obj.RootNode.addChild(sep2)550# triggers an updateData call so the assignment at the end551obj.Proxy = self552
553def updateData(self, fp, prop):554"If a property of the handled feature has changed we have the chance to handle this here"555# fp is the handled feature, prop is the name of the property that has changed556if prop == "p1":557p = fp.getPropertyByName("p1")558self.trl1.translation=(p.x,p.y,p.z)559elif prop == "p2":560p = fp.getPropertyByName("p2")561self.trl2.translation=(p.x,p.y,p.z)562
563def __getstate__(self):564return None565
566def __setstate__(self,state):567return None568
569def makeMolecule():570doc=FreeCAD.newDocument()571a=FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Molecule")572Molecule(a)573ViewProviderMolecule(a.ViewObject)574doc.recompute()575
576# -----------------------------------------------------------------------------
577
578class CircleSet:579def __init__(self, obj):580obj.addProperty("Part::PropertyPartShape","Shape","Circle","Shape")581obj.Proxy = self582
583def execute(self, fp):584pass585
586
587class ViewProviderCircleSet:588def __init__(self, obj):589''' Set this object to the proxy object of the actual view provider '''590obj.Proxy = self591
592def attach(self, obj):593self.coords=coin.SoCoordinate3()594self.lines=coin.SoLineSet()595obj.RootNode.addChild(self.coords)596obj.RootNode.addChild(self.lines)597
598def updateData(self, fp, prop):599if prop == "Shape":600edges = fp.getPropertyByName("Shape").Edges601pts=[]602ver=[]603for i in edges:604length=i.Length605ver.append(10)606for j in range(10):607v=i.valueAt(j/9.0*length)608pts.append((v.x,v.y,v.z))609
610self.coords.point.setValues(pts)611self.lines.numVertices.setValues(ver)612
613def __getstate__(self):614return None615
616def __setstate__(self,state):617return None618
619def makeCircleSet():620x=0.5621comp=Part.Compound([])622for j in range (630):623y=0.5624for i in range (630):625c = Part.makeCircle(0.1, Base.Vector(x,y,0), Base.Vector(0,0,1))626#Part.show(c)627comp.add(c)628y=y+0.5629x=x+0.5630
631doc=FreeCAD.newDocument()632a=FreeCAD.ActiveDocument.addObject("App::FeaturePython","Circles")633CircleSet(a)634ViewProviderCircleSet(a.ViewObject)635a.Shape=comp636doc.recompute()637
638# -----------------------------------------------------------------------------
639
640class EnumTest:641def __init__(self, obj):642''' Add enum properties '''643obj.addProperty("App::PropertyEnumeration","Enum","","Enumeration").Enum=["One","Two","Three"]644obj.addProperty("App::PropertyEnumeration","Enum2","","Enumeration2").Enum2=["One","Two","Three"]645obj.Proxy = self646
647def execute(self, fp):648return649
650class ViewProviderEnumTest:651def __init__(self, obj):652''' Set this object to the proxy object of the actual view provider '''653obj.addProperty("App::PropertyEnumeration","Enum3","","Enumeration3").Enum3=["One","Two","Three"]654obj.addProperty("App::PropertyEnumeration","Enum4","","Enumeration4").Enum4=["One","Two","Three"]655obj.Proxy = self656
657def updateData(self, fp, prop):658print("prop updated:",prop)659
660def __getstate__(self):661return None662
663def __setstate__(self,state):664return None665
666def makeEnumTest():667FreeCAD.newDocument()668a=FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Enum")669EnumTest(a)670ViewProviderEnumTest(a.ViewObject)671
672# -----------------------------------------------------------------------------
673
674class DistanceBolt:675def __init__(self, obj):676''' Add the properties: Length, Edges, Radius, Height '''677obj.addProperty("App::PropertyInteger","Edges","Bolt","Number of edges of the outline").Edges=6678obj.addProperty("App::PropertyLength","Length","Bolt","Length of the edges of the outline").Length=10.0679obj.addProperty("App::PropertyLength","Radius","Bolt","Radius of the inner circle").Radius=4.0680obj.addProperty("App::PropertyLength","Height","Bolt","Height of the extrusion").Height=20.0681obj.Proxy = self682
683def onChanged(self, fp, prop):684if prop == "Edges" or prop == "Length" or prop == "Radius" or prop == "Height":685self.execute(fp)686
687def execute(self, fp):688edges = fp.Edges689if edges < 3:690edges = 3691length = fp.Length692radius = fp.Radius693height = fp.Height694
695m=Base.Matrix()696m.rotateZ(math.radians(360.0/edges))697
698# create polygon699polygon = []700v=Base.Vector(length,0,0)701for i in range(edges):702polygon.append(v)703v = m.multiply(v)704polygon.append(v)705wire = Part.makePolygon(polygon)706
707# create circle708circ=Part.makeCircle(radius)709
710# Create the face with the polygon as outline and the circle as hole711face=Part.Face([wire,Part.Wire(circ)])712
713# Extrude in z to create the final solid714extrude=face.extrude(Base.Vector(0,0,height))715fp.Shape = extrude716
717def makeDistanceBolt():718doc=FreeCAD.newDocument()719bolt=FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Distance_Bolt")720bolt.Label = "Distance bolt"721DistanceBolt(bolt)722bolt.ViewObject.Proxy=0723doc.recompute()724