mp-char.mpiv /size: 43 Kb    last modification: 2020-07-01 14:35
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] intersection_point ((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            if not (flow_xypoints[i] = flow_xypoints[n]) :
327                n := n + 1 ;
328                flow_xypoints[n] := flow_xypoints[i]
329            fi ;
330        endfor ;
331        flow_xypoint := n ;
332        % make straight lines
333        if flow_xypoints[2] = flow_xypoints[flow_xypoint-1] :
334            flow_xypoints[3] := flow_xypoints[flow_xypoint] ;
335            flow_xypoint := 3 ;
336        fi ;
337    endgroup ;
338enddef ;
339
340vardef flow_smooth_connection(expr a,b) =
341    if ypart a = ypart b :
342        a shifted (  if xpart a >= xpart b : - fi (flow_connection_smooth_size/flow_grid_width ),0)
343    else :
344        a shifted (0,if ypart a >= ypart b : - fi (flow_connection_smooth_size/flow_grid_height)  )
345    fi
346enddef ;
347
348vardef flow_trim_points =
349    begingroup
350        save p, a, b, d, i ; numeric a, b ; path p ; pair d ;
351        p := for i=1 upto flow_xypoint-1 : flow_xypoints[i]-- endfor flow_xypoints[flow_xypoint] ;
352        if flow_touchshape :
353            a := flow_shape_line_width/flow_grid_width ;
354            b := flow_shape_line_width/flow_grid_height ;
355        else :
356            a := epsilon ;
357            b := epsilon ;
358        fi ;
359        d := direction infinity of p ;
360        flow_xypoints[flow_xypoint] := flow_xypoints[flow_xypoint] shifted
361        if     xpart d < 0 : (+a,0) ;
362        elseif xpart d > 0 : (-a,0) ;
363        elseif ypart d < 0 : (0,+b) ;
364        elseif ypart d > 0 : (0,-b) ;
365        else               : origin ;
366        fi ;
367        d := direction 0 of p ;
368        flow_xypoints[1] := flow_xypoints[1] shifted
369        if     xpart d < 0 : (-a,0) ;
370        elseif xpart d > 0 : (+a,0) ;
371        elseif ypart d < 0 : (0,-b) ;
372        elseif ypart d > 0 : (0,+b) ;
373        else               : origin ;
374        fi ;
375    endgroup
376enddef ;
377
378vardef flow_trim_points = enddef ;
379
380vardef flow_connection_path =
381    if flow_reverse_connection : reverse fi (flow_xypoints[1] --
382    for i=2 upto flow_xypoint-1 :
383        if flow_smooth :
384            flow_smooth_connection(flow_xypoints[i],flow_xypoints[i-1]) ..
385            controls flow_xypoints[i] and flow_xypoints[i] ..
386            flow_smooth_connection(flow_xypoints[i],flow_xypoints[i+1]) --
387        else :
388            flow_xypoints[i] --
389        fi
390    endfor
391    flow_xypoints[flow_xypoint])
392enddef ;
393
394def flow_draw_connection(expr i,xfrom,yfrom,xto,yto) = % 'i' is a comment reference
395    if flow_xypoint > 0 :
396        flow_collapse_points ;
397        flow_trim_points ;
398        flow_cpath := flow_cpath + 1 ; % maybe also store as x,y
399        flow_cpaths[flow_cpath] := flow_connection_path flow_scaled_to_grid ;
400        flow_cline[flow_cpath]  := flow_connection_line_width ;
401        flow_ccolor[flow_cpath] := flow_connection_line_color ;
402        flow_carrow[flow_cpath] := flow_arrowtip ;
403        flow_cdash[flow_cpath]  := flow_dashline ;
404        flow_ccross[flow_cpath] := flow_showcrossing ;
405        if flow_reverse_connection :
406            flow_connections[xto]  [yto]  [i] := flow_cpaths[flow_cpath] ;
407        else :
408            flow_connections[xfrom][yfrom][i] := flow_cpaths[flow_cpath] ;
409        fi ;
410    else :
411        message("no connection defined") ;
412    fi ;
413    flow_reverse_connection := false ;
414enddef ;
415
416def flow_flush_connections = % protect locals
417    begingroup ;
418    save ip, crossing, cp ; numeric ip ; boolean crossing ; path cp ;
419    ahlength := flow_connection_arrow_size ;
420    flow_dash_pattern := dashpattern(on flow_connection_dash_size off flow_connection_dash_size) ;
421    for i=1 upto flow_cpath :
422        if flow_ccross[i] :
423            crossing := false ;
424            for j=1 upto i :
425                if not  (point infinity of flow_cpaths[i] = point infinity of flow_cpaths[j]) :
426                    ip := flow_cpaths[i] intersection_point flow_cpaths[j] ;
427                    if intersection_found : crossing := true fi ;
428                fi ;
429            endfor ;
430            if crossing :
431                pickup pencircle scaled 2flow_cline[i] ;
432                cp := flow_cpaths[i] ;
433                cp := cp cutbefore point .05 length cp of cp ;
434                cp := cp cutafter  point .95 length cp of cp ;
435                draw cp withcolor flow_chart_background_color ;
436            fi ;
437        fi ;
438        pickup pencircle scaled flow_cline[i] ;
439        if flow_carrow[i] :
440            if flow_cdash[i] :
441                drawarrow flow_cpaths[i] withcolor flow_ccolor[i] dashed flow_dash_pattern ;
442            else :
443                drawarrow flow_cpaths[i] withcolor flow_ccolor[i] ;
444            fi ;
445        else :
446            if flow_cdash[i] :
447                draw flow_cpaths[i] withcolor flow_ccolor[i] dashed flow_dash_pattern ;
448            else :
449                draw flow_cpaths[i] withcolor flow_ccolor[i] ;
450            fi ;
451        fi ;
452        flow_draw_midpoint(i) ;
453    endfor ;
454    endgroup ;
455enddef ;
456
457def flow_draw_midpoint (expr n) =
458    begingroup
459        save p ; pair p ;
460        p := point .5*length(flow_cpaths[n]) of flow_cpaths[n];
461        pickup pencircle scaled 2flow_cline[n] ;
462        if flow_show_mid_points :
463            drawdot p withcolor .7white ;
464        fi ;
465    endgroup ;
466enddef ;
467
468def flow_flush_picture(expr x, yy) =
469    begingroup ;
470    save y ; numeric y ;
471    y := flow_y_pos(yy) ; % maybe move this to the makers
472    if known flow_xytext[x][y] :
473        draw flow_xytext[x][y] ;
474    fi ;
475    if known flow_xylabel[x][y] :
476        draw flow_xylabel[x][y] ;
477    fi ;
478    if known flow_xyexit[x][y] :
479        draw flow_xyexit[x][y] ;
480    fi ;
481    if known flow_xycomment[x][y] :
482        draw flow_xycomment[x][y] ;
483    fi ;
484    endgroup ;
485enddef ;
486
487vardef flow_offset(expr x, y) =
488    flow_xy_offset((x+0.5)*flow_grid_width,(flow_max_y-y+1.5)*flow_grid_height)
489        shifted (-flow_xyline[x][y]/4,-flow_xyline[x][y]/4) % terrible hack (some compensation)
490enddef ;
491
492def flow_chart_draw_text(expr x, y, p) =
493    if known flow_xytext[x][y] :
494        addto flow_xytext[x][y] also
495    else :
496        flow_xytext[x][y] :=
497    fi
498    p shifted flow_offset(x,y) ;
499enddef ;
500
501def flow_chart_draw_label (expr x, y, loc, txt) =
502    begingroup ;
503        save p, s ; path p ; picture s ;
504        p := fullsquare xscaled flow_grid_width yscaled flow_grid_height ;
505        p := p shifted flow_offset(x,y) ;
506        s := txt ;
507        setbounds s to boundingbox s enlarged flow_label_offset ;
508        if known flow_xylabel[x][y] :
509            addto flow_xylabel[x][y] also
510        else :
511            flow_xylabel[x][y] :=
512        fi
513        if     loc = "tr" : anchored.llft(s,0.5[ulcorner p,urcorner p]) ;
514        elseif loc = "t"  : anchored.bot (s,0.5[ulcorner p,urcorner p]) ;
515        elseif loc = "tl" : anchored.lrt (s,0.5[ulcorner p,urcorner p]) ;
516        elseif loc = "br" : anchored.ulft(s,0.5[llcorner p,lrcorner p]) ;
517        elseif loc = "b"  : anchored.top (s,0.5[llcorner p,lrcorner p]) ;
518        elseif loc = "bl" : anchored.urt (s,0.5[llcorner p,lrcorner p]) ;
519        elseif loc = "lb" : anchored.urt (s,0.5[ulcorner p,llcorner p]) ;
520        elseif loc = "l"  : anchored.rt  (s,0.5[ulcorner p,llcorner p]) ;
521        elseif loc = "lt" : anchored.lrt (s,0.5[ulcorner p,llcorner p]) ;
522        elseif loc = "rb" : anchored.ulft(s,0.5[urcorner p,lrcorner p]) ;
523        elseif loc = "r"  : anchored.lft (s,0.5[urcorner p,lrcorner p]) ;
524        elseif loc = "rt" : anchored.llft(s,0.5[urcorner p,lrcorner p]) ;
525        else              : anchored     (s,center p) ;
526        fi ;
527    endgroup ;
528enddef ;
529
530def flow_chart_draw_exit (expr x, y, loc, txt) =
531    begingroup ;
532        save p, s ; path p ; picture s ;
533        p := fullsquare xscaled flow_grid_width yscaled flow_grid_height ;
534        p := p shifted flow_offset(x,y) ;
535        s := txt ;
536        setbounds s to boundingbox s enlarged flow_exit_offset ;
537        if known flow_xyexit[x][y] :
538            addto flow_xyexit[x][y] also
539        else :
540            flow_xyexit[x][y] :=
541        fi
542        if     loc = "t" : anchored.top(s,0.5[ulcorner p,urcorner p]) ;
543        elseif loc = "b" : anchored.bot(s,0.5[llcorner p,lrcorner p]) ;
544        elseif loc = "l" : anchored.lft(s,0.5[ulcorner p,llcorner p]) ;
545        elseif loc = "r" : anchored.rt (s,0.5[urcorner p,lrcorner p]) ;
546        else             : anchored    (s,center p) ;
547        fi ;
548    endgroup ;
549enddef ;
550
551def flow_chart_draw_comment (expr x, y, i, loc, len, txt) = % per connection
552    begingroup ;
553        if known flow_connections[x][y][i] :
554            save p, q, s ; path p, q ; picture s ;
555            p := fullsquare xscaled flow_shape_width yscaled flow_shape_height ;
556            p := p shifted flow_offset(x,y) ;
557            q := flow_connections[x][y][i] ; % already relocated
558            s := txt ;
559            setbounds s to boundingbox s enlarged flow_comment_offset ;
560            if known flow_xycomment[x][y] :
561                addto flow_xycomment[x][y] also
562            else :
563                flow_xycomment[x][y] :=
564            fi
565            if     loc = "tr"   : anchored.llft(s,if len = 0 : 0.5[ulcorner p,urcorner p] else : point len along q fi) ;
566            elseif loc = "t"    : anchored.bot (s,if len = 0 : 0.5[ulcorner p,urcorner p] else : point len along q fi) ;
567            elseif loc = "tl"   : anchored.lrt (s,if len = 0 : 0.5[ulcorner p,urcorner p] else : point len along q fi) ;
568            elseif loc = "br"   : anchored.ulft(s,if len = 0 : 0.5[llcorner p,lrcorner p] else : point len along q fi) ;
569            elseif loc = "b"    : anchored.top (s,if len = 0 : 0.5[llcorner p,lrcorner p] else : point len along q fi) ;
570            elseif loc = "bl"   : anchored.urt (s,if len = 0 : 0.5[llcorner p,lrcorner p] else : point len along q fi) ;
571            elseif loc = "lb"   : anchored.urt (s,if len = 0 : 0.5[ulcorner p,llcorner p] else : point len along q fi) ;
572            elseif loc = "l"    : anchored.rt  (s,if len = 0 : 0.5[ulcorner p,llcorner p] else : point len along q fi) ;
573            elseif loc = "lt"   : anchored.lrt (s,if len = 0 : 0.5[ulcorner p,llcorner p] else : point len along q fi) ;
574            elseif loc = "rb"   : anchored.ulft(s,if len = 0 : 0.5[urcorner p,lrcorner p] else : point len along q fi) ;
575            elseif loc = "r"    : anchored.lft (s,if len = 0 : 0.5[urcorner p,lrcorner p] else : point len along q fi) ;
576            elseif loc = "rt"   : anchored.llft(s,if len = 0 : 0.5[urcorner p,lrcorner p] else : point len along q fi) ;
577            elseif loc = "tr:*" : anchored.llft(s,point 0 of q) ;
578            elseif loc = "t:*"  : anchored.bot (s,point 0 of q) ;
579            elseif loc = "tl:*" : anchored.lrt (s,point 0 of q) ;
580            elseif loc = "br:*" : anchored.ulft(s,point 0 of q) ;
581            elseif loc = "b:*"  : anchored.top (s,point 0 of q) ;
582            elseif loc = "bl:*" : anchored.urt (s,point 0 of q) ;
583            elseif loc = "lb:*" : anchored.urt (s,point 0 of q) ;
584            elseif loc = "l:*"  : anchored.rt  (s,point 0 of q) ;
585            elseif loc = "lt:*" : anchored.lrt (s,point 0 of q) ;
586            elseif loc = "rb:*" : anchored.ulft(s,point 0 of q) ;
587            elseif loc = "r:*"  : anchored.lft (s,point 0 of q) ;
588            elseif loc = "rt:*" : anchored.llft(s,point 0 of q) ;
589            else                : anchored     (s,point 0 of q) ;
590            fi ;
591        fi ;
592    endgroup ;
593enddef ;
594
595boolean flow_reverse_connection ; flow_reverse_connection := false ;
596
597vardef flow_up_on_grid (expr n) =
598    (xpart flow_xypoints[n],(ypart flow_xypoints[n]+1) div 1)
599enddef ;
600
601vardef flow_down_on_grid (expr n) =
602    (xpart flow_xypoints[n],(ypart flow_xypoints[n]) div 1)
603enddef ;
604
605vardef flow_left_on_grid (expr n) =
606    ((xpart flow_xypoints[n]) div 1, ypart flow_xypoints[n])
607enddef ;
608
609vardef flow_right_on_grid (expr n) =
610    ((xpart flow_xypoints[n]+1) div 1, ypart flow_xypoints[n])
611enddef ;
612
613vardef flow_x_on_grid (expr n, xfrom, xto, zfrom) =
614    if (xfrom = xto) and not (zfrom = 0) :
615        if (zfrom=1) : flow_right_on_grid(2) else : flow_left_on_grid(2) fi
616    elseif xpart flow_xypoints[1] < xpart flow_xypoints[6] :
617        flow_right_on_grid(n)
618    else :
619        flow_left_on_grid(n)
620    fi
621enddef ;
622
623vardef flow_y_on_grid (expr n, yfrom, yto, zfrom) =
624    if (yfrom = yto) and not (zfrom = 0) :
625        if (zfrom = 1) : flow_up_on_grid(2) else : flow_down_on_grid(2) fi
626    elseif ypart flow_xypoints[1] < ypart flow_xypoints[6] :
627        flow_up_on_grid(n)
628    else :
629        flow_down_on_grid(n)
630    fi
631enddef ;
632
633vardef flow_xy_on_grid (expr n, m) =
634    (xpart flow_xypoints[n], ypart flow_xypoints[m])
635enddef ;
636
637vardef flow_down_to_grid (expr a,b) =
638    (xpart flow_xypoints[a], ypart flow_xypoints[if ypart flow_xypoints[a]<ypart flow_xypoints[b] : a else : b fi])
639enddef ;
640
641vardef flow_up_to_grid (expr a,b) =
642    (xpart flow_xypoints[a], ypart flow_xypoints[if ypart flow_xypoints[a]>ypart flow_xypoints[b] : a else : b fi])
643enddef ;
644
645vardef flow_left_to_grid (expr a,b) =
646    (xpart flow_xypoints[if xpart flow_xypoints[a]<xpart flow_xypoints[b] : a else : b fi], ypart flow_xypoints[a])
647enddef ;
648
649vardef flow_right_to_grid (expr a,b) =
650    (xpart flow_xypoints[if xpart flow_xypoints[a]>xpart flow_xypoints[b] : a else : b fi], ypart flow_xypoints[a])
651enddef ;
652
653vardef flow_valid_connection (expr xfrom, yfrom, xto, yto) =
654    begingroup ;
655        save ok, vc, pp ; boolean ok ; pair vc ; path pp ;
656        save flow_xyfirst, flow_xylast ; pair flow_xyfirst, flow_xylast ;
657        % check for slanted lines
658        ok := true ;
659        for i=1 upto flow_xypoint-1 :
660            if not ((xpart flow_xypoints[i]=xpart flow_xypoints[i+1]) or (ypart flow_xypoints[i]=ypart flow_xypoints[i+1])) :
661                ok := false ;
662            fi ;
663        endfor ;
664        if not ok :
665            % message("slanted");
666            false
667        elseif flow_forcevalid :
668            % message("force");
669            true
670        elseif (xfrom=xto) and (yfrom=yto) :
671            % message("self");
672            false
673        else :
674            % check for crossing shapes
675            flow_xyfirst := flow_xypoints[1] ;
676            flow_xylast := flow_xypoints[flow_xypoint] ;
677            flow_trim_points ;
678            pp := for i=1 upto flow_xypoint-1 : flow_xypoints[i]-- endfor flow_xypoints[flow_xypoint] ;
679            flow_xypoints[1] := flow_xyfirst ;
680            flow_xypoints[flow_xypoint] := flow_xylast ;
681            for i=1 upto flow_max_x :
682                for j=1 upto flow_max_y :                % was bug: xfrom,yto
683%                     if not ( ( (i,j)=(xfrom,yfrom) ) or ( (i,j)=(xto,yto) ) ) :
684                        if not flow_xyfree[i][j] :
685                            vc := pp intersection_point flow_xypath[i][j] ;
686                            if intersection_found :
687                                ok := false
688                            fi ;
689                        fi ;
690%                     fi ;
691                endfor ;
692            endfor ;
693            % if not ok: message("crossing") ; fi ;
694            ok
695        fi
696    endgroup
697enddef ;
698
699def flow_connect_top_bottom (expr n) (expr xfrom, yyfrom, zfrom) (expr xto, yyto, zto) =
700    yfrom := flow_y_pos(yyfrom) ;
701    yto := flow_y_pos(yyto) ;
702    if flow_points_initialized(xfrom,yfrom,xto,yto,6) :
703        flow_xypoints[1] := flow_xy_top(xfrom,yfrom,zfrom,true) ;
704        flow_xypoints[6] := flow_xy_bottom(xto,yto,zto,true) ;
705        flow_xypoints[2] := flow_up_on_grid(1) ;
706        flow_xypoints[5] := flow_down_on_grid(6) ;
707        flow_xypoints[3] := flow_up_to_grid(2,5) ;
708        flow_xypoints[4] := flow_up_to_grid(2,5) ;
709        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
710            flow_xypoints[3] := flow_x_on_grid(2,xfrom,xto,zfrom) ;
711            flow_xypoints[4] := flow_xy_on_grid(3,5) ;
712        fi ;
713        %%%% begin experiment
714        flow_xypoints[3] := flow_xypoints[3] shifted (flow_dsp_x,0) ;
715        flow_xypoints[4] := flow_xypoints[4] shifted (flow_dsp_x,0) ;
716        if flow_dsp_y>0 :
717            flow_xypoints[2] := flow_xypoints[2] shifted (0,flow_dsp_y) ;
718            flow_xypoints[3] := flow_xypoints[3] shifted (0,flow_dsp_y) ;
719        elseif flow_dsp_y<0 :
720            flow_xypoints[4] := flow_xypoints[4] shifted (0,flow_dsp_y) ;
721            flow_xypoints[5] := flow_xypoints[5] shifted (0,flow_dsp_y) ;
722        fi
723        %%%% end experiment
724        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
725    fi ;
726enddef ;
727
728def flow_connect_left_right (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
729    yfrom := flow_y_pos(yyfrom) ;
730    yto := flow_y_pos(yyto) ;
731    if flow_points_initialized(xfrom,yfrom,xto,yto,6) :
732        flow_xypoints[1] := flow_xy_left(xfrom,yfrom,zfrom,true) ;
733        flow_xypoints[6] := flow_xy_right(xto,yto,zto,true) ;
734        flow_xypoints[2] := flow_left_on_grid(1) ;
735        flow_xypoints[5] := flow_right_on_grid(6) ;
736        flow_xypoints[3] := flow_left_to_grid(2,5) ;
737        flow_xypoints[4] := flow_left_to_grid(2,5) ;
738        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
739            flow_xypoints[3] := flow_y_on_grid(2,yfrom,yto,zfrom) ;
740            flow_xypoints[4] := flow_xy_on_grid(5,3) ;
741        fi ;
742        %%%% begin experiment
743        if flow_dsp_y <> 0 :
744            flow_xypoints[3] := flow_xypoints[3] shifted (0,-flow_dsp_y) ;
745            flow_xypoints[4] := flow_xypoints[4] shifted (0,-flow_dsp_y) ;
746        fi ;
747        %%%% end experiment
748        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
749    fi ;
750enddef ;
751
752def flow_connect_left_top (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
753    yfrom := flow_y_pos(yyfrom) ;
754    yto := flow_y_pos(yyto) ;
755    if flow_points_initialized(xfrom,yfrom,xto,yto,5) :
756        flow_xypoints[1] := flow_xy_left(xfrom,yfrom,zfrom,true) ;
757        flow_xypoints[5] := flow_xy_top(xto,yto,zto,true) ;
758        flow_xypoints[2] := flow_left_on_grid(1) ;
759        flow_xypoints[4] := flow_up_on_grid(5) ;
760        flow_xypoints[3] := flow_left_to_grid(2,5) ;
761        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
762            flow_xypoints[3] := flow_xy_on_grid(2,4) ;
763        fi ;
764        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
765    fi ;
766enddef ;
767
768def flow_connect_left_bottom (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
769    yfrom := flow_y_pos(yyfrom) ;
770    yto := flow_y_pos(yyto) ;
771    if flow_points_initialized(xfrom,yfrom,xto,yto,5) :
772        flow_xypoints[1] := flow_xy_left(xfrom,yfrom,zfrom,true) ;
773        flow_xypoints[5] := flow_xy_bottom(xto,yto,zto,true) ;
774        flow_xypoints[2] := flow_left_on_grid(1) ;
775        flow_xypoints[4] := flow_down_on_grid(5) ;
776        flow_xypoints[3] := flow_left_to_grid(2,5) ;
777        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
778            flow_xypoints[3] := flow_xy_on_grid(2,4) ;
779        fi ;
780        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
781    fi ;
782enddef ;
783
784def flow_connect_right_top (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
785    yfrom := flow_y_pos(yyfrom) ;
786    yto := flow_y_pos(yyto) ;
787    if flow_points_initialized(xfrom,yfrom,xto,yto,5) :
788        flow_xypoints[1] := flow_xy_right(xfrom,yfrom,zfrom,true) ;
789        flow_xypoints[5] := flow_xy_top(xto,yto,zto,true) ;
790        flow_xypoints[2] := flow_right_on_grid(1) ;
791        flow_xypoints[4] := flow_up_on_grid(5) ;
792        flow_xypoints[3] := flow_right_to_grid(2,5) ;
793        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
794            flow_xypoints[3] := flow_xy_on_grid(2,4) ;
795        fi ;
796        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
797    fi ;
798enddef ;
799
800def flow_connect_right_bottom (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
801    yfrom := flow_y_pos(yyfrom) ;
802    yto := flow_y_pos(yyto) ;
803    if flow_points_initialized(xfrom,yfrom,xto,yto,5) :
804        flow_xypoints[1] := flow_xy_right(xfrom,yfrom,zfrom,true) ;
805        flow_xypoints[5] := flow_xy_bottom(xto,yto,zto,true) ;
806        flow_xypoints[2] := flow_right_on_grid(1) ;
807        flow_xypoints[4] := flow_down_on_grid(5) ;
808        flow_xypoints[3] := flow_right_to_grid(2,5) ;
809        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
810            flow_xypoints[3] := flow_xy_on_grid(2,4) ;
811        fi ;
812        %%%% begin experiment
813        flow_xypoints[2] := flow_xypoints[2] shifted (flow_dsp_x,0) ;
814        flow_xypoints[3] := flow_xypoints[3] shifted (flow_dsp_x,0) ;
815        if flow_dsp_y>0 :
816          flow_xypoints[3] := flow_xypoints[3] shifted (0,-flow_dsp_y) ;
817          flow_xypoints[4] := flow_xypoints[4] shifted (0,-flow_dsp_y) ;
818        elseif flow_dsp_y<0 :
819          flow_xypoints[3] := flow_xypoints[3] shifted (0,flow_dsp_y) ;
820          flow_xypoints[4] := flow_xypoints[4] shifted (0,flow_dsp_y) ;
821        fi
822        %%%% end experiment
823        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
824    fi ;
825enddef ;
826
827def flow_connect_left_left (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
828    yfrom := flow_y_pos(yyfrom) ;
829    yto := flow_y_pos(yyto) ;
830    if flow_points_initialized(xfrom,yfrom,xto,yto,6) :
831        flow_xypoints[1] := flow_xy_left(xfrom,yfrom,zfrom,true) ;
832        flow_xypoints[6] := flow_xy_left(xto,yto,zto,true) ;
833        flow_xypoints[2] := flow_left_on_grid(1) ;
834        flow_xypoints[5] := flow_left_on_grid(6) ;
835        flow_xypoints[3] := flow_left_to_grid(2,5) ;
836        flow_xypoints[4] := flow_left_to_grid(5,2) ;
837        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
838            flow_xypoints[3] := flow_y_on_grid(2,yfrom,yto,zfrom) ;
839            flow_xypoints[4] := flow_xy_on_grid(5,3) ;
840        fi ;
841        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
842    fi ;
843enddef ;
844
845def flow_connect_right_right (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
846    yfrom := flow_y_pos(yyfrom) ;
847    yto := flow_y_pos(yyto) ;
848    if flow_points_initialized(xfrom,yfrom,xto,yto,6) :
849        flow_xypoints[1] := flow_xy_right(xfrom,yfrom,zfrom,true) ;
850        flow_xypoints[6] := flow_xy_right(xto,yto,zto,true) ;
851        flow_xypoints[2] := flow_right_on_grid(1) ;
852        flow_xypoints[5] := flow_right_on_grid(6) ;
853        flow_xypoints[3] := flow_right_to_grid(2,5) ;
854        flow_xypoints[4] := flow_right_to_grid(5,2) ;
855        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
856          flow_xypoints[3] := flow_y_on_grid(2,yfrom,yto,zfrom) ;
857          flow_xypoints[4] := flow_xy_on_grid(5,3) ;
858        fi ;
859        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
860    fi ;
861enddef ;
862
863def flow_connect_top_top (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
864    yfrom := flow_y_pos(yyfrom) ;
865    yto := flow_y_pos(yyto) ;
866    if flow_points_initialized(xfrom,yfrom,xto,yto,6) :
867        flow_xypoints[1] := flow_xy_top(xfrom,yfrom,zfrom,true) ;
868        flow_xypoints[6] := flow_xy_top(xto,yto,zto,true) ;
869        flow_xypoints[2] := flow_up_on_grid(1) ;
870        flow_xypoints[5] := flow_up_on_grid(6) ;
871        flow_xypoints[3] := flow_up_to_grid(2,5) ;
872        flow_xypoints[4] := flow_up_to_grid(5,2) ;
873        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
874            flow_xypoints[3] := flow_x_on_grid(2,xfrom,xto,zfrom) ;
875            flow_xypoints[4] := flow_xy_on_grid(3,5) ;
876        fi ;
877        %%%% begin experiment (todo: not value but just + and )
878        if flow_dsp_y <> 0 :
879            flow_xypoints[2] := flow_xypoints[2] shifted (0,flow_dsp_y) ;
880            flow_xypoints[3] := flow_xypoints[3] shifted (0,flow_dsp_y) ;
881            flow_xypoints[4] := flow_xypoints[4] shifted (0,flow_dsp_y) ;
882            flow_xypoints[5] := flow_xypoints[5] shifted (0,flow_dsp_y) ;
883        fi ;
884        %%%% end experiment
885        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
886    fi ;
887enddef ;
888
889def flow_connect_bottom_bottom (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
890    yfrom := flow_y_pos(yyfrom) ;
891    yto := flow_y_pos(yyto) ;
892    if flow_points_initialized(xfrom,yfrom,xto,yto,6) :
893        flow_xypoints[1] := flow_xy_bottom(xfrom,yfrom,zfrom,true) ;
894        flow_xypoints[6] := flow_xy_bottom(xto,yto,zto,true) ;
895        flow_xypoints[2] := flow_down_on_grid(1) ;
896        flow_xypoints[5] := flow_down_on_grid(6) ;
897        flow_xypoints[3] := flow_down_to_grid(2,5) ;
898        flow_xypoints[4] := flow_down_to_grid(5,2) ;
899        if not flow_valid_connection(xfrom,yfrom,xto,yto) :
900            flow_xypoints[3] := flow_x_on_grid(2,xfrom,xto,zfrom) ;
901            flow_xypoints[4] := flow_xy_on_grid(3,5) ;
902        fi ;
903        %%%% begin experiment
904        flow_xypoints[3] := flow_xypoints[3] shifted (flow_dsp_x,0) ;
905        flow_xypoints[4] := flow_xypoints[4] shifted (flow_dsp_x,0) ;
906        if flow_dsp_y<0 :
907            flow_xypoints[2] := flow_xypoints[2] shifted (0,-flow_dsp_y) ;
908            flow_xypoints[3] := flow_xypoints[3] shifted (0,-flow_dsp_y) ;
909        elseif flow_dsp_y>0 :
910            flow_xypoints[4] := flow_xypoints[4] shifted (0,flow_dsp_y) ;
911            flow_xypoints[5] := flow_xypoints[5] shifted (0,flow_dsp_y) ;
912        fi
913        %%%% end experiment
914        flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
915    fi ;
916enddef ;
917
918def flow_connect_bottom_top (expr n) (expr xfrom,yfrom,zfrom) (expr xto,yto,zto) =
919    flow_reverse_connection := true ;
920    flow_connect_top_bottom (n) (xto,yto,zto) (xfrom,yfrom,zfrom) ;
921enddef ;
922
923def flow_connect_right_left (expr n) (expr xfrom,yfrom,zfrom) (expr xto,yto,zto) =
924    flow_reverse_connection := true ;
925    flow_connect_left_right (n) (xto,yto,zto) (xfrom,yfrom,zfrom) ;
926enddef ;
927
928def flow_connect_top_left (expr n) (expr xfrom,yfrom,zfrom) (expr xto,yto,zto) =
929    flow_reverse_connection := true ;
930    flow_connect_left_top (n) (xto,yto,zto) (xfrom,yfrom,zfrom) ;
931enddef ;
932
933def flow_connect_bottom_left (expr n) (expr xfrom,yfrom,zfrom) (expr xto,yto,zto) =
934    flow_reverse_connection := true ;
935    flow_connect_left_bottom (n) (xto,yto,zto) (xfrom,yfrom,zfrom) ;
936enddef ;
937
938def flow_connect_top_right (expr n) (expr xfrom,yfrom,zfrom) (expr xto,yto,zto) =
939    flow_reverse_connection := true ;
940    flow_connect_right_top (n) (xto,yto,zto) (xfrom,yfrom,zfrom) ;
941enddef ;
942
943def flow_connect_bottom_right (expr n) (expr xfrom,yfrom,zfrom) (expr xto,yto,zto) =
944    flow_reverse_connection := true ;
945    flow_connect_right_bottom (n) (xto,yto,zto) (xfrom,yfrom,zfrom) ;
946enddef ;
947
948def flow_draw_test_shape(expr x, y) =
949    flow_draw_shape(x,y,fullcircle,flow_shape_width/flow_grid_width,flow_shape_height/flow_grid_height) ;
950enddef ;
951
952def flow_draw_test_shapes =
953    flow_draw_test_area ;
954    for i=1 upto flow_max_x :
955        for j=1 upto flow_max_y :
956            flow_draw_test_shape(i,j) ;
957            flow_chart_draw_label(i,j,"",textext("\ttx(" & decimal i & "," & decimal j & ")"))
958        endfor ;
959    endfor ;
960enddef;
961
962def flow_draw_test_area =
963    pickup pencircle scaled .5flow_shape_line_width ;
964    for i=1 upto flow_max_x + 1 :
965        draw ((i,1) -- (i,flow_max_y+1)) flow_scaled_to_grid withcolor white/2 ;
966    endfor ;
967    for i=1 upto flow_max_y + 1 :
968        draw ((1,i) -- (flow_max_x+1,i)) flow_scaled_to_grid withcolor white/2 ;
969    endfor ;
970enddef ;
971
972def flow_show_connection(expr n, m) =
973
974    flow_begin_chart(100+n,6,6) ;
975
976        flow_draw_test_area ;
977
978        flow_smooth   := true ;
979        flow_arrowtip := true ;
980        flow_dashline := true ;
981
982        flow_draw_test_shape(2,2) ; flow_draw_test_shape(4,5) ;
983        flow_draw_test_shape(3,3) ; flow_draw_test_shape(5,1) ;
984        flow_draw_test_shape(2,5) ; flow_draw_test_shape(1,3) ;
985        flow_draw_test_shape(6,2) ; flow_draw_test_shape(4,6) ;
986
987        if     (m=1) :
988            flow_connect_top_bottom    (0) (2,2,0) (4,5,0) ;
989            flow_connect_top_bottom    (0) (3,3,0) (5,1,0) ;
990            flow_connect_top_bottom    (0) (2,5,0) (1,3,0) ;
991            flow_connect_top_bottom    (0) (6,2,0) (4,6,0) ;
992        elseif (m=2) :
993            flow_connect_top_top       (0) (2,2,0) (4,5,0) ;
994            flow_connect_top_top       (0) (3,3,0) (5,1,0) ;
995            flow_connect_top_top       (0) (2,5,0) (1,3,0) ;
996            flow_connect_top_top       (0) (6,2,0) (4,6,0) ;
997        elseif (m=3) :
998            flow_connect_bottom_bottom (0) (2,2,0) (4,5,0) ;
999            flow_connect_bottom_bottom (0) (3,3,0) (5,1,0) ;
1000            flow_connect_bottom_bottom (0) (2,5,0) (1,3,0) ;
1001            flow_connect_bottom_bottom (0) (6,2,0) (4,6,0) ;
1002        elseif (m=4) :
1003            flow_connect_left_right    (0) (2,2,0) (4,5,0) ;
1004            flow_connect_left_right    (0) (3,3,0) (5,1,0) ;
1005            flow_connect_left_right    (0) (2,5,0) (1,3,0) ;
1006            flow_connect_left_right    (0) (6,2,0) (4,6,0) ;
1007        elseif (m=5) :
1008            flow_connect_left_left     (0) (2,2,0) (4,5,0) ;
1009            flow_connect_left_left     (0) (3,3,0) (5,1,0) ;
1010            flow_connect_left_left     (0) (2,5,0) (1,3,0) ;
1011            flow_connect_left_left     (0) (6,2,0) (4,6,0) ;
1012        elseif (m=6) :
1013            flow_connect_right_right   (0) (2,2,0) (4,5,0) ;
1014            flow_connect_right_right   (0) (3,3,0) (5,1,0) ;
1015            flow_connect_right_right   (0) (2,5,0) (1,3,0) ;
1016            flow_connect_right_right   (0) (6,2,0) (4,6,0) ;
1017        elseif (m=7) :
1018            flow_connect_left_top      (0) (2,2,0) (4,5,0) ;
1019            flow_connect_left_top      (0) (3,3,0) (5,1,0) ;
1020            flow_connect_left_top      (0) (2,5,0) (1,3,0) ;
1021            flow_connect_left_top      (0) (6,2,0) (4,6,0) ;
1022        elseif (m=8) :
1023            flow_connect_left_bottom   (0) (2,2,0) (4,5,0) ;
1024            flow_connect_left_bottom   (0) (3,3,0) (5,1,0) ;
1025            flow_connect_left_bottom   (0) (2,5,0) (1,3,0) ;
1026            flow_connect_left_bottom   (0) (6,2,0) (4,6,0) ;
1027        elseif (m=9) :
1028            flow_connect_right_top     (0) (2,2,0) (4,5,0) ;
1029            flow_connect_right_top     (0) (3,3,0) (5,1,0) ;
1030            flow_connect_right_top     (0) (2,5,0) (1,3,0) ;
1031            flow_connect_right_top     (0) (6,2,0) (4,6,0) ;
1032        else :
1033            flow_connect_right_bottom  (0) (2,2,0) (4,5,0) ;
1034            flow_connect_right_bottom  (0) (3,3,0) (5,1,0) ;
1035            flow_connect_right_bottom  (0) (2,5,0) (1,3,0) ;
1036            flow_connect_right_bottom  (0) (6,2,0) (4,6,0) ;
1037        fi ;
1038
1039    flow_end_chart ;
1040
1041enddef ;
1042
1043def flow_show_connections =
1044    for f=1 upto 10 :
1045        flow_show_connection(f,f) ;
1046    endfor ;
1047enddef ;
1048
1049%D charts
1050
1051def flow_clip_chart(expr minx, miny, maxx, maxy) =
1052    flow_cmin_x := minx ;
1053    flow_cmax_x := maxx ;
1054    flow_cmin_y := miny ;
1055    flow_cmax_y := maxy ;
1056enddef ;
1057
1058def flow_begin_chart(expr n, maxx, maxy) =
1059    flow_new_chart ;
1060    flow_chart_figure := n ;
1061    flow_chart_scale := 1 ;
1062    if flow_chart_figure>0:
1063        beginfig(flow_chart_figure) ;
1064    fi ;
1065    flow_initialize_grid (maxx, maxy) ;
1066    bboxmargin := 0 ;
1067    flow_cmin_x := 1 ;
1068    flow_cmax_x := maxx ;
1069    flow_cmin_y := 1 ;
1070    flow_cmax_y := maxy ;
1071enddef ;
1072
1073def flow_end_chart =
1074    begingroup ;
1075    save p, c ; path p, c ;
1076    flow_flush_shapes ;
1077    flow_flush_connections ;
1078    flow_flush_pictures ;
1079    flow_cmin_x := flow_cmin_x ;
1080    flow_cmax_x := flow_cmin_x+flow_cmax_x ;
1081    flow_cmin_y := flow_cmin_y-1 ;
1082    flow_cmax_y := flow_cmin_y+flow_cmax_y ;
1083    if flow_reverse_y :
1084        flow_cmin_y := flow_y_pos(flow_cmin_y) ;
1085        flow_cmax_y := flow_y_pos(flow_cmax_y) ;
1086    fi ;
1087    p := (((flow_cmin_x,flow_cmin_y)--(flow_cmax_x,flow_cmin_y)--
1088         (flow_cmax_x,flow_cmax_y)--(flow_cmin_x,flow_cmax_y)--cycle))
1089       flow_scaled_to_grid ;
1090    %draw p withcolor red ;
1091    c := p enlarged flow_chart_clip_offset ;
1092    p := p enlarged flow_chart_offset ;
1093    clip currentpicture to c ;
1094    setbounds currentpicture to p ;
1095    endgroup ;
1096    currentpicture := currentpicture scaled flow_chart_scale ;
1097    if flow_chart_figure>0:
1098        endfig ;
1099    fi ;
1100enddef ;
1101
1102def flow_new_shape(expr x, y, n) =
1103    if known n :
1104        if (x>0) and (x<=flow_max_x) and (y>0) and (y<=flow_max_y) :
1105            flow_draw_shape(x,y,some_shape_path(n), flow_shape_width/flow_grid_width, flow_shape_height/flow_grid_height) ;
1106        else :
1107            message ("shape outside grid ignored") ;
1108        fi ;
1109    else :
1110        message ("shape not known" ) ;
1111    fi ;
1112enddef ;
1113
1114def flow_begin_sub_chart =
1115    begingroup ;
1116    save    flow_shape_line_width, flow_connection_line_width ;
1117    save    flow_shape_line_color, flow_shape_fill_color, flow_connection_line_color ;
1118    string  flow_shape_line_color, flow_shape_fill_color, flow_connection_line_color ;
1119    save    flow_smooth, flow_arrowtip, flow_dashline, flow_peepshape ;
1120    boolean flow_smooth, flow_arrowtip, flow_dashline, flow_peepshape ;
1121enddef ;
1122
1123def flow_end_sub_chart =
1124    endgroup ;
1125enddef ;
1126
1127