【Grasshopper基础1】怎样制作一个Grasshopper电池 / 二次开发基础
2022.10.15 更新注
2年時間不知不覺過去了,在此期間,Rhino也發布了第7個大版本(Rhino7),雖然Grasshopper2和Rhino8也傳出了許多消息,但最終它將會成為什么樣,目前作者也不清楚哈。
Rhino7的發布并未給Grasshopper帶來大的變革,總體開發思路仍然與之前保持了一致。所以【Grasshopper基礎】系列文章所有的概念仍然可以繼續沿用(據說GH2會從底層有一些變革,那就到時候再肝啦)。不過有幾處小的改動,比如.NET Framework版本從v4.7.2升到了v4.8,Visual Studio的插件版本略有變化等等。詳細的就不羅列了,文章細節里會有標明
:)
本文旨在介紹如何使用C#編寫一個Grasshopper內的Hello World電池,包括如何使用和安裝Grasshopper電池模板,如何配置Visual Studio來生成.gha電池,如何配置Grasshopper以識別編譯的電池,如何Debug等。
后續章節會講到如何配合多個電池、多個項目、多個Rhino/Grasshopper SDK。
以下Grasshopper簡稱GH。
- 如何制作一個Grasshopper電池
- 制作Grasshopper電池的主要步驟及準備工作
- 安裝GH電池項目模板并創建一個GH項目
- 確認一切正常
- 認識GH電池模板
- 制作自己的第一個GH電池
- 如何使用非Visual Studio作為GH電池項目的開發環境
- GH電池項目配置要點
- 用JetBrains Rider來構建GH電池
- Visual Studio中的GH模板擴展到底做了什么
制作Grasshopper電池的主要步驟及準備工作
由于GH整個是以.NET為架構編寫的,因此其原生支持的電池也是基于.NET架構。網絡上許多流行的Python電池其實大部分是使用GH包含的IronPython電池再次包裝而成的,可以通過右鍵解包看到源代碼,其很多關于UI方面的拓展性并不強。
在Rhino 6版本之后,由于官方在Visual Studio的拓展商店中上架了GH電池的項目模板,很多配置文件均包含在了模板中,所以用C#或者VB來創建一個自定義的GH電池就變得簡單了許多。我們在這里就選用Visual Studio來作為IDE。
但是這并不是說不用模板就沒法制作GH電池了,本文最后會提到如果是用非VS的IDE(比如VS Code等)如何構建一個GH電池。
需要用到的軟件有:
- Visual Studio 2017 、2019、2022, Community/Professional/Enterprise 均可
- 如果是第一次使用Visual Studio那選用Community版本(社區版本)就可以,這三個版本中只有Community版本是可以免費使用的;
- 確保在Visual Studio安裝時,在“工作負載”選項卡下選擇了“桌面應用和移動應用”下的“.NET桌面開發”組件包,其組件包描述中有.NET Framework這個詞的出現,因為這個是GH電池的依賴框架;
- 如果在之前安裝Visual Studio時未選擇安裝上述組件包,隨時可以使用Visual Studio Installer額外加裝上述組件包。
- Rhino 6/7
安裝GH電池項目模板并創建一個GH項目
啟動Visual Studio(本文中使用的是Visual Studio 2019 Community版),由于我們僅僅是需要安裝一個電池模板,此時不需要創建任何項目,所以我們這里需要選擇那個最不起眼的選項“繼續但無需代碼”。
然后在窗口的最頂端的菜單欄中找到“擴展(X)”-“管理擴展(M)”,在選中左側“聯機”選項卡的前提下,找到右上角的搜索框,搜索Grasshopper。
現在,如果是使用 Visual Studio 2022 版本,對應 Rhino7 版本的二次開發,則可以直接點擊下面的鏈接來下載最新版的插件:
RhinoCommon and Grasshopper templates for Rhino 7
同時,也考慮到下載速度的原因,可以在CSDN的文件共享中下載:
https://download.csdn.net/download/bwkair/86763074
如果網絡不是太差的話,應該就可以出現如上圖所示的搜索結果,直接點擊下載。
下載完成之后,Visual Studio會提示這個插件的安裝已經被安排在了這次Visual Studio關閉之后,所以此時我們需要關閉Visual Studio。在關閉之后等待一小段時間,應該就會彈出插件的安裝界面了,如下圖所示。我們直接選擇接受更改(Modify),并等待安裝完成即可。
發現有的讀者反映在Visual Studio中下載插件似乎一直提示失敗,這可能是Visual Studio默認連接到的是國外服務器,下載速度十分慢。所以這里提供幾個直接下載插件文件的地址,讀者可以手動下載并安裝插件。
下載連接 https://marketplace.visualstudio.com/items?itemName=McNeel.GrasshopperAssemblyforv6
筆者在CSDN.NET上的文件共享 點我下載
安裝完成之后我們再次打開Visual Studio,此時我們選擇創建新項目之后,在上方搜索模板處輸入Grasshopper就可以看到剛剛安裝好的GH電池模板擴展,這里我們就可以選擇 Grasshopper Add-On for v6 (C#) 開始創建我們的新電池了!如下圖所示。
在接下來的配置新項目界面中:
- 項目名稱可以取一個自己喜歡的,也可以參考筆者的HelloGrasshopper。
- 在填入項目名稱之后,解決方案名稱也會同步地改變,此時我們可以不管它。“將解決方案和項目放在同一目錄中”這個選項會決定各個文件的存放的相對路徑,雖然不會影響程序的運行,但這里不推薦勾選,不勾選這個選項時可以使得文件夾結構更加清晰。
- 位置可以選擇一個非系統盤的位置,創建的代碼會被保存在這里。
- 筆者在攥稿時,框架默認被選擇為.NET Framework 4.7.2,以后這個值可能會改變,但無需擔心,GH插件會默認幫我們調整這個框架,這里不需要調整框架選項。
點擊創建按鈕之后,會彈出一個新的窗口,在這里我們需要輸入一些關于電池在GH里面的細節。
- Add-on display name 決定了這個電池在GH插件加載的時候顯示的名字。
- Component class 是C#的類的名字,與GH顯示無關,這里可以使用默認值,任何不能作為C#的類名的字符都不可以出現在這里。
- Name 是該電池在GH里會顯示的電池。
- Nickname 是該電池在GH里選擇顯示簡稱時的名字。
- Category 是該電池在GH里會被放在的大類的名字,比如Params、Math、Sets等(具體見可見下圖的例子)。GH如果本身不存在輸入的大類的名字的話,GH會為這個電池單獨創建一個大類。在這里我們可以填入MyComp,并且以后所有的電池都可以填相同的大類,這樣方便我們找到自己創建的電池。
- Subcategory 是該電池在GH里會被放在大類下的哪個子類里,我們在這里可以填入Hello。
- Description 是該電池在GH里顯示的額外描述性信息,這里我們填入“我的第一個電池”。
按下Finish按鈕之后,一個GH電池的項目就已經生成成功了。在具體介紹如何才能完成所需要的代碼之前,我們還需要確認一下這個GH電池項目是否可以正確運行。
確認一切正常
在我們真正開始寫代碼之前,我們需要確認一下剛剛通過GH電池模板擴展是否正確地配置了我們的項目環境。在剛剛生成的GH電池項目中,直接在Visual Studio菜單欄中找到“啟動”,或者可以按默認的快捷鍵F5來啟動這個項目,來實現對剛剛這個GH電池模板的編譯。
如果一切配置正常的話,此時Rhino應該就會直接啟動了。
此時GH還并不能自動加載我們剛剛編譯成功的電池,因為它并不知道我們剛剛生成的電池的gha文件在哪里,所以我們需要通過在Rhino中設置一下GH自動搜尋電池的路徑。
我們在Rhino的命令欄里輸入GrasshopperDeveloperSettings命令,并回車,這樣下面的一個窗口會彈出
確認保存選項之后,我們再打開Grasshopper,我們應該就能看見我們剛剛自定義的電池出現在了Grasshopper下了。
這個時候,我們的電池并沒有圖標,并且把它拖到GH畫布上之后也會發現它并沒有任何的輸入和輸出 —— 這是正常的,因為我們還沒有給它添加任何代碼,所以它的確是什么也干不了。不過有了這個目前什么也干不了的電池,至少可以說明它是可以正常編譯和被GH識別的,而且它還擁有了我們給它取的名字和說明,這就可以繼續我們的下一步了。
認識GH電池模板
我們關閉剛剛啟動的Rhinoceros回到Visual Studio里面來,我們應該可以在“解決方案管理器”看到下面的內容
- 解決方案“HelloGrasshopper”
- HelloGrasshopper
- Properties
- 引用
- HelloGrasshopperComponent.cs
- HelloGrasshopperInfo.cs
- HelloGrasshopper
其中,HelloGrasshopperInfo.cs 是存放電池描述性信息的cs文件,而HelloGrasshopperComponent.cs 是實現電池機制的地方。
讓我們直接打開 HelloGrasshopperComponent.cs 來看看到底一個電池是如何實現的把。這個文件中應該包含下面幾大類內容
正如C#的基本概念中說的一樣 —— 所有東西都是一個類,所以我們的電池也是一個C#類,這個自定義類是繼承自一個GH電池基礎類 GH_Component ,類名是之前我們在通過GH模板擴展創建這個項目時所輸入的值
public class HelloGrasshopperComponent : GH_Component這個類的構造函數是直接使用了基礎類GH_Component的構造
public HelloGrasshopperComponent(): base("HelloGrasshopper", "HG","我的第一個電池","MyComp", "Hello"){}如果我們在Visual Studio里把鼠標懸停在“base”上面,應該可以看到我們具體使用的是哪一個基礎類的構造函數。并且我們也發現,其實我們在Grasshopper電池模板中輸入的各個屬性的值是直接被放到了這里。我們對這個構造函數進行改變,則相應的電池在GH中顯示的信息和名稱也會有改變。
電池的輸入端和輸出端接口是由下面兩個 override 方法來確定的
protected override void RegisterInputParams(GH_InputParamManager pManager) { } protected override void RegisterOutputParams(GH_OutputParamManager pManager) { }GH在將電池拖入畫布時將會調用這兩個方法來將決定電池初始狀態下有多少個輸入端和輸出端。為什么說是“初始狀態下”呢,因為我們都知道很多GH電池是可以在運行的時候改變輸入和輸出的個數的,這個時候輸入輸出的個數的改變就不是通過這兩個override方法來做到的了。不過目前我們不會進行輸入/輸出的改變,所以這部分內容不會展開,后面會有專門的專題來展開講如何實現這部分內容。
真正實現電池內容邏輯、對輸入端的數據進行操作并輸出的部分是由 SolveInstance 這個方法實現的
protected override void SolveInstance(IGH_DataAccess DA) { }由于目前這里面沒有任何代碼,自然而然這個電池就不能實現任何功能了。讓我們試著在這個函數里添加一行代碼看看GH會有什么樣的結果出現把
AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, $"現在的時間是{DateTime.Now}");此時我們直接編譯啟動Rhino,然后打開Grasshopper,將我們的自定義電池拖到GH的畫布上,我們會神奇的發現這個電池的右上角多了一個橙黃色的小氣泡圖標,電池也整個變成了橙黃色的。當鼠標移到這個小氣泡上點擊左鍵,會出現我們剛剛在輸入的字符串信息,還有當前的時間。AddRuntimeMessage 方法是用來在GH電池上顯示警告或者錯誤信息的,剛剛我們就實現了在GH電池上顯示了一個警告信息,GH電池也自動將整個電池變成了橙黃色的警示顏色。
制作自己的第一個GH電池
我們怎么才能實現像正常電池一樣輸入和輸出數據呢?比如我們想實現一個類似于GH其他電池一樣的電池,在輸入端可以拖入一個人的名字,輸出端可以將“Hello,這個人的名字”輸出出來到一個Panel電池中顯示,應該怎么做呢?就相信大家也猜到了,整體的思路就是下面幾個步驟
- 在 RegisterInputParams 中注冊輸入值
- 在 RegisterOutputParams 中注冊輸出值
- 在 SolveInstance 中處理輸入的字符串,將它與 Hello 拼合之后賦值給輸出端
下面我們就依次實現它們,首先在 RegisterInputParams 中加入下面的代碼
pManager.AddTextParameter("請輸入名字", "名字", "將要打招呼的名字", GH_ParamAccess.item);然后在 RegisterOutputParams 中加入下面的代碼
pManager.AddTextParameter("輸出結果", "結果", "最終生成的打招呼結果", GH_ParamAccess.item);我們可以看到,無論是輸入還是輸出端,都是用pManager這個變量來注冊輸入和輸出值的,如果有多個輸入/輸出量,重復使用這個變量來注冊直到所有輸入/輸出變量都被加入即可。
這時,我們就可以在 SolveInstance 中真正實現我們的字符串處理邏輯了。首先我們需要獲取到在輸入端的我們的輸入值:
string inputStr = string.Empty; bool res = DA.GetData(0, ref inputStr); // 嘗試從輸入端獲取字符串 if (!res) return; // 如果獲取失敗則直接返回然后我們可以處理這個剛剛獲取到的字符串,因為我們已經加入了獲取失敗時直接返回的條件處理,所以我們可以認為輸入端的字符串是被成功獲取到的
string outputStr = "Hello " + inputStr;然后就是將這個處理后的字符串直接送到輸出端了
DA.SetData(0, outputStr);這里需要注意到的是,GetData 和 SetData 的第一個傳參都是數字0,這其實是代表著“第1個輸入”和“第1個輸出” —— 因為我們只在電池的輸入端和輸出端加入了一個參數,它們都是從0開始計數的,就如同列表一樣。而實際上,GH電池底層在存儲輸入端參數和輸出端參數也的確是通過列表(List)來實現的。當我們有多個輸入/輸出端的數據需要獲取的時候,則需要將該傳參換成相應的序號即可,這個序號是從0開始的。
完成上述所有的代碼之后,點擊Visual Studio上的啟動,打開Grasshopper,讓我們拖入剛剛自定義的電池到畫布上來看看效果吧
BOOM!完成!嘗試連入多個輸入值看看結果吧。同時我們也可以在這個SolveInstance里嘗試加入各種自己的代碼,配置不同的輸入/輸出端口,多多嘗試看看GH里運行起來會有什么樣的結果吧!
這節的主要內容就介紹到這里,后續是一些零碎的有關于其他的IDE設置的問題,如非必要,是可以跳過的。感興趣的讀者可以繼續閱讀
如何使用非Visual Studio作為GH電池項目的開發環境
如果你是剛剛接觸編程、剛接觸C#的新手的話,還是十分推薦使用Visual Studio來進行C#的學習和GH電池的開發的,其各個組件都十分好用,畢竟C#這門語言本身也是由微軟開發的,自家的IDE配合自家的語言,食用更方便。
不過,你如果有其他編程語言的基礎,習慣了其他的IDE,或者非常用不習慣Visual Studio這樣龐大的開發環境呢,使用其他IDE來實現對GH電池的開發也沒問題,只不過因為少了GH模板擴展,許多細節需要自己設置。
GH電池項目配置要點
下面列出幾個值得在進行GH電池項目配置時注意的地方:
- GH電池本身是一個dll文件,僅僅是后綴名改變為.gha
- GH電池所基于的框架為 .NET Framework 4.5
- GH電池是一個dll類庫文件 (Class Library)
- 需要添加下列三個引用
- RhinoCommon.dll (在Rhino安裝目錄,System下可找到)
- Grasshopper.dll (在Rhino安裝目錄,Plug-ins\Grasshopper下可找到)
- GH_IO.dll (在Rhino安裝目錄,Plug-ins\Grasshopper下可找到)
- 自定義類繼承自基類 GH_Component,且構造方法采用基類的構造方法并定義電池的相關名字和描述性信息
- 重寫 ComponentGuid 屬性,且這個屬性必須與其他所有GH中電池不同,這是GH用來區別各個電池的唯一指定ID,這也是推薦采用GH模板來建立項目的另一個原因 —— 模板會自動生成非重復GUID,如果自己創建項目,則GUID可能會與其他GH插件中電池的GUID相同。
其他的override方法就按照需求添加即可。下面我們就以JetBrains的Rider作為IDE為例,來看看如何設置非Visual Studio的IDE來構建一個GH電池項目。
用JetBrains Rider來構建GH電池
首先啟動Rider,然后創建一個新的解決方案,此時選擇 .NET 下的 Class Library ,注意不要選到 .NET Core 下的Class Library了。在Framework下拉菜單中選擇 .Net Framework 4.5,如下圖所示
具體的 Solution name 和 Project name 并不是很重要,按照自己的喜好設置名字并選擇一個合適的存儲路徑即可進行創建了。Riders 可能需要一段時間去初始化整個C#的項目。
項目創建完成后,我們需要在左側的項目瀏覽器中找到剛剛的建立的項目并在“Dependencies”(依賴)上點右鍵,選擇“Add References…”(添加引用),將之前提到的RhinoCommon.dll、Grasshopper.dll、以及GH_IO.dll添加至項目中。
此時我們應該可以看到在Dependencies下的Assemblies中出現了上述幾個文件,這可以說明這三個文件被我們的項目引用成功了,但我們仍有一步額外的步驟需要對這三個引用進行操作。
若不去除“Copy Local”復選框,則會導致IDE在編譯該電池時,把之前引用的三個dll文件復制到編譯輸出文件夾,這時,在啟動GH時,GH會重復加載Grasshopper.dll文件,導致GH在啟動過程中報錯。
這里重復一遍,需要對 RhinoCommon.dll、Grashopper.dll、GH_IO.dll 三個引用均按上述設置,把“Copy Local”復選框去除。
確認保存完畢之后,我們就可以開始正常進行電池代碼的工作了。
首先第一步在文件的最前端添加對Grasshopper的引用,然后將我們的自定義類繼承自GH_Component
using Grasshopper.Kernel;namespace ClassLibrary1 {public class Class1 : GH_Component{} }此時,Rider應該已經在“class Class1 : GH_Component”下標上了紅色波浪線,十分智能地提示我們:要繼承GH_Componet,我們需要實現這個類的幾個屬性。我們可以直接點擊左側的紅色小燈泡,選擇“Implement missing members”,Rider就會自動生成這些屬性。
不過,Rider自動完成的代碼部分并不包含Guid的值,所以這里我們要自己設置一個Guid值。筆者就在這里就直接使用一個隨機值了。
public override Guid ComponentGuid { get => new Guid("23333333-1e1b-43fc-9a92-5a3cdfe0ffff"); }另外,我們還需要為我們自己的類添加一個構造方法。還記得前面提過的使用基礎類的構造方法來實現我們自定義類的名字和描述信息嗎?我們依葫蘆畫瓢自己寫一個即可。不要忘記最后的大括號,雖然里面沒代碼,但是這個構造函數的函數體仍然要聲明,不然C#編譯器會報錯。
public Class1() : base("FromRider", "FR", "This is a component from JetBrains Rider.", "MyComp", "JetBrains") { }接下來就是與上文在Visual Studio中構造電池一樣的操作了,在此不再復述。
另外,我們需要額外配置一下編譯的結果,即 —— 把編譯結果由默認的.dll文件重命名為.gha文件,要實現這一點,我們需要在項目的.csproj文件中添加幾行命令。
我們先在Rider左側的項目資源瀏覽器中找到我們的C#項目文件,在上面點擊右鍵,選擇“Edit”-“Edit ‘ClassLibrary1.csproj’”(該文件名字可能會因項目名稱而改變,需要注意的是該文件的后綴名是.csproj)。
csproj是一個xml文件,我們滾動瀏覽到文件的最后發現這里有幾行注釋
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. <Target Name="BeforeBuild"> </Target> <Target Name="AfterBuild"> </Target> -->我們把最后有關于<Target Name="AfterBuild">的標簽移出注釋,并在其中添加一行內容
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. <Target Name="BeforeBuild"> </Target> --> <Target Name="AfterBuild"><Move SourceFiles="$(TargetPath)" DestinationFiles="$(TargetDir)$(ProjectName).gha" /> </Target>然后按下 Ctrl + s 保存一下這個.csproj文件,此時再運行編譯的時候,輸出的.dll文件就會被自動命名為.gha文件了。
在完成電池后,我們需要對編譯的結果進行調試,然后…… Rider中的調試怎么是灰的??這是因為我們在Rider最開始創建項目的時候選擇的是“Class Library”,而默認情況下,類庫是不提供執行功能的。此時我們需要手動添加調試環境。
在Rider的右上角找到“Add Configuration…”添加調試配置,然后在彈出的窗口中點擊左上角的“+”號來添加一個配置,調試目標為 .NET Excutable。
Name是這個配置文件的名字,筆者這里設置為GHComponent,右側的 Exe path填入Rhino的主程序即可。確認保存之后,即可在右上角看到熟悉的啟動按鈕了。這時,整個GH電池項目在Rider中的配置就完成了。
過程中我們發現其實C#的類名、命名空間名字對于電池在GH中正常運行沒有任何影響,但我們仍希望把它們的名字取得更規范一些,而不是像本例中的“ClassLibrary1”一樣是個無意義的名字,容易忘記這個電池具體是做什么的。一個規范的名字可以增強代碼的可讀性。
Visual Studio中的GH模板擴展到底做了什么
經過一次自己手動配置,密密麻麻一大堆內容,大家也應該恍然大悟過來了,原來這就是GH模板為我們實現的幾個內容。在Rider里,因為沒有這個模板,我們需要自己手動配置:
- 項目生成目標為類庫
- 目標框架 .NET Framework 4.5
- 添加下列引用,并配置屬性為“不復制到本地”
- Rhinocommon.dll
- Grasshopper.dll
- GH_IO.dll
- 生成一個Guid,并將其作為電池類屬性ComponentGuid的返回值
- 添加 RegisterInputParams、RegisterOutputParams、SolveInstance 三個 override 方法的函數構造
- 為類庫添加一個構造函數,并依據用戶給定的參數調用基類的構造函數
- 為編譯添加后處理,將編譯結果.dll文件重命名為.gha文件
- 配置一個調試環境,可以直接啟動Rhino主程序
我們知道了GH模板擴展到底做了什么,那么我們在其他任何IDE,都可以實現對GH電池的構建了。
總結
以上是生活随笔為你收集整理的【Grasshopper基础1】怎样制作一个Grasshopper电池 / 二次开发基础的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: UWB信号对服务器有没有干扰,uwb定位
- 下一篇: windows 中搭建Zookeeper