cubicsuperpath.py 5.12 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#!/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
19
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 21 22

"""
import simplepath 
23
from math import *
24

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
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[:]
47
    teta = teta*pi/180.0
48
    B=[x2,y2]
49 50
    if rx==0 or ry==0 or A==B:
        return([[A[:],A[:],A[:]],[B[:],B[:],B[:]]])
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
    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
79 80
    #v=dTeta*2/pi*4*(sqrt(2)-1)/3
    v = 4*tan(dTeta/4)/3
81
    #if not sweepflag:
82
    #    v*=-1
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
    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)
    
100
def CubicSuperPath(simplepath):
101 102 103 104 105 106 107 108
    csp = []
    subpath = -1
    subpathstart = []
    last = []
    lastctrl = []
    for s in simplepath:
        cmd, params = s        
        if cmd == 'M':
109 110
            if last:
                csp[subpath].append([lastctrl[:],last[:],last[:]])
111
            subpath += 1
112
            csp.append([])
113 114 115 116 117 118 119 120 121 122 123 124
            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':
125
            q0=last[:]
126 127 128 129 130 131 132 133 134 135 136
            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]])
137 138
            last = [x3,y3]
            lastctrl = [x2,y2]
139
        elif cmd == 'A':
140 141 142 143 144
            arcp=ArcToPath(last[:],params[:])
            arcp[ 0][0]=lastctrl[:]
            last=arcp[-1][1]
            lastctrl = arcp[-1][0]
            csp[subpath]+=arcp[:-1]
145
        elif cmd == 'Z':
146
            csp[subpath].append([lastctrl[:],last[:],last[:]])
147 148
            last = subpathstart[:]
            lastctrl = subpathstart[:]
149 150
    #append final superpoint
    csp[subpath].append([lastctrl[:],last[:],last[:]])
151
    return csp    
152 153

def unCubicSuperPath(csp):
154 155 156 157 158 159 160
    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
161 162

def parsePath(d):
163
    return CubicSuperPath(simplepath.parsePath(d))
164 165

def formatPath(p):
166
    return simplepath.formatPath(unCubicSuperPath(p))
167 168


169
# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99