FreeCAD 工作臺(Workbench)開發(fā)筆記『二』

通過上一篇筆記的梳理,對工作臺開發(fā)的整體概念和必要的文件已經(jīng)有了大概的了解,接下來需要深入了解一下各個模塊的具體作用及其使用方法。

本節(jié)學(xué)習(xí)目標

  • 了解 FreeCAD 里的基本功能模塊;
  • 實現(xiàn)點擊功能按鈕,創(chuàng)建一個帶有屬性的基本三維對象;
  • 調(diào)整屬性,觀察三維對象是否發(fā)生變化;
  • 保存文檔并重新打開,確認所有屬性保存完整。

一、工作臺可使用的主要模塊

FreeCAD 里有很多模塊,他們在 工作臺宏腳本 里都可以使用,最常使用的有兩個:

  • FreeCAD

    • FreeCAD 又可以簡寫為 App ,主要用來調(diào)用和操作與界面(UI)無關(guān)的功能,它有以下幾種引用方式:
      # 方式一
      from freecad import app
      
      # 方式二
      import FreeCAD as App
      
    • 常用的方法和屬性
      • app.ActiveDocument: 獲取當前活動的文檔;
      • app.newDocument(): 創(chuàng)建一個新的文檔;
      • app.Console.PrintMessage(): 在 FreeCAD 的報告瀏覽器中輸出字符,如:
        app.Console.PrintMessage("測試內(nèi)容")
        
      • app.ActiveDocument.recompute(): 重新計算當前文檔,即重新繪制三維對象。
  • FreeCADGui

    • FreeCADGui 是用來調(diào)用和界面(UI)相關(guān)的功能,它有以下幾種引用方式:
      # 方式一
      from freecad import gui
      
      # 方式二
      import FreeCADGui as Gui
      
    • 常用的方法和屬性
      • gui.addCommand(): 向 FreeCAD 注冊一個命令,如:
        gui.addCommand('createThing', createThing())
        
      • gui.addWorkbench(): 向 FreeCAD 注冊一個工作臺,如:
        gui.addWorkbench(MazeWorkbench())
        
      • gui.Selection.getSelection(): 獲取當前選中的對象,返回是一個數(shù)組

二、調(diào)用其他工作臺的功能

  • 有時候需要在代碼中調(diào)用系統(tǒng)其他工作臺里的功能,比如 Part 工作臺里的功能,那就需要先將其導(dǎo)入,如:
    import Part
    
  • 導(dǎo)入后就可以正常使用了,如:
    # 創(chuàng)建一個 10x10x10 的立方體
    Part.makeBox(10,10,10)
    

三、命令(按鈕)基本定義

  • 在上一次的筆記中使用過一個基本的命令(按鈕):
    class CreateMaze():
      def GetResources(self):
          return {"Pixmap"  : APPICON,  
                  "MenuText": "創(chuàng)建迷宮",
                  "ToolTip" : "創(chuàng)建一個3D迷宮"}
    
      def Activated(self):
          app.Console.PrintMessage("迷宮已創(chuàng)建完成\n")
          return
    
      def IsActive(self):
          '''
          判斷當前命令是否可用
          '''
          return True
    
    • GetResources(): 用于獲取命令(按鈕)的圖標、名稱、提示等基本屬性,該方法 必需 定義;
    • Activated(): 用于命令被調(diào)用時執(zhí)行的功能,該方法 必需 定義;
    • IsActive(): 判斷當前命令是否可用,該方法可選,默認命令為可用;
  • 一個命令通常為一個 python 的類,通過以上規(guī)則進行定義;
  • 在一個工作臺里通常會有多個命令,所以為了方便擴展,可以定義一個基類,如:
    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
    
  • 然后其他命令通過這個基類來繼承,如:
    class CreateMazeA(BaseCommand):
      Pixmap = APPICON
      MenuText = "創(chuàng)建迷宮A"
      ToolTip = "創(chuàng)建一個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)建一個3D迷宮B"
    
      def Activated(self):
          app.Console.PrintMessage("迷宮B已創(chuàng)建完成\n")
          return
    
  • 這樣就可以方便的進行多個命令的創(chuàng)建了。

四、繪制自定義的三維對象

  • 上面只學(xué)習(xí)了基本命令的創(chuàng)建和調(diào)用,但在 FreeCAD 里主要目的還是要創(chuàng)建三維對象,比如常規(guī)的立方體、圓柱體等,他們可以通過不同的工作臺去創(chuàng)建;
  • 這些三維對象都有自己的屬性,比如:高度、寬度、直徑等等;
  • 那創(chuàng)建一個迷宮對象,也會有自己的屬性,比如:墻高度、墻厚度等等;
  • 這里就需要引入 FreeCAD 里的一個概念:腳本對象;
    • 通俗點可以理解為通過腳本創(chuàng)建的對象,它需要可被序列化后保存到 FreeCAD 文件中,以便重新打開時進行反序列化;
    • 它在 FreeCAD 內(nèi)部被稱為 FeaturePython ,用 App::FeaturePython 類型來表示;
  • 通過以上概念的了解,再回來和上面的 命令 結(jié)合,生成一個真正的帶屬性的三維對象;
  • 首先來定義一個三維對象,如(示例在官網(wǎng)的基礎(chǔ)上稍作調(diào)整):
    class Box:
      def __init__(self, obj):
          '''對象實始化,可以添加一些屬性'''
          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)用重新計算時會執(zhí)行該方法'''
          FreeCAD.Console.PrintMessage("Recompute Python Box feature\n")
    
    • __init__():

      • 初始化方法,它接收一個 obj 對象,通常為 App::FeaturePython 對象;
      • 可通過 FreeCAD.ActiveDocument.addObject() 方法來添加,如:
        box = FreeCAD.ActiveDocument.addObject("App::FeaturePython", "Box")
        Box(box)
        
      • obj.Proxy: 這個必需要指定 self ,它會在 FreeCAD 內(nèi)部被調(diào)用
    • onChanged(): 當屬性變更時被調(diào)用,需要注意的點:

      • 在初始化時,類似這樣 obj.addProperty("App::PropertyLength", "Length", "Box", "").Length = 1.0 的語句也會觸發(fā) onChanged 方法,所以如果檢測或?qū)ζ渌麑傩赃M行計算時要小心,可能指定的屬性還不存在。
    • execute(): 當執(zhí)行 重新計算 時,該方法會被調(diào)用

  • 通過上面的代碼,已經(jīng)定義了一個基本的三維對象————立方體,他包含三個屬性:LengthWidth,Height;
  • 這些屬性是通過一個 addProperty 方法來添加的,該方法有 7 個參數(shù):
    • 原型定義:addProperty(self,typ,name='',group='',doc='',attr=0,readonly=False,hidden=False)
    • typ: 屬性類型,如:整型、浮點等,在 FreeCAD 內(nèi)部定義了很多類型;
      • 比如上面使用的 App::PropertyLength 他用來表示長度,是浮點類型的擴展,默認帶有單位;
      • 更多類型可參考:https://wiki.freecad.org/Property
    • name: 屬性的名稱,用英文表示,他會在代碼里用到;
    • group: 屬性的分組,可用中文,相同的分組會在 FreeCAD 的屬性頁中顯示到一起;
    • doc: 屬性的詳細描述,可用中文,當鼠標在對應(yīng)的屬性上停留時顯示;
    • attr: 這是屬性的附加屬性,默認為 0 ,表示沒有特殊的限制,可用值為:
      • 0 -- Prop_None, 無特殊限制
      • 1 -- Prop_ReadOnly, 在屬性編輯器里只讀
      • 2 -- Prop_Transient, 表示屬性值不會在文件里保存,但屬性名稱和類型這些會保存
      • 4 -- Prop_Hidden, 在屬性編輯器里隱藏
      • 8 -- Prop_Output, 作用暫不明,原文描述為:Modified property doesn't touch its parent container
      • 16 -- Prop_NoRecompute, 修改屬性時,不會觸發(fā)重新計算
      • 32 -- Prop_NoPersist, 表示屬性值不會在文件里保存,屬性名稱和類型也都不會保存
    • readonly: 是否只讀,默認為 False
    • hidden: 是否隱藏,默認為 False

五、代碼實現(xiàn)

  • 在概念了解清楚后,進入實際操作

  • init_gui.py 同目錄下,創(chuàng)建一個 maze.py 文件,內(nèi)容如下:

    import Part
    
    class Maze:
        def __init__(self, obj):
            '''對象實始化,可以添加一些屬性'''
            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)用重新計算時會執(zhí)行該方法'''
            # 創(chuàng)建一個立方體
            box = Part.makeBox(fp.Length, fp.Width, fp.Height)
            # 返回給 Shape 對象,用于 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
    ...
    
  • 保存并重新啟動 FreeCAD ,新建一個文檔,然后切換到 迷宮 工作臺;

    FreeCAD_2024-08-29_21-02-21.png

  • 點擊 創(chuàng)建迷宮 按鈕,如果執(zhí)行正確,將會在 FreeCAD 里看到一個 10x10x10 的立方體;

  • 因為還沒有寫真正的迷宮算法,所以僅用一個立方體來做演示;


    FreeCAD_2024-08-29_21-07-05.png

小結(jié)

通過兩篇內(nèi)容的學(xué)習(xí),已將工作臺創(chuàng)建、功能按鈕創(chuàng)建、自定義三維模型創(chuàng)建等功能基本掌握,后面繼續(xù)深入了解通過三維模型的組合完成一個真正三維迷宮的創(chuàng)建。

完整代碼參考:https://github.com/ronggang/study-freecad

參考內(nèi)容

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容