Files
svg2gcode_grbl/cubicsuperpath.py
2020-01-01 16:00:55 -05:00

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