andy@ecrcvax.UUCP (Andrew Dwelly) (07/21/88)
Just before last Christmas, John Pratt posted a postscript program to draw an accurate copy of Escher's square limit program (a la Henderson), for various reasons the program did not work under NeWS 1.0 (bugs, missing primitives etc.). What follows is a version that works under NeWS 1.1 John doesn't have access to the net currently, so I am posting, and collecting replies and comments which I will forward to him. Andy ------------------------------------------------------------------------------ #!/usr/NeWS/bin/psh % TRIANGULAR-DIVISION % Copyright John M. Pratt. ECRC Arabellastr 17, D8000 Munich 81 % -- With acknowledgements to M.C.Escher. % Produces a facsimile of "Square Limit. % Executes under psh, adapts to window size, and provides menu for rotation % Prepared as a exercise of graphic transformation, and curve drawing under NeWS /Fishdict 200 dict def Fishdict begin /Helvetica-Bold findfont 0.5 scalefont setfont % COLOUR CONTROLS /Colourdisplay false def /Parity 0 def /Swap {/Parity 0.5 Parity sub def} def %Parity is 0 or 0.5 /Colour 0 def %colour variable /Dark {/Colour Parity def Colour Set-Colour} def /Light {/Colour 0.5 Parity sub def Colour Set-Colour} def /White {/Colour 1 def Set-White} def /Comp {Colour 1 ne {Set-White} {Parity Set-Colour} ifelse} def /De-Comp{Colour 1 eq {Set-White} {Colour Set-Colour} ifelse} def /Set-Colour { Colourdisplay {1 0.5 sethsbcolor} {setgray} ifelse} def /Set-White { Colourdisplay {0 0 1 sethsbcolor} {1 setgray} ifelse } def % CONSTANTS AND PRECALCULATED TRANSFORMS /cm {28.35 mul} def /HeadMatrix [-0.5 0.5 0.5 0.5 0 10] def % 0 10 translate -Invroot2 Invroot2 scale 45 rotate /UpheadMatrix [-1 1 1 1 -10 -10] def % -45 rotate Root2 neg Root2 scale 0 -10 translate /TailMatrix [-0.5 -0.5 -0.5 0.5 0 10] def % 0 10 translate -Invroot2 Invroot2 scale -45 rotate /UptailMatrix [-1 -1 -1 1 10 -10] def % 45 rotate Root2 -Root2 scale 0 -10 translate /Op1 [-1 0 0 -1 0 20] def %matrix for duple opposite %0 10 translate 180 rotate 0 -10 translate /Head-to-headMatrix [0.5 -0.5 -0.5 -0.5 10 20] def %Op1 HeadMatrix matrix concatmatrix /Transform { 3 dict begin %simulates -- X Y matrix transform /Mat exch def /Y exch def /X exch def Mat 0 get X mul Mat 2 get Y mul Mat 4 get add add %X` on stack Mat 1 get X mul Mat 3 get Y mul Mat 5 get add add %Y` on stack end } def /Downtail {TailMatrix concat} def %apply to CTM /Op {Op1 concat} def %apply to CTM /DwnR {HeadMatrix Transform} def %applies Head matrix to point /UpR {UpheadMatrix Transform} def %applies UpHead matrix to point /DwnL {TailMatrix Transform} def %applies Tail matrix to point /UpL {UptailMatrix Transform} def %applies UpTail matrix to point /Opp {Op1 Transform} def %applies opposite matrix to point /Qflip {exch neg exch} def %Flip by X, X/Y point 180 /Qrot90 {exch neg} def %rotate X/Y point -90 /Qrotm90 {neg exch } def %rotate X/Y point 90 /Qxtran {3 -1 roll add exch} def %adds top to 3rd, X /* {aload pop} bind def % POINTS defined as [X Y] /A [10 10] def /A1 [9 8] def /A2 [7.5 6.2] def /Ah [A * -1 Qxtran -0.5 add ] def /B [6 5.6] def /B1 [4.8 5] def /B2 [2.2 4.5] def /C [0 5] def /C1 [-1.1 5.3] def /C2 [-4.2 6] def /D [B * Qrotm90] def /D1 [A1 * Qrotm90] def /D2 [A2 * Qrotm90] def /E [A * Qrotm90] def /E1 [A1 * DwnL] def /E2 [A2 * DwnL] def /Eh [Ah * Qflip] def /F [B * DwnL] def /F1 [F * 2 Qxtran 2 sub] def /F2 [-2 7] def /G [0 7.6] def /G1 [2 8.2] def /G2 [3.2 9.5 ] def /Gop [G * Opp] def /GuP [G * UpL] def /H [5.1 10] def /H1 [6.5 10.5] def /H2 [8 10.5] def /I1 [0 4] def /I2 [0 2] def /J [0 0] def /J1 [3 0] def /J2 [3 0] def /K [C * Qrot90] def /L [C * DwnR] def /L1 [C1 * DwnR] def /L2 [4.7 11] def /N [0 10.7] def /N1 [I1 * DwnR] def /N2 [I2 * DwnR] def /Nl [N * UpL] def /Nr [N * UpR] def /P [L * Qflip] def /Q1 [4.1 12.4] def /Q2 [2 13.1] def /Sq2 {nm Pupil} def % CURVES defined as [Point Point Point] /a [A1 * A2 * B * ] def /b [B2 * B1 * B * ] def /c [C1 * C2 * D * ] def /d [D2 * D1 * E * ] def /e [E1 * E2 * F * ] def /f [F1 * F2 * G * ] def /ft [F1 * UpL F2 * UpL G * UpL] def /g [G2 * G1 * G * ] def /h [H1 * H2 * A * ] def /ho [H2 * Opp H1 * Opp H * Opp] def /hu [H1 * UpR H2 * UpR A * UpR ] def /i [I2 * I1 * C * ] def /j [J2 * J1 * J * ] def /k [C2 * Qrot90 C1 * Qrot90 K * ] def /l [L1 * L2 * H * ] def /lu [L1 * UpR L2 * UpR H * UpR ] def /n [N2 * N1 * L * ] def /nt [I2 * I1 * C * ] def /nm (J M P) def /p [I2 * I1 * C * ] def /pr [I1 * Qrot90 I2 * Qrot90 Nr * ] def /q [Q2 * Q1 * H * ] def /qo [Q1 * Opp Q2 * Opp G * ] def % OUTLINE GROUPS defined as [curve curve .. arraylength] /OutA [f * e * d * c * i * j * k * a * 8] def /OutB [f * e * hu * lu * nt * pr * k * a * 8] def /OutC [qo * ho * hu * lu * nt * pr * k * a * 8] def /OutD [qo * ho * d * c * p * 5] def /OutE [qo * ho * d * c * i * j * k * a * 8] def /OutF [h * q * 2] def /OutG [ft * a * 2] def /OutH [f * e * d * c * p * 5] def /OutI [h * l * n * 3] def /Out1s [A * E * D * C * J * K * B * 7] def %used for lines /Out2s [A * E * H * UpR C * Nr * K * B * 7] def /Out3s [A * E * D * C * Nl * G * UpL B * 7] def % PROCEDURES /Fish1 {newpath %Convex 90, quadwing, concave 45, Triwing 1 A * moveto OutA * {curveto} repeat N * lineto OutI * {curveto} repeat fill } def /Fish2 {Colour 1 eq {} { %dont draw if white newpath %Convex 45, TriWing2, concave 45, Triwing 1 A * moveto OutB * {curveto} repeat N * lineto OutI * {curveto} repeat fill }ifelse } def /Fish3 {newpath %Convex 90, TriWing3, concave 45, Triwing 1 A * moveto OutG * {curveto} repeat Nl * lineto OutH * {curveto} repeat N * lineto OutI * {curveto} repeat fill } def /Fish4 {Colour 1 eq {} { newpath %Convex 45, Triwing2, concave 180, Duplewing A * moveto OutC * {curveto} repeat Gop * lineto OutF * {curveto} repeat fill }ifelse } def /Fish5 {newpath %Convex 90, Triwing3, concave 180, Duplewing A * moveto OutG * {curveto} repeat Nl * lineto OutD * {curveto} repeat Gop * lineto OutF * {curveto} repeat fill } def /Fish6 {Colour 1 eq {} { newpath %Convex 90, quad, concave 180, Duplewing A * moveto OutE * {curveto} repeat Gop * lineto OutF * {curveto} repeat fill }ifelse } def /Fish1s {newpath %Straight fish with Quadwing for border A * moveto Out1s * {lineto} repeat fill} def /Fish2s {newpath %Straight fish with Triwing1 for border A * moveto Out2s * {lineto} repeat fill} def /Fish3s {newpath %Straight fish with Triwing2 for border A * moveto Out3s * {lineto} repeat fill} def /Spine {newpath %Fishcentre line Ah * moveto C * 0.3 add C * -0.6 Qxtran 0.3 add Eh * curveto Eh * -0.05 add lineto C * -0.3 add -0.6 Qxtran C * -0.3 add Ah * -0.05 add curveto Ah * lineto gsave fill grestore } def /Tailribs {0.15 setlinewidth newpath -6 9 moveto -5 8 -4 7.3 -2.4 6.9 curveto stroke newpath -5.5 6.7 moveto -4.5 6.3 -3.5 6.2 -2.3 6 curveto stroke newpath -2.2 7.1 moveto -2.4 6.7 -2.4 6.2 -2.2 5.8 curveto stroke} def /EyeshapeL { -0.4 0.8 moveto 0.7 1.3 1.5 1.2 2.5 0.8 curveto 1.9 0 1.1 -0.4 0.1 -0.9 curveto 0 -0.2 -0.1 0.3 -0.4 0.8 curveto } def /EyeshapeR { 0 0.8 moveto 1.4 1.6 1.9 1.6 2.6 1.5 curveto 2.4 0.8 1.6 0 0.1 -0.8 curveto 0.1 -0.3 0.1 0.3 0 0.8 curveto } def /Pupil {-3 0.2 moveto White show 0 0 moveto} def /WhiteEye { 0.01 setlinewidth gsave 5.9 6.7 translate EyeshapeR stroke 0.2 0 translate 0.4 0.4 scale EyeshapeR fill grestore gsave 5.6 8.9 translate EyeshapeL stroke 0.2 0.1 translate 0.4 0.4 scale EyeshapeL fill grestore }def /DarkEye {gsave 5.9 6.7 translate EyeshapeR 0.2 0 translate 0.4 0.4 scale EyeshapeR eofill grestore gsave 5.6 8.9 translate EyeshapeL 0.2 0.1 translate 0.4 0.4 scale EyeshapeL eofill grestore} def /Bodylines {Spine Tailribs Colour 1 eq {WhiteEye} {DarkEye} ifelse} def /Ribl {newpath L * moveto l * curveto stroke } def /Ribk {newpath B * moveto k * curveto stroke }def /Ribf {newpath B * moveto ft * curveto stroke } def /Ribb {newpath C * moveto b * curveto stroke } def /Ribg {newpath H * moveto g * curveto stroke} def % WING Outlines for Clip Paths /QuadW {C * moveto b * curveto K * lineto J * lineto closepath}def /TriW1 { %wing on Hypoteneuse for triple H * moveto g * curveto N * lineto L * lineto closepath } def /TriW2 { %wing on head side for triple C * moveto b * curveto K * lineto Nr * lineto closepath } def /TriW3 { %wing on tail side for triple C * moveto b * curveto GuP * lineto Nl * lineto closepath } def /DupleW { %wing for duple H * moveto g * curveto Gop * lineto q * curveto closepath } def /Wingribs %stack WingRib, Translate-offset, Translate-inc, Y-Rotatione-inc {4 copy 4 copy %copy parameters given for 3 ribs 0.15 setlinewidth 0 1 2 {gsave %stack Wr To Ti Sy Loopv dup dup 0.25 mul 0.75 exch sub %stack ----Sy Lv Lv Sx exch 4 -1 roll mul 0.95 exch sub %stack ---To Ti Lv Sx Sy scale %stack --To Ti Lv mul add 0 exch translate %stack --Wr cvx exec %execute WingRibxx grestore } for %stack Sr } def /Quadribs {gsave QuadW clip newpath /Ribk 0.5 0 0 Wingribs grestore 0.2 setlinewidth Ribb } def /Triribs1 {gsave TriW1 clip newpath /Ribl -0.5 0 0.04 Wingribs grestore 0.2 setlinewidth Ribg} def /Triribs2 {gsave TriW2 clip newpath /Ribk 0.5 0.1 0 Wingribs grestore 0.2 setlinewidth Ribb } def /Triribs3 {gsave TriW3 clip newpath /Ribf 0.8 0.6 0.03 Wingribs grestore 0.2 setlinewidth Ribb }def /Dupribs {gsave DupleW clip newpath /Ribl -0.5 0 0.04 Wingribs grestore 0.2 setlinewidth Ribg }def /Decor1 {Comp Bodylines Quadribs Triribs1 De-Comp} def /Decor2 {Comp Bodylines Triribs2 Triribs1 De-Comp} def /Decor3 {Comp Bodylines Triribs3 Triribs1 De-Comp} def /Decor4 {Comp Bodylines Triribs2 Dupribs De-Comp} def /Decor5 {Comp Bodylines Triribs3 Dupribs De-Comp} def /Decor6 {Comp Bodylines Quadribs Dupribs De-Comp} def /Decors {Comp Spine De-Comp} def %STRUCTURAL PROCEDURES /Sq1 {4 { Dark Fish1 Decor1 Swap pause -90 rotate } repeat gsave Downtail 4 { Light Fish3 Decor3 20 0 translate White Fish2 Decor2 -90 rotate Swap pause } repeat grestore } def /Sq8 { gsave -15 15 translate 0.5 0.5 scale 4 { Dark Fish1 Decor1 -90 rotate Light Fish6 Decor6 Op White Fish4 Decor4 -90 rotate Dark Fish3 Decor3 20 0 translate Fish2 Decor2 -90 rotate Light Fish5 Decor5 Op White Fish6 Decor6 -90 rotate Dark Fish1 Decor1 Swap pause -90 rotate }repeat Downtail 4 { Light Swap Fish3 Decor3 20 0 translate White Fish2 Decor2 -90 rotate 3 {Light Fish3 Decor3 20 20 translate White 90 rotate Fish2 Decor2 -90 rotate pause }repeat }repeat grestore } def /Sq20 { gsave -22.5 22.5 translate 0.25 0.25 scale 4 { Dark Fish1 Decor1 -90 rotate Light Fish6 Decor6 Op 4{ White Fish4 Decor4 -90 rotate Dark Fish3 Decor3 20 0 translate Fish2 Decor2 -90 rotate Light Fish5 Decor5 Op } repeat White Fish6 Decor6 -90 rotate Dark Fish1 Decor1 Swap pause -90 rotate }repeat Downtail 4 { Light Swap Fish3 Decor3 20 0 translate White Fish2 Decor2 -90 rotate 9 {Light Fish3 Decor3 20 20 translate White 90 rotate Fish2 Decor2 -90 rotate pause }repeat }repeat grestore } def /Sq44 {gsave -26.25 26.25 translate 0.125 0.125 scale 4 { Dark Fish1 Decors -90 rotate Light Fish6 Decors Op 10{White Fish4 Decors -90 rotate Dark Fish3 Decors 20 0 translate Fish2 Decors -90 rotate Light Fish5 Decors Op } repeat White Fish6 Decors -90 rotate Dark Fish1 Decors Swap pause -90 rotate }repeat Downtail 4 { Light Swap Fish3 Decors 20 0 translate White Fish2 Decors -90 rotate 21 {Light Fish3 Decors 20 20 translate White 90 rotate Fish2 Decors -90 rotate pause }repeat }repeat grestore } def /Sq92 {gsave -28.125 28.125 translate 0.0625 0.0625 scale 4 { Dark Fish1 -90 rotate Light Fish6 Op 22{ White Fish4 -90 rotate Dark Fish3 20 0 translate Fish2 -90 rotate Light Fish5 Op } repeat White Fish6 -90 rotate Dark Fish1 Swap pause -90 rotate }repeat Downtail 4 { Light Swap Fish3 20 0 translate White Fish2 -90 rotate 45 {Light Fish3 20 20 translate White 90 rotate Fish2 -90 rotate pause }repeat }repeat grestore } def /Sq188 {gsave -29.1125 29.1125 translate 0.03125 0.03125 scale 4 { Dark Fish1s -90 rotate Light Fish1s Op 46{ White Fish2s -90 rotate Dark Fish3s 20 0 translate Fish2s -90 rotate Light Fish3s Op } repeat White Fish1s -90 rotate Dark Fish1s Swap pause -90 rotate }repeat grestore } def /Fishes { RotateFactor rotate 0.05 setlinewidth 1 setflat 1 setlinecap Colourdisplay {0 0 1 hsbcolor} {1} ifelse fillcanvas gsave Sq1 Sq2 Sq8 Sq20 Sq44 Sq92 Sq188 grestore } def %end of Fishes /Calcscale {initclip clippath pathbbox 2 copy 2 div exch 2 div exch translate 60 div exch 60 div exch scale pop pop} def /main{ /RotateFactor 0 def /Rotation {/RotateFactor currentkey cvi store /paintclient win send} def /win framebuffer /new DefaultWindow send def {/FrameLabel(Square-Limit) def /PaintClient{gsave Calcscale Fishes grestore} def /PaintIcon {gsave 3 3 scale 10 0 translate Fish1 Decor1 grestore} def /ClientMenu[(0) (10) (30) (45) (60) (90)][ {Rotation} ] /new DefaultMenu send def } win send ColorDisplay? /Colourdisplay exch def %defined in init.ps /reshapefromuser win send /map win send }def main end %of dict ------------------------------------------------------------------------------ Andrew Dwelly E.C.R.C. UUCP: mcvax!unido!ecrcvax!andy pyramid!ecrcvax!andy ArabellaStrasse 17 CSNET:ecrcvax!andy@Germany.CSNET D-8000 Muenchen 81, West Germany UUCP Domain: andy@ecrcvax.UUCP [Bump, Crash ...... Listen; who swears ?. Christopher Robin has fallen down stairs.]