python 实例 cadu_FreeCad数据扩展

除了标注对象类型(如注释,网格和零件对象)之外,FreeCAD还提供了构建100%python脚本对象(称为Python功能)的可能性。这些对象的行为与任何其他FreeCAD对象完全相同,并在文件保存/加载时自动保存和恢复。

这些对象使用python的json模块保存在FreeCAD FcStd文件中。该模块将python对象转换为字符串,允许将其添加到保存的文件中。在加载时,json模块使用该字符串重新创建原始对象,前提是它可以访问创建该对象的源代码。这意味着如果保存这样的自定义对象并在不存在生成该对象的python代码的机器上打开它,则不会重新创建该对象。如果将这些对象分发给其他人,则需要分发创建它的python脚本。

Python功能遵循与所有FreeCAD功能相同的规则:它们分为App和GUI部分。应用程序部分Document对象定义了对象的几何形状,而GUI部分View Provider Object定义了如何在屏幕上绘制对象。与任何其他FreeCAD功能一样,View Provider Object仅在您自己的GUI中运行FreeCAD时可用。有几个属性和方法可用于构建对象。属性必须是FreeCAD提供的任何预定义属性类型,并且将显示在属性视图窗口中,以便用户可以编辑它们。这样,FeaturePython对象就是真正完全参数化的。您可以单独定义Object及其ViewObject的属性。

提示:在以前的版本中,我们使用了Python的cPickle模块。但是,该模块执行任意代码,从而导致安全问题。因此,我们转向Python的json模块。

基本的例子

可以在src / Mod / TemplatePyMod / FeaturePython.py文件中找到以下示例,以及其他几个示例:

'''Examples for a feature class and its view provider.'''

import FreeCAD, FreeCADGui

from pivy import coin

class Box:

def __init__(self, obj):

'''添加Box自定义属性特征'''

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

obj.Proxy = self

def onChanged(self, fp, prop):

'''定义属性改变时的操作'''

FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n")

def execute(self, fp):

'''在进行重新计算时执行某些操作,此方法是必需的'''

FreeCAD.Console.PrintMessage("Recompute Python Box feature\n")

class ViewProviderBox:

def __init__(self, obj):

'''将此对象设置为实际视图提供者的代理对象Set this object to the proxy object of the actual view provider'''

obj.addProperty("App::PropertyColor","Color","Box","Color of the box").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.scale = coin.SoScale()

self.color = coin.SoBaseColor()

data=coin.SoCube()

self.shaded.addChild(self.scale)

self.shaded.addChild(self.color)

self.shaded.addChild(data)

obj.addDisplayMode(self.shaded,"Shaded");

style=coin.SoDrawStyle()

style.style = coin.SoDrawStyle.LINES

self.wireframe.addChild(style)

self.wireframe.addChild(self.scale)

self.wireframe.addChild(self.color)

self.wireframe.addChild(data)

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

l = fp.getPropertyByName("Length")

w = fp.getPropertyByName("Width")

h = fp.getPropertyByName("Height")

self.scale.scaleFactor.setValue(float(l),float(w),float(h))

pass

def getDisplayModes(self,obj):

'''返回显示模式列表Return a list of display modes.'''

modes=[]

modes.append("Shaded")

modes.append("Wireframe")

return modes

def getDefaultDisplayMode(self):

'''返回默认显示模式的名称。它必须在getDisplayModes中定义。Return the name of the default display mode. It must be defined in getDisplayModes.'''

return "Shaded"

def setDisplayMode(self,mode):

'''将attach中定义的显示模式映射到getDisplayModes中定义的那些。\

因为它们具有相同的名称,所以不需要做任何事情。这个方法是可选的

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 optional'''

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):

'''返回XPM格式的图标,该图标将显示在树形视图中。此方法是\

optional,如果未定义,则显示默认图标。

Return the icon in XPM 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):

'''保存文档时,使用Python的json模块存储此对象。

返回所有可序列化对象的元组或无。

When saving the document this object gets stored using Python's json module.\

Since we have some un-serializable parts here -- the Coin stuff -- we must define this method\

to return a tuple of all serializable objects or None.'''

return None

def __setstate__(self,state):

'''当从文档恢复序列化对象时,我们有机会在这里设置一些内部。\

因为没有数据被序列化这里没有什么需要做的。

When restoring the serialized object from document we have the chance to set some internals here.\

Since no data were serialized nothing needs to be done here.'''

return None

def makeBox():

FreeCAD.newDocument()

a=FreeCAD.ActiveDocument.addObject("App::FeaturePython","Box")

Box(a)

ViewProviderBox(a.ViewObject)

makeBox()

可用的属性

属性是FeaturePython对象的真正构建元素。通过它们,用户将能够交互和修改您的对象。在文档中创建新的FeaturePython对象(obj = FreeCAD.ActiveDocument.addObject(“App :: FeaturePython”,“Box”))后,您可以通过发出以下命令获取可用属性的列表:

obj.supportedProperties()

您将获得可用属性的列表:

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

向自定义对象添加属性时,请注意以下事项:

不要在属性描述中使用字符“”(这会破坏.fcstd文件中的xml片段)

属性按字母顺序存储在.fcstd文件中。如果属性中有形状,则按字母顺序在“Shape”之后的任何属性将在形状之后加载,这可能会导致奇怪的行为。

财产类型

默认情况下,可以更新属性。可以使属性为只读,例如在想要显示方法结果的情况下。也可以隐藏酒店。可以使用设置属性类型

obj.setEditorMode(“MyPropertyName”,mode)

其中mode是一个short int,可以设置为:

0 - 默认模式,读写

1 - 只读

2 - 隐藏

在FreeCAD文件重新加载时未设置EditorModes。这可以通过__setstate__函数完成。请参阅http://forum.freecadweb.org/v...。通过使用setEditorMode,属性仅在PropertyEditor中读取。它们仍然可以从python中更改。要真正使它们只读,必须直接在addProperty函数内传递设置。有关示例,请参见http://forum.freecadweb.org/v...。

其他更复杂的例子

此示例使用“ 零件模块”创建八面体,然后使用“关键”创建其硬币表示。

首先是Document对象本身:

import FreeCAD, FreeCADGui, Part

import pivy

from pivy import coin

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(v1,v2,v5)

f2 = self.make_face(v2,v4,v5)

f3 = self.make_face(v4,v3,v5)

f4 = self.make_face(v3,v1,v5)

f5 = self.make_face(v2,v1,v6)

f6 = self.make_face(v4,v2,v6)

f7 = self.make_face(v3,v4,v6)

f8 = self.make_face(v1,v3,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

Then, we have the view provider object, responsible for showing the object in the 3D scene:

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.scale = coin.SoScale()

self.color = coin.SoBaseColor()

self.data=coin.SoCoordinate3()

self.face=coin.SoIndexedLineSet()

self.shaded.addChild(self.scale)

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.scale)

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,1)

self.face.coordIndex.set1Value(2,2)

self.face.coordIndex.set1Value(3,-1)

self.face.coordIndex.set1Value(4,1)

self.face.coordIndex.set1Value(5,3)

self.face.coordIndex.set1Value(6,2)

self.face.coordIndex.set1Value(7,-1)

self.face.coordIndex.set1Value(8,3)

self.face.coordIndex.set1Value(9,4)

self.face.coordIndex.set1Value(10,2)

self.face.coordIndex.set1Value(11,-1)

self.face.coordIndex.set1Value(12,4)

self.face.coordIndex.set1Value(13,0)

self.face.coordIndex.set1Value(14,2)

self.face.coordIndex.set1Value(15,-1)

self.face.coordIndex.set1Value(16,1)

self.face.coordIndex.set1Value(17,0)

self.face.coordIndex.set1Value(18,5)

self.face.coordIndex.set1Value(19,-1)

self.face.coordIndex.set1Value(20,3)

self.face.coordIndex.set1Value(21,1)

self.face.coordIndex.set1Value(22,5)

self.face.coordIndex.set1Value(23,-1)

self.face.coordIndex.set1Value(24,4)

self.face.coordIndex.set1Value(25,3)

self.face.coordIndex.set1Value(26,5)

self.face.coordIndex.set1Value(27,-1)

self.face.coordIndex.set1Value(28,0)

self.face.coordIndex.set1Value(29,4)

self.face.coordIndex.set1Value(30,5)

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值