Mastering Curve Offset Direction in Grasshopper

June 1, 2024
6498e540cb755b0ce3a4e624_Offset Curve Diagram-01.png

Offsetting curves in the desired direction can be tricky, often resulting in overly complex definitions and makeshift solutions. This was one of the biggest pain points in my Grasshopper definitions, so I decided to delve into the logic underlying the offset component. Here I'll explain what I found and present a step-by-step approach to consistently get the desired output.


There are only three factors that matter to the Offset Direction:

  1. Z-Axis of the Offset Plane
  2. Curve direction
  3. Positive or Negative Distance Value

If you can control each of these variables, you'll get the desired Offset Direction. Most likely you have a consistent Offset Plane and Distance Value. Almost all offsetting issues can be solved by constraining the Curve Direction (Variable 2). Flip your curves and make sure that they always face the same direction. Using the "Flip Curve" Component with a guide curve input helps immensely. We will review how the Offset Direction is determined then a few different ways to control Curve Direction.

Offset Direction Vector Math

Here's the core principle:
The positive offset direction at any point along the curve equals the cross product of the Curve Tangent Vector and the Offset Plane Z-Axis

The graphic below helps to visualize this statement. The offset plane is represented to the left of the curve by three axes: X (red), Y (Green), Z (Blue). The curve, in the same image, shows three vectors superimposed: the Z-Axis of the offset plane (Blue), the tangent vector of the curve at that point (Light Blue), and the positive offset direction of the curve (Orange). These vectors are further diagrammed in the second image.



If you flip any of the three core variables, the curve offset direction will change (Flipping the Z-Axis, the Curve Direction, or the distance value from positive to negative). You can carry out these experiments yourself by following the video and script links above. So how can we use this information to get consistent results in our definitions?

Using Curve Offset Step-by-Step

  1. Choose your Offset Plane. No need to pay particular attention to the Z-Axis direction.
  2. Constrain the direction of your Offset Curve
  3. Choose your distance value. If the curve is being offset in the wrong direction, flip your value from positive to negative

Constraining your Curve Direction

There are a couple approaches to this depending on where your curve has originated from and whether it's open or closed. As I've previously mentioned, the Flip Curve component will be your friend here.

The first approach is to control the direction the curve is drawn and maintain that direction through your definition. Whenever you perform an operation that could change the curve direction, you can use your original curve as the "Guide" input for the "Flip Curve" Component and restore the direction

The second approach is to flip the curve in the correct direction only at the end for the Offset function. I've written a few clusters to help with that task.

For open curves, I use my user cluster "Flip Axis" to flip my curve in some general input vector direction. The logic is a little hacky but has surprisingly been one of my most robust components across many of my definitions. Detailed further in the video. Link at the bottom\

For closed curves, I follow a different procedure which works in quite a few situations.

  1. Take the area of the curve
  2. Draw a circle at the centroid using the default Grasshopper component
  3. Flip the curve using your new circle as a guide curve

This only works when the centroid is inside the closed curve. In cases where the centroid doesn't fall within the closed curve, you could write some different logic for step one. I have some alternative approaches for these outlier cases which I would be open to sharing if there is interest.

Resource Links

(Insert Link)

ZIP file with:
- Flip Axis User Cluster
- Offset Curve Visualizer (Human and Wombat Plug-Ins Required)