--- /root/svgloader.py 2003-09-05 15:29:31.000000000 +0200 +++ svgloader.py 2003-09-10 15:42:01.000000000 +0200 @@ -26,7 +26,7 @@ ###End from types import StringType -from math import pi, tan +from math import pi, tan, atan2, sin, sqrt, floor, ceil import os, sys import re from string import strip, split, atoi, lower @@ -505,6 +505,7 @@ last_quad = None last_cmd = cmd = None f13 = 1.0 / 3.0; f23 = 2.0 / 3.0 + circlemagic = 4 * (sqrt(2) - 1) / 3 #print '*', str while 1: match = rx_command.match(str) @@ -673,6 +674,145 @@ path.AppendBezier(p1, p2, p3) last_quad = q + elif cmd in 'Aa': + if len(points) % 7 != 0: + self.loader.add_message("number of parameters of 'A'"\ + " or 'a' must be multiple of 7") + else: + def circleparam (h, x0=0, x1=circlemagic, x2=1, x3=1): + t0 = 0.5 + dt = 0.25 + + while dt >= 0.0001: + pt0 = ( x0*(1-t0)*(1-t0)*(1-t0) + + 3*x1*(1-t0)*(1-t0)*t0 + + 3*x2*(1-t0)*t0*t0 + + x3*t0*t0*t0 ) + + if pt0 > h: + t0 = t0-dt + elif pt0 < h: + t0 = t0+dt + else: + break + dt = dt / 2 + return t0 + + def subdivide (p, t): + p01 = p[0] * (1-t) + p[1] * t + p12 = p[1] * (1-t) + p[2] * t + p23 = p[2] * (1-t) + p[3] * t + p012 = p01 * (1-t) + p12 * t + p123 = p12 * (1-t) + p23 * t + p0123 = p012 * (1-t) + p123 * t + + return [p[0], p01, p012, p0123, p123, p23, p[3]] + + def ellipsesegment (rx, ry, phi0, phi1): + if (phi0 < phi1): + phis = divmod (phi0, pi/2)[0] * pi/2 + phie = phis + pi/2 + else: + phie = divmod (phi1, pi/2)[0] * pi/2 + phis = phie + pi/2 + + y0, y1, y2, y3 = 0, circlemagic, 1, 1 + h0, h1 = sin (abs (phi0-phis)), sin (abs(phi1-phis)) + + c0 = Rotation (phis) (Point (1,0)) + c3 = Rotation (phie) (Point (1,0)) + c1 = c0 + circlemagic * c3 + c2 = c0 * circlemagic + c3 + + if h0 > y0: + t0 = circleparam (h0, y0, y1, y2, y3) + y0, y1, y2, y3 = subdivide ([y0, y1, y2, y3], t0)[3:] + c0, c1, c2, c3 = subdivide ([c0, c1, c2, c3], t0)[3:] + + if h1 < y3: + t1 = circleparam (h1, y0, y1, y2, y3) + c0, c1, c2, c3 = subdivide ([c0, c1, c2, c3], t1)[:4] + + return [Point (c0.x * rx, c0.y * ry), + Point (c1.x * rx, c1.y * ry), + Point (c2.x * rx, c2.y * ry), + Point (c3.x * rx, c3.y * ry)] + + for i in range(0, len(points), 7): + p = trafo.inverse() (path.Node(-1)) + rx = float (abs (points[i])) + ry = float (abs (points[i+1])) + phi = points[i+2] + if points[i+3]: + large_arc = 1 + else: + large_arc = 0 + if points[i+4]: + sweep = 1 + else: + sweep = 0 + if cmd == 'A': + p2 = Point (points[i+5], points[i+6]) + else: + p2 = p + Point (points[i+5], points[i+6]) + + if rx == 0 or ry == 0: + path.AppendLine(trafo (p2)) + else: + phirot = Rotation(phi * degrees) + + p1 = phirot.inverse () ((p - p2) * 0.5) + + l = (p1.x/rx)**2 + (p1.y/ry)**2 + if (l < 0.00001): + continue + + if (l > 1): + rx = rx * sqrt (l) + ry = ry * sqrt (l) + c_ = Point (0,0) + else: + c_ = sqrt ((1-l)/l) * Point ( rx / ry * p1.y, + - ry / rx * p1.x) + + if large_arc == sweep: + c_ = -1 * c_ + + c = phirot (c_) + 0.5 * (p + p2) + + phi1 = atan2 (( p1.y - c_.y) / ry, + ( p1.x - c_.x) / rx) % (2*pi) + phi2 = atan2 ((-p1.y - c_.y) / ry, + (-p1.x - c_.x) / rx) % (2*pi) + + if sweep: + while phi2 < phi1: + phi2 += 2*pi + phi0 = floor (phi1 / (pi/2)) * pi / 2 + + while (phi2 - phi0) > 0: + segment = ellipsesegment (rx, ry, max (phi0, phi1), + min (phi0+pi/2, phi2)) + + path.AppendBezier(trafo (c+phirot (segment[1])), + trafo (c+phirot (segment[2])), + trafo (c+phirot (segment[3]))) + phi0 += pi/2 + + else: + while phi1 < phi2: + phi1 += 2*pi + phi0 = ceil (phi1 / (pi/2)) * pi / 2 + + while (phi0 - phi2) > 0: + segment = ellipsesegment (rx, ry, min (phi0, phi1), + max (phi0-pi/2, phi2)) + + path.AppendBezier(trafo (c+phirot (segment[1])), + trafo (c+phirot (segment[2])), + trafo (c+phirot (segment[3]))) + phi0 -= pi/2 + elif cmd == 'z': path.AppendLine(path.Node(0)) path.ClosePath()