{"id":469,"date":"2008-03-29T22:52:21","date_gmt":"2008-03-30T06:52:21","guid":{"rendered":"http:\/\/www.elbeno.com\/blog\/?p=469"},"modified":"2008-03-29T22:52:21","modified_gmt":"2008-03-30T06:52:21","slug":"approximating-elliptical-arcs-with-bezier-curves","status":"publish","type":"post","link":"https:\/\/www.elbeno.com\/blog\/?p=469","title":{"rendered":"Approximating elliptical arcs with B\u00c3\u00a9zier curves"},"content":{"rendered":"<p>In doing my modulation work with curves and ellipses, I extended the <a href=\"http:\/\/www.xach.com\/lisp\/vecto\/\">vecto<\/a> function for drawing an ellipse to enable an oriented ellipse. Lately it occurred to me that this didn&#8217;t go far enough in terms of functionality, and I began wondering about how to draw part of an elliptical arc.<\/p>\n<p>Vecto&#8217;s ellipse drawing function works by drawing the ellipse in quarters, with four cubic B\u00c3\u00a9zier curves. Each curve&#8217;s control points are calculated according to the radii and <i>kappa<\/i>, the constant that is 4(&radic;2 &#8211; 1)\/3, as <a href=\"http:\/\/www.whizkidtech.redprince.net\/bezier\/circle\/\">explained<\/a> by G. Adam Stanislav. This works fine if you are drawing quarters, halves, or complete ellipses (or circles of course), but what I wanted was a function like this:<\/p>\n<p>(defun approximate-elliptical-arc (cx cy a b theta eta1 eta2)<br \/>\n  &#8230;)<\/p>\n<p>With (cx, cy) being the centre, a and b being the radii, theta being the orientation, and eta1 and eta2 being the start and end angles specifying the arc. The return value would be a B\u00c3\u00a9zier curve, or a list of curves, depending on the required accuracy.<\/p>\n<p>So I did some research and found an <a href=\"http:\/\/www.spaceroots.org\/documents\/ellipse\/elliptical-arc.pdf\">interesting paper<\/a> by Luc Maisonobe on approximating such elliptical arcs with lines, quadratic and cubic B\u00c3\u00a9zier curves. The maths is straightforward, if rather heavy on the constants, and it was less than an hour&#8217;s work to code up the function. I now have functionality to draw arbitrary elliptical (or circular) arc segments.<\/p>\n<p>The interesting thing is that this method of approximating ellipses is not the same as G. Adam Stanislav&#8217;s method: to put it another way, when I compute a quarter-circle arc with a single B\u00c3\u00a9zier curve, the control points are not quite coincident with the <i>kappa<\/i>-method control points. The error in the circle approximation is still undetectable to the eye, but careful comparison of two large circles shows that the <i>kappa<\/i>-method one is slightly larger: the curves are slightly more &#8220;pushed out&#8221;.<\/p>\n<p>G. Adam writes: &#8220;It is my contention that we get the closest to a real circle if we draw the one curve with properties already discussed, and with the center point of the curve lying at the same point the center point of the circumference of a true quadrant of a circle would lie.&#8221; I would be interested to know if he has a proof behind this contention, and\/or an expression for the error in such a curve. The <a href=\"http:\/\/www.whizkidtech.redprince.net\/bezier\/circle\/kappa\/\">derivation of <i>kappa<\/i><\/a> is based around this idea that the midpoint of the curve should be coincident with the midpoint of the arc.<\/p>\n<p>G. Adam&#8217;s method seems accurate. But the Maisonobe method can be used to subdivide the arc, obtaining successively closer approximations to the true arc by using multiple B\u00c3\u00a9zier curves, and includes a method for calculating an upper bound on the error. This, together with the fact that it easily handles start and end angle specification of the arc, leads me to favour it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In doing my modulation work with curves and ellipses, I extended the vecto function for drawing an ellipse to enable an oriented ellipse. Lately it occurred to me that this didn&#8217;t go far enough in terms of functionality, and I began wondering about how to draw part of an elliptical&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13,11,8],"tags":[],"class_list":["post-469","post","type-post","status-publish","format-standard","hentry","category-lisp","category-maths","category-programming"],"_links":{"self":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/469","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=469"}],"version-history":[{"count":0,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/469\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=469"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=469"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=469"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}