Approximating Circles with Bezier Curves 2


Were’s the code for addcurve. Note that there’s a new parameter “first” which is true if the segment being added is the very first segment of the circle. It’s pretty obvious how to use it, and I won’t go back and show you how to back-fit it.

One important thing, however, is that there was a bit of instability in the “chop 90 dgerees off” algorithm. The fix is:


// are we in the first quadrant?
if (acos >= -1e-6 && acos90 >= 0) {
	// a fudge factor. The algorithm is ok with angles slightly
	// more than 90, but not with negative ones.
	break;
}

Also, somehow I managed to mix up the two control points during the final rotation into place. not sure how, but the fix seems to work. The result is damn close to the java “Arc2D” result. One pixel off, at most.


private static void arc_addcurve(GeneralPath pp, Point2D.Double c, double r, Point2D.Double p1hat,
		Point2D.Double p2hat, boolean first) {
	// find midpoint

	midp2.setLocation((p1hat.x + p2hat.x) / 2, (p1hat.y + p2hat.y) / 2);
	hat(midp2, midp2hat);

	// construct vector 90 degress clockwise from midp.

	midp290hat.x = -midp2hat.y;
	midp290hat.y = midp2hat.x;

	// projection of p1hat onto midphat gives us cos
	final double cosTheta = p1hat.x * midp2hat.x + p1hat.y * midp2hat.y;

	// projection of p1hat onto midp90hat gives us -sin
	final double sinTheta = -(p1hat.x * midp290hat.x + p1hat.y * midp290hat.y);

	// at which point, we apply the solution directly out of wikipedia
	final double x2_1 = (4 - cosTheta) / 3;
	final double y2_1 = (1 - cosTheta) * (3 - cosTheta) / 3 / sinTheta;

	final double x3_1 = x2_1;
	final double y3_1 = -y2_1;

	// rotate by midphat to get the final control point vectors
	// I am not at all certain how I managed to scramble this,
	// but it seems to work now.

	final double x3 = x2_1 * midp2hat.x - y2_1 * midp2hat.y;
	final double y3 = y2_1 * midp2hat.x + x2_1 * midp2hat.y;

	final double x2 = x3_1 * midp2hat.x - y3_1 * midp2hat.y;
	final double y2 = y3_1 * midp2hat.x + x3_1 * midp2hat.y;

	// and draw the cubic!
	if (first) {
		pp.lineTo(c.x + p1hat.x * r, c.y + p1hat.y * r);
	}
	
	pp.curveTo(c.x + x2 * r, c.y + y2 * r, //
			c.x + x3 * r, c.y + y3 * r, //
			c.x + p2hat.x * r, c.y + p2hat.y * r);
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: