%!PS % USING CUBIC SPLINE BASIS FUNCTIONS % ================================== % by Don Lancaster % Copyright c 2001 by Don Lancaster & Synergetics, Box 809, Thatcher, AZ, 85552 % (928) 428-4073 Email: don@tinaja.com Website: http://www.tinaja.com % Consulting services available http://www.tinaja.com/info01.html % All commercial rights and all electronic media rights ~fully~ reserved. % Linking usually welcome. Reposting expressly forbidden. Version 1.5 % Use of Bernstein Polynominals and similar basis functions can greatly ease % the understanding and calculation of cubic splines and Bezier curves. This % tutorial gives some fundamentals and guidelines. % IMPORTANT NOTE: Don Lancaster's file gonzo.ps is required for this program. % After obvious location mods, uncomment ONE of the following two lines: (C:\\windows\\desktop\\gonzo\\gonzo.ps) run % use internal gonzo % (A:\\gonzo.ps) run % use external gonzo % NOTE THAT ALL PS FILENAME STRINGS !!!DEMAND!!! DOUBLE REVERSE SLASHES. % GONZO20A Guru Gonzo PostScript power tools (Interim release) % Includes gonzo justification and layout utilities. % Copyright c 1990, 1996, 2001 by Don Lancaster and Synergetics, Box 809, % Thatcher Arizona, 5552 (928) 428-4073 don@tinaja.com support % via http://www.tinaja.com All commercial rights and all electronic % media rights **FULLY** reserved. Reposting is expressly forbidden. %%%%%%%%%%% links menu directory %%%%%%%%%%%% % This code locks pdfmark commands out of a PostScript printer. /pdfmark where {pop}{userdict /pdfmark /cleartomark load put} ifelse % /surl "start url" marks the beginning of a text sequence to be urled. % It also paints the text blue... /surl {mark /blue cvx 0.33 /setgray cvx % change text to blue /currentpoint cvx % remember box start /urly /exch cvx /store cvx /urlx /exch cvx /store cvx ] cvx % complete deferred command printlist exch 3 index exch put % stuff into gonzo printlist exch 1 add exch % increment gonzo list count } def % /eurl "end url" unmarks the end of a text sequence and sets up % the pdfmark needed to define the Acrobat web link. /eurl {mark % start deferred proc exch % position url string % /black cvx 0 /setgray cvx % turn blue marker off % maintextcolor /setrgbcolor cvx % reset to main text color??? /aqua cvx /black cvx /makeurl cvx % defer call of url builder ] cvx % complete deferred proc printlist exch 3 index exch % stuff into gonzo printlist put exch 1 add exch % increment gonzo list count } def % /makeurl generates the pdfmark, receiving a {(urlstring) makeurl}. % Note that it is not called until formatted printlist time... /urlover 0.2 def % fraction of hot area over bounds /makeurl { /cururlname exch store % save the url string mark % start pdfmark currentfont /ScaleMatrix get 3 get /fsize exch store % guess height /Rect [ urlx fsize urlover mul sub % set box left x urly fsize urlover mul sub % set box left y currentpoint exch fsize urlover mul add exch fsize add ] /Border [ 0 0 0] % [0 0 0 ] = none; [0 0 2] = debug /Color [ .7 0 0 ] /Action <> /Subtype /Link /ANN % annotation type pdfmark % call pdf operators } def % /makeurlx generates the box specific pdfmark, receiving % a {(urlstring) makeurl}. % Note that it is not called until formatted printlist time... /makeurlx { /cururlnamex exch store % save the url string mark % start pdfmark /Rect [ xpos % set box left x ypos 0.9 sub % set box left y xpos 2.8 add % box right x ypos 0.9 sub 2.8 add % box right y ] /Border [ 0 0 0] % [0 0 0 ] = none; [0 0 2] = debug /Color [ .7 0 0 ] /Action <> /Subtype /Link /ANN % annotation type pdfmark % call pdf operators } def /maintextcolor {0 0 0 } def % text link specific data /tinaja {(http://www.tinaja.com/magsn01.asp) eurl} def /cubic01 {(http://www.tinaja.com/cubic01.asp) eurl} def /hack62 {(http://www.tinaja.com/glib/hack62.pdf) eurl} def /post01 {(http://www.tinaja.com/post01.asp) eurl} def /increment {(http://www.tinaja.com/text/bezgen3.html) eurl} def /interpolate {(http://members.bellatlantic.net/~vze2vrva/design.html) eurl } def /info01 {(http://www.tinaja.com/info01.asp) eurl} def /bezmath {(http://www.tinaja.com/text/bezmath.html) eurl } def /table {(http://www.tinaja.com/psutils/imtable.psl) eurl } def /maildon {(mailto:don@tinaja.com) eurl} def %%%%%%%%%%%%%%%% New colorizer patches %%%%%%%%%%%%%%%%%% /boxgrays 0.899 def /grayshade boxgrays def /mastergray boxgrays def /staytint {0.33 setgray} def /staytint1 {0.25 setgray} def /showadgrays true def /red {0 settint} def /Zmacro {staytint /ypos ypos 2 add def 72 300 div setlinewidth xpos ypos moveto txtwide 0 rlineto stroke /ypos ypos -2 add def tintoff} def % hair rule /amacro {(zy0) stringmacro /ypos ypos ypara add def 0.33 setgray } def % start drop cap /bmacro {(iFy1) stringmacro /ypos ypos ypara add def black} def % finish drop cap % Gonzo character colorizer /blueon {mark /blue cvx 0.33 /setgray cvx] cvx printlist exch 3 index exch put exch 1 add exch} def /blueoff {mark /beige cvx 0 /setgray cvx] cvx printlist exch 3 index exch put exch 1 add exch} def /tinton {mark 0.33 /setgray cvx] cvx printlist exch 3 index exch put exch 1 add exch} def /tinton1 {mark 0.25 /setgray cvx] cvx printlist exch 3 index exch put exch 1 add exch} def /tinton1b {mark beige cvx % try for aqua after url??? 0.25 /setgray cvx] cvx printlist exch 3 index exch put exch 1 add exch} def /tinton1a {mark /aqua cvx % try for aqua after url??? 0.25 /setgray cvx] cvx printlist exch 3 index exch put exch 1 add exch} def /tinton1p {mark /burple cvx % try for aqua after url??? 0.25 /setgray cvx] cvx printlist exch 3 index exch put exch 1 add exch} def /tinton1r {mark /red cvx % try for aqua after url??? 0.25 /setgray cvx] cvx printlist exch 3 index exch put exch 1 add exch} def /tinton1b {mark /beige cvx % try for beige after url??? 0.25 /setgray cvx] cvx printlist exch 3 index exch put exch 1 add exch} def /tintoff {mark 0 /setgray cvx] cvx printlist exch 3 index exch put exch 1 add exch} def %%%%%%%%%%%%%% COMPACT VERSION OF COLORIZER II %%%%%%%%%%%%%%%%%%%%%% /settint {dup /currenttint exch store 5.999 mul dup floor cvi /&cbar exch store dup floor sub /&cwt exch store [ {/setgray [ /dup cvx 0.3 &cwt 0.59 mul add /ge cvx [1 /exch cvx &cwt 0.59 mul 0.30 add /sub cvx 1 &cwt sub 0.59 mul 0.11 add /div cvx /dup cvx 1 &cwt sub /mul cvx &cwt /add cvx /exch cvx ] cvx [ &cwt 0.59 mul 0.3 add /div cvx /dup cvx &cwt /mul cvx 0] cvx /ifelse cvx /setrgbcolor cvx] cvx /def cvx} {/setgray [/dup cvx 0.59 1 &cwt sub 0.3 mul add /ge cvx [1 &cwt sub 0.3 mul 0.59 add /sub cvx &cwt 0.3 mul 0.11 add /div cvx /dup cvx &cwt /mul cvx 1 &cwt sub /add cvx /exch cvx 1 /exch cvx] cvx [1 &cwt sub 0.3 mul 0.59 add /div cvx /dup cvx 1 &cwt sub /mul cvx /exch cvx 0] cvx /ifelse cvx /setrgbcolor cvx] cvx /def cvx} {/setgray [/dup cvx 0.59 &cwt 0.11 mul add /ge cvx [&cwt 0.11 mul 0.59 add /sub cvx 1 &cwt sub 0.11 mul 0.30 add /div cvx /dup cvx 1 &cwt sub /mul cvx &cwt /add cvx 1 /exch cvx] cvx [0 /exch cvx &cwt 0.11 mul 0.59 add /div cvx /dup cvx &cwt /mul cvx] cvx /ifelse cvx /setrgbcolor cvx] cvx /def cvx} {/setgray [/dup cvx 0.59 1 &cwt sub mul 0.11 add /ge cvx [1 &cwt sub 0.59 mul 0.11 add /sub cvx &cwt 0.59 mul 0.30 add /div cvx /dup cvx &cwt /mul cvx 1 &cwt sub /add cvx 1] cvx [0 /exch cvx 1 &cwt sub 0.59 mul 0.11 add /div cvx /dup cvx 1 &cwt sub /mul cvx /exch cvx] cvx /ifelse cvx /setrgbcolor cvx] cvx /def cvx} {/setgray [/dup cvx 0.11 &cwt 0.30 mul add /ge cvx[&cwt 0.30 mul 0.11 add /sub cvx 1 &cwt sub 0.30 mul 0.59 add /div cvx /dup cvx 1 &cwt sub /mul cvx &cwt /add cvx /exch cvx 1] cvx [ &cwt 0.30 mul 0.11 add /div cvx /dup cvx &cwt /mul cvx /exch cvx 0 /exch cvx ] cvx /ifelse cvx /setrgbcolor cvx ] cvx /def cvx} {/setgray [ /dup cvx 0.30 1 &cwt sub 0.11 mul add /ge cvx[ 1 /exch cvx 1 &cwt sub 0.11 mul 0.30 add /sub cvx &cwt 0.11 mul 0.59 add /div cvx /dup cvx &cwt /mul cvx 1 &cwt sub /add cvx ] cvx [ 1 &cwt sub 0.11 mul 0.30 add /div cvx /dup cvx 1 &cwt sub /mul cvx 0 /exch cvx] cvx /ifelse cvx /setrgbcolor cvx ] cvx /def cvx} ] &cbar get exec exec} bind def /beige {0.10 settint} def % examples of convenience operators /aqua {0.52 settint} def /blue {0.67 settint} def /lime {0.44 settint} def /burple {0.75 settint} def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /guru { gonzo begin ps.util.1 begin printerror nuisance begin} def % guru % activate gonzo utilities 50 50 10 setgrid % create grid % 56 61 showgrid /cstretch 0.015 def /sstretch 0.015 def /font0 /StoneSans-Bold 1.6 gonzofont /font1 /StoneSans 0.95 gonzofont /font3 /StoneSans-Bold 0.85 gonzofont /font8 /StoneSans-Bold [0.65 0 0 0.65 0 0.4] gonzofont /txtwide 36 store /yinc 1.2 store /kern 0.1 store /tabs [7 -2] store aqua 0.33 setgray font1 black font2 /amacro { mark /aqua cvx 0.33 /setgray cvx ] cvx printlist exch 3 index exch % stuff into gonzo printlist put exch 1 add exch } def /bmacro { mark /black cvx ] cvx printlist exch 3 index exch % stuff into gonzo printlist put exch 1 add exch } def % -2 50.5 (optional header here \274) cl aqua 0.33 setgray font0 20 47.3 0.7 add (Using Cubic Spline Basis Functions) cc 20 45.3 0.7 add (for Image Pixel Interpolation) cc black font2 3 43 (|3Don Lancaster Synergetics, Box 809, Thatcher, AZ 85552 |/surl http://www.tinaja.com|/tinaja |/surl don@tinaja.com|/maildon (928) 428-4073 |h |a|0S|1|b|jome very hairy math involving |/tinton1 |3Bernstein Polynominal Basis Functions|1|/tintoff can greatly \ ease the understanding and use of Bezier curves and cubic splines. Basis functions also \ can very much simplify drawing the actual curves. Often, simple table lookups can \ replace complex cubic calculations. Especially when using splines to do image \ expansion or interpolation. |h Cubic spline fundamentals appear in my |3|/surl Cubic Spline Library|1|/cubic01 and \ include |/surl |3this|/hack62 |/surl tutorial|1|/hack62 . |/aqua In general, a cubic spline is a way to \ draw a smooth curve that starts at |/aqua |/tinton1 |3x0,|jy0|1|/tintoff , ends at |/tinton1 |3x3,|jy3|1|/tintoff and whose exact shape can be \ influenced or controlled by intermediate control point pairs |/tinton1 |3x1,|jy1|1|/tintoff and |/tinton1 |3x2,|jy2|1|/tintoff . \ The intermediate points will determine the exit or entry slope and the enthuasiasm of \ initial and final travel. Four data point pairs thus define the entire curve. |h A cubic spline is normally defined as a pair of parametric equations in which |/tinton1 |3t|1|/tintoff usually varies from |/tinton1 |30 to 1|1|/tintoff \274 |h|C|/staytint1 |3x = at|83|3 + bt|82|3 + ct + d |3y = et|83|3 |j+ ft|82|3 |j+ gt + h |h|L|/black |1The cubic constants |/tinton1 |3a|1|/tintoff through |/tinton1 |3h|1|/tintoff can be \ related to the control points by using |/surl |3this math|1|/hack62 . |/aqua Because \ |/aqua |/tinton1 |3t|1|/tintoff changes faster on the "more bent" portions of the \ curve, directly relating |/aqua |/tinton1 |3y|1|/tintoff to |/tinton1 |3x|1|/tintoff is \ nontrivial. Especially since multiple |/tinton1 |3y|1|/tintoff values can result inside \ a loop or a cusp. |h Instead, let's start with an obvious |/tinton1 |31|j=|j1|1|/tintoff and morph it into a bizarre |/tinton1 |3t + (1|j-|jt) = 1|1|/tintoff |h Now, let's cube both sides\274 |h|C|/staytint1 |3t|83|3 + 3t|82|3(1-t) + 3t(1-t)|82|3 + (1-t)|83|3 = 1 |h|L|/black |1or, defining each term as a basis function\274 |h|C|/staytint1 |3 B3(t) + B2(t) + B1(t) + B0(t) = 1 |h|L|/black |1Let's plot these dudes and see what they look like\274 ) cl black beige 0.35 setgray 21 -2.5 (|3\320|j1|j\320) cc aqua 0 55.5 mt line1 40 r % temp align showpage %% start page two 50 50 10 setgrid % create grid /cstretch 0.015 def /sstretch 0.015 def /font0 /StoneSans-Bold 1.6 gonzofont /font1 /StoneSans 0.95 gonzofont /font3 /StoneSans-Bold 0.85 gonzofont /font4 /StoneSans-Bold [1.2 0 0 1.2 0 -0.4] gonzofont /font8 /StoneSans-Bold [0.65 0 0 0.65 0 0.4] gonzofont /txtwide 36 store /yinc 1.2 store /kern 0.1 store /tabs [8 -2] store aqua 0.33 setgray font1 black font2 % t3 + 3t^2*(1-t) + 3t(1-t)^2 + (1-t)^3 = 1 /plotnormalbasis {gsave translate 20 10 showgrid beige 0.5 setgray 0 10 moveto 0 0.01 1 {/tt exch store tt 20 mul 1 tt sub dup dup mul mul 10 mul lineto } for line3 stroke 0 0 moveto 0 0.01 1 {/tt exch store %% (1-t)^2 *3t tt 20 mul 1 tt sub dup mul tt mul 3 mul 10 mul lineto } for line3 stroke 0 0 moveto 0 0.01 1 {/tt exch store tt 20 mul 1 tt sub tt dup mul mul 3 mul 10 mul lineto } for line3 stroke 0 0 moveto 0 0.01 1 {/tt exch store tt 20 mul tt dup dup mul mul 10 mul lineto } for line3 stroke aqua 0.30 setgray 1 setlinecap line3 -0.5 0 mt 21 r 0 -0.5 mt 11 u 20 -0.5 mt 11 u 10 0 mt 0.5 d 20 0 mt 0.5 d 0 10 mt 0.5 l font3 line1 2.1 9 ((B0)) cc 6.667 5 ((B1)) cc 13.333 5 ((B2)) cc 17.7 9 ((B3)) cc 0 -1.5 (t|j=|j0) cc 10 -1.5 (t|j=|j0.5) cc 20 -1.5 (t|j=|j1.0) cc -1.5 -0.3 (0.0) cc -1.5 9.7 (1.0) cc grestore aqua} def 9 41 plotnormalbasis %36 21 showgrid % show grid under waveforms 3 37 (|1We can see two rather remarkable properties here: |h|3|/staytint1 The basis function peaks happen at the spline's control points. |h|/black |1 and\274 |h|3|/staytint1 Any (t) value is the sum of the four basis functions evaluated at \n (t) scaled by their control point values|1. |h|1|/black Or, in mathspeak\274 |h|3|/staytint1 x(t) = x0*B0(t) + x1*B1(t) + x2*B2(t) + x3*B3(t) y(t) = y0*B0(t) |j+ y1*B1(t) |j+ y2*B2(t) + y3*B3(t) |h|1|/black Note that the influence points are always at |/tinton1 |3t = 1/3|1|/tintoff and |/tinton1 |3t = 2/3|1|/tintoff , regardless of where \ they lie in |/tinton1 |3x-y|1|/tintoff space. And that the four unscaled basis point values always add up to one for any allowed value of |/tinton1 |3t|1|/tintoff . |h The easiest way to actually plot a cubic spline is with the |/tinton1 |3curveto|1|/tintoff operator in |/surl |3PostScript|1|/post01 . A fast language independent differental method is |/surl |3shown here|1|/increment . |/tinton1 |t|t|4An image interpolation application |/tinton1 |3Image interpolation|1|/tintoff can be needed any time you want to make a bitmap larger or smaller. Or any time you are resampling or rectifying or masking or changing geometry. The object is to make the image larger or smaller or distorted without introducing artifacts or looking bad. A very useful tutorial on cubic spline image interpolation |/surl |3appears here|1|/interpolate . |h The trick is to take two previous pixels and two post pixels on a scan line and \ suitably evaluate them to create one or more credible new pixels. These new intermediate \ results can then be used vertically with four scan lines to create the actual final \ interpolated pixels. |h Doing the obvious of using the four pixels as control points for a cubic spline \ works. But tends to be blurry because of excessive low pass filtering. We would \ also like a "knob" that lets us adjust how much sharpening we can get. ) cl black beige 0.35 setgray 21 -2.5 (|3-|j2|j-) cc aqua 0 55.5 mt line1 40 r % temp align showpage %% start page three 50 50 10 setgrid % create grid /cstretch 0.015 def /sstretch 0.015 def /font0 /StoneSans-Bold 1.6 gonzofont /font1 /StoneSans 0.95 gonzofont /font3 /StoneSans-Bold 0.85 gonzofont /font4 /StoneSans-Bold [1.2 0 0 1.2 0 -0.4] gonzofont /font8 /StoneSans-Bold [0.65 0 0 0.65 0 0.4] gonzofont /txtwide 36 store /yinc 1.2 store /kern 0.1 store /tabs [7 -2] store aqua 0.33 setgray font1 black font2 /plothiresbasis {gsave translate gsave 0 -1 translate 30 13 showgrid grestore aqua 0.30 setgray 1 setlinecap line3 -0.5 2 mt 31 r % cannot overwrite, so here gsave 0 -1 mt 13 pu 30 pr 13 pd closepath clip newpath % stop excess 0 -0.1 -1 {/aa exch store aa -1 mul 0.75 mul settint 0.5 setgray 0 10 moveto -1 0.01 2 {/tt exch store tt 1 add 10 mul % |tC0(t) = -at|83|3 + at|82|3 tt dup dup mul mul aa mul neg tt dup mul aa mul add 10 mul 2 add lineto } for line3 stroke 0 0 moveto -1 0.01 2 {/tt exch store % |tC1(t) = -(a+2)t|83|3 + (2a+3)t|82|3 - at tt 1 add 10 mul tt dup dup mul mul 2 aa add mul neg tt dup mul 3 aa 2 mul add mul add tt aa mul sub 10 mul 2 add lineto } for line3 stroke 0 0 moveto -1 0.01 2 {/tt exch store tt 1 add 10 mul % |tC2(t) = (a+2)t|83|3 - (a+3)t|82|3 + 1 tt dup dup mul mul 2 aa add mul tt dup mul 3 aa add mul sub 1 add 10 mul 2 add lineto } for line3 stroke 0 0 moveto -1 0.01 2 {/tt exch store tt 1 add 10 mul % |tC3(t) = at|83|3 - 2at|82|3 + at tt dup dup mul mul aa mul tt dup mul aa mul 2 mul sub tt aa mul add 10 mul 2 add lineto } for line3 stroke } for % cycles aa's grestore % undo clip aqua 0.30 setgray 1 setlinecap line3 % -0.5 2 mt 31 r % cannot overwrite 0 -1.5 mt 14 u 10 -1.5 mt 14 u 20 -1.5 mt 14 u 30 -1.5 mt 14 u font3 line1 13.33 -0.5 ((B0)) cc 11.3 7 2.5 add ((B1)) cc 18.5 7 2.5 add ((B2)) cc 16.66 -0.5 ((B3)) cc gsave 0 -1 translate 0 -1.5 (t|j=|j-1) cc 10 -1.5 (t|j=|j0) cc 20 -1.5 (t|j=|j+1) cc 30 -1.5 (t|j=|j+2) cc /yinchold yinc store /yinc 0.9 store 0 -3 (second\nprevious\npixel) cc 10 -3 (first\nprevious\npixel) cc 20 -3 (first\nfollowing\npixel) cc 30 -3 (second\nfollowing\npixel) cc /yinc yinchold store grestore % shift down end -1.5 1.7 (0.0) cc -1.5 11.7 (1.0) cc font3 [0.06 0.33 0.75] 0 get settint 0.5 setgray 33 7 (a = 0.0) cc [0.12 0.33 0.75] 1 get settint 0.5 setgray 33 5.9 (a = -0.5) cc [0.12 0.33 0.70] 2 get settint 0.5 setgray 33 4.8 (a = -1.0) cc grestore aqua} def 6 29 plothiresbasis %36 21 showgrid % show grid under waveforms 3 50.5 (|1Instead, some new |/tinton1 |3high resolution|1|/tintoff basis functions of\274 |h|3|/staytint1 |tB0(t) = at|83|3 - 2at|82|3 + at |tB1(t) = (a+2)t|83|3 - (a+3)t|82|3 + 1 |tB2(t) = -(a+2)t|83|3 + (2a+3)t|82|3 - at |tB3(t) = -at|83|3 + at|82|3 |h|1|/black \274 can be used to advantage as pixel interpolators. Here is how they plot\274 Note that we normally only use the region from |/tinton1 |3t|j=|j0|1|/tintoff to |/tinton1 |3t|j=|j1|1|/tintoff . |h If |/tinton1 |3a|j=|j0|1|/tintoff , we blur somewhat and use only the adjacent \ pixel info. This is pretty much the same as the older |/tinton1 |3bilineal interpolation|1|/tintoff . |h An |/tinton1 |3a|j=|j-0.5|1|/tintoff selection is often \ best for data to be calculated, such as a medical or astronomical image. \ And an |/tinton1 |3a|j=|j-1.0|1|/tintoff choice is often best for people-viewed \ results as it includes additional edge enhancement. |h The needed basis calculations can be done once and then used as |/surl |3fast table|/table |/surl lookups|1|/table . \ Relating a general spline's |/tinton1 |3y|1|/tintoff to |/tinton1 |3x|1|/tintoff rather than \ to |/tinton1 |3t|1|/tintoff is |/surl |3often difficult|1|/bezmath . But since the \ |/tinton1 |3x|1|/tintoff values here will always be |/tinton1 |3-1|1|/tintoff , \ |/tinton1 |30|1|/tintoff , |/tinton1 |31|1|/tintoff , and |/tinton1 |32|1|/tintoff , our \ |3|/tinton1 x(t)|1|/tintoff simplifies to\274 |h|3|C|/staytint1 x(t) = -2(2a|j+|j1)t|83|3 + 3(2a|j+|j1)t|82|3 - 2at |h|L|1|/black From which the inverse |/tinton1 |3t(x)|/tintoff |1 is easily found as\274 |h|3|C|/staytint1 t(x) = 2(2a|j+|j1)x|83|3 - 3(2a|j+|j1)x|82|3 + 2(a|j+|j1)x |h|L|1|/black Underflows or overflows can sometimes happen with sudden changes near \ max or min intensity. These rare events should be suitably clipped. |h Additional support on these concepts can be |/surl |3found here|1|/info01 . ) cl %% \274 can be used that plot something like this\274 black beige 0.35 setgray 21 -2.5 (|3-|j3|j-) cc aqua 0 55.5 mt line1 40 r % temp align showpage % EOF