mp-char.mpiv /size: 44 Kb    last modification: 2025-02-21 11:03
1%D \module
2%D   [       file=mp-char.mpiv,
3%D        version=2011.10.1, % 1998.10.10,
4%D          title=\CONTEXT\ \METAPOST\ graphics,
5%D       subtitle=charts,
6%D         author=Hans Hagen,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
12%C details.
13
14%D This is ancient code .. but I see no need to rewrite it. This is
15%D already a partial rewrite but more could be delegated to \LUA\
16%D when used in \CONTEXT\ but it does not pay off now to look into
17%D that.
18
19%D For historic reason we first build and then flush but we could
20%D as well flush directly which would save us caching.
21
22if unknown context_shap : input "mp-shap.mpiv" ; fi ;
23if   known context_flow : endinput ; fi ;
24
25boolean context_flow ; context_flow := true ;
26
27%D settings
28
29numeric flow_grid_width             ; flow_grid_width             := 60pt ;
30numeric flow_shape_width            ; flow_shape_width            := 45pt ;
31numeric flow_grid_height            ; flow_grid_height            := 40pt ;
32numeric flow_shape_height           ; flow_shape_height           := 30pt ;
33numeric flow_chart_offset           ; flow_chart_offset           :=  2pt ;
34numeric flow_chart_clip_offset      ; flow_chart_offset           := 10pt ;
35string  flow_chart_background_color ; flow_chart_background_color := "white" ;
36boolean flow_show_mid_points        ; flow_show_mid_points        := false ;
37boolean flow_show_con_points        ; flow_show_con_points        := false ;
38boolean flow_show_all_points        ; flow_show_all_points        := false ;
39numeric flow_shape_line_width       ; flow_shape_line_width       := 2pt ;
40string  flow_shape_line_color       ; flow_shape_line_color       := "gray-5" ;
41string  flow_shape_fill_color       ; flow_shape_fill_color       := "gray-9";
42string  flow_connection_line_color  ; flow_connection_line_color  := "gray-2" ;
43
44numeric flow_connection_line_width  ; flow_connection_line_width  := flow_shape_line_width ;
45
46numeric flow_connection_smooth_size ; flow_connection_smooth_size := 5pt ;
47numeric flow_connection_arrow_size  ; flow_connection_arrow_size  := 4pt ;
48numeric flow_connection_dash_size   ; flow_connection_dash_size   := 3pt ;
49
50numeric flow_max_x                  ; flow_max_x                  := 6 ;
51numeric flow_max_y                  ; flow_max_y                  := 4 ;
52
53boolean flow_smooth                 ; flow_smooth                 := true ;
54boolean flow_peepshape              ; flow_peepshape              := false ;
55boolean flow_arrowtip               ; flow_arrowtip               := true ;
56boolean flow_dashline               ; flow_dashline               := false ;
57boolean flow_forcevalid             ; flow_forcevalid             := false ;
58boolean flow_touchshape             ; flow_touchshape             := false ;
59boolean flow_showcrossing           ; flow_showcrossing           := false ;
60boolean flow_reverse_y              ; flow_reverse_y              := true ;
61
62picture flow_dash_pattern           ; flow_dash_pattern           := nullpicture ;
63
64numeric flow_shape_node             ; flow_shape_node             :=  0 ;
65numeric flow_shape_action           ; flow_shape_action           := 24 ;
66numeric flow_shape_procedure        ; flow_shape_procedure        :=  5 ;
67numeric flow_shape_product          ; flow_shape_product          := 12 ;
68numeric flow_shape_decision         ; flow_shape_decision         := 14 ;
69numeric flow_shape_archive          ; flow_shape_archive          := 19 ;
70numeric flow_shape_loop             ; flow_shape_loop             := 35 ;
71numeric flow_shape_wait             ; flow_shape_wait             :=  6 ;
72numeric flow_shape_subprocedure     ; flow_shape_subprocedure     := 20 ;
73numeric flow_shape_singledocument   ; flow_shape_singledocument   := 32 ;
74numeric flow_shape_multidocument    ; flow_shape_multidocument    := 33 ;
75numeric flow_shape_right            ; flow_shape_right            := 66 ;
76numeric flow_shape_left             ; flow_shape_left             := 67 ;
77numeric flow_shape_up               ; flow_shape_up               := 68 ;
78numeric flow_shape_down             ; flow_shape_down             := 69 ;
79
80numeric flow_label_offset           ; flow_label_offset           := 0 ;
81numeric flow_exit_offset            ; flow_exit_offset            := 0 ;
82numeric flow_comment_offset         ; flow_comment_offset         := 0 ;
83
84% vardef some_shape_path (expr type) == imported from mp-shap
85
86def flow_show_shapes(expr n) =
87    flow_begin_chart(n,8,10) ;
88    flow_show_con_points := true ;
89    for i=0 upto 7 :
90        for j=0 upto 9 :
91            flow_new_shape(i+1,j+1,i*10+j);
92        endfor ;
93    endfor ;
94    flow_end_chart ;
95enddef ;
96
97%D connections
98
99def flow_new_chart =
100
101    flow_grid_width             := 60pt ;
102    flow_shape_width            := 45pt ;
103    flow_grid_height            := 40pt ;
104    flow_shape_height           := 30pt ;
105    flow_chart_offset           :=  2pt ;
106    flow_chart_clip_offset      := 10pt ;
107    flow_chart_background_color := "white" ;
108    flow_show_mid_points        := false ;
109    flow_show_con_points        := false ;
110    flow_show_all_points        := false ;
111    flow_shape_line_width       := 2pt ;
112    flow_shape_line_color       := "gray-5" ;
113    flow_shape_fill_color       := "gray-9" ;
114    flow_connection_line_color  := "gray-2" ;
115    flow_connection_line_width  := flow_shape_line_width ;
116    flow_connection_smooth_size := 5pt ;
117    flow_connection_arrow_size  := 4pt ;
118    flow_connection_dash_size   := 3pt ;
119    flow_label_offset           := 0 ;
120    flow_exit_offset            := 0 ;
121    flow_comment_offset         := 0 ;
122
123    flow_max_x                  := 6 ;
124    flow_max_y                  := 4 ;
125
126    flow_smooth                 := true  ;
127    flow_peepshape              := false ;
128    flow_arrowtip               := true  ;
129    flow_dashline               := false ;
130    flow_forcevalid             := false ;
131    flow_touchshape             := false ;
132    flow_showcrossing           := false ;
133    flow_reverse_y              := true ;
134
135    flow_dash_pattern           := nullpicture ;
136
137    numeric flow_xypoint   ; flow_xypoint   := 0 ;
138    numeric flow_cpath     ; flow_cpath     := 0 ;
139
140    pair    flow_xypoints   []   ;
141    boolean flow_xyfree     [][] ;
142    path    flow_xypath     [][] ;
143    numeric flow_xysx       [][] ;
144    numeric flow_xysy       [][] ;
145    string  flow_xyfill     [][] ;
146    string  flow_xydraw     [][] ;
147    numeric flow_xyline     [][] ;
148    boolean flow_xypeep     [][] ;
149    picture flow_xytext     [][] ;
150    picture flow_xylabel    [][] ;
151    picture flow_xyexit     [][] ;
152    picture flow_xycomment  [][] ;
153    path    flow_cpaths     [] ;
154    numeric flow_cline      [] ;
155    string  flow_ccolor     [] ;
156    boolean flow_carrow     [] ;
157    boolean flow_cdash      [] ;
158    boolean flow_ccross     [] ;
159    picture flow_tpicture   [][] ;
160    picture flow_bpicture   [][] ;
161    picture flow_lpicture   [][] ;
162    picture flow_rpicture   [][] ;
163    path    flow_connections[][][] ;
164
165    predefined_shapes[61] := (fullcircle scaled (1.5*predefined_shapes_yradius) xscaled (flow_grid_height/flow_grid_width)) ;
166    predefined_shapes[62] := (fullcircle scaled (2.0*predefined_shapes_yradius) xscaled (flow_grid_height/flow_grid_width)) ;
167
168enddef ;
169
170flow_new_chart ;
171
172def flow_y_pos(expr y) =
173%     if flow_reverse_y :
174        flow_max_y + 1 - y
175%     else :
176%         y
177%     fi
178enddef ;
179
180def flow_initialize_grid(expr maxx, maxy) =
181    flow_max_x := maxx ;
182    flow_max_y := maxy ;
183    flow_dsp_x := 0 ;
184    flow_dsp_y := 0 ;
185    for x=1 upto flow_max_x :
186        for y=1 upto flow_max_y :
187            flow_xyfree[x][y] := true ;
188            flow_xyfill[x][y] := flow_shape_fill_color ;
189            flow_xydraw[x][y] := flow_shape_line_color ;
190            flow_xyline[x][y] := flow_shape_line_width ;
191        endfor ;
192    endfor ;
193enddef ;
194
195def flow_scaled_to_grid =
196    xscaled flow_grid_width yscaled flow_grid_height
197enddef ;
198
199def flow_xy_offset(expr x, y) =
200    (x+.5,y+.5)
201enddef ;
202
203def flow_draw_shape(expr x, yy, p, sx, sy) =
204    begingroup ;
205        save y ; numeric y ;
206        y := flow_y_pos(yy) ;
207        flow_xypath [x][y] := (p xscaled sx yscaled sy) shifted flow_xy_offset(x,y) ;
208        flow_xyfree [x][y] := false ;
209        flow_xysx   [x][y] := sx ;
210        flow_xysy   [x][y] := sy ;
211        flow_xyfill [x][y] := flow_shape_fill_color ;
212        flow_xydraw [x][y] := flow_shape_line_color ;
213        flow_xyline [x][y] := flow_shape_line_width ;
214        flow_xypeep [x][y] := flow_peepshape ;
215    endgroup ;
216enddef ;
217
218vardef flow_i_point (expr x, y, p, t) =
219    begingroup ;
220        save q, ok ; pair q ; boolean ok ;
221        q := flow_xypath[x][y] intersectionpoint ((p) shifted flow_xy_offset(x,y)) ;
222        ok := true ;
223        if not ok :
224            message (t & " of shape (" & decimal x & "," & decimal y & ") limited") ;
225        fi ;
226        q
227    endgroup
228enddef ;
229
230vardef flow_trimmed (expr x, y, z, t) =
231    if flow_touchshape and t :
232        flow_xyline[x][y]/z
233    else :
234        epsilon
235    fi
236enddef ;
237
238numeric flow_zfactor ; flow_zfactor := 1/3 ;
239
240vardef flow_xy_bottom (expr x, y, z, t) =
241    flow_i_point(x, y, ((0,0)--(0,-2)) shifted (flow_zfactor*z*flow_xysx[x][y],0), "bottom")
242    shifted(0,-flow_trimmed(x,y,flow_grid_height,t))
243enddef ;
244
245vardef flow_xy_top (expr x, y, z, t) =
246    flow_i_point (x, y, ((0,0)--(0,2))  shifted (flow_zfactor*z*flow_xysx[x][y],0), "top")
247    shifted(0,flow_trimmed(x,y,flow_grid_height,t))
248enddef ;
249
250vardef flow_xy_left (expr x, y, z, t) =
251    flow_i_point (x, y, ((0,0)--(-2,0)) shifted (0,flow_zfactor*z*flow_xysy[x][y]), "left")
252    shifted(-flow_trimmed(x,y,flow_grid_width,t),0)
253enddef ;
254
255vardef flow_xy_right (expr x, y, z, t) =
256    flow_i_point (x, y, ((0,0)--(2,0))  shifted (0,flow_zfactor*z*flow_xysy[x][y]), "right")
257    shifted(flow_trimmed(x,y,flow_grid_width,t),0)
258enddef ;
259
260def flow_flush_shapes =
261    for x=1 upto flow_max_x :
262        for y=1 upto flow_max_y :
263            flow_flush_shape(x, y) ;
264        endfor ;
265    endfor ;
266enddef ;
267
268def flow_flush_pictures =
269    for x=1 upto flow_max_x :
270        for y=1 upto flow_max_y :
271            flow_flush_picture(x, y) ;
272        endfor ;
273    endfor ;
274enddef ;
275
276def flow_draw_connection_point(expr x, y, z) =
277    pickup pencircle scaled if (z=0): 2 fi flow_xyline[x][y] ;
278    drawdot flow_xy_bottom(x,y,z,false) flow_scaled_to_grid withcolor (1,0,0) ;
279    drawdot flow_xy_top   (x,y,z,false) flow_scaled_to_grid withcolor (0,1,0) ;
280    drawdot flow_xy_left  (x,y,z,false) flow_scaled_to_grid withcolor (0,0,1) ;
281    drawdot flow_xy_right (x,y,z,false) flow_scaled_to_grid withcolor (1,1,0) ;
282enddef ;
283
284def flow_flush_shape(expr x, yy) =
285    begingroup ;
286        save y ; numeric y ;
287        y := flow_y_pos(yy) ;
288        if not flow_xyfree[x][y] :
289            pickup pencircle scaled flow_xyline[x][y] ;
290            if flow_xypeep[x][y] :
291                fill (flow_xypath[x][y] peepholed (unitsquare shifted (x,y)))
292                    flow_scaled_to_grid withpen pencircle scaled 0
293                    withcolor flow_chart_background_color ;
294            else :
295                fill flow_xypath[x][y] flow_scaled_to_grid withcolor flow_xyfill[x][y] ;
296            fi ;
297            draw flow_xypath[x][y] flow_scaled_to_grid withcolor flow_xydraw[x][y] ;
298            if flow_show_con_points or flow_show_all_points :
299                flow_draw_connection_point(x, y, 0) ;
300            fi ;
301            if flow_show_all_points :
302                for i=-1 upto 1 :
303                    flow_draw_connection_point(x, y, i) ;
304                endfor ;
305            fi ;
306        fi ;
307    endgroup ;
308enddef ;
309
310vardef flow_points_initialized(expr xfrom, yfrom, xto, yto, n) =
311    if unknown flow_xyfree[xfrom][yfrom] or unknown flow_xyfree[xto][yto] :
312        flow_xypoint := 0 ; false
313    elseif not flow_xyfree[xfrom][yfrom] and not flow_xyfree[xto][yto] :
314        flow_xypoint := n ; true
315    else :
316        flow_xypoint := 0 ; false
317    fi
318enddef ;
319
320def flow_collapse_points = % this can become a core macro
321    begingroup ;
322        % remove redundant points
323        save n ; numeric n ;
324        n := 1 ;
325        for i=2 upto flow_xypoint :
326% message(flow_xypoints[i]);
327% message(flow_xypoints[n]);
328          % if not (flow_xypoints[i] = flow_xypoints[n]) :
329            if abs(flow_xypoints[i] - flow_xypoints[n]) > eps :
330                n := n + 1 ;
331                flow_xypoints[n] := flow_xypoints[i]
332            fi ;
333        endfor ;
334        flow_xypoint := n ;
335        % make straight lines
336% message(flow_xypoints[2]);
337% message(flow_xypoints[flow_xypoint-1]);
338      % if flow_xypoints[2] = flow_xypoints[flow_xypoint-1] :
339        if abs(flow_xypoints[2] - flow_xypoints[flow_xypoint-1]) < eps :
340            flow_xypoints[3] := flow_xypoints[flow_xypoint] ;
341            flow_xypoint := 3 ;
342        fi ;
343    endgroup ;
344enddef ;
345
346vardef flow_smooth_connection(expr a,b) =
347    if ypart a = ypart b :
348        a shifted (  if xpart a >= xpart b : - fi (flow_connection_smooth_size/flow_grid_width ),0)
349    else :
350        a shifted (0,if ypart a >= ypart b : - fi (flow_connection_smooth_size/flow_grid_height)  )
351    fi
352enddef ;
353
354% vardef flow_trim_points =
355%     begingroup
356%         save p, a, b, d, i ; numeric a, b ; path p ; pair d ;
357%         p := for i=1 upto flow_xypoint-1 : flow_xypoints[i]-- endfor flow_xypoints[flow_xypoint] ;
358%         if flow_touchshape :
359%             a := flow_shape_line_width/flow_grid_width ;
360%             b := flow_shape_line_width/flow_grid_height ;
361%         else :
362%             a := epsilon ;
363%             b := epsilon ;
364%         fi ;
365%         d := direction infinity of p ;
366%         flow_xypoints[flow_xypoint] := flow_xypoints[flow_xypoint] shifted
367%         if     xpart d < 0 : (+a,0) ;
368%         elseif xpart d > 0 : (-a,0) ;
369%         elseif ypart d < 0 : (0,+b) ;
370%         elseif ypart d > 0 : (0,-b) ;
371%         else               : origin ;
372%         fi ;
373%         d := direction 0 of p ;
374%         flow_xypoints[1] := flow_xypoints[1] shifted
375%         if     xpart d < 0 : (-a,0) ;
376%         elseif xpart d > 0 : (+a,0) ;
377%         elseif ypart d < 0 : (0,-b) ;
378%         elseif ypart d > 0 : (0,+b) ;
379%         else               : origin ;
380%         fi ;
381%     endgroup
382% enddef ;
383
384vardef flow_trim_points = enddef ;
385
386vardef flow_connection_path =
387    if flow_reverse_connection : reverse fi (flow_xypoints[1] --
388    for i=2 upto flow_xypoint-1 :
389        if flow_smooth :
390            flow_smooth_connection(flow_xypoints[i],flow_xypoints[i-1]) ..
391            controls flow_xypoints[i] and flow_xypoints[i] ..
392            flow_smooth_connection(flow_xypoints[i],flow_xypoints[i+1]) --
393        else :
394            flow_xypoints[i] --
395        fi
396    endfor
397    flow_xypoints[flow_xypoint])
398enddef ;
399
400def flow_draw_connection(expr i,xfrom,yfrom,xto,yto) = % 'i' is a comment reference
401    if flow_xypoint > 0 :
402        flow_collapse_points ;
403        flow_trim_points ;
404        flow_cpath := flow_cpath + 1 ; % maybe also store as x,y
405        flow_cpaths[flow_cpath] := flow_connection_path flow_scaled_to_grid ;
406        flow_cline[flow_cpath]  := flow_connection_line_width ;
407        flow_ccolor[flow_cpath] := flow_connection_line_color ;
408        flow_carrow[flow_cpath] := flow_arrowtip ;
409        flow_cdash[flow_cpath]  := flow_dashline ;
410        flow_ccross[flow_cpath] := flow_showcrossing ;
411        if flow_reverse_connection :
412            flow_connections[xto]  [yto]  [i] := flow_cpaths[flow_cpath] ;
413        else :
414            flow_connections[xfrom][yfrom][i] := flow_cpaths[flow_cpath] ;
415        fi ;
416    else :
417        message("no connection defined") ;
418    fi ;
419    flow_reverse_connection := false ;
420enddef ;
421
422def flow_flush_connections = % protect locals
423    begingroup ;
424    save ip, crossing, cp ; numeric ip ; boolean crossing ; path cp ;
425    ahlength := flow_connection_arrow_size ;
426    flow_dash_pattern := dashpattern(on flow_connection_dash_size off flow_connection_dash_size) ;
427    for i=1 upto flow_cpath :
428        if flow_ccross[i] :
429            crossing := false ;
430            for j=1 upto i :
431                if not (point infinity of flow_cpaths[i] = point infinity of flow_cpaths[j]) :
432                    ip := flow_cpaths[i] intersection_point flow_cpaths[j] ;
433                    if intersection_found : crossing := true fi ;
434                fi ;
435            endfor ;
436            if crossing :
437                pickup pencircle scaled 2flow_cline[i] ;
438                cp := flow_cpaths[i] ;
439                cp := cp cutbefore point .05 length cp of cp ;
440                cp := cp cutafter  point .95 length cp of cp ;
441                draw cp withcolor flow_chart_background_color ;
442            fi ;
443        fi ;
444        pickup pencircle scaled flow_cline[i] ;
445        if flow_carrow[i] :
446            if flow_cdash[i] :
447                drawarrow flow_cpaths[i] withcolor flow_ccolor[i] dashed flow_dash_pattern ;
448            else :
449                drawarrow flow_cpaths[i] withcolor flow_ccolor[i] ;
450            fi ;
451        else :
452            if flow_cdash[i] :
453                draw flow_cpaths[i] withcolor flow_ccolor[i] dashed flow_dash_pattern ;
454            else :
455                draw flow_cpaths[i] withcolor flow_ccolor[i] ;
456            fi ;
457        fi ;
458        flow_draw_midpoint(i) ;
459    endfor ;
460    endgroup ;
461enddef ;
462
463def flow_draw_midpoint (expr n) =
464    begingroup
465        save p ; pair p ;
466        p := point .5*length(flow_cpaths[n]) of flow_cpaths[n];
467        pickup pencircle scaled 2flow_cline[n] ;
468        if flow_show_mid_points :
469            drawdot p withcolor .7white ;
470        fi ;
471    endgroup ;
472enddef ;
473
474def flow_flush_picture(expr x, yy) =
475    begingroup ;
476    save y ; numeric y ;
477    y := flow_y_pos(yy) ; % maybe move this to the makers
478    if known flow_xytext[x][y] :
479        draw flow_xytext[x][y] ;
480    fi ;
481    if known flow_xylabel[x][y] :
482        draw flow_xylabel[x][y] ;
483    fi ;
484    if known flow_xyexit[x][y] :
485        draw flow_xyexit[x][y] ;
486    fi ;
487    if known flow_xycomment[x][y] :
488        draw flow_xycomment[x][y] ;
489    fi ;
490    endgroup ;
491enddef ;
492
493vardef flow_offset(expr x, y) =
494    flow_xy_offset((x+0.5)*flow_grid_width,(flow_max_y-y+1.5)*flow_grid_height)
495        shifted (-flow_xyline[x][y]/4,-flow_xyline[x][y]/4) % terrible hack (some compensation)
496enddef ;
497
498def flow_chart_draw_text(expr x, y, p) =
499    if known flow_xytext[x][y] :
500        addto flow_xytext[x][y] also
501    else :
502        flow_xytext[x][y] :=
503    fi
504    p shifted flow_offset(x,y) ;
505enddef ;
506
507def flow_chart_draw_label (expr x, y, loc, txt) =
508    begingroup ;
509        save p, s ; path p ; picture s ;
510        p := fullsquare xscaled flow_grid_width yscaled flow_grid_height ;
511        p := p shifted flow_offset(x,y) ;
512        s := txt ;
513        setbounds s to boundingbox s enlarged flow_label_offset ;
514        if known flow_xylabel[x][y] :
515            addto flow_xylabel[x][y] also
516        else :
517            flow_xylabel[x][y] :=
518        fi
519        if     loc = "tr" : anchored.llft(s,0.5[ulcorner p,urcorner p]) ;
520        elseif loc = "t"  : anchored.bot (s,0.5[ulcorner p,urcorner p]) ;
521        elseif loc = "tl" : anchored.lrt (s,0.5[ulcorner p,urcorner p]) ;
522        elseif loc = "br" : anchored.ulft(s,0.5[llcorner p,lrcorner p]) ;
523        elseif loc = "b"  : anchored.top (s,0.5[llcorner p,lrcorner p]) ;
524        elseif loc = "bl" : anchored.urt (s,0.5[llcorner p,lrcorner p]) ;
525        elseif loc = "lb" : anchored.urt (s,0.5[ulcorner p,llcorner p]) ;
526        elseif loc = "l"  : anchored.rt  (s,0.5[ulcorner p,llcorner p]) ;
527        elseif loc = "lt" : anchored.lrt (s,0.5[ulcorner p,llcorner p]) ;
528        elseif loc = "rb" : anchored.ulft(s,0.5[urcorner p,lrcorner p]) ;
529        elseif loc = "r"  : anchored.lft (s,0.5[urcorner p,lrcorner p]) ;
530        elseif loc = "rt" : anchored.llft(s,0.5[urcorner p,lrcorner p]) ;
531        else              : anchored     (s,center p) ;
532        fi ;
533    endgroup ;
534enddef ;
535
536def flow_chart_draw_exit (expr x, y, loc, txt) =
537    begingroup ;
538        save p, s ; path p ; picture s ;
539        p := fullsquare xscaled flow_grid_width yscaled flow_grid_height ;
540        p := p shifted flow_offset(x,y) ;
541        s := txt ;
542        setbounds s to boundingbox s enlarged flow_exit_offset ;
543        if known flow_xyexit[x][y] :
544            addto flow_xyexit[x][y] also
545        else :
546            flow_xyexit[x][y] :=
547        fi
548        if     loc = "t" : anchored.top(s,0.5[ulcorner p,urcorner p]) ;
549        elseif loc = "b" : anchored.bot(s,0.5[llcorner p,lrcorner p]) ;
550        elseif loc = "l" : anchored.lft(s,0.5[ulcorner p,llcorner p]) ;
551        elseif loc = "r" : anchored.rt (s,0.5[urcorner p,lrcorner p]) ;
552        else             : anchored    (s,center p) ;
553        fi ;
554    endgroup ;
555enddef ;
556
557def flow_chart_draw_comment (expr x, y, i, loc, len, txt) = % per connection
558    begingroup ;
559        if known flow_connections[x][y][i] :
560            save p, q, s ; path p, q ; picture s ;
561            p := fullsquare xscaled flow_shape_width yscaled flow_shape_height ;
562            p := p shifted flow_offset(x,y) ;
563            q := flow_connections[x][y][i] ; % already relocated
564            s := txt ;
565            setbounds s to boundingbox s enlarged flow_comment_offset ;
566            if known flow_xycomment[x][y] :
567                addto flow_xycomment[x][y] also
568            else :
569                flow_xycomment[x][y] :=
570            fi
571            if     loc = "tr"   : anchored.llft(s,if len = 0 : 0.5[ulcorner p,urcorner p] else : point len along q fi) ;
572            elseif loc = "t"    : anchored.bot (s,if len = 0 : 0.5[ulcorner p,urcorner p] else : point len along q fi) ;
573            elseif loc = "tl"   : anchored.lrt (s,if len = 0 : 0.5[ulcorner p,urcorner p] else : point len along q fi) ;
574            elseif loc = "br"   : anchored.ulft(s,if len = 0 : 0.5[llcorner p,lrcorner p] else : point len along q fi) ;
575            elseif loc = "b"    : anchored.top (s,if len = 0 : 0.5[llcorner p,lrcorner p] else : point len along q fi) ;
576            elseif loc = "bl"   : anchored.urt (s,if len = 0 : 0.5[llcorner p,lrcorner p] else : point len along q fi) ;
577            elseif loc = "lb"   : anchored.urt (s,if len = 0 : 0.5[ulcorner p,llcorner p] else : point len along q fi) ;
578            elseif loc = "l"    : anchored.rt  (s,if len = 0 : 0.5[ulcorner p,llcorner p] else : point len along q fi) ;
579            elseif loc = "lt"   : anchored.lrt (s,if len = 0 : 0.5[ulcorner p,llcorner p] else : point len along q fi) ;
580            elseif loc = "rb"   : anchored.ulft(s,if len = 0 : 0.5[urcorner p,lrcorner p] else : point len along q fi) ;
581            elseif loc = "r"    : anchored.lft (s,if len = 0 : 0.5[urcorner p,lrcorner p] else : point len along q fi) ;
582            elseif loc = "rt"   : anchored.llft(s,if len = 0 : 0.5[urcorner p,lrcorner p] else : point len along q fi) ;
583            elseif loc = "tr:*" : anchored.llft(s,point 0 of q) ;
584            elseif loc = "t:*"  : anchored.bot (s,point 0 of q) ;
585            elseif loc = "tl:*" : anchored.lrt (s,point 0 of q) ;
586            elseif loc = "br:*" : anchored.ulft(s,point 0 of q) ;
587            elseif loc = "b:*"  : anchored.top (s,point 0 of q) ;
588            elseif loc = "bl:*" : anchored.urt (s,point 0 of q) ;
589            elseif loc = "lb:*" : anchored.urt (s,point 0 of q) ;
590            elseif loc = "l:*"  : anchored.rt  (s,point 0 of q) ;
591            elseif loc = "lt:*" : anchored.lrt (s,point 0 of q) ;
592            elseif loc = "rb:*" : anchored.ulft(s,point 0 of q) ;
593            elseif loc = "r:*"  : anchored.lft (s,point 0 of q) ;
594            elseif loc = "rt:*" : anchored.llft(s,point 0 of q) ;
595            else                : anchored     (s,point 0 of q) ;
596            fi ;
597        fi ;
598    endgroup ;
599enddef ;
600
601boolean flow_reverse_connection ; flow_reverse_connection := false ;
602
603vardef flow_up_on_grid (expr n) =
604    (xpart flow_xypoints[n],(ypart flow_xypoints[n]+1) div 1)
605enddef ;
606
607vardef flow_down_on_grid (expr n) =
608    (xpart flow_xypoints[n],(ypart flow_xypoints[n]) div 1)
609enddef ;
610
611vardef flow_left_on_grid (expr n) =
612    ((xpart flow_xypoints[n]) div 1, ypart flow_xypoints[n])
613enddef ;
614
615vardef flow_right_on_grid (expr n) =
616    ((xpart flow_xypoints[n]+1) div 1, ypart flow_xypoints[n])
617enddef ;
618
619vardef flow_x_on_grid (expr n, xfrom, xto, zfrom) =
620    if (xfrom = xto) and not (zfrom = 0) :
621        if (zfrom=1) : flow_right_on_grid(2) else : flow_left_on_grid(2) fi
622    elseif xpart flow_xypoints[1] < xpart flow_xypoints[6] :
623        flow_right_on_grid(n)
624    else :
625        flow_left_on_grid(n)
626    fi
627enddef ;
628
629vardef flow_y_on_grid (expr n, yfrom, yto, zfrom) =
630    if (yfrom = yto) and not (zfrom = 0) :
631        if (zfrom = 1) : flow_up_on_grid(2) else : flow_down_on_grid(2) fi
632    elseif ypart flow_xypoints[1] < ypart flow_xypoints[6] :
633        flow_up_on_grid(n)
634    else :
635        flow_down_on_grid(n)
636    fi
637enddef ;
638
639vardef flow_xy_on_grid (expr n, m) =
640    (xpart flow_xypoints[n], ypart flow_xypoints[m])
641enddef ;
642
643vardef flow_down_to_grid (expr a,b) =
644    (xpart flow_xypoints[a], ypart flow_xypoints[if ypart flow_xypoints[a]<ypart flow_xypoints[b] : a else : b fi])
645enddef ;
646
647vardef flow_up_to_grid (expr a,b) =
648    (xpart flow_xypoints[a], ypart flow_xypoints[if ypart flow_xypoints[a]>ypart flow_xypoints[b] : a else : b fi])
649enddef ;
650
651vardef flow_left_to_grid (expr a,b) =
652    (xpart flow_xypoints[if xpart flow_xypoints[a]<xpart flow_xypoints[b] : a else : b fi], ypart flow_xypoints[a])
653enddef ;
654
655vardef flow_right_to_grid (expr a,b) =
656    (xpart flow_xypoints[if xpart flow_xypoints[a]>xpart flow_xypoints[b] : a else : b fi], ypart flow_xypoints[a])
657enddef ;
658
659vardef flow_valid_connection (expr xfrom, yfrom, xto, yto) =
660    begingroup ;
661        save ok, vc, pp ; boolean ok ; pair vc ; path pp ;
662        save flow_xyfirst, flow_xylast ; pair flow_xyfirst, flow_xylast ;
663        % check for slanted lines
664        ok := true ;
665        for i=1 upto flow_xypoint-1 :
666            if not ((xpart flow_xypoints[i]=xpart flow_xypoints[i+1]) or (ypart flow_xypoints[i]=ypart flow_xypoints[i+1])) :
667                ok := false ;
668            fi ;
669        endfor ;
670        if not ok :
671            % message("slanted");
672            false
673        elseif flow_forcevalid :
674            % message("force");
675            true
676        elseif (xfrom=xto) and (yfrom=yto) :
677            % message("self");
678            false
679        else :
680            % check for crossing shapes
681            flow_xyfirst := flow_xypoints[1] ;
682            flow_xylast := flow_xypoints[flow_xypoint] ;
683            flow_trim_points ;
684            pp := for i=1 upto flow_xypoint-1 : flow_xypoints[i]-- endfor flow_xypoints[flow_xypoint] ;
685            flow_xypoints[1] := flow_xyfirst ;
686            flow_xypoints[flow_xypoint] := flow_xylast ;
687            for i=1 upto flow_max_x :
688                for j=1 upto flow_max_y :                % was bug: xfrom,yto
689%                     if not ( ( (i,j)=(xfrom,yfrom) ) or ( (i,j)=(xto,yto) ) ) :
690                        if not flow_xyfree[i][j] :
691                            vc := pp intersection_point flow_xypath[i][j] ;
692                            if intersection_found :
693                                ok := false
694                            fi ;
695                        fi ;
696%                     fi ;
697                endfor ;
698            endfor ;
699            % if not ok: message("crossing") ; fi ;
700            ok
701        fi
702    endgroup
703enddef ;
704
705def flow_connect_top_bottom (expr n) (expr xfrom, yyfrom, zfrom) (expr xto, yyto, zto) =
706    begingroup ; save yfrom, yto ;
707    yfrom := flow_y_pos(yyfrom) ;
708    yto := flow_y_pos(yyto) ;
709    if flow_points_initialized(xfrom,yfrom,xto,yto,6) :
710        flow_xypoints[1] := flow_xy_top(xfrom,yfrom,zfrom,true) ;
711        flow_xypoints[6] := flow_xy_bottom(xto,yto,zto,true) ;
712        flow_xypoints[2] := flow_up_on_grid(1) ;
713        flow_xypoints[5] := flow_down_on_grid(6) ;
714        flow_xypoints[3] := flow_up_to_grid(2,5) ;
715        flow_xypoints[4] := flow_up_to_grid(2,5) ;
716        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
717            flow_xypoints[3] := flow_x_on_grid(2,xfrom,xto,zfrom) ;
718            flow_xypoints[4] := flow_xy_on_grid(3,5) ;
719        fi ;
720        %%%% begin experiment
721        flow_xypoints[3] := flow_xypoints[3] shifted (flow_dsp_x,0) ;
722        flow_xypoints[4] := flow_xypoints[4] shifted (flow_dsp_x,0) ;
723        if flow_dsp_y>0 :
724            flow_xypoints[2] := flow_xypoints[2] shifted (0,flow_dsp_y) ;
725            flow_xypoints[3] := flow_xypoints[3] shifted (0,flow_dsp_y) ;
726        elseif flow_dsp_y<0 :
727            flow_xypoints[4] := flow_xypoints[4] shifted (0,flow_dsp_y) ;
728            flow_xypoints[5] := flow_xypoints[5] shifted (0,flow_dsp_y) ;
729        fi
730        %%%% end experiment
731        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
732    fi ;
733    endgroup ;
734enddef ;
735
736def flow_connect_left_right (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
737    begingroup ; save yfrom, yto ;
738    yfrom := flow_y_pos(yyfrom) ;
739    yto := flow_y_pos(yyto) ;
740    if flow_points_initialized(xfrom,yfrom,xto,yto,6) :
741        flow_xypoints[1] := flow_xy_left(xfrom,yfrom,zfrom,true) ;
742        flow_xypoints[6] := flow_xy_right(xto,yto,zto,true) ;
743        flow_xypoints[2] := flow_left_on_grid(1) ;
744        flow_xypoints[5] := flow_right_on_grid(6) ;
745        flow_xypoints[3] := flow_left_to_grid(2,5) ;
746        flow_xypoints[4] := flow_left_to_grid(2,5) ;
747        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
748            flow_xypoints[3] := flow_y_on_grid(2,yfrom,yto,zfrom) ;
749            flow_xypoints[4] := flow_xy_on_grid(5,3) ;
750        fi ;
751        %%%% begin experiment
752        if flow_dsp_y <> 0 :
753            flow_xypoints[3] := flow_xypoints[3] shifted (0,-flow_dsp_y) ;
754            flow_xypoints[4] := flow_xypoints[4] shifted (0,-flow_dsp_y) ;
755        fi ;
756        %%%% end experiment
757        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
758    fi ;
759    endgroup ;
760enddef ;
761
762def flow_connect_left_top (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
763    begingroup ; save yfrom, yto ;
764    yfrom := flow_y_pos(yyfrom) ;
765    yto := flow_y_pos(yyto) ;
766    if flow_points_initialized(xfrom,yfrom,xto,yto,5) :
767        flow_xypoints[1] := flow_xy_left(xfrom,yfrom,zfrom,true) ;
768        flow_xypoints[5] := flow_xy_top(xto,yto,zto,true) ;
769        flow_xypoints[2] := flow_left_on_grid(1) ;
770        flow_xypoints[4] := flow_up_on_grid(5) ;
771        flow_xypoints[3] := flow_left_to_grid(2,5) ;
772        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
773            flow_xypoints[3] := flow_xy_on_grid(2,4) ;
774        fi ;
775        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
776    fi ;
777    endgroup ;
778enddef ;
779
780def flow_connect_left_bottom (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
781    begingroup ; save yfrom, yto ;
782    yfrom := flow_y_pos(yyfrom) ;
783    yto := flow_y_pos(yyto) ;
784    if flow_points_initialized(xfrom,yfrom,xto,yto,5) :
785        flow_xypoints[1] := flow_xy_left(xfrom,yfrom,zfrom,true) ;
786        flow_xypoints[5] := flow_xy_bottom(xto,yto,zto,true) ;
787        flow_xypoints[2] := flow_left_on_grid(1) ;
788        flow_xypoints[4] := flow_down_on_grid(5) ;
789        flow_xypoints[3] := flow_left_to_grid(2,5) ;
790        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
791            flow_xypoints[3] := flow_xy_on_grid(2,4) ;
792        fi ;
793        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
794    fi ;
795    endgroup
796enddef ;
797
798def flow_connect_right_top (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
799    begingroup ; save yfrom, yto ;
800    yfrom := flow_y_pos(yyfrom) ;
801    yto := flow_y_pos(yyto) ;
802    if flow_points_initialized(xfrom,yfrom,xto,yto,5) :
803        flow_xypoints[1] := flow_xy_right(xfrom,yfrom,zfrom,true) ;
804        flow_xypoints[5] := flow_xy_top(xto,yto,zto,true) ;
805        flow_xypoints[2] := flow_right_on_grid(1) ;
806        flow_xypoints[4] := flow_up_on_grid(5) ;
807        flow_xypoints[3] := flow_right_to_grid(2,5) ;
808        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
809            flow_xypoints[3] := flow_xy_on_grid(2,4) ;
810        fi ;
811        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
812    fi ;
813    endgroup
814enddef ;
815
816def flow_connect_right_bottom (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
817    begingroup ; save yfrom, yto ;
818    yfrom := flow_y_pos(yyfrom) ;
819    yto := flow_y_pos(yyto) ;
820    if flow_points_initialized(xfrom,yfrom,xto,yto,5) :
821        flow_xypoints[1] := flow_xy_right(xfrom,yfrom,zfrom,true) ;
822        flow_xypoints[5] := flow_xy_bottom(xto,yto,zto,true) ;
823        flow_xypoints[2] := flow_right_on_grid(1) ;
824        flow_xypoints[4] := flow_down_on_grid(5) ;
825        flow_xypoints[3] := flow_right_to_grid(2,5) ;
826        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
827            flow_xypoints[3] := flow_xy_on_grid(2,4) ;
828        fi ;
829        %%%% begin experiment
830        flow_xypoints[2] := flow_xypoints[2] shifted (flow_dsp_x,0) ;
831        flow_xypoints[3] := flow_xypoints[3] shifted (flow_dsp_x,0) ;
832        if flow_dsp_y>0 :
833          flow_xypoints[3] := flow_xypoints[3] shifted (0,-flow_dsp_y) ;
834          flow_xypoints[4] := flow_xypoints[4] shifted (0,-flow_dsp_y) ;
835        elseif flow_dsp_y<0 :
836          flow_xypoints[3] := flow_xypoints[3] shifted (0,flow_dsp_y) ;
837          flow_xypoints[4] := flow_xypoints[4] shifted (0,flow_dsp_y) ;
838        fi
839        %%%% end experiment
840        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
841    fi ;
842    endgroup
843enddef ;
844
845def flow_connect_left_left (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
846    begingroup ; save yfrom, yto ;
847    yfrom := flow_y_pos(yyfrom) ;
848    yto := flow_y_pos(yyto) ;
849    if flow_points_initialized(xfrom,yfrom,xto,yto,6) :
850        flow_xypoints[1] := flow_xy_left(xfrom,yfrom,zfrom,true) ;
851        flow_xypoints[6] := flow_xy_left(xto,yto,zto,true) ;
852        flow_xypoints[2] := flow_left_on_grid(1) ;
853        flow_xypoints[5] := flow_left_on_grid(6) ;
854        flow_xypoints[3] := flow_left_to_grid(2,5) ;
855        flow_xypoints[4] := flow_left_to_grid(5,2) ;
856        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
857            flow_xypoints[3] := flow_y_on_grid(2,yfrom,yto,zfrom) ;
858            flow_xypoints[4] := flow_xy_on_grid(5,3) ;
859        fi ;
860        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
861    fi ;
862    endgroup
863enddef ;
864
865def flow_connect_right_right (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
866    begingroup ; save yfrom, yto ;
867    yfrom := flow_y_pos(yyfrom) ;
868    yto := flow_y_pos(yyto) ;
869    if flow_points_initialized(xfrom,yfrom,xto,yto,6) :
870        flow_xypoints[1] := flow_xy_right(xfrom,yfrom,zfrom,true) ;
871        flow_xypoints[6] := flow_xy_right(xto,yto,zto,true) ;
872        flow_xypoints[2] := flow_right_on_grid(1) ;
873        flow_xypoints[5] := flow_right_on_grid(6) ;
874        flow_xypoints[3] := flow_right_to_grid(2,5) ;
875        flow_xypoints[4] := flow_right_to_grid(5,2) ;
876        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
877          flow_xypoints[3] := flow_y_on_grid(2,yfrom,yto,zfrom) ;
878          flow_xypoints[4] := flow_xy_on_grid(5,3) ;
879        fi ;
880        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
881    fi ;
882    endgroup
883enddef ;
884
885def flow_connect_top_top (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
886    begingroup ; save yfrom, yto ;
887    yfrom := flow_y_pos(yyfrom) ;
888    yto := flow_y_pos(yyto) ;
889    if flow_points_initialized(xfrom,yfrom,xto,yto,6) :
890        flow_xypoints[1] := flow_xy_top(xfrom,yfrom,zfrom,true) ;
891        flow_xypoints[6] := flow_xy_top(xto,yto,zto,true) ;
892        flow_xypoints[2] := flow_up_on_grid(1) ;
893        flow_xypoints[5] := flow_up_on_grid(6) ;
894        flow_xypoints[3] := flow_up_to_grid(2,5) ;
895        flow_xypoints[4] := flow_up_to_grid(5,2) ;
896        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
897            flow_xypoints[3] := flow_x_on_grid(2,xfrom,xto,zfrom) ;
898            flow_xypoints[4] := flow_xy_on_grid(3,5) ;
899        fi ;
900        %%%% begin experiment (todo: not value but just + and )
901        if flow_dsp_y <> 0 :
902            flow_xypoints[2] := flow_xypoints[2] shifted (0,flow_dsp_y) ;
903            flow_xypoints[3] := flow_xypoints[3] shifted (0,flow_dsp_y) ;
904            flow_xypoints[4] := flow_xypoints[4] shifted (0,flow_dsp_y) ;
905            flow_xypoints[5] := flow_xypoints[5] shifted (0,flow_dsp_y) ;
906        fi ;
907        %%%% end experiment
908        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
909    fi ;
910    endgroup
911enddef ;
912
913def flow_connect_bottom_bottom (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
914    begingroup ; save yfrom, yto ;
915    yfrom := flow_y_pos(yyfrom) ;
916    yto := flow_y_pos(yyto) ;
917    if flow_points_initialized(xfrom,yfrom,xto,yto,6) :
918        flow_xypoints[1] := flow_xy_bottom(xfrom,yfrom,zfrom,true) ;
919        flow_xypoints[6] := flow_xy_bottom(xto,yto,zto,true) ;
920        flow_xypoints[2] := flow_down_on_grid(1) ;
921        flow_xypoints[5] := flow_down_on_grid(6) ;
922        flow_xypoints[3] := flow_down_to_grid(2,5) ;
923        flow_xypoints[4] := flow_down_to_grid(5,2) ;
924        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
925            flow_xypoints[3] := flow_x_on_grid(2,xfrom,xto,zfrom) ;
926            flow_xypoints[4] := flow_xy_on_grid(3,5) ;
927        fi ;
928        %%%% begin experiment
929        flow_xypoints[3] := flow_xypoints[3] shifted (flow_dsp_x,0) ;
930        flow_xypoints[4] := flow_xypoints[4] shifted (flow_dsp_x,0) ;
931        if flow_dsp_y<0 :
932            flow_xypoints[2] := flow_xypoints[2] shifted (0,-flow_dsp_y) ;
933            flow_xypoints[3] := flow_xypoints[3] shifted (0,-flow_dsp_y) ;
934        elseif flow_dsp_y>0 :
935            flow_xypoints[4] := flow_xypoints[4] shifted (0,flow_dsp_y) ;
936            flow_xypoints[5] := flow_xypoints[5] shifted (0,flow_dsp_y) ;
937        fi
938        %%%% end experiment
939        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
940    fi ;
941    endgroup
942enddef ;
943
944def flow_connect_bottom_top (expr n) (expr xfrom,yfrom,zfrom) (expr xto,yto,zto) =
945    flow_reverse_connection := true ;
946    flow_connect_top_bottom (n) (xto,yto,zto) (xfrom,yfrom,zfrom) ;
947enddef ;
948
949def flow_connect_right_left (expr n) (expr xfrom,yfrom,zfrom) (expr xto,yto,zto) =
950    flow_reverse_connection := true ;
951    flow_connect_left_right (n) (xto,yto,zto) (xfrom,yfrom,zfrom) ;
952enddef ;
953
954def flow_connect_top_left (expr n) (expr xfrom,yfrom,zfrom) (expr xto,yto,zto) =
955    flow_reverse_connection := true ;
956    flow_connect_left_top (n) (xto,yto,zto) (xfrom,yfrom,zfrom) ;
957enddef ;
958
959def flow_connect_bottom_left (expr n) (expr xfrom,yfrom,zfrom) (expr xto,yto,zto) =
960    flow_reverse_connection := true ;
961    flow_connect_left_bottom (n) (xto,yto,zto) (xfrom,yfrom,zfrom) ;
962enddef ;
963
964def flow_connect_top_right (expr n) (expr xfrom,yfrom,zfrom) (expr xto,yto,zto) =
965    flow_reverse_connection := true ;
966    flow_connect_right_top (n) (xto,yto,zto) (xfrom,yfrom,zfrom) ;
967enddef ;
968
969def flow_connect_bottom_right (expr n) (expr xfrom,yfrom,zfrom) (expr xto,yto,zto) =
970    flow_reverse_connection := true ;
971    flow_connect_right_bottom (n) (xto,yto,zto) (xfrom,yfrom,zfrom) ;
972enddef ;
973
974def flow_draw_test_shape(expr x, y) =
975    flow_draw_shape(x,y,fullcircle,flow_shape_width/flow_grid_width,flow_shape_height/flow_grid_height) ;
976enddef ;
977
978def flow_draw_test_shapes =
979    flow_draw_test_area ;
980    for i=1 upto flow_max_x :
981        for j=1 upto flow_max_y :
982            flow_draw_test_shape(i,j) ;
983            flow_chart_draw_label(i,j,"",textext("\ttx(" & decimal i & "," & decimal j & ")"))
984        endfor ;
985    endfor ;
986enddef;
987
988def flow_draw_test_area =
989    pickup pencircle scaled .5flow_shape_line_width ;
990    for i=1 upto flow_max_x + 1 :
991        draw ((i,1) -- (i,flow_max_y+1)) flow_scaled_to_grid withcolor white/2 ;
992    endfor ;
993    for i=1 upto flow_max_y + 1 :
994        draw ((1,i) -- (flow_max_x+1,i)) flow_scaled_to_grid withcolor white/2 ;
995    endfor ;
996enddef ;
997
998def flow_show_connection(expr n, m) =
999
1000    flow_begin_chart(100+n,6,6) ;
1001
1002        flow_draw_test_area ;
1003
1004        flow_smooth   := true ;
1005        flow_arrowtip := true ;
1006        flow_dashline := true ;
1007
1008        flow_draw_test_shape(2,2) ; flow_draw_test_shape(4,5) ;
1009        flow_draw_test_shape(3,3) ; flow_draw_test_shape(5,1) ;
1010        flow_draw_test_shape(2,5) ; flow_draw_test_shape(1,3) ;
1011        flow_draw_test_shape(6,2) ; flow_draw_test_shape(4,6) ;
1012
1013        if     (m=1) :
1014            flow_connect_top_bottom    (0) (2,2,0) (4,5,0) ;
1015            flow_connect_top_bottom    (0) (3,3,0) (5,1,0) ;
1016            flow_connect_top_bottom    (0) (2,5,0) (1,3,0) ;
1017            flow_connect_top_bottom    (0) (6,2,0) (4,6,0) ;
1018        elseif (m=2) :
1019            flow_connect_top_top       (0) (2,2,0) (4,5,0) ;
1020            flow_connect_top_top       (0) (3,3,0) (5,1,0) ;
1021            flow_connect_top_top       (0) (2,5,0) (1,3,0) ;
1022            flow_connect_top_top       (0) (6,2,0) (4,6,0) ;
1023        elseif (m=3) :
1024            flow_connect_bottom_bottom (0) (2,2,0) (4,5,0) ;
1025            flow_connect_bottom_bottom (0) (3,3,0) (5,1,0) ;
1026            flow_connect_bottom_bottom (0) (2,5,0) (1,3,0) ;
1027            flow_connect_bottom_bottom (0) (6,2,0) (4,6,0) ;
1028        elseif (m=4) :
1029            flow_connect_left_right    (0) (2,2,0) (4,5,0) ;
1030            flow_connect_left_right    (0) (3,3,0) (5,1,0) ;
1031            flow_connect_left_right    (0) (2,5,0) (1,3,0) ;
1032            flow_connect_left_right    (0) (6,2,0) (4,6,0) ;
1033        elseif (m=5) :
1034            flow_connect_left_left     (0) (2,2,0) (4,5,0) ;
1035            flow_connect_left_left     (0) (3,3,0) (5,1,0) ;
1036            flow_connect_left_left     (0) (2,5,0) (1,3,0) ;
1037            flow_connect_left_left     (0) (6,2,0) (4,6,0) ;
1038        elseif (m=6) :
1039            flow_connect_right_right   (0) (2,2,0) (4,5,0) ;
1040            flow_connect_right_right   (0) (3,3,0) (5,1,0) ;
1041            flow_connect_right_right   (0) (2,5,0) (1,3,0) ;
1042            flow_connect_right_right   (0) (6,2,0) (4,6,0) ;
1043        elseif (m=7) :
1044            flow_connect_left_top      (0) (2,2,0) (4,5,0) ;
1045            flow_connect_left_top      (0) (3,3,0) (5,1,0) ;
1046            flow_connect_left_top      (0) (2,5,0) (1,3,0) ;
1047            flow_connect_left_top      (0) (6,2,0) (4,6,0) ;
1048        elseif (m=8) :
1049            flow_connect_left_bottom   (0) (2,2,0) (4,5,0) ;
1050            flow_connect_left_bottom   (0) (3,3,0) (5,1,0) ;
1051            flow_connect_left_bottom   (0) (2,5,0) (1,3,0) ;
1052            flow_connect_left_bottom   (0) (6,2,0) (4,6,0) ;
1053        elseif (m=9) :
1054            flow_connect_right_top     (0) (2,2,0) (4,5,0) ;
1055            flow_connect_right_top     (0) (3,3,0) (5,1,0) ;
1056            flow_connect_right_top     (0) (2,5,0) (1,3,0) ;
1057            flow_connect_right_top     (0) (6,2,0) (4,6,0) ;
1058        else :
1059            flow_connect_right_bottom  (0) (2,2,0) (4,5,0) ;
1060            flow_connect_right_bottom  (0) (3,3,0) (5,1,0) ;
1061            flow_connect_right_bottom  (0) (2,5,0) (1,3,0) ;
1062            flow_connect_right_bottom  (0) (6,2,0) (4,6,0) ;
1063        fi ;
1064
1065    flow_end_chart ;
1066
1067enddef ;
1068
1069def flow_show_connections =
1070    for f=1 upto 10 :
1071        flow_show_connection(f,f) ;
1072    endfor ;
1073enddef ;
1074
1075%D charts
1076
1077def flow_clip_chart(expr minx, miny, maxx, maxy) =
1078    flow_cmin_x := minx ;
1079    flow_cmax_x := maxx ;
1080    flow_cmin_y := miny ;
1081    flow_cmax_y := maxy ;
1082enddef ;
1083
1084def flow_begin_chart(expr n, maxx, maxy) =
1085    flow_new_chart ;
1086    flow_chart_figure := n ;
1087    flow_chart_scale := 1 ;
1088    if flow_chart_figure>0:
1089        beginfig(flow_chart_figure) ;
1090    fi ;
1091    flow_initialize_grid (maxx, maxy) ;
1092    bboxmargin := 0 ;
1093    flow_cmin_x := 1 ;
1094    flow_cmax_x := maxx ;
1095    flow_cmin_y := 1 ;
1096    flow_cmax_y := maxy ;
1097enddef ;
1098
1099def flow_end_chart =
1100    begingroup ;
1101    save p, c ; path p, c ;
1102    flow_flush_shapes ;
1103    flow_flush_connections ;
1104    flow_flush_pictures ;
1105    flow_cmin_x := flow_cmin_x ;
1106    flow_cmax_x := flow_cmin_x+flow_cmax_x ;
1107    flow_cmin_y := flow_cmin_y-1 ;
1108    flow_cmax_y := flow_cmin_y+flow_cmax_y ;
1109    if flow_reverse_y :
1110        flow_cmin_y := flow_y_pos(flow_cmin_y) ;
1111        flow_cmax_y := flow_y_pos(flow_cmax_y) ;
1112    fi ;
1113    p := (((flow_cmin_x,flow_cmin_y)--(flow_cmax_x,flow_cmin_y)--
1114         (flow_cmax_x,flow_cmax_y)--(flow_cmin_x,flow_cmax_y)--cycle))
1115       flow_scaled_to_grid ;
1116    %draw p withcolor red ;
1117    c := p enlarged flow_chart_clip_offset ;
1118    p := p enlarged flow_chart_offset ;
1119    clip currentpicture to c ;
1120    setbounds currentpicture to p ;
1121    endgroup ;
1122    currentpicture := currentpicture scaled flow_chart_scale ;
1123    if flow_chart_figure>0:
1124        endfig ;
1125    fi ;
1126enddef ;
1127
1128def flow_new_shape(expr x, y, n) =
1129    if known n :
1130        if (x>0) and (x<=flow_max_x) and (y>0) and (y<=flow_max_y) :
1131            flow_draw_shape(x,y,some_shape_path(n), flow_shape_width/flow_grid_width, flow_shape_height/flow_grid_height) ;
1132        else :
1133            message ("shape outside grid ignored") ;
1134        fi ;
1135    else :
1136        message ("shape not known" ) ;
1137    fi ;
1138enddef ;
1139
1140def flow_begin_sub_chart =
1141    begingroup ;
1142    save    flow_shape_line_width, flow_connection_line_width ;
1143    save    flow_shape_line_color, flow_shape_fill_color, flow_connection_line_color ;
1144    string  flow_shape_line_color, flow_shape_fill_color, flow_connection_line_color ;
1145    save    flow_smooth, flow_arrowtip, flow_dashline, flow_peepshape ;
1146    boolean flow_smooth, flow_arrowtip, flow_dashline, flow_peepshape ;
1147enddef ;
1148
1149def flow_end_sub_chart =
1150    endgroup ;
1151enddef ;
1152
1153