%D \module %D [ file=mp-step.mpii, %D version=2001.05.22, %D title=\CONTEXT\ \METAPOST\ graphics, %D subtitle=steps, %D author=Hans Hagen, %D date=\currentdate, %D copyright={PRAGMA / Hans Hagen \& Ton Otten}] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See licen-en.pdf for %C details. if known context_step : endinput ; fi ; boolean context_step ; context_step := true ; %D In the associated \TEX\ module \type {m-steps}, we describe %D three methods. The first method uses a different kind of %D code than the other two. The method we decided to use, %D is based on positional information (paths) provided by %D \CONTEXT. def initialize_step_variables = save line_method, line_h_offset, line_v_offset ; numeric line_method ; line_method := 1 ; numeric line_h_offset ; line_h_offset := 3pt ; numeric line_v_offset ; line_v_offset := 3pt ; enddef ; def begin_step_chart = initialize_step_variables ; save steps, texts, t, b, tb, nofcells ; picture cells[][], texts[][][], lines[][][] ; numeric t, b ; t := 1 ; b := 2 ; numeric nofcells ; nofcells := 0 ; enddef ; def analyze_step_chart = numeric n[], l[][], r[][] ; pair p[] ; n[t] := n[b] := 0 ; numeric tb ; for i=1 upto nofcells : for nn = t, b : if bbwidth(cells[nn][i])>0 : n[nn] := n[nn] + 1 ; fi ; l[t][i] := r[t][i] := l[b][i] := r[b][i] := 0 ; endfor ; endfor ; % count left and right points for i=1 upto nofcells-1 : for j=i upto nofcells-1 : for nn = t, b : if bbwidth(texts[nn][i][j])>0 : l[nn][i] := l[nn][i] + 1 ; r[nn][j+1] := r[nn][j+1] + 1 ; fi ; endfor ; endfor ; endfor ; % calculate left and right points vardef do (expr nn, mm, ii, ss) = if (l[nn][ii] + r[nn][ii]) > 1 : ss else : .5 fi [ ulcorner cells[mm][ii], urcorner cells[mm][ii] ] enddef ; % combined rows tb := if n[t]>0 : t else : b fi ; enddef ; vardef get_step_chart_top_line (expr i, j) = if bbwidth(cells[tb][i])>0 : if bbwidth(texts[t][i][j])>0 : if bbwidth(cells[tb][j+1])>0 : p[1] := top do(t, tb, i, .6) ; p[3] := top do(t, tb, j+1, .4) ; p[2] := .5[p[1],p[3]] ; if line_method = 1 : p[2] := p[2] shifted (0, ypart (llcorner texts[t][i][j] - ulcorner cells[tb][j+1])) ; elseif line_method = 2 : p[2] := center texts[t][i][j] ; else : % nothing fi ; p[1] := p[1] shifted (0,+line_v_offset) ; p[2] := p[2] shifted (0,-line_v_offset) ; p[3] := p[3] shifted (0,+line_v_offset) ; (p[1] {up} ... p[2] ... {down} p[3]) else : origin fi else : origin fi else : origin fi enddef ; vardef get_step_chart_bot_line (expr i, j) = if bbwidth(cells[b][i])>0 : if bbwidth(texts[b][i][j])>0 : if bbwidth(cells[b][j+1])>0 : p[1] := (bot do(b, b, i, .6)) shifted (0,-bbheight(cells[b][i])) ; p[3] := (bot do(b, b, j+1, .4)) shifted (0,-bbheight(cells[b][j+1])) ; p[2] := .5[p[1],p[3]] ; if line_method = 1 : p[2] := p[2] shifted (0, -ypart (llcorner cells[b][j+1] - ulcorner texts[b][i][j])) ; elseif line_method = 2 : p[2] := center texts[b][i][j] ; fi ; p[1] := p[1] shifted (0,-line_v_offset) ; p[2] := p[2] shifted (0,+line_v_offset) ; p[3] := p[3] shifted (0,-line_v_offset) ; (p[1] {down} ... p[2] ... {up} p[3]) else : origin fi else : origin fi else : origin fi enddef ; def end_step_chart = for i=1 upto nofcells : for nn = t, b : if bbwidth(cells[nn][i]) >0 : draw cells[nn][i] ; fi ; endfor ; endfor ; for i=1 upto nofcells : for j=i upto nofcells : for nn = t, b : if known lines[nn][i][j] : if bbwidth(lines[nn][i][j])>0 : draw lines[nn][i][j] ; fi ; fi ; endfor ; endfor ; endfor ; for i=1 upto nofcells : for j=i upto nofcells : for nn = t, b : if bbwidth(texts[nn][i][j])>0 : draw texts[nn][i][j] ; fi ; endfor ; endfor ; endfor ; enddef ; %D Step tables. def begin_step_table = initialize_step_variables ; picture cells[], texts[], lines[] ; numeric nofcells ; nofcells := 0 ; enddef ; def end_step_table = for i=1 upto nofcells : if known cells[i] : if bbwidth(cells[i])>0 : draw cells[i] ; fi ; fi ; endfor ; for i=1 upto nofcells : if known lines[i] : if bbwidth(lines[i])>0 : draw lines[i] ; fi ; fi ; endfor ; for i=1 upto nofcells : if known texts[i] : if bbwidth(texts[i])>0 : draw texts[i] ; fi ; fi ; endfor ; enddef ; vardef get_step_table_line (expr i) = pair prev, self, next ; if known texts[i] : self := lft .5[llcorner texts[i], ulcorner texts[i] ] ; prev := rt if known texts[i-1] : .3 else : .5 fi [lrcorner cells[i] , urcorner cells[i] ] ; next := rt if known texts[i+1] : .7 else : .5 fi [lrcorner cells[i+1], urcorner cells[i+1]] ; self := self shifted (-line_h_offset,0) ; prev := prev shifted (+line_h_offset,0) ; next := next shifted (+line_h_offset,0) ; prev {right} ... self ... {left} next else : origin fi enddef ; %D The older method let \METAPOST\ do the typesetting. The %D macros needed for that are included here for educational %D purposes. %D %D \starttypen %D def initialize_step_variables = %D save line_color, line_width, arrow_alternative, %D text_fill_color, text_line_color, text_line_width, text_offset, %D cell_fill_color, cell_line_color, cell_line_width, cell_offset, %D line_h_offset, line_v_offset ; %D color line_color ; line_color := .4white ; %D numeric line_width ; line_width := 1.5pt ; %D color text_fill_color ; text_fill_color := white ; %D color text_line_color ; text_line_color := red ; %D numeric text_line_width ; text_line_width := 1pt ; %D numeric text_offset ; text_offset := 2pt ; %D color cell_fill_color ; cell_fill_color := white ; %D color cell_line_color ; cell_line_color := blue ; %D numeric cell_line_width ; cell_line_width := 1pt ; %D numeric cell_offset ; cell_offset := 2pt ; %D numeric line_alternative ; line_alternative := 1 ; %D numeric line_h_offset ; line_h_offset := 3pt ; %D numeric line_v_offset ; line_v_offset := 3pt ; %D enddef ; %D %D def begin_step_chart = %D begingroup ; %D initialize_step_variables ; %D save steps, texts, t, b ; %D picture cells[][] ; numeric nofcells ; nofcells := 0 ; %D picture texts[][][] ; numeric noftexts ; noftexts := 0 ; %D numeric t, b ; t := 1 ; b := 2 ; %D enddef ; %D \stoptypen %D %D We use a couple of macros to store the content. In the %D second (third) alternative we will directly fill the %D cells. %D %D \starttypen %D def set_step_chart_cells (expr one, two) = %D nofcells := nofcells + 1 ; noftexts := 0 ; %D cells[t][nofcells] := textext.rt(one) ; %D cells[b][nofcells] := textext.rt(two) ; %D enddef ; %D %D def set_step_chart_texts (expr one, two) = %D noftexts := noftexts + 1 ; %D texts[t][nofcells][noftexts] := textext.rt(one) ; %D texts[b][nofcells][noftexts] := textext.rt(two) ; %D enddef ; %D \stoptypen %D %D If you compare the building macro with the later %D alternative, you will notice that here we explicitly %D have to calculate the distances and positions. %D %D \starttypen %D def end_step_chart = %D numeric dx ; dx := 0 ; path p ; %D numeric n[] ; n[t] := n[b] := 0 ; %D numeric stepsvdistance[] ; %D vardef bbwidth (expr p) = (xpart (lrcorner p - llcorner p)) enddef ; %D vardef bbheight (expr p) = (ypart (urcorner p - lrcorner p)) enddef ; %D stepsvdistance[t] := stepsvdistance[b] := 0 ; %D for i=1 upto nofcells : %D % find largest bbox %D p := boundingbox steps %D [if bbwidth(cells[t][i])>bbwidth(cells[b][i]): t else: b fi][i] ; %D % assign largest bbox %D for nn = t, b : %D if bbwidth(cells[nn][i])>0 : %D setbounds cells[nn][i] to p enlarged cell_offset ; %D n[nn] := n[nn] + 1 ; %D fi ; %D endfor ; %D % determine height %D if n[t]>0 : %D stepsvdistance[t] := bbheight(cells[t][1]) + intertextdistance ; %D fi ; %D % add to row %D for nn = t, b : %D cells[nn][i] := cells[nn][i] shifted (dx,stepsvdistance[nn]) ; %D if bbwidth(cells[nn][i])>0 : %D dowithpath (boundingbox cells[nn][i], %D cell_line_width, cell_line_color, cell_background_color) ; %D fi ; %D endfor ; %D % calculate position %D dx := dx + interstepdistance + bbwidth(cells[b][i]) ; %D endfor ; %D boolean stacked ; stacked := false ; %D numeric l[][], r[][], l[][], r[][] ; %D pair pa, pb, pc ; path p[] ; %D for i=1 upto nofcells : %D l[t][i] := r[t][i] := l[b][i] := r[b][i] := 0 ; %D endfor ; %D % count left and right points %D for i=1 upto nofcells : for j=1 upto nofcells : for nn = t, b : %D if known texts[nn][i][j] : if bbwidth(texts[nn][i][j])>0 : %D l[nn][i] := l[nn][i] + 1 ; %D r[nn][j+i] := r[nn][j+i] + 1 ; %D stacked := (stacked or (j>1)) ; %D setbounds texts[nn][i][j] to boundingbox texts[nn][i][j] enlarged cell_offset ; %D fi fi ; %D endfor ; endfor ; endfor ; %D % calculate left and right points %D vardef do (expr nn, mm, ii, ss) = %D if (l[nn][ii] > 0) and (r[nn][ii] > 0) : ss else : .5 fi %D [ ulcorner cells[mm][ii],urcorner cells[mm][ii] ] %D enddef ; %D % draw arrow from left to right point %D def dodo (expr nn, ii, jj, dd) = %D drawarrow p[nn] %D withpen pencircle scaled arrow_line_width %D withcolor arrow_line_color ; %D transform tr ; tr := identity %D shifted point .5 along p[nn] %D shifted -center texts[nn][ii][jj] %D if not stacked : shifted (0,dd) fi ; %D dowithpath ((boundingbox texts[nn][ii][jj]) transformed tr, %D text_line_width, text_line_color, text_fill_color) ; %D enddef ; %D % draw top and bottom text boxes %D for i=1 upto nofcells : for j=1 upto nofcells : %D pickup pencircle scaled arrow_line_width ; %D if known texts[t][i][j] : if bbwidth(texts[t][i][j]) > 0 : %D pa := top do(t, if n[t]>0 : t else : b fi, i, .6) ; %D pb := top do(t, if n[t]>0 : t else : b fi, j+i, .4) ; %D pc := .5[pa,pb] shifted (0,+step_arrow_depth) ; %D p[t] := pa {up} .. if not stacked : pc .. fi {down} pb ; %D dodo(t, i, j, +intertextdistance) ; %D fi fi ; %D if known texts[b][i][j] : if bbwidth(texts[b][i][j]) > 0 : %D pa := (bot do(b, b, i, .6)) shifted (0,-bbheight(cells[b][i])) ; %D pb := (bot do(b, b, j+i, .4)) shifted (0,-bbheight(cells[b][j+i])) ; %D pc := .5[pa,pb] shifted (0,-step_arrow_depth) ; %D p[b] := pa {down} .. if not stacked : pc .. fi {up} pb ; %D dodo(b, i, j, -intertextdistance) ; %D fi fi ; %D endfor ; endfor ; %D endgroup ; %D enddef ; %D \stoptypen %D %D If you compare both methods, you will notice that the %D first method is the cleanest, but not the most efficient %D (since it needs \TEX\ runs within \METAPOST\ runs within %D \TEX\ runs).