Simple Geometry (VB) |
This article shows how to use some of the simpler geometry types and classes in the RhinoCommon and Grasshopper SDK. We'll discuss how to deal with different access levels of input data and invalid Structs vs. invalid and null Classes. You should have read the My First Component and Simple Mathematics topics before starting this one.
This component will perform a simple Circle|Line Split operation. We'll retrieve a single Circle and a single Line input, make sure the data is valid, project the line onto the circle plane, determine whether or not the Split operation is valid and then output the two arcs on either side of the slicing line.
Before you start with this topic, create a new class that derives from GH_Component, as outlined in the My First Component topic.
This part of the component is very similar to the Simple Mathematics topic. Except this time there will be no default values.
... Protected Overrides Sub RegisterInputParams(ByVal pManager As GH_Component.GH_InputParamManager) pManager.AddCircleParameter("Circle", "C", "The circle to slice", GH_ParamAccess.item) pManager.AddLineParameter("Line", "L", "Slicing line", GH_ParamAccess.item) End Sub ...
The second parameter is of type Param_Line and it works very similar to the Param_Circle type discussed above.
Our component will output two arcs on success, or nulls on failure.
... Protected Overrides Sub RegisterOutputParams(ByVal pManager As GH_Component.GH_OutputParamManager) pManager.AddArcParameter("Arc A", "A", "First Split result.", GH_ParamAccess.item) pManager.AddArcParameter("Arc B", "B", "Second Split result.", GH_ParamAccess.item) End Sub ...
The SolveInstance() implementation for this component is responsible for the following steps:
Item 2 and 9 however can be approached from different directions. First I'll show you the recommended approach and then we'll have a look at the alternatives:
... Protected Overrides Sub SolveInstance(ByVal DA As Grasshopper.Kernel.IGH_DataAccess) '1. Declare placeholder variables and assign initial invalid data. ' This way, if the input parameters fail to supply valid data, we know when to abort. Dim circle As Rhino.Geometry.Circle = Rhino.Geometry.Circle.Unset Dim line As Rhino.Geometry.Line = Rhino.Geometry.Line.Unset '2. Retrieve input data. If (Not DA.GetData(0, circle)) Then Return If (Not DA.GetData(1, line)) Then Return '3. Abort on invalid inputs. If (Not circle.IsValid) Then Return If (Not line.IsValid) Then Return '4. Project line segment onto circle plane. line.Transform(Rhino.Geometry.Transform.PlanarProjection(circle.Plane)) '5. Test projected segment for validity. If (line.Length < Rhino.RhinoMath.ZeroTolerance) Then AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Line could not be projected onto the Circle plane") Return End If '6. Solve intersections and 7. Abort if there are less than two intersections. Dim t1 As Double Dim p1 As Rhino.Geometry.Point3d Dim t2 As Double Dim p2 As Rhino.Geometry.Point3d Select Case Rhino.Geometry.Intersect.Intersection.LineCircle(line, circle, t1, p1, t2, p2) Case Rhino.Geometry.Intersect.LineCircleIntersection.None AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "No intersections were found") Return Case Rhino.Geometry.Intersect.LineCircleIntersection.Single AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Only a single intersection was found") Return End Select '8. Create slicing arcs. Dim ct As Double circle.ClosestParameterTo(p1, ct) Dim tan As Rhino.Geometry.Vector3d = circle.TangentAt(ct) '9. Assign output arcs. DA.SetData(0, New Rhino.Geometry.Arc(p1, tan, p2)) DA.SetData(1, New Rhino.Geometry.Arc(p1, -tan, p2)) End Sub ...
As I mentioned before, the first input parameter is of type Param_Circle and it contains data of type GH_Circle. But when we're accessing the parameter via the DA.GetData(0, circle) method, we're using Rhino.Geometry.Circle instead of Grasshopper.Kernel.Types.GH_Circle. The DA.GetData() method is capable of converting data from the intrinsic parameter type into requested types, provided the conversion makes sense. GH_Circle to Rhino.Geometry.Circle is a perfectly valid conversion, GH_Circle to Rhino.Geometry.Transform would not be.
The Grasshopper Component SDK has been designed on the premise that the bulk of all Components that operate on data only care about the data itself, not how it is wrapped up inside the Grasshopper data structures. The conversion routines that translate GH_Circle data into Rhino.Geometry.Circle data (and obviously also GH_Number into System.Double, and GH_Colour into System.Drawing.Color etc.), have been highly optimised and should be used in almost all circumstances.
If however you feel the need to get access to the GH_Circle data directly, you can retrieve that instance in the same fashion:
... Dim circle As Grasshopper.Kernel.Data.GH_Circle = Nothing If (Not DA.GetData(0, circle)) Then Return ...
Similarly, you are allowed to store output data in different formats as well. Instead of:
DA.SetData(0, New Rhino.Geometry.Arc(p1, tan, p2))
Dim gh_arc As New Grasshopper.Kernel.Types.GH_Arc(New Rhino.Geometry.Arc(p1, tan, p2)) DA.SetData(0, gh_arc)