#!/usr/bin/env python """ cubicsuperpath.py Copyright (C) 2005 Aaron Spike, aaron@ekips.org This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ import simplepath from math import * def matprod(mlist): prod = mlist[0] for m in mlist[1:]: a00 = prod[0][0] * m[0][0] + prod[0][1] * m[1][0] a01 = prod[0][0] * m[0][1] + prod[0][1] * m[1][1] a10 = prod[1][0] * m[0][0] + prod[1][1] * m[1][0] a11 = prod[1][0] * m[0][1] + prod[1][1] * m[1][1] prod = [[a00, a01], [a10, a11]] return prod def rotmat(teta): return [[cos(teta), -sin(teta)], [sin(teta), cos(teta)]] def applymat(mat, pt): x = mat[0][0] * pt[0] + mat[0][1] * pt[1] y = mat[1][0] * pt[0] + mat[1][1] * pt[1] pt[0] = x pt[1] = y def norm(pt): return sqrt(pt[0] * pt[0] + pt[1] * pt[1]) def ArcToPath(p1, params): A = p1[:] rx, ry, teta, longflag, sweepflag, x2, y2 = params[:] teta = teta * pi / 180.0 B = [x2, y2] if rx == 0 or ry == 0: return ([[A, A, A], [B, B, B]]) mat = matprod((rotmat(teta), [[1 / rx, 0], [0, 1 / ry]], rotmat(-teta))) applymat(mat, A) applymat(mat, B) k = [-(B[1] - A[1]), B[0] - A[0]] d = k[0] * k[0] + k[1] * k[1] k[0] /= sqrt(d) k[1] /= sqrt(d) d = sqrt(max(0, 1 - d / 4)) if longflag == sweepflag: d *= -1 O = [(B[0] + A[0]) / 2 + d * k[0], (B[1] + A[1]) / 2 + d * k[1]] OA = [A[0] - O[0], A[1] - O[1]] OB = [B[0] - O[0], B[1] - O[1]] start = acos(OA[0] / norm(OA)) if OA[1] < 0: start *= -1 end = acos(OB[0] / norm(OB)) if OB[1] < 0: end *= -1 if sweepflag and start > end: end += 2 * pi if (not sweepflag) and start < end: end -= 2 * pi NbSectors = int(abs(start - end) * 2 / pi) + 1 dTeta = (end - start) / NbSectors # v=dTeta*2/pi*0.552 # v=dTeta*2/pi*4*(sqrt(2)-1)/3 v = 4 * tan(dTeta / 4) / 3 # if not sweepflag: # v*=-1 p = [] for i in range(0, NbSectors + 1, 1): angle = start + i * dTeta v1 = [O[0] + cos(angle) - (-v) * sin(angle), O[1] + sin(angle) + (-v) * cos(angle)] pt = [O[0] + cos(angle), O[1] + sin(angle)] v2 = [O[0] + cos(angle) - v * sin(angle), O[1] + sin(angle) + v * cos(angle)] p.append([v1, pt, v2]) p[0][0] = p[0][1][:] p[-1][2] = p[-1][1][:] mat = matprod((rotmat(teta), [[rx, 0], [0, ry]], rotmat(-teta))) for pts in p: applymat(mat, pts[0]) applymat(mat, pts[1]) applymat(mat, pts[2]) return (p) def CubicSuperPath(simplepath): csp = [] subpath = -1 subpathstart = [] last = [] lastctrl = [] for s in simplepath: cmd, params = s if cmd == 'M': if last: csp[subpath].append([lastctrl[:], last[:], last[:]]) subpath += 1 csp.append([]) subpathstart = params[:] last = params[:] lastctrl = params[:] elif cmd == 'L': csp[subpath].append([lastctrl[:], last[:], last[:]]) last = params[:] lastctrl = params[:] elif cmd == 'C': csp[subpath].append([lastctrl[:], last[:], params[:2]]) last = params[-2:] lastctrl = params[2:4] elif cmd == 'Q': q0 = last[:] q1 = params[0:2] q2 = params[2:4] x0 = q0[0] x1 = 1. / 3 * q0[0] + 2. / 3 * q1[0] x2 = 2. / 3 * q1[0] + 1. / 3 * q2[0] x3 = q2[0] y0 = q0[1] y1 = 1. / 3 * q0[1] + 2. / 3 * q1[1] y2 = 2. / 3 * q1[1] + 1. / 3 * q2[1] y3 = q2[1] csp[subpath].append([lastctrl[:], [x0, y0], [x1, y1]]) last = [x3, y3] lastctrl = [x2, y2] elif cmd == 'A': arcp = ArcToPath(last[:], params[:]) arcp[0][0] = lastctrl[:] last = arcp[-1][1] lastctrl = arcp[-1][0] csp[subpath] += arcp[:-1] elif cmd == 'Z': csp[subpath].append([lastctrl[:], last[:], last[:]]) last = subpathstart[:] lastctrl = subpathstart[:] # append final superpoint csp[subpath].append([lastctrl[:], last[:], last[:]]) return csp def unCubicSuperPath(csp): a = [] for subpath in csp: if subpath: a.append(['M', subpath[0][1][:]]) for i in range(1, len(subpath)): a.append(['C', subpath[i - 1][2][:] + subpath[i][0][:] + subpath[i][1][:]]) return a def parsePath(d): return CubicSuperPath(simplepath.parsePath(d)) def formatPath(p): return simplepath.formatPath(unCubicSuperPath(p)) # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99