1# path-attribute
2
3A *path-attribute* is used provide the origin and direction of a line
4object (arc, arrow, line, move, or spline).  It is an error to use a
5*path-attribute* on
6a block object (box, circle, cylinder, dot, ellipse, file, oval, or text).
7
8There are seven forms:
9
10  *  **from** *position*
11  *  **then**? **to** *position*
12  *  **then**? **go**? *direction* *distance*?
13  *  **then**? **go**? *direction* **until**? **even with** *place*
14  *  (**then**|**go**) *distance*? **heading** *compass-angle*
15  *  (**then**|**go**) *distance*? *compass-direction*
16  *  **close**
17
18The "`from`" attribute is used to assign the starting location
19of the line object (its ".start" value).  The other six forms
20(collectively called "to" forms) assign
21intermediate vertexes or the end point (.end).   If the "`from`"
22is omitted, then "`from previous.end`" is assumed, or if there
23is no previous object, "`from (0,0)`".   If no "to" forms are
24provided then a single movement in the current layout direction
25by either the "linewid" or "lineht" (depending on layout direction)
26is used.
27
28The "from" can occur
29either before or after the various "to" subclauses.  That does not
30matter.  But the order of the various "to" subclauses do matter, of course.
31
32If there are two consecutive *direction* clauses (*direction* is
33always one of "`up`", "`down`", "`left`", or "`right`") then
34the two will be combined to specify a single line segment.
35Hence, the following are equivalent:
36
37
38  *  ... **right 4cm up 3cm** ...
39  *  ... **go 5cm heading 53.13010235** ...
40
41~~~ pikchr
42leftmargin = 1cm
43A1: arrow thick right 4cm up 3cm
44dot at A1.start
45X1: line thin color gray from (0,-3mm) down 0.4cm
46X2: line same from (4cm,-3mm) down 0.4cm
47arrow thin color gray from X1 to X2 "4cm" above
48X3: line same from (4cm+3mm,0) right 0.4cm
49X4: line same from (4cm+3mm,3cm) right .4cm
50arrow thin color gray from X3 to X4 "3cm" aligned above
51X5: line same from A1.start go 4mm heading 90+53.13010235
52X6: line same from A1.end go 4mm heading 90+53.13010235
53arrow thin color gray from X5 to X6 "5cm" below aligned
54line same from (0,1cm) up 1cm
55spline -> from 1.5cm heading 0 from A1.start \
56   to 1.5cm heading 10 from A1.start \
57   to 1.5cm heading 20 from A1.start \
58   to 1.5cm heading 30 from A1.start \
59   to 1.5cm heading 40 from A1.start \
60   to 1.5cm heading 53.13 from A1.start \
61   thin color gray "53.13°" aligned center small
62~~~
63
64If two separate movements are desired, one 4cm right and another 3cm up,
65then the "right" and "up" subphrases must be separated by the "`then`" keyword:
66
67  *  ... **right 4cm then up 3cm** ...
68
69~~~ pikchr
70leftmargin = 1cm
71A1: arrow thick right 4cm then up 3cm
72dot at A1.start
73X1: line thin color gray from (0,-3mm) down 0.4cm
74X2: line same from (4cm,-3mm) down 0.4cm
75arrow thin color gray from X1 to X2 "4cm" above
76X3: line same from (4cm+3mm,0) right 0.4cm
77X4: line same from (4cm+3mm,3cm) right .4cm
78arrow thin color gray from X3 to X4 "3cm" aligned above
79~~~
80
81## The "`until even with`" subclause
82
83The "until even with" clause is a Pikchr extension (it does not exist
84in PIC) that makes it easier to specify paths that follow a
85"Manhattan geometry" (lines are axis-aligned) or that negotiate around
86obstacles.  The phrase:
87
88>  go *direction* until even with *position*
89
90Means to continue the line in the specified *direction* until the
91coordinate being changed matches the corresponding coordinate in
92*position* If the line is going up or down, then it continues until
93the Y coordinate matches the Y coordinate of *position*.  If the line
94is going left or right, then it continues until
95the X coordinate matches the X coordinate of *position*.
96
97For example, suppose in the diagram below that we want to draw an arrow
98that begins on Origin.s and ends on Destination.s but goes around
99the Obstacle oval, clearing it by at least one centimeter.
100
101~~~ pikchr toggle
102box "Origin"
103Obstacle: oval ht 300% wid 30% with .n at linewid right of Origin.ne;
104box "Destination" with .nw at linewid right of Obstacle.n
105line invis from 1st oval.s to 1st oval.n "Obstacle" aligned
106~~~
107
108The arrow might look like this:
109
110~~~
111   arrow from Origin.s \
112      down until even with 1cm below Obstacle.s \
113      then right until even with Destination.s \
114      then to Destination.s
115~~~
116
117And we have (annotations added):
118
119~~~ pikchr toggle
120box "Origin"
121Obstacle: oval ht 300% wid 30% with .n at linewid right of Origin.ne;
122box "Destination" with .nw at linewid right of Obstacle.n
123line invis from 1st oval.s to 1st oval.n "Obstacle" aligned
124X: \
125   arrow from Origin.s \
126      down until even with 1cm below Obstacle.s \
127      then right until even with Destination.s \
128      then to Destination.s
129
130line invis color gray from X.start to 2nd vertex of X \
131    "down until even with" aligned small \
132    "1cm below Obstacle.s" aligned small
133line invis color gray from 2nd vertex of X to 3rd vertex of X \
134    "right until even with Destination.s" aligned small above
135line invis color gray from 3nd vertex of X to 4rd vertex of X \
136    "to Destination.s" aligned small above
137
138# Evidence that the alternative arrow is equivalent:
139assert( 2nd vertex of X == (Origin.s, 1cm below Obstacle.s) )
140assert( 3nd vertex of X == (Destination.s, 1cm below Obstacle.s) )
141~~~
142
143The "**(** *position* **,** *position* **)**" syntax can be used
144in a similar way.  The "**(** *position* **,** *position* **)**"
145syntax means a point whose X coordinate is taken from the first
146position and whose Y coordinate is taken from the second position.
147So the line around the obstacle could have been written like this:
148
149~~~
150   arrow from Origin.s \
151     to (Origin.s, 1cm below Obstacle.s) \
152     then to (Destination.s, 1cm below Obstacle.s) \
153     then to Destination.s
154~~~
155
156However, we believe the "`until even with`" notation is easier.
157
158## The "`close`" subclause
159
160The "`close`" attribute closes a multi-segment path so that it
161forms a polygon.  When "`close`" is used, the "`.end`" point of the
162object is no longer the last vertex in the path but is instead
163one of "`.e`", "`.s`", "`.w`", or "`.n`" according to the current
164layout direction, as it would be for a block object.
165
166The following diagram illustrates this behavior.  The "`.end`" of
167each line is tagged with a red dot.  The line that uses "`close`"
168has its end at the "`.e`" point of the bounding box since the
169layout direction is "right".  The line without "`close`" has its
170"`.end`" at the last vertex of the line.
171
172~~~ pikchr toggle
173line right 2cm then down .5cm then up 1cm right 1cm \
174   then up 1cm left 1cm then down .5cm then left 2cm \
175   close "with 'close'"
176dot color red at last line.end
177
178move to 2.5cm south of last line.start
179line right 2cm then down .5cm then up 1cm right 1cm \
180   then up 1cm left 1cm then down .5cm then left 2cm \
181   then down 1cm "without 'close'"
182dot color red at last line.end
183~~~
184