Click or drag to resize

Simple Mathematics (VB)

This article contains a brief example of a component that deals with some simple mathematics and multiple input and output parameters. We'll discuss parameter order, legacy support for changing component layouts and default values for input parameters. We will not be dealing with any of the basics of component development. You should have read the My First Component topic before starting this one.

For this component we'll bundle the Sine, Cosine and Tangent trigonometry functions while allowing inputs to be specified in either Radians or Degrees. We'll need to define two input parameter (one of which will have a default value) and three output parameters.

Before you start with this topic, create a new class that derives from GH_Component, as outlined in the My First Component topic.

Input parameters

This component will require two input parameters, one of which has a default value. We'll need to register these parameters inside the RegisterInputParams subroutine:

VB
...
Protected Overrides Sub RegisterInputParams(ByVal pManager As GH_Component.GH_InputParamManager)
  pManager.AddNumberParameter("Angle", "A", "The angle to measure", GH_ParamAccess.item)
  pManager.AddBooleanParameter("Radians", "R", "Work in Radians", GH_ParamAccess.item, True) 'The default value is 'True'
End Sub
...
The first parameter is of type Number meaning it accepts floating point values. It has a name, abbreviation, description and access level defined. The second parameter is of type Boolean and it will accept True and False values. The pManager object allows us to specify a single default value for many parameter types. You must always assign the correct access level to every input and output parameter.

The order in which we register the parameters is also the order in which they'll appear on the component. We should not change the order (or the types, or the number) of the parameters once the Component has been released to the world. Every Grasshopper file that was saved with one of our components will expect to be deserialized by the exact same component layout. If you add an additional parameter to an component and someone tries to open a file which was saved while an older version of that component, it will fail to deserialize as the data in the file no longer matches the new layout. An exception will be thrown and Grasshopper will short circuit that particular instance. The entire component and all connections to it will be missing when the file is eventually displayed to the user.

If you must change the parameter layout of a component, you should create a completely new GH_Component class with a different ComponentGuid, while maintaining the old Component type for legacy file purposes. You can hide Components from the Grasshopper GUI by overriding the Exposure Property of the GH_Component class and changing the return value to GH_Exposure.hidden:

VB
Public Overrides ReadOnly Property Exposure() As Grasshopper.Kernel.GH_Exposure
  Get
    Return GH_Exposure.hidden
  End Get
End Property

Output parameters

Our component will also need three output parameters. Output parameters differ from input parameters in that they have much fewer options. Users cannot add expressions to them, there are no default values, they don't support persistent data. Outputs are always cleared when the component expires, and they are slowly filled out from within the SolveInstance() routine.

VB
...
Protected Overrides Sub RegisterOutputParams(ByVal pManager As GH_Component.GH_OutputParamManager)
  pManager.AddNumberParameter("Sin", "sin", "The sine of the Angle.", GH_ParamAccess.item)
  pManager.AddNumberParameter("Cos", "cos", "The cosine of the Angle.", GH_ParamAccess.item)
  pManager.AddNumberParameter("Tan", "tan", "The tangent of the Angle.", GH_ParamAccess.item)
End Sub
...

SolveInstance

The SolveInstance implementation for this component is hardly any more complicated than it was for My First Component. The only difference is that we now have more than one parameter on each side.

VB
...
Protected Overrides Sub SolveInstance(ByVal DA As Grasshopper.Kernel.IGH_DataAccess)
  'Declare variables to contain all inputs.
  'We can assign some initial values that are either sensible or indicative.
  Dim angle As Double = Double.NaN
  Dim radians As Boolean = False

  'Use the DA object to retrieve the data inside the input parameters.
  'If the retrieval fails (for example if there is no data) we need to abort.
  If (Not DA.GetData(0, angle)) Then Return
  If (Not DA.GetData(1, radians)) Then Return

  'If the angle value is not a valid number, we should abort.
  If (Not Rhino.RhinoMath.IsValidDouble(angle)) Then Return

  'If the user wants to work in degrees rather than radians, 
  'we assume that angle is defined in degrees. 
  'We need to convert it into Radians again.
  If (Not radians) Then
    angle = Rhino.RhinoMath.ToRadians(angle)
  End If

  'Now we are ready to assign the outputs via the DA object.
  'Since the Sin(), Cos() and Tan() never fail, we might as well 
  'combine them with the assignment.
  DA.SetData(0, Math.Sin(angle))
  DA.SetData(1, Math.Cos(angle))
  DA.SetData(2, Math.Tan(angle))
End Sub
...