通過上一篇筆記的梳理挽霉,對(duì)工作臺(tái)開發(fā)的整體概念和必要的文件已經(jīng)有了大概的了解,接下來需要深入了解一下各個(gè)模塊的具體作用及其使用方法。
本節(jié)學(xué)習(xí)目標(biāo)
- 了解
FreeCAD
里的基本功能模塊; - 實(shí)現(xiàn)點(diǎn)擊功能按鈕,創(chuàng)建一個(gè)帶有屬性的基本三維對(duì)象株憾;
- 調(diào)整屬性,觀察三維對(duì)象是否發(fā)生變化;
- 保存文檔并重新打開嗤瞎,確認(rèn)所有屬性保存完整墙歪。
一、工作臺(tái)可使用的主要模塊
在 FreeCAD
里有很多模塊贝奇,他們?cè)?工作臺(tái)
和 宏腳本
里都可以使用虹菲,最常使用的有兩個(gè):
-
FreeCAD
-
FreeCAD
又可以簡(jiǎn)寫為App
,主要用來調(diào)用和操作與界面(UI)無關(guān)的功能掉瞳,它有以下幾種引用方式:# 方式一 from freecad import app # 方式二 import FreeCAD as App
- 常用的方法和屬性
-
app.ActiveDocument
: 獲取當(dāng)前活動(dòng)的文檔毕源; -
app.newDocument()
: 創(chuàng)建一個(gè)新的文檔; -
app.Console.PrintMessage()
: 在FreeCAD
的報(bào)告瀏覽器中輸出字符陕习,如:app.Console.PrintMessage("測(cè)試內(nèi)容")
-
app.ActiveDocument.recompute()
: 重新計(jì)算當(dāng)前文檔霎褐,即重新繪制三維對(duì)象。
-
-
-
FreeCADGui
-
FreeCADGui
是用來調(diào)用和界面(UI)相關(guān)的功能该镣,它有以下幾種引用方式:# 方式一 from freecad import gui # 方式二 import FreeCADGui as Gui
- 常用的方法和屬性
-
gui.addCommand()
: 向FreeCAD
注冊(cè)一個(gè)命令冻璃,如:gui.addCommand('createThing', createThing())
-
gui.addWorkbench()
: 向FreeCAD
注冊(cè)一個(gè)工作臺(tái),如:gui.addWorkbench(MazeWorkbench())
-
gui.Selection.getSelection()
: 獲取當(dāng)前選中的對(duì)象损合,返回是一個(gè)數(shù)組
-
-
二省艳、調(diào)用其他工作臺(tái)的功能
- 有時(shí)候需要在代碼中調(diào)用系統(tǒng)其他工作臺(tái)里的功能,比如
Part
工作臺(tái)里的功能塌忽,那就需要先將其導(dǎo)入拍埠,如:import Part
- 導(dǎo)入后就可以正常使用了失驶,如:
# 創(chuàng)建一個(gè) 10x10x10 的立方體 Part.makeBox(10,10,10)
三土居、命令(按鈕)基本定義
- 在上一次的筆記中使用過一個(gè)基本的命令(按鈕):
class CreateMaze(): def GetResources(self): return {"Pixmap" : APPICON, "MenuText": "創(chuàng)建迷宮", "ToolTip" : "創(chuàng)建一個(gè)3D迷宮"} def Activated(self): app.Console.PrintMessage("迷宮已創(chuàng)建完成\n") return def IsActive(self): ''' 判斷當(dāng)前命令是否可用 ''' return True
-
GetResources()
: 用于獲取命令(按鈕)的圖標(biāo)、名稱嬉探、提示等基本屬性擦耀,該方法 必需 定義; -
Activated()
: 用于命令被調(diào)用時(shí)執(zhí)行的功能涩堤,該方法 必需 定義眷蜓; -
IsActive()
: 判斷當(dāng)前命令是否可用,該方法可選胎围,默認(rèn)命令為可用吁系;
-
- 一個(gè)命令通常為一個(gè)
python
的類,通過以上規(guī)則進(jìn)行定義白魂; - 在一個(gè)工作臺(tái)里通常會(huì)有多個(gè)命令汽纤,所以為了方便擴(kuò)展,可以定義一個(gè)基類福荸,如:
class BaseCommand(object): def GetResources(self): return {'Pixmap': self.Pixmap, 'MenuText': self.MenuText, 'ToolTip': self.ToolTip} def Activated(self): return def IsActive(self): if app.ActiveDocument is None: return False else: return True
- 然后其他命令通過這個(gè)基類來繼承蕴坪,如:
class CreateMazeA(BaseCommand): Pixmap = APPICON MenuText = "創(chuàng)建迷宮A" ToolTip = "創(chuàng)建一個(gè)3D迷宮A" def Activated(self): app.Console.PrintMessage("迷宮A已創(chuàng)建完成\n") return class CreateMazeB(BaseCommand): Pixmap = APPICON MenuText = "創(chuàng)建迷宮B" ToolTip = "創(chuàng)建一個(gè)3D迷宮B" def Activated(self): app.Console.PrintMessage("迷宮B已創(chuàng)建完成\n") return
- 這樣就可以方便的進(jìn)行多個(gè)命令的創(chuàng)建了。
四、繪制自定義的三維對(duì)象
- 上面只學(xué)習(xí)了基本命令的創(chuàng)建和調(diào)用背传,但在 FreeCAD 里主要目的還是要?jiǎng)?chuàng)建三維對(duì)象呆瞻,比如常規(guī)的立方體、圓柱體等径玖,他們可以通過不同的工作臺(tái)去創(chuàng)建痴脾;
- 這些三維對(duì)象都有自己的屬性,比如:高度挺狰、寬度明郭、直徑等等;
- 那創(chuàng)建一個(gè)迷宮對(duì)象丰泊,也會(huì)有自己的屬性薯定,比如:墻高度、墻厚度等等瞳购;
- 這里就需要引入
FreeCAD
里的一個(gè)概念:腳本對(duì)象话侄;- 通俗點(diǎn)可以理解為通過腳本創(chuàng)建的對(duì)象,它需要可被序列化后保存到
FreeCAD
文件中学赛,以便重新打開時(shí)進(jìn)行反序列化年堆; - 它在
FreeCAD
內(nèi)部被稱為FeaturePython
,用App::FeaturePython
類型來表示盏浇;
- 通俗點(diǎn)可以理解為通過腳本創(chuàng)建的對(duì)象,它需要可被序列化后保存到
- 通過以上概念的了解变丧,再回來和上面的
命令
結(jié)合,生成一個(gè)真正的帶屬性的三維對(duì)象绢掰; - 首先來定義一個(gè)三維對(duì)象痒蓬,如(示例在官網(wǎng)的基礎(chǔ)上稍作調(diào)整):
class Box: def __init__(self, obj): '''對(duì)象實(shí)始化,可以添加一些屬性''' 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): '''Do something when a property has changed''' FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n") def execute(self, fp): '''在調(diào)用重新計(jì)算時(shí)會(huì)執(zhí)行該方法''' FreeCAD.Console.PrintMessage("Recompute Python Box feature\n")
-
__init__()
:- 初始化方法滴劲,它接收一個(gè)
obj
對(duì)象攻晒,通常為App::FeaturePython
對(duì)象; - 可通過
FreeCAD.ActiveDocument.addObject()
方法來添加班挖,如:box = FreeCAD.ActiveDocument.addObject("App::FeaturePython", "Box") Box(box)
-
obj.Proxy
: 這個(gè)必需要指定self
鲁捏,它會(huì)在FreeCAD
內(nèi)部被調(diào)用
- 初始化方法滴劲,它接收一個(gè)
-
onChanged()
: 當(dāng)屬性變更時(shí)被調(diào)用,需要注意的點(diǎn):- 在初始化時(shí)萧芙,類似這樣
obj.addProperty("App::PropertyLength", "Length", "Box", "").Length = 1.0
的語句也會(huì)觸發(fā)onChanged
方法给梅,所以如果檢測(cè)或?qū)ζ渌麑傩赃M(jìn)行計(jì)算時(shí)要小心,可能指定的屬性還不存在双揪。
- 在初始化時(shí)萧芙,類似這樣
execute()
: 當(dāng)執(zhí)行重新計(jì)算
時(shí)动羽,該方法會(huì)被調(diào)用
-
- 通過上面的代碼,已經(jīng)定義了一個(gè)基本的三維對(duì)象————立方體盟榴,他包含三個(gè)屬性:
Length
曹质,Width
,Height
; - 這些屬性是通過一個(gè)
addProperty
方法來添加的羽德,該方法有7
個(gè)參數(shù):- 原型定義:
addProperty(self,typ,name='',group='',doc='',attr=0,readonly=False,hidden=False)
-
typ
: 屬性類型几莽,如:整型、浮點(diǎn)等宅静,在FreeCAD
內(nèi)部定義了很多類型章蚣;- 比如上面使用的
App::PropertyLength
他用來表示長度,是浮點(diǎn)類型的擴(kuò)展姨夹,默認(rèn)帶有單位纤垂; - 更多類型可參考:https://wiki.freecad.org/Property
- 比如上面使用的
-
name
: 屬性的名稱,用英文表示磷账,他會(huì)在代碼里用到峭沦; -
group
: 屬性的分組,可用中文逃糟,相同的分組會(huì)在FreeCAD
的屬性頁中顯示到一起吼鱼; -
doc
: 屬性的詳細(xì)描述,可用中文绰咽,當(dāng)鼠標(biāo)在對(duì)應(yīng)的屬性上停留時(shí)顯示菇肃; -
attr
: 這是屬性的附加屬性,默認(rèn)為0
取募,表示沒有特殊的限制琐谤,可用值為:- 0 -- Prop_None, 無特殊限制
- 1 -- Prop_ReadOnly, 在屬性編輯器里只讀
- 2 -- Prop_Transient, 表示屬性值不會(huì)在文件里保存,但屬性名稱和類型這些會(huì)保存
- 4 -- Prop_Hidden, 在屬性編輯器里隱藏
- 8 -- Prop_Output, 作用暫不明玩敏,原文描述為:Modified property doesn't touch its parent container
- 16 -- Prop_NoRecompute, 修改屬性時(shí)斗忌,不會(huì)觸發(fā)重新計(jì)算
- 32 -- Prop_NoPersist, 表示屬性值不會(huì)在文件里保存,屬性名稱和類型也都不會(huì)保存
-
readonly
: 是否只讀聊品,默認(rèn)為False
-
hidden
: 是否隱藏飞蹂,默認(rèn)為False
- 原型定義:
五几苍、代碼實(shí)現(xiàn)
在概念了解清楚后翻屈,進(jìn)入實(shí)際操作
-
在
init_gui.py
同目錄下,創(chuàng)建一個(gè)maze.py
文件妻坝,內(nèi)容如下:import Part class Maze: def __init__(self, obj): '''對(duì)象實(shí)始化伸眶,可以添加一些屬性''' obj.addProperty("App::PropertyLength", "Length", "Maze", "長").Length = 10.0 obj.addProperty("App::PropertyLength", "Width", "Maze", "寬").Width = 10.0 obj.addProperty("App::PropertyLength", "Height", "Maze", "高").Height = 10.0 obj.Proxy = self def execute(self, fp): '''在調(diào)用重新計(jì)算時(shí)會(huì)執(zhí)行該方法''' # 創(chuàng)建一個(gè)立方體 box = Part.makeBox(fp.Length, fp.Width, fp.Height) # 返回給 Shape 對(duì)象,用于 FreeCAD 界面顯示 fp.Shape = box
-
修改
init_gui.py
文件刽宪,添加創(chuàng)建迷宮的代碼厘贼,找到以下代碼:class CreateMaze(): ... def Activated(self): app.Console.PrintMessage("迷宮已創(chuàng)建完成\n") return ...
修改為:
class CreateMaze(): ... def Activated(self): from .maze import Maze maze = app.ActiveDocument.addObject("Part::FeaturePython", "Maze") Maze(maze) maze.ViewObject.Proxy = 0 app.ActiveDocument.recompute() app.Console.PrintMessage("迷宮已創(chuàng)建完成\n") return ...
-
保存并重新啟動(dòng)
FreeCAD
,新建一個(gè)文檔圣拄,然后切換到迷宮
工作臺(tái)嘴秸;
FreeCAD_2024-08-29_21-02-21.png 點(diǎn)擊
創(chuàng)建迷宮
按鈕,如果執(zhí)行正確,將會(huì)在FreeCAD
里看到一個(gè)10x10x10
的立方體岳掐;-
因?yàn)檫€沒有寫真正的迷宮算法凭疮,所以僅用一個(gè)立方體來做演示;
FreeCAD_2024-08-29_21-07-05.png
小結(jié)
通過兩篇內(nèi)容的學(xué)習(xí)串述,已將工作臺(tái)創(chuàng)建执解、功能按鈕創(chuàng)建、自定義三維模型創(chuàng)建等功能基本掌握纲酗,后面繼續(xù)深入了解通過三維模型的組合完成一個(gè)真正三維迷宮的創(chuàng)建衰腌。
完整代碼參考:https://github.com/ronggang/study-freecad
參考內(nèi)容
- 腳本對(duì)象: https://wiki.freecad.org/Scripted_objects
- 保存腳本對(duì)象: https://wiki.freecad.org/Scripted_objects_saving_attributes
- FeaturePython: https://wiki.freecad.org/App_FeaturePython