% -- private ------------------------------------------------ /pathformdict 32 dict def pathformdict begin /path-display { { (moveto) == [ 3 1 roll ] == } { (lineto) == [ 3 1 roll ] == } { (curveto) == [ 7 1 roll ] == } { (closepath) == } pathforall } def % a path array is an array of arrays indicating path commands % [[x y] T T ] = moveto % [[x y] T F ] = lineto % [[x1 y1 dx1 dy1 dx3 dy3 x3 y3] F T] = curveto % where P1 = P0 + dP0, P2 = P3 - dP3 % [F F] = closepath /path-to-array { 8 dict begin [ { /cy exch def /cx exch def /lx cx def /ly cy def [[cx cy] true true] } { /cy exch def /cx exch def [[cx cy] true false] } { [ 7 1 roll ] /C exch def [[C 0 get cx sub C 1 get cy sub /cx C 4 get def /cy C 5 get def cx C 2 get sub cy C 3 get sub cx cy ] false true] } { /cx lx def /cy ly def [false false] } pathforall ] end } def % p /pa-subdivide { 24 dict begin [ exch % p { aload pop % TT TF FT FF { { % TT: moveto % leave it in place, and redefine the current point aload pop /cy exch def /cx exch def % for path closing: /lx cx def /ly cy def [[cx cy] true true] } { % FT: curveto % bisect a bezier curve % new P3 = (4(P0 + P3) + 3(dP0 - dP3))/8 % new dP3 = (2(P3 - P0) - (dP0 + dP3))/8 aload pop /cy3 exch def /cx3 exch def /cdy3 exch def /cdx3 exch def /cdy0 exch def /cdx0 exch def /cdx cx3 cx sub 0.25 mul cdx3 cdx0 add 0.125 mul sub def /cdy cy3 cy sub 0.25 mul cdy3 cdy0 add 0.125 mul sub def [[cdx0 0.5 mul cdy0 0.5 mul cdx cdy cx cx3 add 0.5 mul cdx0 cdx3 sub 0.375 mul add cy cy3 add 0.5 mul cdy0 cdy3 sub 0.375 mul add ] false true ] [[cdx cdy cdx3 0.5 mul cdy3 0.5 mul cx3 cy3 ] false true ] /cx cx3 def /cy cy3 def } ifelse } { { % TF: lineto % make into a single Bezier curve aload pop /cy3 exch def /cx3 exch def /dx cx3 cx sub 3 div def /dy cy3 cy sub 3 div def [[dx dy dx dy cx3 cy3] false true] /cx cx3 def /cy cy3 def } { % FF: closepath [false false] /cx lx def /cy ly def } ifelse } ifelse } forall % commands in the path array ] end } def % p pars /f % pars [x y] f => [[fx fy] [fxx fxy fyx fyy]] /pa-transform { load 24 dict begin /f exch def /pars exch def [ exch % p { aload pop % TT TF FT FF { { % TT: moveto aload pop /cy exch def /cx exch def /lx cx def /ly cy def /cf pars [cx cy] f def /clf cf def [[cf 0 get 0 get cf 0 get 1 get] true true] }{ % FT: curveto aload pop /cy3 exch def /cx3 exch def /cdy3 exch def /cdx3 exch def /cdy0 exch def /cdx0 exch def [[ % fdP0 = jac(cf)(dP0) /df cf 1 get def df 0 get cdx0 mul df 1 get cdy0 mul add df 2 get cdx0 mul df 3 get cdy0 mul add /cx cx3 def /cy cy3 def /cf pars [cx cy] f def % fdP2 = jac(cf)(dP3) /df cf 1 get def df 0 get cdx3 mul df 1 get cdy3 mul add df 2 get cdx3 mul df 3 get cdy3 mul add cf 0 get aload pop ] false true] } ifelse }{ { % TF: lineto aload pop /cy exch def /cx exch def /cf pars [cx cy] f def [[cf 0 get 0 get cf 0 get 1 get] true false] } { % FF: closepath /cx lx def /cy ly def /cf clf def [false false] } ifelse } ifelse } forall ] end } def /array-to-path { { aload pop % TT TF FT FF { { % TT: moveto aload pop moveto } { % FT: curveto currentpoint /cy exch def /cx exch def /C exch def cx C 0 get add cy C 1 get add /cx C 4 get def /cy C 5 get def cx C 2 get sub cy C 3 get sub cx cy curveto } ifelse } { { % TF: lineto aload pop lineto } { % FF: closepath closepath } ifelse } ifelse } forall } def end % --- public ----------------------------------------------- % pars f N=subdvision count % applies f to current path with N subdivisions % f: pars [x y] -> [[fx fy][fxx fxy fyx fyy]] % returns a path array encoding the transform of the current path /pform { pathformdict begin /N exch def load /f exch def /pars exch def path-to-array N { pa-subdivide } repeat pars /f pa-transform end } def % a path-array is on the stack: turns it into a path /popen { pathformdict begin array-to-path end } def