-
-
Save zeffii/e95497b28170ec70d4bb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from math import sqrt, cos, sin, acos, degrees, radians, pi | |
# public domain from https://github.com/regebro/svg.path/blob/master/src/svg/path/path.py | |
# it's pretty cool, but it seems taming the boundary conditions isn't easy | |
class Arc(object): | |
def __init__(self, start, radius, rotation, arc, sweep, end): | |
"""radius is complex, rotation is in degrees, | |
large and sweep are 1 or 0 (True/False also work)""" | |
self.start = start | |
self.radius = radius | |
self.rotation = rotation | |
self.arc = bool(arc) | |
self.sweep = bool(sweep) | |
self.end = end | |
self._parameterize() | |
def __repr__(self): | |
return '<Arc start=%s radius=%s rotation=%s arc=%s sweep=%s end=%s>' % ( | |
self.start, self.radius, self.rotation, self.arc, self.sweep, self.end) | |
def __eq__(self, other): | |
if not isinstance(other, Arc): | |
return NotImplemented | |
return self.start == other.start and self.end == other.end and \ | |
self.radius == other.radius and self.rotation == other.rotation and\ | |
self.arc == other.arc and self.sweep == other.sweep | |
def __ne__(self, other): | |
if not isinstance(other, Arc): | |
return NotImplemented | |
return not self == other | |
def _parameterize(self): | |
# Conversion from endpoint to center parameterization | |
# http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes | |
cosr = cos(radians(self.rotation)) | |
sinr = sin(radians(self.rotation)) | |
dx = (self.start.real - self.end.real) / 2 | |
dy = (self.start.imag - self.end.imag) / 2 | |
x1prim = cosr * dx + sinr * dy | |
x1prim_sq = x1prim * x1prim | |
y1prim = -sinr * dx + cosr * dy | |
y1prim_sq = y1prim * y1prim | |
rx = self.radius.real | |
rx_sq = rx * rx | |
ry = self.radius.imag | |
ry_sq = ry * ry | |
# Correct out of range radii | |
radius_check = (x1prim_sq / rx_sq) + (y1prim_sq / ry_sq) | |
if radius_check > 1: | |
rx *= sqrt(radius_check) | |
ry *= sqrt(radius_check) | |
rx_sq = rx * rx | |
ry_sq = ry * ry | |
t1 = rx_sq * y1prim_sq | |
t2 = ry_sq * x1prim_sq | |
c = sqrt(abs((rx_sq * ry_sq - t1 - t2) / (t1 + t2))) | |
if self.arc == self.sweep: | |
c = -c | |
cxprim = c * rx * y1prim / ry | |
cyprim = -c * ry * x1prim / rx | |
self.center = complex((cosr * cxprim - sinr * cyprim) + | |
((self.start.real + self.end.real) / 2), | |
(sinr * cxprim + cosr * cyprim) + | |
((self.start.imag + self.end.imag) / 2)) | |
ux = (x1prim - cxprim) / rx | |
uy = (y1prim - cyprim) / ry | |
vx = (-x1prim - cxprim) / rx | |
vy = (-y1prim - cyprim) / ry | |
n = sqrt(ux * ux + uy * uy) | |
p = ux | |
theta = degrees(acos(p / n)) | |
if uy < 0: | |
theta = -theta | |
self.theta = theta % 360 | |
n = sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy)) | |
p = ux * vx + uy * vy | |
if p == 0: | |
delta = degrees(acos(0)) | |
else: | |
delta = degrees(acos(p / n)) | |
if (ux * vy - uy * vx) < 0: | |
delta = -delta | |
self.delta = delta % 360 | |
if not self.sweep: | |
self.delta -= 360 | |
def point(self, pos): | |
angle = radians(self.theta + (self.delta * pos)) | |
cosr = cos(radians(self.rotation)) | |
sinr = sin(radians(self.rotation)) | |
x = cosr * cos(angle) * self.radius.real - sinr * sin(angle) * self.radius.imag + self.center.real | |
y = sinr * cos(angle) * self.radius.real + cosr * sin(angle) * self.radius.imag + self.center.imag | |
return complex(x, y) | |
# M30,30" + Ar([30,30,0,1,1,116,133] | |
def sv_main(sx=3.0, sy=3.0, rx=3.0, ry=3.0, xaxis_rot=0, flag1=1, flag2=1, x=11.6, y=13.3, num_verts=20): | |
verts = [[]] | |
edges = [[]] | |
in_sockets = [ | |
['s', 'sx', sx], | |
['s', 'sy', sy], | |
['s', 'rx', rx], | |
['s', 'ry', ry], | |
['s', 'xaxis_rot', xaxis_rot], | |
['s', 'flag1', flag1], | |
['s', 'flag2', flag2], | |
['s', 'x', x], | |
['s', 'y', y], | |
['s', 'num_verts', num_verts]] | |
out_sockets = [ | |
['v', 'verts', verts], | |
['s', 'edges', edges]] | |
start = complex(sx,sy) | |
radius = complex(rx,ry) | |
end = complex(x,y) | |
arc = Arc(start, radius, xaxis_rot, flag1, flag2, end) | |
for i in range(num_verts): | |
pos = i/num_verts | |
point = arc.point(pos) | |
x = point.real | |
y = point.imag | |
verts[0].append([x,y,0]) | |
return in_sockets, out_sockets |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment