% turtle.ps -- graphics turtle. % @author Eric Laroche % @version @(#)$Id: pst-turtle.pro 1092 2019-10-01 20:19:35Z herbert $ % % turtle.ps -- graphics turtle. % Copyright (C) 1997-2001 Eric Laroche. % % This program is free software; % you can redistribute it and/or modify it. % % 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. % % the '(graphics) turtle' is a 'cursor' that has a position (x and y % coordinate), a heading and a pen up/down state. procedures as % forward, left, etc. are used as drawing idioms. % % the turtle object consists of: cx cy phi penstate. cx and cy are the % initialial coordinates, established when creating the turtle, they are % the turtles zero coordinates. phi is the turtle heading, zero means % in x direction (i.e. to the right), 90 means in the y direction (i.e. % up). penstate is a boolean indicating whether the pen is down (true) % or up (false). % implicit to the turtle object is: currentpoint. % % note that using path constructing operators moveto, rmoveto, lineto, % rlineto, arc, etc. will affect the turtle's state in a way that the % turtle's current point is changed together with the postscript vm's % current point by these operators. contrary the turtle's heading % isn't affected by these operators. % % the turtle procedures indicate syntaxes using <turtle> (an array % containing the turtle state) as abstract turtle object. % % no syntax is indicated with the abbreviated function names. % % these procedures are not handling newpath, closepath, % setlinewidth, setlinejoin, setlinecap, stroke, fill, etc. % % a current point must be set before using the turtle object and after % starting a new path. i.e. a typical initialization sequence would be % e.g. 'newpath 200 200 moveto turtle 90 setheading'. % % create a turtle object. % this saves the current point as zero point to return to by 'home'. % a turtle object is an array of: [cx cy phi penstate]. % - turtle -> <turtle> % % on stack: { x y } boolean N@name type InitXnode /tx@TurtleDict 50 dict def tx@TurtleDict begin % /nodeCounter 0 def /nodeCnt++ { nodeCounter 1 add /nodeCounter exch def } def %/saveNode { % { currentpoint } % false % (N@Turtle) nodeCounter 2 string cvs concatstrings 32 rightTrim cvn % 10 % {InitPnode} % tx@NodeDict begin NewNode end % nodeCnt++ %} def /saveNode { tx@Dict begin (Turtle) nodeCounter 2 string cvs concatstrings 32 rightTrim cvn { currentpoint } def end } def % /turtle { % get initial position. % initial position is current point. 2 setlinejoin currentpoint % phi and penstate 0 true % note: not doing any newpath. 4 array astore } bind def % destroy a turtle object. % note: this procedure serves for compatibility % to older turtle formats. % <turtle> unturtle -> - /unturtle { % return to turtle object's initial position. dup 0 get 1 index 1 get % <turtle> cx cy moveto % note: not doing any newpath. pop % - } bind def % return turtle object size. % note: this procedure serves for compatibility % to older turtle formats. % - turtlesize -> 1 /turtlesize { % 1 entry on the stack (an array with cx cy phi penstate). 1 } bind def % normalize direction. phi must be >= 0 and < 360. % <turtle> normalizephi -> <turtle> /normalizephi { dup 2 get % <turtle> phi % note: denormalized typically by less than two circles, % so the loops won't take too long. % cut while larger or equal 2 pi. { dup 360 % <turtle> phi phi 360 lt { exit } if 360 sub } loop % increment while less zero. { dup 0 % <turtle> phi phi 0 ge { exit } if 360 add } loop exch dup 2 4 -1 roll put % <turtle> } bind def % relatively move to, action depending on penstate. % <turtle> dx dy pmoveto -> <turtle> /pmoveto { % move or draw, depending on penstate 2 index 3 get { rlineto } { rmoveto } ifelse } def % where we are, from initial point (in setxy coordinates). % <turtle> xy -> <turtle> x y /xy { currentpoint % <turtle> x' y' exch 2 index 0 get sub % <turtle> y' x exch 2 index 1 get sub % <turtle> x y } bind def % calculate relative movements from setxy coordinates. % <turtle> x y rxy -> <turtle> x' y' /rxy { 3 -1 roll % x y <turtle> xy % x y <turtle> x'' y'' 5 -2 roll % <turtle> x'' y'' x y exch 4 -1 roll sub exch 3 -1 roll sub % <turtle> x' y' } bind def % logo language turtle functions % put penstate in 'up' position. % logo language turtle function % <turtle> penup -> <turtle> /penup { % false means 'up'. dup 3 false put } bind def % put penstate in 'down' position. % logo language turtle function % <turtle> pendown -> <turtle> /pendown { % true means 'down'. dup 3 true put } bind def % advance in current direction. % logo language turtle function % <turtle> d forward -> <turtle> /forward { % dx is d cos phi. 1 index 2 get cos 1 index mul % <turtle> d dx % dy is d sin phi. 2 index 2 get sin 3 -1 roll mul % <turtle> dx dy pmoveto saveNode } def % back up in current direction. % logo language turtle function % <turtle> d back -> <turtle> /back { neg forward } bind def % change direction to the left (counterclockwise, positive direction). % logo language turtle function % <turtle> omega left -> <turtle> /left { 1 index 2 get % <turtle> omega phi add % <turtle> phi' 1 index 2 3 -1 roll put normalizephi } bind def % change direction to the right (clockwise, negative direction). % logo language turtle function % <turtle> omega right -> <turtle> /right { neg left } bind def % move to a specified point. % logo language turtle function % <turtle> x y setxy -> <turtle> /setxy { rxy % <turtle> x' y' pmoveto % <turtle> } bind def % move to a specified point (only x changes). % logo language turtle function % <turtle> x setx -> <turtle> /setx { 0 rxy % <turtle> x' y' pop 0 pmoveto % <turtle> } bind def % move to a specified point (only y changes). % logo language turtle function % <turtle> y sety -> <turtle> /sety { 0 exch rxy % <turtle> x' y' exch pop 0 exch pmoveto % <turtle> } bind def % set the heading. % logo language turtle function % <turtle> phi' setheading -> <turtle> /setheading { 1 index 2 3 -1 roll put normalizephi } bind def % set heading towards a point. % logo language turtle function % <turtle> x y towards -> <turtle> /towards { rxy % <turtle> x' y' % check if both zero. 1 index 0 eq 1 index 0 eq and { % set heading to zero. pop pop 0 } { exch atan } ifelse setheading } bind def % go home; heading to zero. % logo language turtle function % <turtle> home -> <turtle> /home { 0 dup setxy 0 setheading } bind def % get x coordinate. % logo language turtle function % <turtle> xcor -> cx <turtle> x /xcor { xy pop } bind def % get y coordinate. % logo language turtle function % <turtle> ycor -> <turtle> y /ycor { xy exch pop } bind def % get heading. % logo language turtle function % <turtle> heading -> <turtle> phi /heading { dup 2 get } bind def % get pen state. % logo language turtle function % note: only the turtle relevant stuff given. % <turtle> drawstate -> <turtle> penstate /drawstate { dup 3 get } bind def % % logo language turtle function abbreviations % /bk { back } bind def /fd { forward } bind def /lt { left } bind def /pd { pendown } bind def /pu { penup } bind def /rt { right } bind def /seth { setheading } bind def % end % end of pst-turtle.pro