How to close a PShape with 2 arcs and two lines

There are a few gotchas, so consult their reference pages carefully. Be careful about how you include the minimum number of points per curve-type points to get an effect, and lead and follow with the needed extra points – e.g. with a control points for curveVertex, and leading with a normal point for bezierVertex.

“The first and last points in a series of curveVertex() lines will be used to guide the beginning and end of a the curve.” curveVertex() / Reference / Processing.org

You can use either to approximate a circle, then use that to draw arcs. The control point math for the bezierVertex version can get a bit complex – for discussion see How to create circle with Bézier curves?. For curveVertex (Catmull-Rom splines) you really just need to find points on the circumference using the parametric equation for a circle.

Here is an example that draws an arc portion of a ring (doughnut). It draws a vertex, an arc of curveVertex, and a vertex. If you connect two of them running in different directions within the same beginShape/endShape (an inner arc and an outer arc) then you get a ring arc, and it can be closed and filled.

Notice it has the same subtle animation problems that arc has, and that the “resolution” setting is necessary to prevent distortion.

/**
 * Curve Vertex Arc Ring
 * Draw arc with curveVertex. Mouse changes angle, thickness. Key toggles points.
 * 2018-11-12 Jeremy Douglass - Processing 3.4
 * https://discourse.processing.org/t/how-to-close-a-pshape-with-2-arcs-and-two-lines/5287/12
 */
boolean seePoints;
void setup() {
  size(400, 200);
}

void draw() {
  background(192);
  // mouse-controlled angle
  float r = width / 4.0 - 20;
  float angle = mouseX/(float)width * TWO_PI;
  translate(width/4, height/2);
  // vertex arc ring
  beginShape();
  float r2 = r * mouseY/(float)height;
  curveVertexRing(0, 0, r, r2, 0, angle);
  endShape(CLOSE);
  // arc
  translate(width/2, 0);
  arc(0, 0, 2*r, 2*r, 0, angle, PIE);
}

void keyReleased() {
  seePoints = !seePoints;
}

void curveVertexRing(float cx, float cy, float r, float r2, float start, float stop) {
  curveVertexArc(cx, cy, r, start, stop);
  curveVertexArc(cx, cy, r2, stop, start);
}

void curveVertexArc(float cx, float cy, float r, float start, float stop) {
  float resolution = TWO_PI/32; // angle per curve point -- too few distorts
  float x, y;
  float a = start;
  int segments =  max(ceil(abs(stop-start)/resolution), 4);
  vertex(cx + r * cos(start), cy + r * sin(start));  
  float step = (stop-start)/(float)segments;
  for (int i=0; i<=segments; i++) {
    // define curve point with parametric equation for circle
    x = cx + r * cos(a);
    y = cy + r * sin(a);
    curveVertex(x, y);
    a += step;
    if (seePoints) ellipse(x, y, 10, 10); // inspect control points
  }
  vertex(cx + r * cos(stop), cy + r * sin(stop));
}

CurveVertexArcRing--screenshot

1 Like