Three parallel beziers

The answer is yes but the solution is not as simple as it might seem. The problem is that any curve that is “parallel and constant distance from a Bezier curve” (aka an offset curve) is not a Bezier curve so cannot be drawn using the bezier(...) function.

The solution is described here but as you can see it seems complicated.

Fortunately Processing provides the necessary functions that allow us to calculate points on the offset curve which can be used to draw the offset curve. This image shows 5 curves, the black curve is a Bezier curve and the 4 red curves are offset curves at -30, -15 ,15 and 30 pixels from the Bezier curve.

Although the red curves look like Bezier curves they are not.

Basically this sketch calculates the unit vector perpendicular to the Bezier curve and at a known position on the Bezier curve. This vector is multiplied by the offset and used to calculate the matching point on the offset curve. This is repeated many times along the length of the Bezier curve so that we can draw the offset curve.

// XY coordinate pairs for a cubic Bezier curve
float[] b0 = new float[] {340, 80, 40, 40, 360, 360, 60, 320};
// This array holds the distance of each offset curve from the Bezier curve
float[] offsets = new float[] {-30, -15, 15, 30};

void setup() {
  size(400, 400);
}

void draw() {
  background(220);
  drawBezier(b0, offsets, 200);
}

void drawBezier(final float[] bp, final float[] d, int steps) {
  stroke(0);
  strokeWeight(1);
  noFill();
  // Draw Bezier curve (black)
  bezier(bp[0], bp[1], bp[2], bp[3], bp[4], bp[5], bp[6], bp[7]); 
  // Draw offset curves (red)
  stroke(200, 0, 0);
  float prev_x = 0, prev_y = 0;
  for (int j = 0; j < d.length; j++) {
    for (int i = 0; i <= steps; i++) {
      float t = i / float(steps);
      float bx = bezierPoint(bp[0], bp[2], bp[4], bp[6], t);
      float by = bezierPoint(bp[1], bp[3], bp[5], bp[7], t);
      float tx = bezierTangent(bp[0], bp[2], bp[4], bp[6], t);
      float ty = bezierTangent(bp[1], bp[3], bp[5], bp[7], t);
      float a = atan2(ty, tx) - HALF_PI;
      if (i == 0) {
        prev_x = cos(a) * d[j] + bx;
        prev_y = sin(a) * d[j] + by;
      } else {
        float cx = cos(a) * d[j] + bx;
        float cy = sin(a) * d[j] + by;
        line(prev_x, prev_y, cx, cy);
        prev_x = cx;
        prev_y = cy;
      }
    }
  }
}
6 Likes