Entry
Approximating elliptical arc
Jul 5th, 2000 10:00
Nathan Wallace, unknown unknown, Hans Nowak, Snippet 121, Robert Kern
"""
Packages: maths;graphics
"""
"""Approximating an elliptical arc with B‚zier curves.
The algorithm is an elliptical generalization of the formulae in
Jim Fitzsimmon's TeX tutorial <URL: http://www.tinaja.com/bezarc1.pdf>.
This incarnation was originally made by Robert Kern <kernr@ncifcrf.gov>
for Andy Robinson's piddlePDF back end."""
import math
def bezierArc(x1,y1, x2,y2, startAng=0, extent=90):
"""bezierArc(x1,y1, x2,y2, startAng=0, extent=90) --> List of Bézier
curve control points.
(x1, y1) and (x2, y2) are the corners of the enclosing rectangle such that
x1<x2 and y1<y2. The coordinate system has coordinates that increase to the
right and down. Angles, measured in degress, start with 0 to the right (the
positive X axis) and increase counter-clockwise. The arc extends from startAng
to startAng+extent. I.e. startAng=0 and extent=180 yields an openside-down
semi-circle.
The resulting coordinates are of the form (x1,y1, x2,y2, x3,y3, x4,y4) such that
the curve goes from (x1, y1) to (x4, y4) with (x2, y2) and (x3, y3) as their
respective Bézier control points."""
if math.abs(extent) <= 90:
arcList = [startAng]
fragAngle = float(extent)
Nfrag = 1
else:
arcList = []
Nfrag = int(math.ceil(math.abs(extent)/90.))
fragAngle = float(extent) / Nfrag
x_cen = (x1+x2)/2.
y_cen = (y1+y2)/2.
rx = (x2-x1)/2.
ry = (y2-y1)/2.
halfAng = fragAngle * math.pi / 360.
kappa = 4. / 3. * (1. - math.cos(halfAng)) / math.sin(halfAng)
pointList = []
for i in range(Nfrag):
theta0 = (startAng + i*fragAngle) * math.pi / 180.
theta1 = (startAng + (i+1)*fragAngle) *pi / 180.
pointList.append((x_cen + rx * math.cos(theta0),
y_cen - ry * math.sin(theta0),
x_cen + rx * (math.cos(theta0) - kappa * math.sin(theta0)),
y_cen - ry * (math.sin(theta0) + kappa * math.cos(theta0)),
x_cen + rx * (math.cos(theta1) + kappa * math.sin(theta1)),
y_cen - ry * (math.sin(theta1) - kappa * math.cos(theta1)),
x_cen + rx * math.cos(theta1),
y_cen - ry * math.sin(theta1)))
return pointList