Grasshopper Scripting 107
Examples (I)
In the previous lesson we described and used the concept of nested loop, and used it with basic types and Points. In this lesson we will cover specific problems that cannot be solved directly with Grasshopper components just because they rely on complex arrangement where a value has to be calculated upon a previous one.
Subdividing a Curve
Let’s get down to a useful example of loops and interation in GH. We are going to build a component that subdivides a curve into segments but not in an homogeneous way but adaptive.

This means our polyline will have more segments and points in zones with higher curvature. We will measure the gap between the straight segment we add and the curve as the quality of our subdivision:
- Take the end points of the curve, insert them in order in a list.
- Take the first point in the list and it’s neighbor.
- Build a line with those two points.
- Find the mid point of the line.
- If the distance from the midpoint to the curve is larger than, say, 1/100th of the curve’s length…
- Project the midpoint to the curve and insert it in the point list in the right place.
- Move to the next point in the list. If you reach the last one, start again with step 2.
- Keep doing this until you run through all the list once without adding any new point. Then finish.
Let’s see the code implementation:
private void RunScript(Curve x, double y, ref object A)
{
//To find the Curve's endpoints we need to evaluate the extremes of its domain.
Point3d startPoint = x.PointAt(x.Domain.Min);
//retrieve Curve's start point
Point3d endPoint = x.PointAt(x.Domain.Max);
//retrieve Curve's end point
//declare a point for the middle point
Point3d mPt;
//set the tolerance to a fraction of the Curve's length
double tolerance = x.GetLength() / y;
//Print some info to the user
Print("Tolerance will be {0}", tolerance.ToString());
//initialize a flag to keep the loop running
bool keepOn = true;
//initialize a counter for the number of iterations we perform
int c = 0;
//declare a list to hold our points
List<Point3d> ptList = new List<Point3d>();
//add the start point
ptList.Add(startPoint);
//if the curve is closed we might want to add some more points to ensure we run the subdivison
if(x.IsClosed)
{
Point3d p1 = x.PointAt((x.Domain.Max - x.Domain.Min) * 0.25 + x.Domain.Min);
Point3d p2 = x.PointAt((x.Domain.Max - x.Domain.Min) * 0.5 + x.Domain.Min);
Point3d p3 = x.PointAt((x.Domain.Max - x.Domain.Min) * 0.75 + x.Domain.Min);
ptList.Add(p1);
ptList.Add(p2);
ptList.Add(p3);
}
//add the endpoint
ptList.Add(endPoint);
//declare a double to hold a parameter
double t = 0;
//declare a double to hold a distance
double d = 0;
//this loop will keep running until keepOn is false or we reach 100 iterations
while ((keepOn) && (c < 100))
{
//deactivate the loop by default, we will activate it later if we add a point
keepOn = false;
//iterate through the list of points
for (int i = 0; i < ptList.Count - 1; i++)
{
//calculate the midpoint using a function
mPt = midPt(ptList[i], ptList[i + 1]);
//try to find the closest point to mPt on the curve, the function modifies the t number with the parameter
//on x for the closest point and returns a true if successful
bool flag = x.ClosestPoint(mPt, out t);
//if the closest point is found
if (flag){
//build a 3D point on x at the t parameter
Point3d cPt = x.PointAt(t);
//retrieve the distance between the closest point and the mid point
d = cPt.DistanceTo(mPt);
//if the distance is bigger than our tolerance
if (d > tolerance){
//insert the point
ptList.Insert(i + 1, cPt);
//re-activate the loop, as we have added a point
keepOn = true;
//increase the count to skip the recently added point
i++;
}//end of d>tolerance if
}//end of flag if
}//end of list loop
//increase the counter and start again
c++;
}
//at the end, output A and print some info
A = ptList;
Print("Solution reached in {0} steps", c + 1);
}
//<Custom additional code>
//this function returns the midpoint of two given points
Point3d midPt(Point3d a, Point3d b){
return (a + b) / 2;
}
Koch snowflake:
A beautiful example, the Koch snowflake, is an example of a recursive system that can be described with very simple rules:
- Take a polygon (a regular triangle in the most famous case)
- Take the first side of the polygon.
- Divide the side in three parts and build a regular triangle with the edge coincident with the middle segment.
- Replace the side with the newly created 4 sides.
- Move to the next side.
- Repeat.
Let’s see a simple code implementation:
private void RunScript(double x, int y, ref object A)
{
//declare a list for our points
List<Point3d> ptList = new List<Point3d> ();
//create the first 4 points of the triangle, 4 because we want it to be a closed polyline
ptList.Add(new Point3d(0, x, 0));
ptList.Add(new Point3d(-x * Math.Cos(Math.PI / 6), -x * Math.Sin(Math.PI / 6), 0));
ptList.Add(new Point3d(x * Math.Cos(Math.PI / 6), -x * Math.Sin(Math.PI / 6), 0));
ptList.Add(new Point3d(0, x, 0));
//declare a point for each of the 3 points we'll add to each side
Point3d Pt0, Pt1, Pt2;
//initialize a counter for the number of iterations we perform
int c = 0;
//this loop will keep running until the lists becomes too big or we reach the number of iterations
while ((ptList.Count < 2000) && (c < y))
{
//iterate through the list of points
for (int i = 0; i < ptList.Count - 1; i++)
{
//calculate each of the three points using functions
Pt0 = PtA(ptList[i], ptList[i + 1]);
Pt1 = PtB(ptList[i], ptList[i + 1]);
Pt2 = PtC(ptList[i], ptList[i + 1]);
//add the points to the list in the right place
ptList.Insert(i + 1, Pt0);
ptList.Insert(i + 2, Pt1);
ptList.Insert(i + 3, Pt2);
//shift the iterator to skip the newly added points
i += 3;
}//end of list loop
//increase the counter and start again
c++;
}
//at the end, output A as a polyline and print some info
A = new Polyline(ptList);
Print("Solution reached in {0} steps with {1} vertices", c + 1, ptList.Count);
}
//<Custom additional code>
//this function returns the a point at one third of two given points
Point3d PtA(Point3d a, Point3d b){
return a + ((b - a) / 3);
}
//this function returns the tip point in the sierpinski division
Point3d PtB(Point3d a, Point3d b){
Point3d p1 = a + ((b - a) / 3);
Point3d p2 = a + (2 * (b - a) / 3);
//declare a transformation where we rotate the second-third point 60º around the first-third
Transform trans = Transform.Rotation(-Math.PI / 3, Vector3d.ZAxis, p1);
//apply the transformation
p2.Transform(trans);
return p2;
}
//this function returns the a point at one third of two given points
Point3d PtC(Point3d a, Point3d b){
return a + (2 * (b - a) / 3);
}
Nice, isn’t it?
Download here these definitions (GH 0.9.0014)[:]
