Sto provando a implementare i calcoli del percorso SVG in Python, ma sto riscontrando problemi con le curve Arc.Implementazione di curve di arco SVG in Python
Penso che il problema sia nella conversione dalla parametrizzazione da punto finale a centro, ma non riesco a trovare il problema. È possibile trovare note su come implementarlo nella sezione F6.5 di SVG specifications. Ho anche esaminato le implementazioni in altre lingue e non riesco a vedere cosa fanno di diverso.
implementazione oggetto il mio arco è qui:
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 _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((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):
if self.arc == self.sweep:
angle = radians(self.theta - (self.delta * pos))
else:
angle = radians(self.delta + (self.delta * pos))
x = sin(angle) * self.radius.real + self.center.real
y = cos(angle) * self.radius.imag + self.center.imag
return complex(x, y)
È possibile verificare questo con il seguente codice che trarrà le curve con il modulo Turtle. (Il raw_input() alla fine è solo per quello lo schermo non scompare quando il programma si chiude).
arc1 = Arc(0j, 100+50j, 0, 0, 0, 100+50j)
arc2 = Arc(0j, 100+50j, 0, 1, 0, 100+50j)
arc3 = Arc(0j, 100+50j, 0, 0, 1, 100+50j)
arc4 = Arc(0j, 100+50j, 0, 1, 1, 100+50j)
import turtle
t = turtle.Turtle()
t.penup()
t.goto(0, 0)
t.dot(5, 'red')
t.write('Start')
t.goto(100, 50)
t.dot(5, 'red')
t.write('End')
t.pencolor = t.color('blue')
for arc in (arc1, arc2, arc3, arc4):
t.penup()
p = arc.point(0)
t.goto(p.real, p.imag)
t.pendown()
for x in range(1,101):
p = arc.point(x*0.01)
t.goto(p.real, p.imag)
raw_input()
Il problema:
Ognuno di questi quattro archi tratte dovrebbe trarre dal punto di partenza al punto finale. Tuttavia, sono tratti dai punti sbagliati. Due curve vanno dalla fine all'inizio e due vanno da 100, da -50 a 0,0 anziché da 0,0 a 100, 50.
Parte del problema è che le note di implementazione forniscono la formula da come eseguire il modulo di conversione endpoint al centro, ma non spiega cosa fa geometricamente, quindi non sono del tutto chiaro su cosa fa ogni passaggio. Una spiegazione di ciò sarebbe anche utile.
Grazie per il mixaggio di cos/sin. Anche con queste modifiche, però, non funziona correttamente, ma ora le cose diventano più sensate. –
@LennartRegebro: Ho inserito il codice modificato qui: http://pastebin.com/dp8bYVSq. Sembra produrre l'output atteso. –
Lo fa, devo aver aggiustato qualcos'altro anche sulla strada. Troppo stanco con questo per capire cosa. Grazie! (Il primo era solo un avanzo da me che testava le cose per cercare di capire il codice, ma gli altri errori erano reali. Avevo appena capito il mixaggio di cos/sin, ma che self.arc == self.sweep era il torto mi avrebbe richiesto ore in più per capire –