Bezier approximation of a circular arc, in Processing
22 March 2009 / code, reference
/*
Processing (http://www.processing.org, v.1.0.1) Java program for
Approximating a circular arc with a cubic Bezier curve.
Reasonably accurate for angles up to a quarter-circle or so.
The solution is taken from this PDF by Richard DeVeneza:
http://www.tinaja.com/glib/bezcirc2.pdf
linked from this excellent site by Don Lancaster:
http://www.tinaja.com/cubic01.asp
Note: written for clarity; not optimized!
*/
void setup(){
size(600,600);
}
//--------------------------
// Global variables:
// The true coordinates of the Bezier control points:
float px0,py0;
float px1,py1;
float px2,py2;
float px3,py3;
float radius = 200; // radius of the circular arc
float cx = 300; // center point of the circular arc
float cy = 300;
//--------------------------
void draw(){
background(230);
// Establish arc parameters.
// (Note: assert theta != TWO_PI)
float theta = radians(mouseX/3.0); // spread of the arc.
float startAngle = radians(mouseY/8.0); // as in arc()
float endAngle = startAngle + theta; // as in arc()
// Compute raw Bezier coordinates.
float x0 = cos(theta/2.0);
float y0 = sin(theta/2.0);
float x3 = x0;
float y3 = 0-y0;
float x1 = (4.0-x0)/3.0;
float y1 = ((1.0-x0)*(3.0-x0))/(3.0*y0); // y0 != 0...
float x2 = x1;
float y2 = 0-y1;
// Compute rotationally-offset Bezier coordinates, using:
// x' = cos(angle) * x - sin(angle) * y;
// y' = sin(angle) * x + cos(angle) * y;
float bezAng = startAngle + theta/2.0;
float cBezAng = cos(bezAng);
float sBezAng = sin(bezAng);
float rx0 = cBezAng * x0 - sBezAng * y0;
float ry0 = sBezAng * x0 + cBezAng * y0;
float rx1 = cBezAng * x1 - sBezAng * y1;
float ry1 = sBezAng * x1 + cBezAng * y1;
float rx2 = cBezAng * x2 - sBezAng * y2;
float ry2 = sBezAng * x2 + cBezAng * y2;
float rx3 = cBezAng * x3 - sBezAng * y3;
float ry3 = sBezAng * x3 + cBezAng * y3;
// Compute scaled and translated Bezier coordinates.
px0 = cx + radius*rx0;
py0 = cy + radius*ry0;
px1 = cx + radius*rx1;
py1 = cy + radius*ry1;
px2 = cx + radius*rx2;
py2 = cy + radius*ry2;
px3 = cx + radius*rx3;
py3 = cy + radius*ry3;
// Draw the Bezier control points.
stroke(0,0,0, 64);
fill (0,0,0, 64);
ellipse(px0,py0, 8,8);
ellipse(px1,py1, 8,8);
ellipse(px2,py2, 8,8);
ellipse(px3,py3, 8,8);
line (cx,cy, px0,py0);
line (px0,py0, px1,py1);
line (px1,py1, px2,py2);
line (px2,py2, px3,py3);
line (px3,py3, cx,cy);
//--------------------------
// BLUE IS THE "TRUE" CIRULAR ARC:
noFill();
stroke(0,0,180, 128);
arc(cx, cy, radius*2, radius*2, startAngle, endAngle);
//--------------------------
// RED IS THE BEZIER APPROXIMATION OF THE CIRCULAR ARC:
noFill();
stroke(255,0,0, 128);
bezier(px0,py0, px1,py1, px2,py2, px3,py3);
}
« Prev post: Art and Code recap!
» Next post: Criteria for a Music Department Head Search