%!PS-Adobe-3.1 % PS ropeadope border % ====================================================== % Copyright c 2019 by Don Lancaster & Synergetics, Box 809, Thatcher, AZ, 85552 % (928) 428-4073 Email: don@tinaja.com Website: http://www.tinaja.com % Consulting services available http://www.tinaja.com/info01.html % All commercial rights and all electronic media rights ~fully~ reserved. % Linking usually welcome. Reposting expressly forbidden. Version 1.1 % A revision of our older rope border. Includes self-knotting. % A gonzo tutorial is found at https://www.tinaja.com/glib/gonzotut.pdf % A PostScript Reference Manual at % % https://www.adobe.com/content/dam/acom/en/devnet/actionscript/articles/PLRM.pdf % A PostScript Video at https://www.youtube.com/watch?v=C_tWW560tAE % Intended for acrobat distiller use via command line //acrodist /F % Can be used with GhostScript or Google Drive if want_to_trace is false % IMPORTANT: Change these two lines to switch betweeen tracing code and any result! /want_to_trace { false } store % not used in this example /want_to_see_grid {true} store %%////// Extracted Gonzo Utilities ////// /mt {moveto} def /li {lineto} def /rm {rmoveto} def /rl {rlineto} def /ct {curveto} def /cp {closepath} def /f {fill} def /pd {0 exch neg rl} def /pr { 0 rl} def /pu {0 exch rl} def /pl {neg 0 rl} def /line1 {.06 dup setlinewidth 5 mul /erase exch def} def /line2 {.12 dup setlinewidth 5 mul /erase exch def} def /line3 {.18 dup setlinewidth 5 mul /erase exch def} def /thingridlines {0} def /setgrid { /blocksize exch def translate % simplified blocksize dup scale} def /showgrid {gsave /vblocks exch def /hblocks exch def thingridlines setlinewidth [{0 0 moveto 0 vblocks rlineto stroke} 1 hblocks 1 add] xrpt [{0 0 moveto hblocks 0 rlineto stroke} 1 vblocks 1 add] yrpt fatterborder { gsave newpath 0 0.96 blocksize div dtransform round idtransform setlinewidth pop 2 setlinecap 0 0 moveto hblocks 0 rlineto 0 vblocks rlineto hblocks neg 0 rlineto closepath stroke grestore} if fat5 { gsave newpath 0 0.48 blocksize div dtransform round idtransform setlinewidth pop mark {5 0 moveto 0 vblocks rlineto stroke} 5 hblocks 5 div cvi] xrpt mark {0 5 moveto hblocks 0 rlineto stroke} 5 vblocks 5 div cvi] yrpt grestore} if fatter10 { gsave 18 setwebtint % emphasize here newpath 0 0.96 blocksize div dtransform round idtransform setlinewidth pop mark {10 0 moveto 0 vblocks rlineto stroke} 10 hblocks 10 div cvi] xrpt mark {0 10 moveto hblocks 0 rlineto stroke} 10 vblocks 10 div cvi] yrpt grestore} if grestore} def /fatterborder {true } store /fat5 {true} store /fatter10 { true} store /showdots { false } store /dot { showdots { currentpoint newpath 0.150 0 360 arc fill }if} def /mdot { mt dot} def /random {rand 65536 div 32768 div mul cvi} def % as in -- 6 random -- /gonzofont {dup type cvlit /arraytype eq {exch findfont exch makefont} {exch findfont exch scalefont} ifelse setfont mark /spacewidth ( ) stringwidth pop /cstretch cvx /add cvx /sstretch cvx /add cvx /def cvx currentfont dup backcdict exch (F?) dup 1 14 index (xxxxx) cvs 4 get put put /setfont cvx ] cvx def} def 50 dict /backcdict exch def % used "backwards" during compiling to get % fontname given the "made" font dictionary /cstretch 0 store /sstretch 0 store % repeats [ proc distance trips] xrpt /xrpt{gsave aload pop /trips exch def /dist exch def /rproc exch def trips { gsave rproc grestore dist 0 translate } repeat grestore} def /yrpt{gsave aload pop /trips exch def /dist exch def /rproc exch def trips { gsave rproc grestore 0 dist translate } repeat grestore} def % timing utilities. use stopwatchon and stopwatchoff for simple % one shot timing. For multiple time totals, use resettimer % starttimer stoptimer ... starttimer stoptimer reporttimer /mergestr {2 copy length exch length add string dup dup 4 3 roll 4 index length exch putinterval 3 1 roll exch 0 exch putinterval} def /stopwatchoff {stoptimer reporttimer} def % for single shots /stopwatchon {resettimer starttimer} def % for single shots /reporttimer {mytime 1000 div (\rElapsed time: ) print 20 string cvs print ( seconds.\r) print flush} def % to host /resettimer {/mytime 0 def} def % reset timer /starttimer {usertime /mytimenow exch def} def % add to time so far /stoptimer {usertime mytimenow sub /mytime exch mytime add def} def % for multiple timing intervals % curvetrace - creates a smooth curved path from a data point list. % enter with currentpoint set and absolute array. % 0 0 as initial data appends path; any other values % creates new path /curvetrace {/curvelist exch def tension 0 eq {/tension .000001 def} if curvelist length 3 div 1 sub cvi /#triads exch def /ptr 0 def firstpoint morepoint} def /tension 2.83301 def % default value for best fit SLIGHTLY REVISED! /showtick false def % don't show points /ticklen 15 def % length of ticks /tickhead ticklen 4 div def /prvx { curvelist ptr 3 sub get } def /curx { curvelist ptr get } def /prvy { curvelist ptr 2 sub get } def /cury { curvelist ptr 1 add get } def /prva { curvelist ptr 1 sub get } def /cura { curvelist ptr 2 add get 180 sub} def /showtic1 { showtick true eq {gsave currentpoint newpath translate cura 180 add rotate ticklen neg 2 div 0 moveto ticklen 0 rlineto tickhead neg dup rlineto tickhead dup rlineto tickhead dup neg exch rlineto 0 setlinewidth stroke 0 ticklen neg 2 div moveto 0 ticklen rlineto stroke grestore} if }def /firstpoint { curx cury 2 copy abs exch abs add 0 eq {pop pop currentpoint curvelist exch 1 exch put curvelist exch 0 exch put}{moveto} ifelse showtic1 /ptr ptr 3 add def}def /morepoint {#triads { curx prvx sub dup mul cury prvy sub dup mul add sqrt tension div /zdist exch def prva cos zdist mul prvx add prva sin zdist mul prvy add cura cos zdist mul curx add cura sin zdist mul cury add curx cury curveto showtic1 /ptr ptr 3 add def} repeat} def /showtick false def % timing utilities. use stopwatchon and stopwatchoff for simple % one shot timing. For multiple time totals, use resettimer % starttimer stoptimer ... starttimer stoptimer reporttimer /stopwatchoff {stoptimer reporttimer} def % for single shots /stopwatchon {resettimer starttimer} def % for single shots /reporttimer {mytime 1000 div (\rElapsed time: ) print 20 string cvs print ( seconds.\r) print flush} def % to host /resettimer {/mytime 0 def} def % reset timer /starttimer {usertime /mytimenow exch def} def % add to time so far /stoptimer {usertime mytimenow sub /mytime exch mytime add def} def % for multiple timing interval % insert image proc ( not needed in this example ) /jpegimageprocwithlink { % hoffset voffset hres vres urlfrom urlto save /snap2 exch def /inurllink exch store % grab link filename /infilename exch store % grab passed pix file /photoscale exch store /vpixels exch store /hpixels exch store % (\nvpixels = )print vpixels == % (\nhpixels = )print hpixels == % (\photoscale = ) print photoscale == % (\ninurllink = ) print inurllink == % (\ninfilemane = ) print infilename == translate % adjust position for final figure ??? inurllink setareaurl % autolink sizing /DeviceRGB setcolorspace % pick color model 0 0 translate % set page position hpixels vpixels scale % magnify unit square photoscale dup scale /infile infilename (r) file def % establish input read file /Data {infile /DCTDecode filter} def % define a data source << % start image dicationary /ImageType 1 % always one /Width hpixels % JPEG width in pixels /Height vpixels % JPEG height in pixels /ImageMatrix [hpixels 0 0 vpixels neg 0 vpixels ] /DataSource Data % proc to get filtered JPEG /BitsPerComponent 8 % color resolution /Decode [0 1 0 1 0 1] % per red book 4.10 >> image % call the image operator ypos snap2 restore /ypos exch def } def /setareaurl { % for auto include routine /cururlname exch store mark % start pdfmark /Rect [ 0 0 hpixels photoscale mul vpixels photoscale mul ] /Border [ 0 0 0] % [0 0 0 ] = none; [0 0 2] = debug /Color [ .7 0 0 ] /Action <> /Subtype /Link /ANN % annotation type pdfmark % call pdf operators } def % ///////// (A) WEB FRIENDLY COLOR UTILITIES ///////////// % tintmat is a self-generating list of 216 triple color values /webtintmat [ 0 1 5 { /a exch store 0 1 5 { /b exch store 0 1 5 { 5 div b 5 div a 5 div }for } for } for ] def % setwebtint accepts a color number 0 to 215 and then % sets the PostScript color generator for later use... /setwebtint { abs cvi 216 cvi mod % restrict range webtintmat exch 3 mul 3 getinterval % get values from table aload pop setrgbcolor} def % and set them % The blocks are arranged as red to the right, green % up in order of increasing blue. % Some "pure color" sequences are % red: 0 1 2 3 4 5 % orange: 0 7 8 15 16 23 (sort of) % yellow: 0 7 14 21 28 35 % green: 0 6 12 18 24 30 % aqua: 0 42 84 126 168 210 % blue: 0 36 72 108 144 180 % magenta: 0 37 74 111 148 185 % purple 0 73 73 110 147 183 (sort of) % gray 0 43 86 129 172 215 /want_to_trace false store % not used here want_to_trace { % code used by tracing program but not yet Google Drive compatible /imagelocaldirectory (C:/Users/don/Desktop/canal/images/) store % sin fwd slashes for win /imageremotedirectory (http://www.tinaja.com/canal/images/) store % sin fwd slashes for chrome /imageurl imageremotedirectory (prep1.jpg) mergestr store % goto remote image % /imagelocalsource imagelocaldirectory (prep1.jpg) mergestr store % /imagelocalsource (C:/Users/don/Desktop/google_drive/Meowrrr/meowwr1a.jpg) store /imagelocalsource (C:/Users/don/Desktop/google_drive/Ivy/ivyvid1.jpg) store gsave 66 100 % page translate ( data for jpegimageprocwithlink ) 946 1223 % hpixels and vpixels 0.445 % photoscale imagelocalsource % local jpg source imageurl % image url on clickthru jpegimageprocwithlink grestore } if %%%%%%%%%%% ROPEADOPE CODE %%%%%%%%%%%%%%%%%% /roundpath {/rpd exch def /rprad exch def rpd length 1 sub cvi /rppoints exch def rpd 0 get rpd 1 get moveto 2 2 rppoints 2 sub {/rpvalue exch def 0 1 3 {rpd exch rpvalue add get } for rprad arcto pop pop pop pop} for rpd rppoints 1 sub get rpd rppoints get lineto} def % gonzoexcerpt /showsegrule true def /hdist {pdis 2 div dup mul zdis 2 div dup mul add sqrt} def /hangle {zdis pdis atan} def % pathtosteparray converts a path {ang0 ang1 ... angn} into an array % { {xa0 ya0 xb0 yb0} {xa1 ya1 xb1 yb1} ...} The "a" points are zdis normal % "above" path center, while "b" points are zdis normal "below" path center. /pathtosteparray {mark exch {/curang exch def currentpoint /yref exch def /xref exch def mark curang hangle add dup cos hdist mul xref add exch sin hdist mul yref add curang hangle sub dup cos hdist mul xref add exch sin hdist mul yref add ] curang cos pdis mul curang sin pdis mul rlineto} forall ] /edgepointarray exch def} def % drawelement grabs three edgepoint sets and passes them on to drawproc /drawelement {0 1 edgepointarray length 3 sub {/aposn exch def edgepointarray aposn 2 add get aload pop /y5 exch def /x5 exch def /y4 exch def /x4 exch def edgepointarray aposn 1 add get aload pop /y3 exch def /x3 exch def /y2 exch def /x2 exch def edgepointarray aposn get aload pop /y1 exch def /x1 exch def /y0 exch def /x0 exch def save /dpsnap exch def drawproc clear dpsnap restore} for} def % rope1 builds a rope turn of one-half pdis. 500 max. drawarope automates it. /half1 {x2 x0 sub 2 div x0 add y2 y0 sub 2 div y0 add} def %service sub /half2 {x4 x2 sub 2 div x2 add y4 y2 sub 2 div y2 add} def %service sub /rope1 {newpath 0.5 [x2 y2 half2 x3 y3 x1 y1 half1 x2 y2] roundpath showsegrule {gsave 130 setwebtint fill grestore 0.167 setlinewidth stroke}{newpath} ifelse} def % modified for new color /drawarope {/drawproc {rope1} def pathtosteparray drawelement} def % hsquareknot draws a horizontal square knot, aided by rsqloop1 and lsqloop1 /rsqloop1 [0 0 0 0 0 0 0 0 0 0 0 15 30 45 45 45 30 15 0 0 -15 -30 -45 -60 -75 -90 -90 -90 -105 -120 -135 -150 -165 -180 -180 165 150 135 135 135 150 165 180 180 180 180 180 -165 -150 -135 -135 -135] def /lsqloop1 [180 180 180 180 180 180 180 180 180 180 180 165 150 135 135 135 150 165 180 180 -165 -150 -135 -120 -105 -90 -90 -90 -75 -60 -45 -30 -15 0 0 15 30 45 45 45 30 15 0 0 0 0 0 -15 -30 -45 -45 -45] def % The "knot" part illusion gets done by a left rsqloop1 write, a % right rsqloop1 write, and then a selective lsqloop1 rewrite of % only aposn ropettes 8.9,10, 23,24,25,26,27,28,29, and 42,43,44,45. /hsquareknot {save /squaresnap exch def % draw "under" knot loop currentpoint /yhold exch def /xhold exch def rsqloop1 drawarope save /sssnap exch def xhold % draw "over" knot loop 31.5 pdis mul add yhold moveto lsqloop1 drawarope clear sssnap restore /showsegrule { % set up specific overwrites aposn 1 add dup 8 ge exch 10 le and % 8,9,10 aposn 1 add dup 23 ge exch 29 le and % 23,24,25,26,27,28,29 or aposn 1 add dup 42 ge exch 45 le and % 42,43,44,45 or} def xhold yhold moveto rsqloop1 drawarope % conditionally overwrite ropettes clear squaresnap restore} def %%%%%%%%%%% ROPEADOPE DEMO %%%%%%%%%%%%%%%%%% /want_to_see_grid true store % view background grid? 30 setwebtint % this sets a 10x grid 50 50 10 setgrid want_to_see_grid {50 55 showgrid} if % show grid ? 9 setwebtint % darker brown outline 3.5 1 translate 0.6 dup scale % special adjustment for rope only /pdis 1.3 def /zdis 2.6 def 10 80 moveto hsquareknot % to change the number of ropettes in the rope, the number before {-90} % repeat is down the left side. The number before {0} repeat is to the % bottom right. The number before {90} repeat is up the right side. % and the number before {180} repeat closes the top from the right. % the other unrepeated numbers in the array are simply the direction the % next turn in the rope is to go. 10 pdis 2.5 mul add 80 moveto [ % start instruction array 180 180 180 180 % go west four ropettes -165 -150 -135 -120 -105 -90 % turn south 50 {-90} repeat % go down 50 ropettes -90 -75 -60 -45 -30 -15 % turn east 0 0 0 % go east four ropettes 40 {0} repeat % go east 40 ropettes 15 30 45 60 75 90 % turn north 50 {90} repeat % go north 50 ropettes 90 105 120 135 150 165 180 % turn west 12 {180} repeat % go west 12 ropettes ] % finish non knot array drawarope % follow array instructions showpage %EOF