181 lines
5.3 KiB
Python
Executable File
181 lines
5.3 KiB
Python
Executable File
#!/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
|