-
Notifications
You must be signed in to change notification settings - Fork 15
The BHoM Toolkit
Before reading this page, please check out:
This page explains how to create what we call a Toolkit.
A Toolkit is a Visual Studio solution that can contain one or more of the following:
- A BHoM_Adapter project, that allows to implement the connection with an external software.
- A BHoM_Engine project, that should contain the Engine methods specific to your Toolkit.
- A BHoM_oM project, that should contain any oM class (types) specific to your Toolkit.
In order to implement a new Toolkit, we prepared a Toolkit Template that does all the scaffolding for you: create an new Toolkit using the BHoM Toolkit Template.
Once you have created the Visual Studio solution using the template, you only need to implement the Adapter, and any Engine method and/or oM class that the Adapter should be using.
Let's get started!
This will install the Template in the system and it is required only once per machine.
Take SoftwareName_Toolkit.zip from the documentation
repo (documentation\templates\Toolkit template
) and copy it over to your Visual Studio ProjectTemplates
folder, generally in: C:\userName\Documents\Visual Studio 20xx\Templates\ProjectTemplates
Reboot Visual Studio.
-
Open Visual Studio. Do File --> New Project and search for "BHoM". Select the template "BHoM Toolkit Template".
-
If Visual Studio displays the checkbox "Place solution and project in the same directory" (VS version 2019 onwards), select it:
(For all other VS versions, just make sure that the checkbox "Create directory for solution" is ticked))
-
Specify your "SoftwareName" as the name of the solution. PascalCase, no spaces.
-
As parent root folder, specify the folder where you keep all other BHoM repos (generally, your GitHub folder
C:\Users\userName\GitHub\
). -
Confirm to create the new Toolkit solution.
This will result in a folder under your GitHub folder, such as ...\GitHub\SoftwareName
, with the template code inside, and the solution will open in Visual Studio.
Once the solution is created:
-
Close Visual Studio.
-
(Applies only if you couldn't do step 1. "Place solution and project in the same directory")
Go in the repo folder, which will be called "SoftwareName". It will contain only the solution file "SoftwareName.sln" and another folder "SoftwareName".
Enter in this "SoftwareName" folder, take all the folders and files and move them one folder up, so they sit together with the .sln file.
Delete the resulting empty folder "SoftwareName".
-
Rename the solution name and the folder name:
7.1. Add "_Toolkit" to the solution name
7.2. Add "_Toolkit" to the toolkit containing folder name.
-
Open the solution again.
If you could do step 1. "Place solution and project in the same directory", everything will be working and you are good to go.
Otherwise, if you couldn't do step 1, you will get "Project loading errors" due to the folder renaming of step 7. To correct:
In Solution Explorer, right click each project and do "Remove". Then right-click on the Solution name and do "Add Existing Project". Browse and select the
SoftwareName_Adapter
,SoftwareName_Engine
andSoftwareName_oM
projects in their new location.
The template creates the correct file names, class names and namespaces to be used for you. To get started there are four files to have a first look at:
Main file for the adapter class. Here you will have any applicable constructors (could be creating an adapter from a file name for example, or any other applicable). The will also be the place to store any com-object or similar if that exist in the softwares api as a local field.
Creation of any object should be done in this file. some methods to get you started for creating Bars have been added in the template. If any conversion of object from BHoM-type to SoftwareName_Type can be done without any com-calls being made it is recomended to use the To_SoftwareNme to do the conversion, otherwhise it should be done here. Any comcalls sending objects to the software should be done from this file.
Main file for reading out objects from the software. Example methods in place for reading out bar as well as dependant properties. As for create, if conversion can be done without any com calls, it is best practice to do this the the SoftwareName _Engine in the ToBHoM.cs file
Contains a method for returning a free index that can be used in the creation process. Important method to implement to get pushing of dependant properties working correctly. Some more info given in the template. For example see: GSA Next Index and Add link to robot file.
The BHoMAdapter has two abstract method needed to be implemented by each adapter:
- Create
- Read
As the name suggests this is the method responsible for creating the objects in the software. The methods for creating objects should sit in the .cs file called Create in the CRUD folder and be part of the same partial class as the main adapter as well as under the same namespace:
namespace BH.Adapter.GSA
{
public partial class GSAAdapter
{
protected override bool Create<T>(IEnumerable<T> objects, bool replaceAll = false)
...
}
}
The create process generally consists of some conversion from BHoM to the object model of the specific software and a Com-call using the software's API.
If no com calls are necessary for the conversion, best practice is to do this conversion in the Engine project as extension methods called ToSoftwareName
in the public static class convert.
If com calls are required for the conversion, the conversion should generally be done in a create method for the specific type.
See the GSA_Toolkit for an example of the former and the Robot_Toolkit for an example of the latter.
The read method is responsible for returning all objects of an specific type. The methods for reading objects should sit in the .cs file called Read in the CRUD folder and be part of the same partial class as the main adapter as well as under the same namespace:
namespace BH.Adapter.GSA
{
public partial class GSAAdapter
{
protected override IEnumerable<IBHoMObject> Read(Type type, IList indices)
...
}
}
The general implementation for this is to use the overrided read method as a dispatcher depending on the type that then calls the correct read method depending on the requested type. See GSA_Toolkit and Robot_Toolkit
A lot of functionality for Pushing as well as Pulling objects from a software has been implemented as helper methods in the BHoMAdapter base class. Some functionality implemented that can be utilised are:
- Merging objects deemed to be the same
- Merging incoming objects with objects already existing in the model
- Pushing of dependant objects
- Applying an software specific 'id' to the objects being pushed
To utilise these methods some additional methods will need to be implemented as well as some settings done. After all settings have been gone through one by one, some general code snippets that could be copied will be presented lower down this page.
An example of pushing of dependant objects would be pushing bars into an analysis package. To be able to create a bar one generally first need to create nodes as well as section properties. To get the BHoMAdapter to do this for you, one setting in the config needs to be set and one method needs to be implemented.
First the one need to set the config file (which is generally done in the constructor):
Config.SeparateProperties = true;
Then the following method needs to be implemented:
protected override List<Type> DependencyTypes<T>()
For the example case of the bar, where we want to first push nodes and section properties this could be implemented as (a slightly more general implementation for several types will be given lower down):
namespace BH.Adapter.GSA
{
public partial class GSAAdapter
{
/***************************************************/
/**** BHoM Adapter Interface ****/
/***************************************************/
protected override List<Type> DependencyTypes<T>()
{
Type type = typeof(T);
if(type = typeof(Bar)
return new List<Type>(){typeof(ISectionProperty), typeof(Node)};
}
}
}
This code should sit in the .cs file called DependencyTypes and be placed under the Types folder. For an example file that will work for most structural adapters the following file from the gsa toolkit can be copied over:
The BHoMAdapter is if set up to do so, making use of IEqualityComparers for merging of both incoming objects deemed the same as well as merging incoming objects with objects already in the model. Example of a couple of EqualityComparers have already been implemented:
To make use of these comparers and get the BHoMAdapter to merge for example nodes that are in the same position one need to make sure two settings in the Config are set:
Config.MergeWithComparer = true;
Config.ProcessInMemory = false;
On top of this You will need to override the method called Comparer<T>()
. For the example of merging nodes based on the position an implementation of this method could look like:
namespace BH.Adapter.GSA
{
public partial class GSAAdapter
{
/***************************************************/
/**** BHoM Adapter Interface ****/
/***************************************************/
protected override IEqualityComparer<T> Comparer<T>()
{
Type type = typeof(T);
if (type == typeof(Node))
return (IEqualityComparer<T>)new BH.Engine.Structure.NodeDistanceComparer(3); //Create a node distance comparer checking down to 3 decimal places
else
return EqualityComparer<T>.Default;
}
}
}
This should sit in the .cs file called Comparer.cs under the folder Types. For an implementation of this that would work as a starting point for most structural adapters please see this.
If merging has been implemented according to the above, the method called UpdateObejcts will be called for any objects deemed to already exist in the model. The standard implementation for this is to delete the existing ones and the create the new ones. If this does not work for the software you are implementing this method can be overridden.
The adapter has a mechanism in place to apply an software specific Id to the objects being pushed.
- The name of the visual studio solution and also the repository should be 'SoftwareName'_Toolkit.
- For the general case this solution will contain one or two projects:
- 'SoftwareName'_Adapter - Main project that will contain all methods for communication with the software.
- 'SoftwareName'_Engine - Optional project to host helper methods not requiring any connection with the application. Could be thing as converters and queries to get out specific information required for the software.
The _Adapter project should have the following folder and file structure (Example from the GSA_Adapter):
All files in this project should be part of a partial class called 'SoftwareName'Adapter. The main file .cs in the project called the same thing should be inheriting from the
BHoMAdapter
. The namespace used should beBH.Adapter.'SoftwareName'
(Example from gsa adapter):namespace BH.Adapter.GSA { public partial class GSAAdapter : BHoMAdapter { //Basic code for the adapter constructor, local fields and properties in this file } }The engine project should follow the guidlines outlined here: the Engine
Namespace for this repo should be
BH.Engine.'SoftwareName'
-
Introduction to the BHoM:
What is the BHoM for?
Structure of the BHoM
Technical Philosophy of the BHoM -
Getting Started:
Installing the BHoM
Using the BHoM
Submitting an Issue
Getting started for developers -
Use GitHub & Visual Studio:
Using the SCRUM Board
Resolving an Issue
Avoiding Conflicts
Creating a new Repository
Using Visual Studio
Using Visual Studio Code -
Contribute:
The oM
The Engine
The Adapter
The Toolkit
The UI
The Tests -
Guidelines:
Unit convention
Geometry
BHoM_Engine Classes
The IImmutable Interface
Handling Exceptional Events
BHoM Structural Conventions
BHoM View Quality Conventions
Code Versioning
Wiki Style
Coding Style
Null Handling
Code Attributes
Creating Icons
Changelog
Releases and Versioning
Open Sourcing Procedure
Dataset guidelines -
Foundational Interfaces:
IElement Required Extension Methods -
Continuous Integration:
Introduction
Check-PR-Builds
Check-Core
Check-Installer -
Code Compliance:
Compliance -
Further Reading:
FAQ
Structural Adapters
Mongo_Toolkit
Socket_Toolkit