Skip to content

Instantly share code, notes, and snippets.

@zeffii
Forked from anonymous/arcto_Scriptnode.py
Created August 7, 2014 17:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zeffii/e95497b28170ec70d4bb to your computer and use it in GitHub Desktop.
Save zeffii/e95497b28170ec70d4bb to your computer and use it in GitHub Desktop.
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