%%% Global variables. %%% Global variable. %%% Character coordinates that lay outside path boundaries after %%% transformation are clipped to the boundaries. %%% Variable textpathClip determines if such characters should be %%% output at path boundaries, thereby acting as a visual indicator %%% that something went wrong, or if text outside path boundaries %%% should be omitted. Variable textpathClip can be either one (omit) %%% or zero (don't omit). newinternal textpathClip; textpathClip := 1; %%% Global variable. %%% Variable textpathLetterSpace determines the amount of space that %%% is additionally inserted between all characters. This can be %%% useful, when drawing text along a concacve shape or in general %%% along paths with a high curvature. Variable textpathLetterSpace %%% can contain positive or negative values. newinternal textpathLetterSpace; textpathLetterSpace := 0bp; %%% Global variable. newinternal textpathRotation; textpathRotation := 0; %%% Global variable. newinternal textpathAbsRotation; textpathAbsRotation := 0; newinternal textpathRepeat; textpathRepeat := 1; newinternal textpathStretch; textpathStretch := 1; newinternal textpathHSpace; textpathHSpace := 0; newinternal textpathShift; textpathShift := 0; newinternal textpathSoulLetterSpace; textpathSoulLetterSpace := 10bp; newinternal textpathFancyStrokes; textpathFancyStrokes := 1; newinternal textpathStrokePrecision; textpathStrokePrecision := 10; newinternal textpathCureSqrt; textpathCureSqrt := 1; newinternal textpathDebug; textpathDebug := 0; pair textpathHookCoord, textpathHookPoint; newinternal textpathHookRoot; textpathHookCoord := origin; textpathHookPoint := origin; textpathHookRot := 0; %%% User Macros. %%% User macro. %%% Set text along a path. %%% Parameters: %%% * a text string t that is fed into TeX through latexmp, %%% * a path p the text should follow. %%% * a numeric variable j that controls justification: %%% j=0: text is left aligned on the path, %%% j=0.5: text is centered on the path, %%% j=1: text is right aligned on the path, %%% The general rule is the character at fraction j of the total %%% text width is transformed to the point at fraction j of the total %%% path width. j should be from the interval [0, 1]. %%% Return value: %%% * a picture variable containing text following a path. def textpath(expr t, p, j)= textpathFont("", t, p, j) enddef; %%% User macro. %%% Set text in arbitrary font along a path. %%% Parameters: %%% * a string f that is a valid LaTeX font selection command, e.g., \itshape, %%% * a text string t that is fed into TeX through latexmp, %%% * a path p the text should follow. %%% * a numeric variable j that controls justification: %%% j=0: text is left aligned on the path, %%% j=0.5: text is centered on the path, %%% j=1: text is right aligned on the path, %%% The general rule is the character at fraction j of the total %%% text width is transformed to the point at fraction j of the total %%% path width. j should be from the interval [0, 1]. %%% Return value: %%% * a picture variable containing text following a path. vardef textpathFont(expr f, t, p, j)= save pre, post; string pre, post; pre := f & "\spaced{"; post := "}"; textpathPic(strToPic(pre & t & post), p, j, "") enddef; %%% User macro. %%% Set text along a path. %%% Parameters: %%% * a text string t that is fed into TeX through latexmp, %%% * a path p the text should follow. %%% * a numeric variable j that controls justification: %%% j=0: text is left aligned on the path, %%% j=0.5: text is centered on the path, %%% j=1: text is right aligned on the path, %%% The general rule is the character at fraction j of the total %%% text width is transformed to the point at fraction j of the total %%% path width. j should be from the interval [0, 1]. %%% Return value: %%% * a picture variable containing text following a path. vardef textpathRaw(expr t, p, j)= save temp, pic, pre, post; numeric temp; picture pic; string pre, post; pre := "\rule[-30bp]{0pt}{30bp}"; post := ""; temp := textpathSoulLetterSpace; textpathSoulLetterSpace := 0bp; pic := textpathPicRaw(strToPic(pre & t & post), p, j, ""); textpathSoulLetterSpace := temp; pic enddef; %%% Internal Macros. %%% Internal macro. %%% Convert a string into a picture using TeX via latexmp package. %%% Parameters: %%% * a string. %%% Return value: %%% * a picture variable. vardef strToPic(expr s)= save loffset, pic; numeric loffset; picture pic; loffset := labeloffset; labeloffset := 0bp; pic := thelabel.urt(textext(s), origin); labeloffset := loffset; pic enddef; %%% Internal working macro. %%% Set text from picture variable along a path with justification j. %%% Parameters: %%% * a picture that contains the text that has to be transformed onto a path, %%% * a path p the text should follow, %%% * a numeric variable that controls justification, %%% * a string: "debug" indicates debug mode. %%% Return value: %%% * a picture variable containing text following a path. vardef textpathPic(expr textpic, p, j, debug)= save tb, db, pic, item, bitem, banker, k, i, lenp, lenpic, bx, cx, ltextpathHSpace; numeric tb, db, k, i, lenp, lenpic, ltextpathHSpace, bx, cx; picture pic, item, bitem; pair banker; pic := nullpicture; lenp := arclength(p); lenpic := 0; k := 0; for item within textpic: if textual item: bitem := item shifted (-k*textpathSoulLetterSpace, 0bp) shifted (k*textpathLetterSpace, 0bp); x := xpart lrcorner bitem; if x > lenpic: lenpic := x; fi k := k + 1; fi endfor if textpathStretch=1: ltextpathHSpace := lenp/textpathRepeat - lenpic; else: ltextpathHSpace := textpathHSpace; fi k := 0; for item within textpic: if textual item: bitem := item shifted (-k*textpathSoulLetterSpace, 0bp) shifted (k*textpathLetterSpace, textpathShift); banker := (xpart center bitem, ypart item); if textpathStretch=1: bx := (xpart banker) + j*ltextpathHSpace; else: bx := (xpart banker) + j*(lenp - textpathRepeat*lenpic - (textpathRepeat-1)*ltextpathHSpace); fi bitem := bitem shifted -banker; for i:= 1 upto textpathRepeat: cx := (i-1)*(lenpic + ltextpathHSpace) + bx; if (textpathClip=0) or ((cx>=0) and (cx<=lenp)): tb := arctime cx of p; if textpathAbsRotation=0: db := textpathRotation + angle direction tb of p; else: db := textpathRotation; fi if not (debug="debug"): addto pic also bitem rotated db shifted point tb of p; else: addto pic contour fullcircle scaled 2bp shifted point tb of p; fi fi endfor k := k + 1; else: show "Warning! Unsupported picture element found!"; fi endfor pic enddef; %%% Internal working macro. %%% Set text from picture variable along a path with justification j. %%% Parameters: %%% * a picture that contains the text that has to be transformed onto a path, %%% * a path p the text should follow, %%% * a numeric variable that controls justification, %%% * a string: "debug" indicates debug mode. %%% Return value: %%% * a picture variable containing text following a path. vardef textpathPicRaw(expr textpic, p, j, debug)= save tb, db, pic, item, bitem, banker, i, lenp, lenpic, bx, cx, ltextpathHSpace, pp, np, dpp; numeric tb, db, dpp, i, h, lenp, lenpic, ltextpathHSpace, bx, cx; picture pic, item, bitem; pair banker; path pp, np; show textpic; pic := nullpicture; lenp := arclength(p); lenpic := xpart (lrcorner textpic - llcorner textpic); if textpathStretch=1: ltextpathHSpace := lenp/textpathRepeat - lenpic; else: ltextpathHSpace := textpathHSpace; fi for item within textpic: if textual item: % show "t=" & textpart item & " ASCII=" & decimal ASCII textpart item & " font=" & fontpart item; bitem := item shifted (0, textpathShift); banker := (xpart center bitem, 30bp); if textpathStretch=1: bx := (xpart banker) + j*ltextpathHSpace; else: bx := (xpart banker) + j*(lenp - textpathRepeat*lenpic - (textpathRepeat-1)*ltextpathHSpace); fi bitem := bitem shifted -banker; for i:=1 upto textpathRepeat: cx := (i-1)*(lenpic + ltextpathHSpace) + bx; if (textpathClip=0) or ((cx>=0) and (cx<=lenp)): tb := arctime cx of p; if textpathAbsRotation=0: db := textpathRotation + angle direction tb of p; else: db := textpathRotation; fi addto pic also bitem rotated db shifted point tb of p; fi endfor if ((fontpart item="cmex10") and ((ASCII textpart item>=112) and (ASCII textpart item<=116))) or ((fontpart item="cmsy5") and (ASCII textpart item=112)) or ((fontpart item="cmsy6") and (ASCII textpart item=112)) or ((fontpart item="cmsy7") and (ASCII textpart item=112)) or ((fontpart item="cmsy8") and (ASCII textpart item=112)) or ((fontpart item="cmsy9") and (ASCII textpart item=112)) or ((fontpart item="cmsy10") and (ASCII textpart item=112)) or ((fontpart item="cmbsy10") and (ASCII textpart item=112)) or ((fontpart item="fourier-mex") and (ASCII textpart item=114)) or ((fontpart item="fourier-ms") and (ASCII textpart item=112)) or ((fontpart item="MnSymbolE5") and (ASCII textpart item=186)) or ((fontpart item="MnSymbolE5") and (ASCII textpart item=189)) or ((fontpart item="MnSymbolE10") and (ASCII textpart item=186)): textpathHookCoord := urcorner item shifted (-xpart center item, -30bp + textpathShift); textpathHookRot := db; textpathHookPoint := point tb of p; % addto pic contour fullcircle scaled 2bp shifted textpathHookCoord rotated db shifted point tb of p withcolor green; else: textpathHookCoord := origin; fi elseif stroked item: if textpathFancyStrokes=0: bitem := item shifted (0, textpathShift); banker := (xpart center bitem, 30bp); if textpathStretch=1: bx := (xpart banker) + j*ltextpathHSpace; else: bx := (xpart banker) + j*(lenp - textpathRepeat*lenpic - (textpathRepeat-1)*ltextpathHSpace); fi bitem := bitem shifted -banker; for i:=1 upto textpathRepeat: cx := (i-1)*(lenpic + ltextpathHSpace) + bx; if (textpathClip=0) or ((cx>=0) and (cx<=lenp)): tb := arctime cx of p; if textpathAbsRotation=0: db := textpathRotation + angle direction tb of p; else: db := textpathRotation; fi addto pic also bitem rotated db shifted point tb of p; fi endfor else: pp := pathpart item; for i=1 upto textpathRepeat: if (textpathHookCoord=origin) or (textpathCureSqrt=0): banker := (0, ypart point 0 of pp - 30bp + textpathShift); if textpathStretch=1: bx := (xpart point 0 of pp) + j*ltextpathHSpace; else: bx := (xpart point 0 of pp) + j*(lenp - textpathRepeat*lenpic - (textpathRepeat-1)*ltextpathHSpace); fi dpp := angle direction 0 of pp; cx := (i-1)*(lenpic + ltextpathHSpace) + bx; tb := arctime cx of p; if textpathAbsRotation=0: db := textpathRotation + angle direction tb of p; else: db := textpathRotation; fi np := banker rotated db shifted point tb of p%{dir (dpp+db)} elseif textpathCureSqrt=1: np := textpathHookCoord shifted (dir(-90)*xpart point 0 of makepath penpart item); np := np rotated textpathHookRot shifted textpathHookPoint%{dir textpathHookRot} fi for h:=1 upto textpathStrokePrecision: hide( banker := (0, ypart point (h/textpathStrokePrecision) of pp - 30bp + textpathShift); if textpathStretch=1: bx := (xpart point (h/textpathStrokePrecision) of pp) + j*ltextpathHSpace; else: bx := (xpart point (h/textpathStrokePrecision) of pp) + j*(lenp - textpathRepeat*lenpic - (textpathRepeat-1)*ltextpathHSpace); fi cx := (i-1)*(lenpic + ltextpathHSpace) + bx; dpp := angle direction (h/textpathStrokePrecision) of pp; tb := arctime cx of p; if textpathAbsRotation=0: db := textpathRotation + angle direction tb of p; else: db := textpathRotation; fi ) ..banker rotated db shifted point tb of p%{dir (dpp+db)} endfor; addto pic doublepath np withpen penpart item; endfor fi else: show "Warning! Unsupported picture element found!"; fi endfor pic enddef;