├── yak ├── yak_login.bat ├── yak_search.bat ├── yak_push.bat └── manifest.yml ├── .gitignore ├── References └── MacOS │ ├── .gitignore │ └── README.md ├── Shared ├── README.md ├── src │ └── SharedExample.cs ├── interface │ └── ISharedExample.cs └── Shared.csproj ├── SharedRhino ├── README.md ├── interface │ └── ISharedRhinoExample.cs ├── src │ └── SharedRhinoExample.cs └── SharedRhino.csproj ├── TestShared ├── README.md ├── TestShared.csproj └── TestSharedExample.cs ├── TestSharedRhino ├── README.md ├── TestSharedRhino.csproj ├── TestSharedRhinoExample.cs └── RhinoInsideInit.cs ├── Artwork ├── PluginRhino.ico ├── PluginRhino.xcf ├── PluginRhino.webp ├── PluginRhino_1024.png ├── PluginRhino_128.png ├── PluginRhino_16.png ├── PluginRhino_24.png ├── PluginRhino_256.png ├── PluginRhino_32.png ├── PluginRhino_64.png ├── PluginGrasshopper.ico ├── PluginGrasshopper.webp ├── PluginGrasshopper.xcf ├── PluginGrasshopper_128.png ├── PluginGrasshopper_16.png ├── PluginGrasshopper_24.png ├── PluginGrasshopper_256.png ├── PluginGrasshopper_32.png └── PluginGrasshopper_1024.png ├── TODO.md ├── PluginRhino ├── README.md ├── EmbeddedResources │ └── PluginRhino.ico ├── Properties │ └── AssemblyInfo.cs ├── PluginRhino.cs ├── Commands │ └── ExampleCommand.cs └── PluginRhino.csproj ├── PluginGrasshopper ├── README.md ├── EmbeddedResources │ ├── PluginGrasshopper_16.png │ └── PluginGrasshopper_24.png ├── Properties │ ├── AssemblyInfo.cs │ └── ResourceLoader.cs ├── PluginLoader.cs ├── PluginGrasshopper.csproj ├── Components │ └── ExampleComponent.cs └── PluginInfo.cs ├── test.DebugR7.runsettings ├── test.DebugR8.runsettings ├── CommonSettingsFinal.csproj ├── Packages.props ├── CommonReferencesTests.csproj ├── BuildYakOnlyRhino7.bat ├── BuildYakOnlyRhino8.bat ├── CommonReferencesGrasshopper.csproj ├── PackagesRhino7.props ├── CommonVariables.bat ├── PackagesRhino8.props ├── BuildRhino7.bat ├── BuildRhino8.bat ├── LICENSE ├── Directory.Packages.props ├── CommonTasks.csproj ├── CommonReferencesRhino.csproj ├── CommonReferencesSystemDrawing.csproj ├── CommonVariables.csproj ├── CommonTargets.csproj ├── README.md ├── CommonSettings.csproj └── PluginTemplate.sln /yak/yak_login.bat: -------------------------------------------------------------------------------- 1 | yak login -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vs/ 2 | bin/ 3 | obj/ 4 | -------------------------------------------------------------------------------- /References/MacOS/.gitignore: -------------------------------------------------------------------------------- 1 | System.Drawing.Common.dll -------------------------------------------------------------------------------- /Shared/README.md: -------------------------------------------------------------------------------- 1 | # Shared functionality NOT depending on Rhino 2 | -------------------------------------------------------------------------------- /SharedRhino/README.md: -------------------------------------------------------------------------------- 1 | # Shared functionality depending on Rhino 2 | -------------------------------------------------------------------------------- /TestShared/README.md: -------------------------------------------------------------------------------- 1 | # Test assembly for shared functionality NOT depending on Rhino 2 | 3 | -------------------------------------------------------------------------------- /TestSharedRhino/README.md: -------------------------------------------------------------------------------- 1 | # Test assembly for shared functionality depending on Rhino 2 | -------------------------------------------------------------------------------- /yak/yak_search.bat: -------------------------------------------------------------------------------- 1 | 2 | yak search --all --prerelease PLUGIN_NAME 3 | 4 | set /p=Hit ENTER to continue... 5 | -------------------------------------------------------------------------------- /Artwork/PluginRhino.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginRhino.ico -------------------------------------------------------------------------------- /Artwork/PluginRhino.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginRhino.xcf -------------------------------------------------------------------------------- /Artwork/PluginRhino.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginRhino.webp -------------------------------------------------------------------------------- /Artwork/PluginRhino_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginRhino_1024.png -------------------------------------------------------------------------------- /Artwork/PluginRhino_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginRhino_128.png -------------------------------------------------------------------------------- /Artwork/PluginRhino_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginRhino_16.png -------------------------------------------------------------------------------- /Artwork/PluginRhino_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginRhino_24.png -------------------------------------------------------------------------------- /Artwork/PluginRhino_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginRhino_256.png -------------------------------------------------------------------------------- /Artwork/PluginRhino_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginRhino_32.png -------------------------------------------------------------------------------- /Artwork/PluginRhino_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginRhino_64.png -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | 2 | * Create PluginRhino/Properties/AssemblyInfo.cs automatically based on metadata in CommonVariables.csproj 3 | -------------------------------------------------------------------------------- /Artwork/PluginGrasshopper.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginGrasshopper.ico -------------------------------------------------------------------------------- /Artwork/PluginGrasshopper.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginGrasshopper.webp -------------------------------------------------------------------------------- /Artwork/PluginGrasshopper.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginGrasshopper.xcf -------------------------------------------------------------------------------- /Artwork/PluginGrasshopper_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginGrasshopper_128.png -------------------------------------------------------------------------------- /Artwork/PluginGrasshopper_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginGrasshopper_16.png -------------------------------------------------------------------------------- /Artwork/PluginGrasshopper_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginGrasshopper_24.png -------------------------------------------------------------------------------- /Artwork/PluginGrasshopper_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginGrasshopper_256.png -------------------------------------------------------------------------------- /Artwork/PluginGrasshopper_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginGrasshopper_32.png -------------------------------------------------------------------------------- /Artwork/PluginGrasshopper_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/Artwork/PluginGrasshopper_1024.png -------------------------------------------------------------------------------- /PluginRhino/README.md: -------------------------------------------------------------------------------- 1 | # Rhino plug-in 2 | 3 | Directory [EmbeddedResources](EmbeddedResources) contains images which you might want to adapt. 4 | 5 | -------------------------------------------------------------------------------- /PluginRhino/EmbeddedResources/PluginRhino.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/PluginRhino/EmbeddedResources/PluginRhino.ico -------------------------------------------------------------------------------- /PluginGrasshopper/README.md: -------------------------------------------------------------------------------- 1 | # Grasshopper plug-in 2 | 3 | Directory [EmbeddedResources](EmbeddedResources) contains images which you might want to adapt. 4 | 5 | -------------------------------------------------------------------------------- /PluginGrasshopper/EmbeddedResources/PluginGrasshopper_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/PluginGrasshopper/EmbeddedResources/PluginGrasshopper_16.png -------------------------------------------------------------------------------- /PluginGrasshopper/EmbeddedResources/PluginGrasshopper_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shapediver/GrasshopperPluginTemplate/HEAD/PluginGrasshopper/EmbeddedResources/PluginGrasshopper_24.png -------------------------------------------------------------------------------- /yak/yak_push.bat: -------------------------------------------------------------------------------- 1 | 2 | cd bin/yak 3 | 4 | dir *.yak 5 | 6 | set /p=Hit ENTER to push the Yak packages shown above... 7 | yak push *.yak 8 | 9 | set /p=Hit ENTER to continue... 10 | -------------------------------------------------------------------------------- /yak/manifest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: $name$ 3 | version: $version$ 4 | authors: 5 | - $authors$ 6 | description: > 7 | $description$ 8 | url: $url$ 9 | icon: icon.png 10 | keywords: 11 | $keywords$ 12 | -------------------------------------------------------------------------------- /PluginGrasshopper/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using Grasshopper.Kernel; 2 | 3 | // Define the loading mechanism Grasshopper shall use for this plugin 4 | // see https://www.grasshopper3d.com/forum/topics/how-to-define-per-gha-loading-mechanism 5 | // for more information 6 | [assembly: Grasshopper.Kernel.GH_Loading(GH_LoadingDemand.Default)] 7 | -------------------------------------------------------------------------------- /Shared/src/SharedExample.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace PluginTemplate.Shared 3 | { 4 | 5 | /// 6 | /// Example implementation of a shared interface not dependent on RhinoCommon. 7 | /// 8 | public class SharedExample : ISharedExample 9 | { 10 | public int Add(int a, int b) 11 | { 12 | return a + b; 13 | } 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /References/MacOS/README.md: -------------------------------------------------------------------------------- 1 | Copy `System.Drawing.Common.dll` from a Rhino 8 Mac application bundle here. 2 | Right-click the Rhino 8 app icon, choose "Show content," and navigate to Contents/Frameworks/RhCore.framework/Versions/Current/Resources/ 3 | 4 | See the related [thread](https://discourse.mcneel.com/t/windows-forms-on-gh-and-rhino-8/171307/23) on McNeel Discourse. Looks like there is a better solution already, which still has to be incorporated here. 5 | -------------------------------------------------------------------------------- /Shared/interface/ISharedExample.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace PluginTemplate.Shared 3 | { 4 | 5 | /// 6 | /// Example of a shared interface not dependent on RhinoCommon. 7 | /// 8 | public interface ISharedExample { 9 | 10 | /// 11 | /// Compute the sum of two integers. 12 | /// 13 | /// 14 | /// 15 | /// 16 | int Add(int a, int b); 17 | 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /test.DebugR7.runsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | x64 7 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test.DebugR8.runsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | x64 7 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /CommonSettingsFinal.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | $(AssemblyName) 9 | $(AssemblyName) 10 | 11 | 12 | -------------------------------------------------------------------------------- /SharedRhino/interface/ISharedRhinoExample.cs: -------------------------------------------------------------------------------- 1 | using Rhino.Geometry; 2 | 3 | namespace PluginTemplate.SharedRhino 4 | { 5 | 6 | /// 7 | /// Example of a shared interface dependent on RhinoCommon. 8 | /// 9 | public interface ISharedRhinoExample { 10 | 11 | /// 12 | /// Intersect a plane with a line. 13 | /// 14 | /// 15 | /// 16 | /// 17 | Point3d PlaneLineIntersection(Plane plane, Line line); 18 | 19 | 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /CommonReferencesTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | true 13 | 14 | 15 | $(MSBuildThisFileDirectory)\test.$(Configuration).runsettings 16 | 17 | 18 | -------------------------------------------------------------------------------- /BuildYakOnlyRhino7.bat: -------------------------------------------------------------------------------- 1 | call "CommonVariables.bat" 2 | call "%VsDevTools%" 3 | 4 | set Configuration=ReleaseR7 5 | 6 | REM build Yak package 7 | set Stage=BuildYakPackage 8 | msbuild /t:%Stage% /p:Configuration=%Configuration% PluginGrasshopper\PluginGrasshopper.csproj || GOTO error 9 | 10 | :done 11 | if "%~1"=="" ( 12 | set /p=Done. Hit ENTER to close... 13 | %SystemRoot%\explorer.exe %YakTargetDir% 14 | ) 15 | exit /b 0 16 | 17 | :error 18 | if "%~1"=="" ( 19 | if "%Stage%"=="" ( 20 | set /p=An error happened. Hit ENTER to close... 21 | ) else ( 22 | set /p=An error happened in stage %Stage%. Hit ENTER to close... 23 | ) 24 | ) 25 | exit /b 1 26 | -------------------------------------------------------------------------------- /BuildYakOnlyRhino8.bat: -------------------------------------------------------------------------------- 1 | call "CommonVariables.bat" 2 | call "%VsDevTools%" 3 | 4 | set Configuration=ReleaseR8 5 | 6 | REM build Yak package 7 | set Stage=BuildYakPackage 8 | msbuild /t:%Stage% /p:Configuration=%Configuration% PluginGrasshopper\PluginGrasshopper.csproj || GOTO error 9 | 10 | :done 11 | if "%~1"=="" ( 12 | set /p=Done. Hit ENTER to close... 13 | %SystemRoot%\explorer.exe %YakTargetDir% 14 | ) 15 | exit /b 0 16 | 17 | :error 18 | if "%~1"=="" ( 19 | if "%Stage%"=="" ( 20 | set /p=An error happened. Hit ENTER to close... 21 | ) else ( 22 | set /p=An error happened in stage %Stage%. Hit ENTER to close... 23 | ) 24 | ) 25 | exit /b 1 26 | -------------------------------------------------------------------------------- /CommonReferencesGrasshopper.csproj: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /PluginGrasshopper/PluginLoader.cs: -------------------------------------------------------------------------------- 1 | using Grasshopper; 2 | using Grasshopper.Kernel; 3 | using System; 4 | using System.Drawing; 5 | using System.Reflection; 6 | using System.Runtime.InteropServices; 7 | 8 | namespace PluginTemplate.PluginGrasshopper 9 | { 10 | public class PluginLoader : GH_AssemblyPriority 11 | { 12 | public override GH_LoadingInstruction PriorityLoad() 13 | { 14 | Instances.ComponentServer.AddCategoryIcon("PluginTemplate", ResourceLoader.LoadBitmap("PluginGrasshopper_16.png")); 15 | Instances.ComponentServer.AddCategorySymbolName("PluginTemplate", 'P'); 16 | return GH_LoadingInstruction.Proceed; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /SharedRhino/src/SharedRhinoExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Rhino.Geometry; 3 | 4 | namespace PluginTemplate.SharedRhino 5 | { 6 | 7 | /// 8 | /// Example implementation of a shared interface dependent on RhinoCommon. 9 | /// 10 | public class SharedRhinoExample : ISharedRhinoExample 11 | { 12 | public Point3d PlaneLineIntersection(Plane plane, Line line) 13 | { 14 | if (Rhino.Geometry.Intersect.Intersection.LinePlane(line, plane, out double lineParameter)) 15 | { 16 | return line.PointAt(lineParameter); 17 | } 18 | throw new Exception("Line does not intersect plane."); 19 | } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /PackagesRhino7.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /CommonVariables.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | REM VsDevTools might need to be adapted according your installation of Visual Studio 4 | set "VsDevTools=C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat" 5 | 6 | REM where to find yak 7 | if exist "C:\Program Files\Rhino 8\System\yak.exe" ( 8 | set "YakExecutable=C:\Program Files\Rhino 8\System\yak.exe" 9 | ) else if exist "C:\Program Files\Rhino 7\System\yak.exe" ( 10 | set "YakExecutable=C:\Program Files\Rhino 7\System\yak.exe" 11 | ) else ( 12 | echo [WARN] yak.exe not found in default Rhino 7/8 locations. 13 | set "YakExecutable=" 14 | ) 15 | 16 | REM name of the solution to build 17 | set "Name=PluginTemplate" 18 | 19 | REM where to copy resulting yak packages 20 | set "YakTargetDir=bin\packages" 21 | 22 | -------------------------------------------------------------------------------- /PackagesRhino8.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /PluginRhino/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using Rhino.PlugIns; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // Plug-in Description Attributes - all of these are optional. 7 | // These will show in Rhino's option dialog, in the tab Plug-ins. 8 | [assembly: PlugInDescription(DescriptionType.Address, "")] 9 | [assembly: PlugInDescription(DescriptionType.Country, "")] 10 | [assembly: PlugInDescription(DescriptionType.Email, "")] 11 | [assembly: PlugInDescription(DescriptionType.Phone, "")] 12 | [assembly: PlugInDescription(DescriptionType.Fax, "")] 13 | [assembly: PlugInDescription(DescriptionType.Organization, "")] 14 | [assembly: PlugInDescription(DescriptionType.UpdateUrl, "")] 15 | [assembly: PlugInDescription(DescriptionType.WebSite, "")] 16 | 17 | // Icons should be Windows .ico files and contain 32-bit images in the following sizes: 16, 24, 32, 48, and 256. 18 | [assembly: PlugInDescription(DescriptionType.Icon, "PluginTemplate.PluginRhino.EmbeddedResources.PluginRhino.ico")] 19 | 20 | -------------------------------------------------------------------------------- /PluginRhino/PluginRhino.cs: -------------------------------------------------------------------------------- 1 | using Rhino; 2 | using System; 3 | 4 | namespace PluginTemplate.PluginRhino 5 | { 6 | /// 7 | /// Every RhinoCommon .rhp assembly must have one and only one PlugIn-derived 8 | /// class. DO NOT create instances of this class yourself. It is the 9 | /// responsibility of Rhino to create an instance of this class. 10 | /// To complete plug-in information, please also see all PlugInDescription 11 | /// attributes in AssemblyInfo.cs 12 | /// 13 | public class PluginRhino : Rhino.PlugIns.PlugIn 14 | { 15 | public PluginRhino() 16 | { 17 | Instance = this; 18 | } 19 | 20 | ///Gets the only instance of the MyRhinoPlugin1 plug-in. 21 | public static PluginRhino Instance { get; private set; } 22 | 23 | // You can override methods here to change the plug-in behavior on 24 | // loading and shut down, add options pages to the Rhino _Option command 25 | // and maintain plug-in wide options in a document. 26 | } 27 | } -------------------------------------------------------------------------------- /BuildRhino7.bat: -------------------------------------------------------------------------------- 1 | call "CommonVariables.bat" 2 | call "%VsDevTools%" 3 | 4 | set Configuration=ReleaseR7 5 | 6 | REM prepare build Yak package 7 | set Stage=PrepareBuildYakPackage 8 | msbuild /t:%Stage% /p:Configuration=%Configuration% %Name%.sln || GOTO error 9 | 10 | REM build 11 | set Stage=restore 12 | msbuild /t:%Stage% /p:Configuration=%Configuration% %Name%.sln || GOTO error 13 | set Stage=build 14 | msbuild /t:%Stage% /p:Configuration=%Configuration% /p:TreatWarningsAsErrors=true %Name%.sln || GOTO error 15 | 16 | REM build Yak package 17 | set Stage=BuildYakPackage 18 | msbuild /t:%Stage% /p:Configuration=%Configuration% PluginGrasshopper\PluginGrasshopper.csproj || GOTO error 19 | 20 | :done 21 | if "%~1"=="" ( 22 | set /p=Done. Hit ENTER to close... 23 | %SystemRoot%\explorer.exe %YakTargetDir% 24 | ) 25 | exit /b 0 26 | 27 | :error 28 | if "%~1"=="" ( 29 | if "%Stage%"=="" ( 30 | set /p=An error happened. Hit ENTER to close... 31 | ) else ( 32 | set /p=An error happened in stage %Stage%. Hit ENTER to close... 33 | ) 34 | ) 35 | exit /b 1 36 | -------------------------------------------------------------------------------- /BuildRhino8.bat: -------------------------------------------------------------------------------- 1 | call "CommonVariables.bat" 2 | call "%VsDevTools%" 3 | 4 | set Configuration=ReleaseR8 5 | 6 | REM prepare build Yak package 7 | set Stage=PrepareBuildYakPackage 8 | msbuild /t:%Stage% /p:Configuration=%Configuration% %Name%.sln || GOTO error 9 | 10 | REM build 11 | set Stage=restore 12 | msbuild /t:%Stage% /p:Configuration=%Configuration% %Name%.sln || GOTO error 13 | set Stage=build 14 | msbuild /t:%Stage% /p:Configuration=%Configuration% /p:TreatWarningsAsErrors=true %Name%.sln || GOTO error 15 | 16 | REM build Yak package 17 | set Stage=BuildYakPackage 18 | msbuild /t:%Stage% /p:Configuration=%Configuration% PluginGrasshopper\PluginGrasshopper.csproj || GOTO error 19 | 20 | :done 21 | if "%~1"=="" ( 22 | set /p=Done. Hit ENTER to close... 23 | %SystemRoot%\explorer.exe %YakTargetDir% 24 | ) 25 | exit /b 0 26 | 27 | :error 28 | if "%~1"=="" ( 29 | if "%Stage%"=="" ( 30 | set /p=An error happened. Hit ENTER to close... 31 | ) else ( 32 | set /p=An error happened in stage %Stage%. Hit ENTER to close... 33 | ) 34 | ) 35 | exit /b 1 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 ShapeDiver 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | true 8 | 9 | false 10 | true 11 | 12 | 15 | 16 | 19 | 20 | 23 | 24 | -------------------------------------------------------------------------------- /CommonTasks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Shared/Shared.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | $(CommonNamespace).Shared 9 | $(CommonName).Shared 10 | Shared functionality not depending on Rhino 11 | 15 | true 16 | true 17 | true 18 | true 19 | 20 | 21 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /SharedRhino/SharedRhino.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | $(CommonNamespace).SharedRhino 10 | $(CommonName).SharedRhino 11 | Shared functionality depending on Rhino 12 | 16 | true 17 | true 18 | true 19 | true 20 | 21 | 22 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /TestShared/TestShared.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | $(CommonNamespace).Tests.Shared 10 | $(CommonName).Tests.Shared 11 | Tests for shared functionality not depending on Rhino 12 | 16 | true 17 | true 18 | true 19 | true 20 | 21 | 22 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /PluginGrasshopper/Properties/ResourceLoader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace PluginTemplate.PluginGrasshopper 10 | { 11 | /// 12 | /// Load and convert embedded assembly resources 13 | /// 14 | internal static class ResourceLoader 15 | { 16 | static string GetResourcePath(string resourceName) 17 | { 18 | return $"{typeof(ResourceLoader).Namespace}.EmbeddedResources.{resourceName}"; 19 | } 20 | 21 | public static Bitmap LoadBitmap(string resourceName) 22 | { 23 | var assembly = typeof(ResourceLoader).Assembly; 24 | using (var stream = assembly.GetManifestResourceStream(GetResourcePath(resourceName))) 25 | { 26 | if (stream == null) 27 | throw new Exception($"Failed to load resource {resourceName}"); 28 | return new Bitmap(stream); 29 | } 30 | } 31 | 32 | public static Icon LoadIcon (string resourceName) 33 | { 34 | var assembly = typeof(ResourceLoader).Assembly; 35 | using (var stream = assembly.GetManifestResourceStream(GetResourcePath(resourceName))) 36 | { 37 | if (stream == null) 38 | throw new Exception($"Failed to load resource {resourceName}"); 39 | return new Icon(stream); 40 | } 41 | } 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /TestSharedRhino/TestSharedRhino.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | $(CommonNamespace).Tests.SharedRhino 11 | $(CommonName).Tests.SharedRhino 12 | Tests for shared functionality depending on Rhino 13 | 17 | true 18 | true 19 | true 20 | true 21 | 22 | 23 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /CommonReferencesRhino.csproj: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | $(ProgramW6432)\Rhino 7\System\Rhino.exe 13 | 14 | 15 | Program 16 | false 17 | 18 | 19 | $(DefineConstants),RHINOCOMMON_EQUAL_7 20 | $(DefineConstants),RHINOCOMMON_GREATER_EQUAL_7 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | $(ProgramW6432)\Rhino 8\System\Rhino.exe 29 | 30 | 31 | Program 32 | false 33 | 34 | 35 | $(DefineConstants),RHINOCOMMON_EQUAL_8 36 | $(DefineConstants),RHINOCOMMON_GREATER_EQUAL_7 37 | $(DefineConstants),RHINOCOMMON_GREATER_EQUAL_8 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /CommonReferencesSystemDrawing.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | $(MSBuildThisFileDirectory)\References\MacOS\System.Drawing.Common.dll 20 | False 21 | 22 | 23 | 27 | 28 | $(DefineConstants),USING_MCNEEL_SYSTEM_DRAWING 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /TestShared/TestSharedExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | using PluginTemplate.Shared; 5 | 6 | namespace PluginTemplate.Tests.Shared 7 | { 8 | [TestClass] 9 | public class TestSharedExample 10 | { 11 | /// 12 | /// Test setup for complete class, will be called once for all tests contained herein 13 | /// Change signature to "async static Task" in case of async tests 14 | /// 15 | /// 16 | [ClassInitialize] 17 | public static void ClassInitialize(TestContext context) 18 | { 19 | // TODO 20 | } 21 | 22 | /// 23 | /// Test setup per test, will be called once for each test 24 | /// Change signature to "async Task" in case of async tests 25 | /// 26 | [TestInitialize] 27 | public void TestInitialize() 28 | { 29 | // TODO 30 | } 31 | 32 | /// 33 | /// Test method 34 | /// Change signature to "async Task" in case of async tests 35 | /// 36 | [TestMethod] 37 | public void Test_Add_00() 38 | { 39 | var sharedExample = new SharedExample(); 40 | Assert.AreEqual(3, sharedExample.Add(1, 2)); 41 | } 42 | 43 | /// 44 | /// Test cleanup per test, will be called once for each test 45 | /// Change signature to "async Task" in case of async tests 46 | /// 47 | [TestCleanup] 48 | public void TestCleanup() 49 | { 50 | // TODO 51 | } 52 | 53 | /// 54 | /// Test cleanup for complete class, will be called once for all tests contained herein 55 | /// Change signature to "async static Task" in case of async tests 56 | /// 57 | [ClassCleanup] 58 | public static void ClassCleanup() 59 | { 60 | // TODO 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /PluginRhino/Commands/ExampleCommand.cs: -------------------------------------------------------------------------------- 1 | using Rhino; 2 | using Rhino.Commands; 3 | using Rhino.Geometry; 4 | using Rhino.Input; 5 | using Rhino.Input.Custom; 6 | using System; 7 | using System.Collections.Generic; 8 | 9 | namespace PluginTemplate.PluginRhino 10 | { 11 | public class ExampleCommand : Command 12 | { 13 | public ExampleCommand() 14 | { 15 | // Rhino only creates one instance of each command class defined in a 16 | // plug-in, so it is safe to store a refence in a static property. 17 | Instance = this; 18 | } 19 | 20 | ///The only instance of this command. 21 | public static ExampleCommand Instance { get; private set; } 22 | 23 | ///The command name as it appears on the Rhino command line. 24 | public override string EnglishName => "PluginTemplateExampleCommand"; 25 | 26 | protected override Result RunCommand(RhinoDoc doc, RunMode mode) 27 | { 28 | /// The following code shows a possibility to differentiate between versions of RhinoCommon and .NET at compile time. 29 | 30 | /// The RHINOCOMMON_* constants are defined in "CommonReferencesRhino.csproj" 31 | #if RHINOCOMMON_EQUAL_7 32 | RhinoApp.WriteLine("RHINOCOMMON_EQUAL_7 is defined."); 33 | #endif 34 | 35 | #if RHINOCOMMON_EQUAL_8 36 | RhinoApp.WriteLine("RHINOCOMMON_EQUAL_8 is defined."); 37 | #endif 38 | 39 | #if RHINOCOMMON_GREATER_EQUAL_7 40 | RhinoApp.WriteLine("RHINOCOMMON_GREATER_EQUAL_7 is defined."); 41 | #endif 42 | 43 | #if RHINOCOMMON_GREATER_EQUAL_8 44 | RhinoApp.WriteLine("RHINOCOMMON_GREATER_EQUAL_8 is defined."); 45 | #endif 46 | 47 | /// see https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives 48 | #if NETFRAMEWORK 49 | RhinoApp.WriteLine("NETFRAMEWORK is defined."); 50 | #endif 51 | 52 | #if NET7_0_OR_GREATER 53 | RhinoApp.WriteLine("NET7_0_OR_GREATER is defined."); 54 | #endif 55 | 56 | return Result.Success; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /PluginRhino/PluginRhino.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | $(CommonNamespace).PluginRhino 10 | $(CommonName).PluginRhino 11 | $(CommonName) 12 | $(Product) 13 | .rhp 14 | 18 | true 19 | true 20 | true 21 | true 22 | 26 | true 27 | 28 | 29 | 34 | 35 | 36 | 37 | 38 | 39 | 43 | 44 | <_Parameter1>$(RhinoPluginGuid) 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /CommonVariables.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 13 | 14 | 0 15 | 1 16 | 0 17 | 20 | -alpha 21 | 22 | 25 | 26 | 00000000-0000-0000-0000-000000000000 27 | 00000000-0000-0000-0000-000000000000 28 | 29 | 33 | 34 | PluginTemplate 35 | PluginTemplate 36 | 37 | 40 | 41 | Alex Schiftner 42 | alex@shapediver.com 43 | ShapeDiver 44 | ShapeDiver GmbH 2024 45 | A template plug-in for Grasshopper and Rhino 46 | $(CommonName) 47 | $(CommonAuthors), $(CommonCompany) 48 | $(CommonProduct) 49 | https://github.com/shapediver/GrasshopperPluginTemplate 50 | $(MSBuildThisFileDirectory)/Artwork/PluginRhino_64.png 51 | - Rhino 52 | - Grasshopper 53 | - Template 54 | 55 | 56 | -------------------------------------------------------------------------------- /TestSharedRhino/TestSharedRhinoExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | using Rhino.Geometry; 5 | using PluginTemplate.SharedRhino; 6 | 7 | namespace PluginTemplate.Tests.SharedRhino 8 | { 9 | [TestClass] 10 | public class TestSharedRhinoExample 11 | { 12 | /// 13 | /// Test setup for complete class, will be called once for all tests contained herein 14 | /// Change signature to "async static Task" in case of async tests 15 | /// 16 | /// 17 | [ClassInitialize] 18 | public static void ClassInitialize(TestContext context) 19 | { 20 | // TODO 21 | } 22 | 23 | /// 24 | /// Test setup per test, will be called once for each test 25 | /// Change signature to "async Task" in case of async tests 26 | /// 27 | [TestInitialize] 28 | public void TestInitialize() 29 | { 30 | // TODO 31 | } 32 | 33 | /// 34 | /// Test method 35 | /// Change signature to "async Task" in case of async tests 36 | /// 37 | [TestMethod] 38 | public void Test_PlaneLineIntersection_00() 39 | { 40 | var sharedRhinoExample = new SharedRhinoExample(); 41 | var point = sharedRhinoExample.PlaneLineIntersection(Plane.WorldXY, new Line(new Point3d(1,1,-1), new Point3d(1,1,1))); 42 | Assert.AreEqual(0, point.DistanceToSquared(new Point3d(1,1,0))); 43 | } 44 | 45 | /// 46 | /// Test cleanup per test, will be called once for each test 47 | /// Change signature to "async Task" in case of async tests 48 | /// 49 | [TestCleanup] 50 | public void TestCleanup() 51 | { 52 | // TODO 53 | } 54 | 55 | /// 56 | /// Test cleanup for complete class, will be called once for all tests contained herein 57 | /// Change signature to "async static Task" in case of async tests 58 | /// 59 | [ClassCleanup] 60 | public static void ClassCleanup() 61 | { 62 | // TODO 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /PluginGrasshopper/PluginGrasshopper.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | $(CommonNamespace).PluginGrasshopper 12 | $(CommonName).PluginGrasshopper 13 | $(CommonName) 14 | $(Product) 15 | .gha 16 | 20 | true 21 | true 22 | true 23 | true 24 | 28 | true 29 | 30 | 31 | 36 | 37 | 38 | 39 | 40 | 41 | 45 | 46 | <_Parameter1>$(GrasshopperPluginGuid) 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /PluginGrasshopper/Components/ExampleComponent.cs: -------------------------------------------------------------------------------- 1 | using Grasshopper; 2 | using Grasshopper.Kernel; 3 | using Rhino.Geometry; 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace PluginTemplate.PluginGrasshopper 8 | { 9 | public class ExampleComponent : GH_Component 10 | { 11 | /// 12 | /// Each implementation of GH_Component must provide a public 13 | /// constructor without any arguments. 14 | /// Category represents the Tab in which the component will appear, 15 | /// Subcategory the panel. If you use non-existing tab or panel names, 16 | /// new tabs/panels will automatically be created. 17 | /// 18 | public ExampleComponent() 19 | : base("ExampleComponent", "Nickname", 20 | "Description", 21 | "PluginTemplate", "Example") 22 | { 23 | } 24 | 25 | /// 26 | /// Registers all the input parameters for this component. 27 | /// 28 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 29 | { 30 | } 31 | 32 | /// 33 | /// Registers all the output parameters for this component. 34 | /// 35 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 36 | { 37 | } 38 | 39 | /// 40 | /// This is the method that actually does the work. 41 | /// 42 | /// The DA object can be used to retrieve data from input parameters and 43 | /// to store data in output parameters. 44 | protected override void SolveInstance(IGH_DataAccess DA) 45 | { 46 | } 47 | 48 | /// 49 | /// Provides an Icon for every component that will be visible in the User Interface. 50 | /// Icons need to be 24x24 pixels. 51 | /// You can add image files to your project resources and access them like this: 52 | /// return Resources.IconForThisComponent; 53 | /// 54 | protected override System.Drawing.Bitmap Icon => ResourceLoader.LoadBitmap("PluginGrasshopper_24.png"); 55 | 56 | /// 57 | /// Each component must have a unique Guid to identify it. 58 | /// It is vital this Guid doesn't change otherwise old ghx files 59 | /// that use the old ID will partially fail during loading. 60 | /// 61 | public override Guid ComponentGuid => new Guid("69E66DAA-0427-4ABF-9CE9-277D645F4A7D"); 62 | } 63 | } -------------------------------------------------------------------------------- /CommonTargets.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | $(OutputPath)/net48 9 | 10 | 11 | $(OutputPath) 12 | 13 | 14 | $(YakBuildPath)/manifest.yml 15 | 16 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /TestSharedRhino/RhinoInsideInit.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Microsoft.Win32; 3 | using System; 4 | using System.IO; 5 | using System.Reflection; 6 | 7 | using RRT = Rhino.Runtime; 8 | 9 | namespace PluginTemplate.Tests.SharedRhino 10 | { 11 | /// 12 | /// Shared VS test assembly class using Rhino.Inside. 13 | /// Inspired by this repo: https://github.com/tmakin/RhinoCommonUnitTesting 14 | /// 15 | [TestClass] 16 | public static class RhinoInsideInit 17 | { 18 | private static bool initialized = false; 19 | private static string rhinoDir; 20 | 21 | 22 | [AssemblyInitialize] 23 | public static void AssemblyInitialize(TestContext context) 24 | { 25 | //get the correct rhino 7 installation directory 26 | #if RHINOCOMMON_GREATER_EQUAL_8 27 | rhinoDir = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\McNeel\Rhinoceros\8.0\Install", "Path", null) as string ?? string.Empty; 28 | #elif RHINOCOMMON_GREATER_EQUAL_7 29 | rhinoDir = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\McNeel\Rhinoceros\7.0\Install", "Path", null) as string ?? string.Empty; 30 | #endif 31 | Assert.IsTrue(System.IO.Directory.Exists(rhinoDir), "Rhino system dir not found: {0}", rhinoDir); 32 | context.WriteLine(" The current Rhino installation is " + rhinoDir); 33 | 34 | if (initialized) 35 | { 36 | throw new InvalidOperationException("Initialize Rhino.Inside once"); 37 | } 38 | else 39 | { 40 | RhinoInside.Resolver.Initialize(); 41 | initialized = true; 42 | context.WriteLine("Rhino.Inside init has started"); 43 | } 44 | 45 | // Ensure we are running the tests in x64 46 | Assert.IsTrue(Environment.Is64BitProcess, "Tests must be run as x64"); 47 | 48 | // Set path to rhino system directory 49 | string envPath = Environment.GetEnvironmentVariable("path"); 50 | Environment.SetEnvironmentVariable("path", envPath + ";" + rhinoDir); 51 | 52 | // Start a headless rhino instance using Rhino.Inside 53 | StartRhino(); 54 | 55 | // We have to load grasshopper.dll on the current AppDomain manually for some reason 56 | AppDomain.CurrentDomain.AssemblyResolve += ResolveGrasshopper; 57 | } 58 | 59 | /// 60 | /// Starting Rhino - loading the relevant libraries 61 | /// 62 | [STAThread] 63 | public static void StartRhino() 64 | { 65 | #if RHINOCOMMON_GREATER_EQUAL_7 66 | var _rhinoCore = new RRT.InProcess.RhinoCore(null, RRT.InProcess.WindowStyle.NoWindow); 67 | #endif 68 | } 69 | 70 | 71 | /// 72 | /// Add Grasshopper.dll to the current Appdomain 73 | /// 74 | private static Assembly ResolveGrasshopper(object sender, ResolveEventArgs args) 75 | { 76 | var name = args.Name; 77 | 78 | if (name.StartsWith("Grasshopper")) 79 | { 80 | var path = Path.Combine(Path.GetFullPath(Path.Combine(rhinoDir, @"..\")), "Plug-ins\\Grasshopper\\Grasshopper.dll"); 81 | return Assembly.LoadFrom(path); 82 | } 83 | if (name.StartsWith("GH_IO")) 84 | { 85 | var path = Path.Combine(Path.GetFullPath(Path.Combine(rhinoDir, @"..\")), "Plug-ins\\Grasshopper\\GH_IO.dll"); 86 | return Assembly.LoadFrom(path); 87 | } 88 | else 89 | { 90 | return null; 91 | } 92 | 93 | 94 | 95 | } 96 | } 97 | } 98 | 99 | -------------------------------------------------------------------------------- /PluginGrasshopper/PluginInfo.cs: -------------------------------------------------------------------------------- 1 | using Grasshopper; 2 | using Grasshopper.Kernel; 3 | using System; 4 | using System.Drawing; 5 | using System.Reflection; 6 | using System.Runtime.InteropServices; 7 | 8 | namespace PluginTemplate.PluginGrasshopper 9 | { 10 | public class PluginInfo : GH_AssemblyInfo 11 | { 12 | public override string Name 13 | { 14 | get 15 | { 16 | return Assembly.GetExecutingAssembly().GetCustomAttribute().Title; 17 | } 18 | } 19 | 20 | public override Bitmap Icon => ResourceLoader.LoadBitmap("PluginGrasshopper_24.png"); 21 | 22 | public override Bitmap AssemblyIcon => Icon; 23 | 24 | public override string Description 25 | { 26 | get 27 | { 28 | var description = Assembly.GetExecutingAssembly().GetCustomAttribute().Description; 29 | var configuration = Assembly.GetExecutingAssembly().GetCustomAttribute().Configuration; 30 | if (configuration.ToLowerInvariant().Contains("debug")) 31 | { 32 | description = $"{description}, {Version} ({configuration})"; 33 | } 34 | return description; 35 | } 36 | } 37 | 38 | public override string AssemblyDescription => Description; 39 | 40 | public override Guid Id 41 | { 42 | get 43 | { 44 | return new Guid(Assembly.GetExecutingAssembly().GetCustomAttribute().Value); 45 | } 46 | } 47 | 48 | public override string AuthorName 49 | { 50 | get 51 | { 52 | var company = Assembly.GetExecutingAssembly().GetCustomAttribute().Company; 53 | 54 | var attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(); 55 | if (attributes != null) 56 | { 57 | foreach (var attribute in attributes) 58 | { 59 | if (attribute.Key == "Authors") 60 | { 61 | return $"{attribute.Value}, {company}"; 62 | } 63 | } 64 | } 65 | 66 | return company; 67 | } 68 | } 69 | 70 | public override string AuthorContact 71 | { 72 | get 73 | { 74 | var attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(); 75 | if (attributes != null) 76 | { 77 | foreach (var attribute in attributes) 78 | { 79 | if (attribute.Key == "AuthorContact") 80 | { 81 | return attribute.Value; 82 | } 83 | } 84 | } 85 | return ""; 86 | } 87 | } 88 | 89 | public override string Version 90 | { 91 | get 92 | { 93 | var version = Assembly.GetExecutingAssembly().GetCustomAttribute().InformationalVersion; 94 | return version.ToString(); 95 | } 96 | } 97 | 98 | public override string AssemblyVersion 99 | { 100 | get 101 | { 102 | var version = Assembly.GetExecutingAssembly().GetCustomAttribute().InformationalVersion; 103 | return version.ToString(); 104 | } 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Grasshopper and Rhino Plug-in Template 2 | This repository contains a template for plug-ins to Grasshopper and [Rhino](https://www.rhino3d.com/). 3 | The template follows best practices we use at ShapeDiver. 4 | 5 | ## Features 6 | 7 | ### Centralized versioning and metadata 8 | 9 | see [CommonVariables.csproj](CommonVariables.csproj) 10 | 11 | The version of all assemblies built by the solution can be configured in a central place. 12 | The same principle is used for further metadata like plug-in authorship, and properties 13 | of the [Package Manifest](https://developer.rhino3d.com/guides/yak/the-package-manifest/) 14 | for the [Yak Package Manager](https://developer.rhino3d.com/guides/yak/). 15 | 16 | 17 | ### Centralized nuget package versioning 18 | see [Directory.Packages.props](Directory.Packages.props) 19 | 20 | Version of nuget packages are configured in a central place for all projects. 21 | 22 | ### Shared assembly between Grasshopper and Rhino plug-in 23 | 24 | The setup includes two shared assemblies: 25 | 26 | * [Shared](Shared) for shared code which does not depend on Rhino. 27 | * [SharedRhino](SharedRhino) for shared code depending on Rhino. 28 | 29 | ### Setup for unit tests, including tests using Rhino.Inside 30 | 31 | Two test projects are used for unit testing of the shared assemblies. Since [Rhino.Inside](https://github.com/mcneel/rhino.inside) this is very useful, 32 | because one can test and debug code depending on Rhino without starting Rhino. 33 | 34 | * [TestShared](TestShared) tests for the assembly [Shared](Shared) 35 | * [TestSharedRhino](TestSharedRhino) tests for the assembly [SharedRhino](SharedRhino) 36 | 37 | How to use this? Start the _Test Explorer_ in Visual Studio. 38 | 39 | ### Build scripts for Rhino 7 and 8, Windows and Mac 40 | 41 | The solution includes separate build configurations for Rhino 7 and Rhino 8. Rhino 6 can easily be added. 42 | 43 | The following batch scripts are available for building using a single click. 44 | 45 | * [BuildRhino7.bat](BuildRhino7.bat) build for Rhino 7 including yak package 46 | * [BuildRhino8.bat](BuildRhino8.bat) build for Rhino 8 including yak package 47 | * [BuildYakOnlyRhino7.bat](BuildYakOnlyRhino7.bat) build yak package for Rhino 7 (requires the plugins to be built separately beforehand) 48 | * [BuildYakOnlyRhino8.bat](BuildYakOnlyRhino8.bat) build yak package for Rhino 8 (requires the plugins to be built separately beforehand) 49 | 50 | ### Multi-targeting for Rhino 8 51 | 52 | The solution is configured to build a multi-targeted yak package in case of Rhino 8 (.NET Framework 4.8, .NET 7 for Windows and Mac). 53 | 54 | Note: There is still a [bug related to this](https://discourse.mcneel.com/t/net-multi-targeting-for-yak-packages/166183/10?u=snabela) in yak for Rhino 8 SR 4, this should be fixed soon. 55 | 56 | 57 | ## How to use this 58 | 59 | Download the code or fork the repository. 60 | Please open GitHub issues or submit a PR in case you find a problem or have suggestions for improvement. 61 | 62 | Building the solution is supposed work out of the box in Visual Studio 2022. 63 | We still need to test and add instructions for building using Visual Studio Code on Mac. 64 | 65 | The following steps are important when starting your own plug-in from this: 66 | 67 | * Review and adapt the variable values in [CommonVariables.csproj](CommonVariables.csproj). 68 | * Create a new Guid for the Grasshopper plug-in and replace `00000000-0000-0000-0000-000000000000`. 69 | * Create a new Guid for the Rhino plug-in and replace `00000000-0000-0000-0000-000000000000`. 70 | * Set your version number. 71 | * Adapt information about Author, Company, Copyright, Product 72 | * Review and adapt the variable values in [CommonVariables.bat](CommonVariables.bat). 73 | * Installation path of Visual Studio 74 | * Path to Yak package manager 75 | * In case you don't need a Rhino or Grasshopper plug-in, remove it from the solution. 76 | * Set Rhino plug-in metadata in [AssemblyInfo.cs](PluginRhino/Properties/AssemblyInfo.cs) (still need to implement to create this automatically). 77 | * Adapt the images in [PluginGrasshopper/EmbeddedResources](PluginGrasshopper/EmbeddedResources) and [PluginRhino/EmbeddedResources](PluginRhino/EmbeddedResources). 78 | 79 | 80 | -------------------------------------------------------------------------------- /CommonSettings.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 11 | 12 | 13 | 16 | 17 | DebugR7 18 | DebugR7;DebugR8;ReleaseR7;ReleaseR8 19 | $(MSBuildThisFileDirectory)\bin\$(Configuration)\ 20 | 21 | 22 | 26 | 27 | net48 28 | 29 | 30 | net48;net8.0-windows 31 | 32 | 33 | $(TargetFrameworks);net7.0-windows 34 | 35 | 36 | 39 | 40 | 44 | 7.3 45 | 49 | true 50 | 55 | True 56 | True 57 | $(DefaultItemExcludes);Windows\**\* 58 | $(DefaultItemExcludes);MacOS\**\* 59 | 60 | 61 | 65 | 71 | 72 | 75 | 76 | $([System.DateTime]::Now.ToString("o")) 77 | 78 | 79 | 82 | 83 | true 84 | full 85 | false 86 | $(DefineConstants),DEBUG,TRACE 87 | prompt 88 | 4 89 | 90 | 91 | 92 | pdbonly 93 | true 94 | $(DefineConstants) 95 | prompt 96 | 4 97 | 98 | 99 | 105 | 106 | 107 | 108 | 109 | 113 | 114 | true 115 | $(CommonVersionMajor).$(CommonVersionMinor).$(CommonVersionPatch)$(CommonVersionSuffix) 116 | $(CommonAuthors) 117 | $(CommonCompany) 118 | $(CommonCopyright) 119 | $(CommonProduct) 120 | 126 | false 127 | 128 | 129 | 130 | 135 | 136 | <_Parameter1>AuthorContact 137 | <_Parameter2>$(CommonAuthorContact) 138 | 139 | 140 | <_Parameter1>Authors 141 | <_Parameter2>$(CommonAuthors) 142 | 143 | 144 | <_Parameter1>BuildTimestamp 145 | <_Parameter2>$(BuildTimestamp) 146 | 147 | 148 | 149 | 150 | 153 | 154 | 155 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /PluginTemplate.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.8.34408.163 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "Shared\Shared.csproj", "{DE0D681B-7381-4C5A-8BC9-9468A49530DE}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharedRhino", "SharedRhino\SharedRhino.csproj", "{979B3977-171C-4556-B258-67DCDB22EA50}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestShared", "TestShared\TestShared.csproj", "{8038AC47-3427-417F-B332-5C690A527EAC}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestSharedRhino", "TestSharedRhino\TestSharedRhino.csproj", "{30CF2229-F954-42B2-A309-339276B7FAE5}" 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{FAB810F0-1304-456B-AED3-6130C47D9E9E}" 15 | EndProject 16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{9A99AD89-394A-42BD-AE87-B50612D1F2DC}" 17 | EndProject 18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{81FD4852-BD3E-4D54-85F4-1D38CBDB9EF5}" 19 | EndProject 20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PluginGrasshopper", "PluginGrasshopper\PluginGrasshopper.csproj", "{72892D62-9108-4903-851F-2FD850096605}" 21 | EndProject 22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PluginRhino", "PluginRhino\PluginRhino.csproj", "{1868DD53-EF87-4564-A98B-C377DC38847B}" 23 | EndProject 24 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{BE2713C1-7811-4EE6-A885-7E3A904B43A7}" 25 | ProjectSection(SolutionItems) = preProject 26 | .gitignore = .gitignore 27 | BuildRhino7.bat = BuildRhino7.bat 28 | BuildRhino8.bat = BuildRhino8.bat 29 | BuildYakOnlyRhino7.bat = BuildYakOnlyRhino7.bat 30 | BuildYakOnlyRhino8.bat = BuildYakOnlyRhino8.bat 31 | CommonReferencesGrasshopper.csproj = CommonReferencesGrasshopper.csproj 32 | CommonReferencesRhino.csproj = CommonReferencesRhino.csproj 33 | CommonReferencesTests.csproj = CommonReferencesTests.csproj 34 | CommonSettings.csproj = CommonSettings.csproj 35 | CommonSettingsFinal.csproj = CommonSettingsFinal.csproj 36 | CommonVariables.bat = CommonVariables.bat 37 | CommonVariables.csproj = CommonVariables.csproj 38 | Directory.Packages.props = Directory.Packages.props 39 | Packages.props = Packages.props 40 | PackagesRhino7.props = PackagesRhino7.props 41 | PackagesRhino8.props = PackagesRhino8.props 42 | README.md = README.md 43 | test.DebugR7.runsettings = test.DebugR7.runsettings 44 | test.DebugR8.runsettings = test.DebugR8.runsettings 45 | TODO.md = TODO.md 46 | EndProjectSection 47 | EndProject 48 | Global 49 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 50 | DebugR7|Any CPU = DebugR7|Any CPU 51 | DebugR8|Any CPU = DebugR8|Any CPU 52 | ReleaseR7|Any CPU = ReleaseR7|Any CPU 53 | ReleaseR8|Any CPU = ReleaseR8|Any CPU 54 | EndGlobalSection 55 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 56 | {DE0D681B-7381-4C5A-8BC9-9468A49530DE}.DebugR7|Any CPU.ActiveCfg = DebugR7|Any CPU 57 | {DE0D681B-7381-4C5A-8BC9-9468A49530DE}.DebugR7|Any CPU.Build.0 = DebugR7|Any CPU 58 | {DE0D681B-7381-4C5A-8BC9-9468A49530DE}.DebugR8|Any CPU.ActiveCfg = DebugR8|Any CPU 59 | {DE0D681B-7381-4C5A-8BC9-9468A49530DE}.DebugR8|Any CPU.Build.0 = DebugR8|Any CPU 60 | {DE0D681B-7381-4C5A-8BC9-9468A49530DE}.ReleaseR7|Any CPU.ActiveCfg = ReleaseR7|Any CPU 61 | {DE0D681B-7381-4C5A-8BC9-9468A49530DE}.ReleaseR7|Any CPU.Build.0 = ReleaseR7|Any CPU 62 | {DE0D681B-7381-4C5A-8BC9-9468A49530DE}.ReleaseR8|Any CPU.ActiveCfg = ReleaseR8|Any CPU 63 | {DE0D681B-7381-4C5A-8BC9-9468A49530DE}.ReleaseR8|Any CPU.Build.0 = ReleaseR8|Any CPU 64 | {979B3977-171C-4556-B258-67DCDB22EA50}.DebugR7|Any CPU.ActiveCfg = DebugR7|Any CPU 65 | {979B3977-171C-4556-B258-67DCDB22EA50}.DebugR7|Any CPU.Build.0 = DebugR7|Any CPU 66 | {979B3977-171C-4556-B258-67DCDB22EA50}.DebugR8|Any CPU.ActiveCfg = DebugR8|Any CPU 67 | {979B3977-171C-4556-B258-67DCDB22EA50}.DebugR8|Any CPU.Build.0 = DebugR8|Any CPU 68 | {979B3977-171C-4556-B258-67DCDB22EA50}.ReleaseR7|Any CPU.ActiveCfg = ReleaseR7|Any CPU 69 | {979B3977-171C-4556-B258-67DCDB22EA50}.ReleaseR7|Any CPU.Build.0 = ReleaseR7|Any CPU 70 | {979B3977-171C-4556-B258-67DCDB22EA50}.ReleaseR8|Any CPU.ActiveCfg = ReleaseR8|Any CPU 71 | {979B3977-171C-4556-B258-67DCDB22EA50}.ReleaseR8|Any CPU.Build.0 = ReleaseR8|Any CPU 72 | {8038AC47-3427-417F-B332-5C690A527EAC}.DebugR7|Any CPU.ActiveCfg = DebugR7|Any CPU 73 | {8038AC47-3427-417F-B332-5C690A527EAC}.DebugR7|Any CPU.Build.0 = DebugR7|Any CPU 74 | {8038AC47-3427-417F-B332-5C690A527EAC}.DebugR8|Any CPU.ActiveCfg = DebugR8|Any CPU 75 | {8038AC47-3427-417F-B332-5C690A527EAC}.DebugR8|Any CPU.Build.0 = DebugR8|Any CPU 76 | {8038AC47-3427-417F-B332-5C690A527EAC}.ReleaseR7|Any CPU.ActiveCfg = ReleaseR7|Any CPU 77 | {8038AC47-3427-417F-B332-5C690A527EAC}.ReleaseR8|Any CPU.ActiveCfg = ReleaseR8|Any CPU 78 | {30CF2229-F954-42B2-A309-339276B7FAE5}.DebugR7|Any CPU.ActiveCfg = DebugR7|Any CPU 79 | {30CF2229-F954-42B2-A309-339276B7FAE5}.DebugR7|Any CPU.Build.0 = DebugR7|Any CPU 80 | {30CF2229-F954-42B2-A309-339276B7FAE5}.DebugR8|Any CPU.ActiveCfg = DebugR8|Any CPU 81 | {30CF2229-F954-42B2-A309-339276B7FAE5}.DebugR8|Any CPU.Build.0 = DebugR8|Any CPU 82 | {30CF2229-F954-42B2-A309-339276B7FAE5}.ReleaseR7|Any CPU.ActiveCfg = ReleaseR7|Any CPU 83 | {30CF2229-F954-42B2-A309-339276B7FAE5}.ReleaseR8|Any CPU.ActiveCfg = ReleaseR8|Any CPU 84 | {72892D62-9108-4903-851F-2FD850096605}.DebugR7|Any CPU.ActiveCfg = DebugR7|Any CPU 85 | {72892D62-9108-4903-851F-2FD850096605}.DebugR7|Any CPU.Build.0 = DebugR7|Any CPU 86 | {72892D62-9108-4903-851F-2FD850096605}.DebugR8|Any CPU.ActiveCfg = DebugR8|Any CPU 87 | {72892D62-9108-4903-851F-2FD850096605}.DebugR8|Any CPU.Build.0 = DebugR8|Any CPU 88 | {72892D62-9108-4903-851F-2FD850096605}.ReleaseR7|Any CPU.ActiveCfg = ReleaseR7|Any CPU 89 | {72892D62-9108-4903-851F-2FD850096605}.ReleaseR7|Any CPU.Build.0 = ReleaseR7|Any CPU 90 | {72892D62-9108-4903-851F-2FD850096605}.ReleaseR8|Any CPU.ActiveCfg = ReleaseR8|Any CPU 91 | {72892D62-9108-4903-851F-2FD850096605}.ReleaseR8|Any CPU.Build.0 = ReleaseR8|Any CPU 92 | {1868DD53-EF87-4564-A98B-C377DC38847B}.DebugR7|Any CPU.ActiveCfg = DebugR7|Any CPU 93 | {1868DD53-EF87-4564-A98B-C377DC38847B}.DebugR7|Any CPU.Build.0 = DebugR7|Any CPU 94 | {1868DD53-EF87-4564-A98B-C377DC38847B}.DebugR8|Any CPU.ActiveCfg = DebugR8|Any CPU 95 | {1868DD53-EF87-4564-A98B-C377DC38847B}.DebugR8|Any CPU.Build.0 = DebugR8|Any CPU 96 | {1868DD53-EF87-4564-A98B-C377DC38847B}.ReleaseR7|Any CPU.ActiveCfg = ReleaseR7|Any CPU 97 | {1868DD53-EF87-4564-A98B-C377DC38847B}.ReleaseR7|Any CPU.Build.0 = ReleaseR7|Any CPU 98 | {1868DD53-EF87-4564-A98B-C377DC38847B}.ReleaseR8|Any CPU.ActiveCfg = ReleaseR8|Any CPU 99 | {1868DD53-EF87-4564-A98B-C377DC38847B}.ReleaseR8|Any CPU.Build.0 = ReleaseR8|Any CPU 100 | EndGlobalSection 101 | GlobalSection(SolutionProperties) = preSolution 102 | HideSolutionNode = FALSE 103 | EndGlobalSection 104 | GlobalSection(NestedProjects) = preSolution 105 | {DE0D681B-7381-4C5A-8BC9-9468A49530DE} = {FAB810F0-1304-456B-AED3-6130C47D9E9E} 106 | {979B3977-171C-4556-B258-67DCDB22EA50} = {FAB810F0-1304-456B-AED3-6130C47D9E9E} 107 | {8038AC47-3427-417F-B332-5C690A527EAC} = {9A99AD89-394A-42BD-AE87-B50612D1F2DC} 108 | {30CF2229-F954-42B2-A309-339276B7FAE5} = {9A99AD89-394A-42BD-AE87-B50612D1F2DC} 109 | {72892D62-9108-4903-851F-2FD850096605} = {81FD4852-BD3E-4D54-85F4-1D38CBDB9EF5} 110 | {1868DD53-EF87-4564-A98B-C377DC38847B} = {81FD4852-BD3E-4D54-85F4-1D38CBDB9EF5} 111 | EndGlobalSection 112 | GlobalSection(ExtensibilityGlobals) = postSolution 113 | SolutionGuid = {19C0329D-CEE7-45E5-9852-A4F542A845CD} 114 | EndGlobalSection 115 | EndGlobal 116 | --------------------------------------------------------------------------------