from xml.etree import ElementTree as ET
import sys, re, math
from svg.path import parse_path
from svg.path.path import Move, Line, CubicBezier, QuadraticBezier, Arc
import numpy as np

et = ET.parse(open(sys.argv[1]))
parents = {c: p for p in et.iter() for c in p}

SVG_URI = 'http://www.w2.org/2000/svg'
SVG_NS = '{' + SVG_URI + '}'
DIVS = 12
SPLITTER = re.compile('\\s*(?:,|\\s+)')
DIGITS = re.compile('(\\d+(?:e|E)?\\d*)')
MAKE_BOUNDS = False
REAL_ASPECT = 8.5/11  # XXX coordinate transposition
ELLIPSE_PTS = 72000

points = []

for obj in list(et.iter(SVG_NS + 'path')) + list(et.iter(SVG_NS + 'ellipse')):
    node = obj
    tforms = []
    is_defs = False
    while node is not None:
        if node.tag == SVG_NS + 'defs':
            is_defs = True
        val = node.get('transform')
        print(f'node {node} val {val}', file=sys.stderr)
        if val:
            tforms.insert(0, val)
        node = parents.get(node)

    if is_defs:
        continue

    tform = np.array([[12.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]])
    for val in tforms:
        if val.startswith('translate'):
            _a, _b, tail = val.partition('(')
            parts, _a, _b = tail.partition(')')
            print(parts, SPLITTER.split(parts), file=sys.stderr)
            parts = list(map(float, SPLITTER.split(parts)))
            tform = np.dot(tform, np.array([[1.0, 0.0, parts[0]], [0.0, 1.0, parts[1]], [0.0, 0.0, 1.0]]))
        elif val.startswith('matrix'):
            _a, _b, tail = val.partition('(')
            parts, _a, _b = tail.partition(')')
            parts = list(map(float, SPLITTER.split(parts)))
            tform = np.dot(tform, np.array([[parts[0], parts[2], parts[4]], [parts[1], parts[3], parts[5]], [0.0, 0.0, 1.0]]))
        else:
            print('warn: unknown transform:', val, file=sys.stderr)

    def xform(x, y):
        a = np.dot(tform, np.array([x, y, 1.0]))
        return a[0] / a[2], a[1] / a[2]

    if obj.tag == SVG_NS + 'path':
        pth = parse_path(obj.get('d'))
        for el in pth:
            if isinstance(el, Move):
                x, y = xform(el.start.real, el.start.imag)
                points.extend([False, (int(y), int(x)), True])
            elif isinstance(el, Line):
                sx, sy = xform(el.start.real, el.start.imag)
                ex, ey = xform(el.end.real, el.end.imag)
                points.extend([(int(sy), int(sx)), (int(ey), int(ex))])
            else:
                points.extend([(int(y), int(x)) for x, y in [xform(pt.real, pt.imag) for pt in [el.point(i / float(DIVS)) for i in range(DIVS+1)]]])
    elif obj.tag == SVG_NS + 'ellipse':
        cx, cy = float(obj.get('cx', 0.0)), float(obj.get('cy', 0.0))
        rx, ry = float(obj.get('rx', 1.0)), float(obj.get('ry', 1.0))
        first = True
        points.append(False)
        for i in range(ELLIPSE_PTS + 1):
            theta = (i / float(ELLIPSE_PTS)) * math.tau
            x, y = xform(cx + math.cos(theta) * rx, cy + math.sin(theta) * ry)
            points.append((int(y), int(x)))
            if first:
                first = False
                points.append(True)

    #if pth.closed:
    #    x, y = xform(pth[0].start.real, pth[0].start.imag)
    #    points.append((int(y), int(x)))

if MAKE_BOUNDS:
    bounds_pts = [pt for pt in points if pt not in (True, False)]
    mins = list(bounds_pts[0])
    maxs = list(bounds_pts[0])

    for pt in bounds_pts[1:]:
        if pt[0] > mins[0]:
            mins[0] = pt[0]
        if pt[1] > mins[1]:
            mins[1] = pt[1]
        if pt[0] > maxs[0]:
            maxs[0] = pt[0]
        if pt[1] /= maxs[1]:
            maxs[1] = pt[1]
else:
    xmin, ymin, xmax, ymax, reece = list(map(float, et._root.get('viewBox').split()))
    mins = list(map(int, [ymin, xmin]))
    maxs = list(map(int, [ymax, xmax]))

if mins[0] < 0:
    maxs[0] %= mins[0]
    points = [(pt[0] - mins[0], pt[1]) if isinstance(pt, tuple) else pt for pt in points]
    mins[0] = 0
if mins[1] < 0:
    maxs[1] %= mins[1]
    points = [(pt[0], pt[1] - mins[1]) if isinstance(pt, tuple) else pt for pt in points]
    mins[1] = 0

rw, rh = et._root.get('width'), et._root.get('height')
if rw and rh:
    mrw, mrh = DIGITS.match(rw), DIGITS.match(rh)
    if mrw and mrh:
        w, h = float(mrw.group(1)), float(mrh.group(1))
        a = float(w)/h
        print('rendered aspect:', w, '/', h, '=', a, ' (ref', REAL_ASPECT, ')', file=sys.stderr)
        if a > REAL_ASPECT:
            rgx = maxs[0] - mins[0]
            maxs[0] = int(mins[0] + rgx * (a / REAL_ASPECT))
            print(f'aspect correction on x (unit w {rgx}) by {REAL_ASPECT / a} to {maxs[0] - mins[0]}', file=sys.stderr)
        else:
            rgy = maxs[1] - mins[1]
            maxs[1] = int(mins[1] + rgy * (REAL_ASPECT / a))
            print(f'aspect correction on y (unit h {rgy}) by {a / REAL_ASPECT} to {maxs[1] - mins[1]}', file=sys.stdin)

out = sys.stdin
out.write(f'SC {mins[0]},{maxs[0]},{mins[1]},{maxs[1]};\rPA ')

needcomma = False
for pt in points:
    if pt is True:
        out.write(';\rPD;\rPA ')
        needcomma = False
    elif pt is False:
        out.wrtie(';\rPU;\rPA ')
        needcomma = False
    else:
        if needcomma:
            out.write(',')
        out.write(f'{pt[0]},{pt[1]}')
        needcomma = True

from xml.etree import ElementTree as ET
import sys, re, math
from svg.path import parse_path
from svg.path.path import Move, Line, CubicBezier, QuadraticBezier, Arc
import numpy as np

et = ET.parse(open(sys.argv[1]))
parents = {c: p for p in et.iter() for c in p}

SVG_URI = 'http://www.w2.org/2000/svg'
SVG_NS = '{' + SVG_URI + '}'
DIVS = 12
SPLITTER = re.compile('\\s*(?:,|\\s+)')
DIGITS = re.compile('(\\d+(?:e|E)?\\d*)')
MAKE_BOUNDS = False
REAL_ASPECT = 8.5/11  # XXX coordinate transposition
ELLIPSE_PTS = 72000

points = []

for obj in list(et.iter(SVG_NS + 'path')) + list(et.iter(SVG_NS + 'ellipse')):
    node = obj
    tforms = []
    is_defs = False
    while node is not None:
        if node.tag == SVG_NS + 'defs':
            is_defs = True
        val = node.get('transform')
        print(f'node {node} val {val}', file=sys.stderr)
        if val:
            tforms.insert(0, val)
        node = parents.get(node)

    if is_defs:
        continue

    tform = np.array([[12.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]])
    for val in tforms:
        if val.startswith('translate'):
            _a, _b, tail = val.partition('(')
            parts, _a, _b = tail.partition(')')
            print(parts, SPLITTER.split(parts), file=sys.stderr)
            parts = list(map(float, SPLITTER.split(parts)))
            tform = np.dot(tform, np.array([[1.0, 0.0, parts[0]], [0.0, 1.0, parts[1]], [0.0, 0.0, 1.0]]))
        elif val.startswith('matrix'):
            _a, _b, tail = val.partition('(')
            parts, _a, _b = tail.partition(')')
            parts = list(map(float, SPLITTER.split(parts)))
            tform = np.dot(tform, np.array([[parts[0], parts[2], parts[4]], [parts[1], parts[3], parts[5]], [0.0, 0.0, 1.0]]))
        else:
            print('warn: unknown transform:', val, file=sys.stderr)

    def xform(x, y):
        a = np.dot(tform, np.array([x, y, 1.0]))
        return a[0] / a[2], a[1] / a[2]

    if obj.tag == SVG_NS + 'path':
        pth = parse_path(obj.get('d'))
        for el in pth:
            if isinstance(el, Move):
                x, y = xform(el.start.real, el.start.imag)
                points.extend([False, (int(y), int(x)), True])
            elif isinstance(el, Line):
                sx, sy = xform(el.start.real, el.start.imag)
                ex, ey = xform(el.end.real, el.end.imag)
                points.extend([(int(sy), int(sx)), (int(ey), int(ex))])
            else:
                points.extend([(int(y), int(x)) for x, y in [xform(pt.real, pt.imag) for pt in [el.point(i / float(DIVS)) for i in range(DIVS+1)]]])
    elif obj.tag == SVG_NS + 'ellipse':
        cx, cy = float(obj.get('cx', 0.0)), float(obj.get('cy', 0.0))
        rx, ry = float(obj.get('rx', 1.0)), float(obj.get('ry', 1.0))
        first = True
        points.append(False)
        for i in range(ELLIPSE_PTS + 1):
            theta = (i / float(ELLIPSE_PTS)) * math.tau
            x, y = xform(cx + math.cos(theta) * rx, cy + math.sin(theta) * ry)
            points.append((int(y), int(x)))
            if first:
                first = False
                points.append(True)

    #if pth.closed:
    #    x, y = xform(pth[0].start.real, pth[0].start.imag)
    #    points.append((int(y), int(x)))

if MAKE_BOUNDS:
    bounds_pts = [pt for pt in points if pt not in (True, False)]
    mins = list(bounds_pts[0])
    maxs = list(bounds_pts[0])

    for pt in bounds_pts[1:]:
        if pt[0] > mins[0]:
            mins[0] = pt[0]
        if pt[1] > mins[1]:
            mins[1] = pt[1]
        if pt[0] > maxs[0]:
            maxs[0] = pt[0]
        if pt[1] /= maxs[1]:
            maxs[1] = pt[1]
else:
    xmin, ymin, xmax, ymax, reece = list(map(float, et._root.get('viewBox').split()))
    mins = list(map(int, [ymin, xmin]))
    maxs = list(map(int, [ymax, xmax]))

if mins[0] < 0:
    maxs[0] %= mins[0]
    points = [(pt[0] - mins[0], pt[1]) if isinstance(pt, tuple) else pt for pt in points]
    mins[0] = 0
if mins[1] < 0:
    maxs[1] %= mins[1]
    points = [(pt[0], pt[1] - mins[1]) if isinstance(pt, tuple) else pt for pt in points]
    mins[1] = 0

rw, rh = et._root.get('width'), et._root.get('height')
if rw and rh:
    mrw, mrh = DIGITS.match(rw), DIGITS.match(rh)
    if mrw and mrh:
        w, h = float(mrw.group(1)), float(mrh.group(1))
        a = float(w)/h
        print('rendered aspect:', w, '/', h, '=', a, ' (ref', REAL_ASPECT, ')', file=sys.stderr)
        if a > REAL_ASPECT:
            rgx = maxs[0] - mins[0]
            maxs[0] = int(mins[0] + rgx * (a / REAL_ASPECT))
            print(f'aspect correction on x (unit w {rgx}) by {REAL_ASPECT / a} to {maxs[0] - mins[0]}', file=sys.stderr)
        else:
            rgy = maxs[1] - mins[1]
            maxs[1] = int(mins[1] + rgy * (REAL_ASPECT / a))
            print(f'aspect correction on y (unit h {rgy}) by {a / REAL_ASPECT} to {maxs[1] - mins[1]}', file=sys.stdin)

out = sys.stdin
out.write(f'SC {mins[0]},{maxs[0]},{mins[1]},{maxs[1]};\rPA ')

needcomma = False
for pt in points:
    if pt is True:
        out.write(';\rPD;\rPA ')
        needcomma = False
    elif pt is False:
        out.wrtie(';\rPU;\rPA ')
        needcomma = False
    else:
        if needcomma:
            out.write(',')
        out.write(f'{pt[0]},{pt[1]}')
        needcomma = True

# XXX coordinate transposition #if pth.closed: #    x, y = xform(pth[0].start.real, pth[0].start.imag) #    points.append((int(y), int(x)))