From: charliep@hpcvrs.cv.hp.com (Charles Patton)
Newsgroups: comp.sources.hp48
Subject: v02i015: suite3d - Suite3D (Graphing/viewing utilities) v2.0, Part01/01
Date: 1 Oct 91 03:18:28 GMT
Followup-To: comp.sys.hp48
Checksum: 3121927216 (verify with brik -cv)
Submitted-by: Charles Patton
Posting-number: Volume 2, Issue 15
Archive-name: suite3d/part01
BEGIN_RDME Suite3D.rdm
_Suite3D Version 2.0 Additions and Changes_
In addition to the slopefield, pseudo-contour, oblique perspective,
Phong-Shaded, and movie plotting capabilities, version 2.0 introduces
*Major Feature* POSTSCRIPT(TM) output for all the graphing routines in a
form suitable for editing/viewing with Adobe Illustrator(TM), sending to a
POSTSCRIPT printer, or including in a \special {\illustration} TeX(TM)
command. Included is a PS-output version of the standard DRAW command.
All the output is in terms of line segments, Bezier curves, and fill-
regions so that it can be scaled to arbitrary size or printed at
very high resolution without loss of smoothness.
If you have ever wanted to produce high-quality function-graph illustrations
with the flexibility that '48 provides, this is for you! (You might be able
to tell that I'm pretty happy with this item.)
*Significant Addition* (relatively) fast WIREFRAME graphing in oblique
3D perspective with adjustable grid spacing.
*Easier View Switching* The 3D plotting parameters have been rearranged
so that all the routines can compute an appropriate XRNG and YRNG from
these. Once set, you can go from view to view with no manual adjustments.
*Other Enhancements*
A Movie single-step has been added so that you can easily step through a
Movie frame-by-frame.
All routines now use user-specified number of X-increments and Y-increments,
as appropriate, so that the WIREFRAME grid, the lattice of slopefield
segements, and number of Movie frames, etc. all references these numbers
rather than being "hard coded" as in the earlier versions.
END_RDME
BEGIN_DOC Suite3D.doc
@ Version 2.0 @
_Introduction_
The programs contained in this document comprise a suite of 3D
graphing/viewing utilities for the HP-48 (an HP-28 version will be
forthcoming provided sufficient interest.)
We had several requirements to consider in creating these
programs. Our aims were that they be (1) purely user code, (2)
relatively short, and (3) psychologically effective. Aims (1) and (2)
are due to our target audience of educators, many of whom have little
contact with technology beyond their use of the HP-48 or HP-28. We
expect that, in many situations, one user will obtain the code in
printed form, enter it into their machine, and transmit it to others
via the infrared I/O.
In exploring visualization techniques on a variety of machines we
found that increasing "realism" (read: ray-traced, Phong-shaded,
hidden-line, etc.) in the graphical presentation of functions of two
variables did not necessarily correlate with increasing ease of
comprehension. These programs represent the results of some of these
experiments (including time-to-completion as an important factor).
We invite you to try them out and experiment yourself. All
suggestions, additions, corrections, insights, commentary, and
criticisms are welcome.
_NO WARRANTY_
This work is provided on an "as is" basis. Hewlett-Packard Co.
provides no warranty whatsoever, either express or implied regarding
the work, including warranties with respect to its merchantability or
fitness for any purpose whatsoever.
_Copyright_
Copyright (C), 1991, Hewlett-Packard Co. Permission to copy all or
part of this work is granted provided that the copies are not made or
distributed for resale (excepting nominal copying fees) and the
_NO WARRANTY_ and this copyright notice are included verbatim. Other
permissions can be arranged by contacting the author.
_Correspondence_
Correspondence on Suite3D suite should be sent to Charles Patton at one of the
following addresses:
snail-mail:
M.S. 5U-L9
Hewlett-Packard Co.
1000 N.E. Circle Blvd.
Corvallis, OR 97330
e-mail:
charliep@cv.hp.com (for Internet hosts)
hplabs!hpcvrs!charliep (for UUCP hosts)
_Organization_
Analogous to the built-in plotting routines, all the Suite3D
programs assume that the function of interest is stored in EQ.
Further, they assume that the function is represented as an expression
in the variables 'X' and 'Y' (e.g. u,v -> sin(u+v) is represented as
'SIN(X+Y)' in EQ). Insure that 'X' and 'Y' are formal (no variables
'X' and 'Y' along the current path).
The viewing region and other Suite3D plotting parameters are stored
in the sub-directory, VPAR. VPAR contains the variables:
Xleft and Xright,
controlling the width of the view-volume,
Yfar and Ynear,
controlling the depth of the view-volume,
Zlow and Zhigh,
controlling the height of the view volume,
Xe, Ye, and Ze,
the coordinates of the eye-point,
Nx and Ny,
the number of X- and Y-increments desired, and
hidden
the flag indicating that hidden-line plotting should be used
in the Yview plotter.
VPAR was implemented as a sub-directory so that the REVIEW key can be
used to examine the state of these variables in a way which reminds
the user of their meaning.
Other than VPAR, the programs here are organized into a single directory for
convenience. Inter-dependence of the programs and other variables is
noted in the program description.
_Oversized PICTs_
All of the programs seem to work reasonably well with arbitrary sized
PICT grobs. However, ShapeToShade only draws to the upper-left-hand-corner
of the grob, and Movie only shows the display-sized region of the grob (what
else could it do?) The POSTSCRIPT plotting routines scale their results to
the size of the default PICT grob, but this should pose few problems.
_Descriptions of the Programs_
SlopeField:
The SlopeField program plots a lattice of line segments whose
slopes represent the function value at their centerpoint. Using
SlopeField to plot F(X,Y) allows your eye to pick out integral curves
of the differential equation dy/dx=F(x,y). It is quite useful in
understanding where the "arbitrary constant" in anti-derivatives comes
from.
The number of lattice points per row is determined by Nx and the
number of lattice points per column is determined by Ny. The input region
sampled is given by Xleft < X < Xright and Ynear < Y < Yfar.
psContour:
The psContour program (pseudo-contour) program uses SlopeField to
produce a fast contour plot of the current function. By plotting the
direction field perpendicular to the gradient of the function it
allows your eye to pick out the integral curves (contours) without
actually plotting them. The apparent contours are evenly spaced
visually and so give no information on how steep the graph is at any
particular point.
The number of lattice points per row is determined by Nx and the
number of lattice points per column is determined by Ny. The input region
sampled is given by Xleft < X < Xright and Ynear < Y < Yfar.
YView:
The YView program provides an oblique-view, perspective, 3D
surface plot (viewing toward increasing Y). This produces a sequence of
plots of the function along Y=constant lines in the input domain. These
plots are perspective-projected onto the view-plane relative to the eye
point. In overhead view:
Yfar
+----------------+
. | | .
| |
Xleft | /\ |Xright
. | / \ | .
. | . . |.
+----------------+
. . . . Ynear
. . .
. . . .
---------.----..---.--------------------- view-plane
. . .
. . .
* eye-point (Xe,Ye,Ze)
|<- XRNG ->|
The same picture holds with Zlow replacing Xleft, Zhigh replacing Xright,
and YRNG replacing XRNG (and turning your head 90 degrees to the right.)
In short, Ynear and Yfar and Ny determine the Y-inputs sampled;
Xleft, Xright, and the eye-point determine the XRNG; Zlow, Zhigh,
and the eye-point determine the YRNG. This computation is performed by
the utility, SetWindow.
This is a simple "divide-by-depth" method for perspective
plotting where the viewplane is always 1 unit from the viewpoint and
is parallel to the x-z plane. Since the perspective transformation in
the case can be implemented by a simple change of coordinates,
plotting individual sections is no slower than ordinary plots.
If 'hidden' is non-zero, each plot of a sampled point will erase the
column of pixels below it. Since the curves are plotted back-to-front,
this results in a hidden-line plot of the surface. It works best if
RES is #1 or #2 and connected-mode is on (CNCT.)
Note: To abort this routine, press the [ON] key and then press
the [ENTER] key.
WIREFRAME:
The WIREFRAME program plots an oblique-perspective view of a wire-frame
model of the surface with Nx vertices in each row and Ny vertices in each
column. It calls SetWindow to set the XRNG and YRNG and uses much the same
technique as Yview. The sampled region is determined by Xleft, Xright, Ynear,
and Yfar.
ShapeToShade:
The ShapeToShade program plots the function as a Phong-shaded
figure viewed from above with a light source from above, that
is, shaded according to the angle the tangent plane makes with the incident
light source. It assumes that the variable DPAR contains sixteen 4x4 GROBS
to serve as the dithering pattern. The dither patterns included are probably
not the best possible: insights along these lines are most welcome. The
variables Xleft, Xright, Yfar, and Ynear determine the inputs sampled.
Movie:
The Movie program plots Ny cross-sections of the function plot
varying the Y-value from Yfar to Ynear. The viewing window is determined
by Xleft, Xright, Zlow, and Zhigh. Having plotted these frames, it calls the
utility program, uSMOV (utility-show-movie), to play them back in
repeated sequence.
Note: To abort this routine in the plotting phase, press the [ON]
key and then press the [ENTER] key. To end the movie press any key
(e.g. [ENTER]).
uSMOV:
The uSMOV (utility show-movie) program takes an alternating sequence of
grobs and descriptors (with <2n> on the top of the stack) from the
stack and shows them in sequence, thus producing a movie effect. Stop
the show with any key press but [ON].
SSTMovie:
After stopping Movie or uSMOV, you can use SSTMovie to step through
the sequence of movie frames. To show the next frame, press any key but
[ENTER] or [ON]. Press [ENTER] to quit.
SetWindow:
This utility maps the view volume and eye-point coordinates into the
appropriate XRNG and YRNG values for perspective plotting (see the picture
in the YView description.) It also gets all the plotting parameters onto
the stack.
_The POSTSCRIPT Drawing Utilities_
Since the PS utilities take up a fair amount of space, and are not of
immediate use to someone without Adobe Illustrator and/or a POSTSCRIPT
printer, all of the above programs have been designed to work properly
even if the PS utility set is not installed. If this is your situation,
simply delete the section of the Suite3D listing starting at the comment,
@ Begin POSTSCRIPT Stuff @, before you send the file to the '48, otherwise,
read on.
When POSTSCRIPT Output Mode is switched on (using PSTOGGLE,) all of the
plotting routines above will, in addition to their normal function,
accumulate POSTSCRIPT commands corresponding to what they were attempting
to plot on the '48 display. These are saved in a sequence of variables,
PSOUT, PSOUT&, PSOUT&&, etc. Although the output is simply ASCII text
saved as '48 character strings, it is broken up into at-most-4Kbyte
chunks so that it is easier to handle on the '48. When this text is
inserted into a "boilerplate" file (described below) the resulting
file can be sent to a POSTSCRIPT printer, or edited/viewed in the
Adobe Illustrator, or compatible, POSTSCRIPT Drawing program.
_Descriptions of the User-intended Programs__
PSTOGGLE:
When executed, this routine switches between normal (no-PS output)
and PS-output definitions of the basic graphics routines (that is, draw,
line, and tile) used in the other Suite3D programs. The new state ("PS is ON"
or "PS is OFF") is displayed on completion of the routine.
PSRESET:
This routine should be used to simply clear any leftover data in the
output variables PSOUT, PSOUT&, etc. making room for a new run.
_Using the PS Capabilities_
_The Boilerplate File_
To effectively use the PS output from the '48 you need to have a
"boilerplate" POSTSCRIPT file in which you can insert your '48 output (it can
even reside on the '48 if you have room .. in this case you can have your '48
talk directly to a POSTSCRIPT printer ..) The easiest way to get one is to create
a new illustration in Illustrator with no actual drawing but with the Fill set to
NONE, the Line Width set to, say, .5, and the Line Color set to 100% BLACK.
Save this as a POSTSCRIPT (i.e. text) file HP48PS.ai or some such name.
Open the resulting file with a text editor so you can see what it looks like.
There are two regions of interest. The first is the line near the top of the
file that looks like
%%BoundingBox:x1 y1 x2 y2
where x1, x2, y1, and y2 are integers. You should change these to
%%BoundingBox:0 0 131 64
While this is not strictly necessary, it will allow you to include the '48
produced illustration directly in a TeX document an have the size computed
correctly.
The next region of interest is near the end of file and begins with
%%Note:
and ends with
%%Trailer
Clear out anything between these two (this is the region where the '48
output will be inserted) and save the resulting file. This will be your
"boilerplate" file.
_Creating the Output_
This part is quite easy. After you have found a nice view with one of
the graphing utilities (with PS output turned off to speed things up) set the
RES quite high ( #13d RES [ENTER] will do nicely ) and numeric display
format quite small ( 2 FIX [ENTER] seems pretty good ) to save on room, use
PSRESET to clear the variables (if you want to get rid of a previous session)
and PSTOGGLE to activate PS mode. Now re-active the chosen plotting routine
and let it finish.
When it is finished, transfer the contents of all the non-empty PSOUT variables
(in ASCII mode, please) in order (PSOUT, PSOUT&, PSOUT&&, etc.) into the region
of the boilerplate file noted above. Save the resulting file under a new name
(to preserve your boilerplate file) and you are ready to send it to a POSTSCRIPT
printer, include it in a TeX, or muck around with it in a POSTSCRIPT drawing
program.
_RAM Requirements, etc._
The routines require very different amounts of RAM (corresponding directly
with the output size.) A reasonable psContour results in under 4K of output
while a ShapeToShade can result in nearly 40K of output. The other routines
fall between these two (with reasonable settings for Nx, Ny, RES, and FIX.)
If desired, one could modify the PSADDTO routine (see below) to simply send
accumulated data out over one of the datacomm ports thus passing off the space
requirements to the machine at the other end of the line.
_What's Been Tried_
I've used the PS output in the form discussed above with equally good
results in Illustrator88 on a Mac IIx, direct printing to an Apple LaserWriter,
in a Textures TeX file, and in Adobe Illustrator 1.1 under Windows 3.0.
POSTSCRIPT, Adobe Illustrator, and Illustrator88 are trademarks of Adobe Systems
Corporation;
Textures is a trademark of Blue Sky Research, Inc.;
Apple LaserWriter is a trademark of Apple Computer, Inc.;
Windows is a trademark of MicroSoft Corporation;
TeX is a trademark of the American Mathematical Society.
_Descriptions of the Utilities_
PSTILE:
This utility takes a screen location (as #pixel_row #pixel_column)
followed by two unused parameters and a gray-scale value in the range [0,1],
returns these unchanged to the stack and outputs the PS code to draw a
filled-in 4x4 square at the corresponding location and with the corresponding
gray-scale fill.
PSADDTO:
This utility takes a string off the stack and adds it to the current
PS output variable, checking for overflow of the 4000 character limit
and starting a new output variable if the limit is exceeded.
PSDRAW:
Draws the current EQ (assumed to be a single expression) and outputs
a PS representation of the curve drawn as a connected sequence of Bezier
curves.
PSLINE:
Takes a pair of complex numbers representing the endpoints of a line,
draws the line on the screen and outputs the corresponding PS line drawing
command.
CURRENTOUT:
A variable containing the name of the current PS output variable
('PSOUT', 'PSOUT&', 'PSOUT&&', etc.)
PSCO:
Takes a complex number and returns, as a string, the corresponding
PS coordinate value.
PSCOPAIR:
Takes a pair of complex numbers representing the third and fourth of
four Bezier curve control points and returns these as a string representing
the PS cross-over sequence of a Bezier curve.
END_DOC
BYTES: #1A05h 7789
BEGIN_RPL Suite3D
%%HP: T(3)A(R)F(.);
DIR
VPAR
DIR
Xleft
0
Xright
3
Ynear
0
Yfar
3
Zlow
-1
Zhigh
2.5
Xe
2.5
Ye
-1.5
Ze
2
Nx
13
Ny
8
Hidden
0
END
SlopeField
\<< {VPAR Nx} RCL
{VPAR Ny} RCL
{VPAR Xleft} RCL {VPAR Xright} RCL DUP2 XRNG
{VPAR Ynear} RCL {VPAR Yfar} RCL DUP2 YRNG
EQ
0 0 0 0 0 0 0
\-> numx numy left right bot top der hstp vstp hofs vofs x y d
\<< ERASE {# 0d # 0d } PVIEW
right left - numx / 'hstp' STO
top bot - numy / 'vstp' STO
hstp .4 * 'hofs' STO
vstp .4 * 'vofs' STO
bot vstp 2 / + top
FOR y
y 'Y' STO
left hstp 2 / +
right
FOR x
x 'X' STO
der \->NUM 'd' STO
'IFTE(ABS(d*hofs)>vofs,vofs/d+i*vofs,hofs+i*hofs*d)' \->NUM
x y R\->C DUP2 + 3 ROLLD SWAP - line
hstp
STEP
vstp
STEP
\>>
{ X Y } PURGE { } PVIEW
\>>
psContour
\<< EQ
\<< \-> dx dy 'IFTE(dy==0,MAXR,-dx/dy)' \>>
\-> eq slp
\<<
IFERR eq X \.d
eq Y \.d
2 \->LIST
'slp' APPLY
{ X Y } SHOW STEQ
SlopeField
THEN eq STEQ ERRM DOERR
END eq STEQ
\>>
\>>
YView
\<< SetWindow 0
\<< \-> K
\<<
CASE
K TYPE DUP 0 ==
THEN
DROP X K R\->C
X -50 R\->C
DUP2 LINE TLINE
K
END
1 ==
THEN K
END
K EVAL 1 \->LIST
'PRASE' APPLY
END
\>>
\>> \-> Xleft Xright Ynear Yfar Xe Ye Ze Nx Ny prase u hline
\<< 'EQ' RCL
'u' \-> eq u
\<< eq { X '(X-Xe)*u+Xe' Y 'u+Ye' } |
Ze - 'u' / Ze +
{ X u } SHOW
COLCT
IF prase
THEN { & 'hline(&)' } \|vMATCH DROP
END
IFERR
'EQ' STO 'X' INDEP
ERASE
Ynear Yfar - 8 /
\-> stp
\<< Yfar Ye -
Ynear Ye -
FOR u
draw
IF KEY
THEN DROP
"outa here" DOERR
END
stp
STEP
\>>
THEN eq STEQ ERRM DOERR
ELSE eq STEQ
END
{ } PVIEW
\>>
\>>
\>>
WIREFRAME
\<< SetWindow 0 0 0 0
\-> Xmin Xmax Ynear Yfar Xe Ye Ze numx numy prase u v bd1 bd2
\<< 'u' 'v' \-> u v
\<< EQ { X v Y 'u+Ye' } |
Ze - 'u' / Ze +
{ v u } SHOW COLCT ERASE
{ # 0d # 0d } PVIEW
Ynear Yfar - numy /
Xmax Xmin - numx /
\-> eq stpu stpx
\<< Yfar Ye -
Ynear Ye -
FOR u
0 'bd1' STO
Xmin 'v' STO
0 numx
START
v Xe - u / Xe +
eq \->NUM R\->C
IF bd1
THEN DUP2 line
ELSE 1 'bd1' STO
END
IF bd2
THEN numx 2 + ROLL OVER line
END
stpx 'v' STO+
NEXT
1 'bd2' STO
stpu
STEP
numx 1 + DROPN
\>> { } PVIEW
\>>
\>>
\>>
ShapeToShade
\<< {VPAR Xleft} RCL
{VPAR Xright} RCL
{VPAR Ynear} RCL
{VPAR Yfar} RCL
0 0 0 \-> xmin xmax ymin ymax x y eq
\<< xmax xmin - 32 /
ymin ymax - 15.001 /
'x' 'y'
\-> xstp ystp x y
\<< EQ DUP
X \.d .4 - 2 ^ SWAP
Y \.d .4 + 2 ^ +
1 + -.35 ^
{ X x Y y } | COLCT
'eq' STO
ERASE {# 0d # 0d } PVIEW
# 0d
ymax ymin
FOR y
# 0d
xmin xmax
FOR x
DUP2 SWAP 2 \->LIST
PICT SWAP
eq \->NUM
IF
DUP TYPE 0 \=/
THEN
DROP 1
END
tile
15.99 * IP
DPAR SWAP 16 - NEG GET
REPL
4 +
xstp
STEP
DROP
4 +
ystp
STEP DROP { } PVIEW
\>>
\>>
\>>
DPAR {
GROB 4 4 00400000
GROB 4 4 00402000
GROB 4 4 90000080
GROB 4 4 40104010
GROB 4 4 20802090
GROB 4 4 8050A010
GROB 4 4 50A05080
GROB 4 4 A050A050
GROB 4 4 50A050A0
GROB 4 4 A050A070
GROB 4 4 70A050E0
GROB 4 4 D070D060
GROB 4 4 B0E0B0E0
GROB 4 4 70D0F0B0
GROB 4 4 F0B0D0F0
GROB 4 4 F0B0F0F0 }
Movie
\<< {VPAR Xleft} RCL {VPAR Xright} RCL XRNG
{VPAR Zlow} RCL {VPAR Zhigh} RCL YRNG
{VPAR Ynear} RCL {VPAR Yfar} RCL
{VPAR Ny} RCL
EQ
0 0
\-> ynear yfar numy eq ystp y
\<< 'y' 'y' STO
eq { X Y } SHOW
{ Y y } |
ynear yfar - numy / 'ystp' STO
IFERR STEQ
'X' INDEP
FUNCTION
0 yfar ynear
FOR y
ERASE draw
y PICT RCL ROT 2 +
IF KEY
THEN
DROP "outa here"
DOERR
END
ystp
STEP
THEN
eq STEQ
ERRM DOERR
END
eq STEQ
\>> uSMOV
\>>
uSMOV
\<< \-> n
\<< { # 0d # 0d } PVIEW
DO n ROLL
n ROLL
DUP PICT {# 0d # 0d } ROT REPL
UNTIL KEY
END DROP n
\>>
\>>
SSTMovie
\<<
DO
\-> n
\<< n ROLL n ROLL DUP PICT
{# 0d # 0d } ROT REPL n
{ # 0d # 0d } PVIEW
\>>
UNTIL 0 WAIT
51.1 ==
END
\>>
EQ
'2*(2-Y)*EXP(-((X-.5)^2+(Y-1.2)^2))+Y*EXP(-2*((X-2)^2+(Y-2)^2))'
PPAR
{ (-2,0) (2,5) X # 8d (0,0) FUNCTION Y }
SetWindow
\<< PATH
VPAR
Xleft Xright Ynear Yfar Zlow Zhigh Xe Ye Ze Nx Ny Hidden 0
\-> Xleft Xright Ynear Yfar Zlow Zhigh Xe Ye Ze Nx Ny Hidden Ue
\<< EVAL
\<< \-> u y '(u-Ue)/(y-Ye)+Ue' SWAP OVER MAX ROT ROT MIN SWAP \>>
\-> proj
\<< Xe 'Ue' STO
MAXR \->NUM DUP NEG
Xleft Ynear proj EVAL
Xleft Yfar proj EVAL
Xright Ynear proj EVAL
Xright Yfar proj EVAL
XRNG
Ze 'Ue' STO
MAXR \->NUM DUP NEG
Zlow Ynear proj EVAL
Zlow Yfar proj EVAL
Zhigh Ynear proj EVAL
Zhigh Yfar proj EVAL
YRNG
\>>
Xleft Xright Ynear Yfar Xe Ye Ze Nx Ny Hidden
\>>
\>>
draw
DRAW
line
LINE
tile
\<< \>>
@ Begin POSTSCRIPT Stuff @
PSTOGGLE
\<< "PS is "
IF 'draw' RCL 'PSDRAW' SAME
THEN {DRAW} 1 GET 'draw' STO
{LINE} 1 GET 'line' STO
\<<\>> 'tile' STO "Off" +
ELSE 'PSDRAW' 'draw' STO
'PSLINE' 'line' STO
'PSTILE' 'tile' STO "On" +
END 1 DISP
\>>
PSRESET
\<< "'PSOUT" 'PSOUT'
DO "" SWAP STO
"&" + DUP STR\-> DUP
UNTIL VTYPE -1 ==
END
DROP2 'PSOUT' 'CURRENTOUT' STO
\>>
PSTILE
\<< DUP \->STR
" g
"
+ 5 PICK B\->R
DUP 4 + \->STR " " +
SWAP \->STR " " +
8 PICK # 64d SWAP - B\->R
DUP 4 - \->STR
" " + SWAP \->STR " " +
\-> X2 X1 Y1 Y2
\<< X2 + Y1 +
"m
"
+ X2 + Y2 +
"L
"
+ X1 + Y2 +
"L
"
+ X1 + Y1 +
"L
"
+ X2 + Y1 +
"L
f
"
+
\>> PSADDTO
\>>
PSADDTO
\<<
IF CURRENTOUT SIZE 4000 >
THEN 'CURRENTOUT' RCL \->STR
1 OVER SIZE 1 - SUB "&" + STR\->
DUP 'CURRENTOUT' STO STO
ELSE
'CURRENTOUT' RCL SWAP STO+
END
\>>
CURRENTOUT
PSOUT
PSCOPAIR
\<< 'PPAR(1)' EVAL DUP
'PPAR(2)' EVAL SWAP -
\-> p1 p2 o d
\<< p2 o - C\->R
d C\->R ROT SWAP / 64 *
ROT ROT / 131 *
p1 o - C\->R d C\->R
ROT SWAP / 64 *
ROT ROT / 131 *
\>> \-> y2 x2 y1 x1
\<< x1 \->STR " " +
y1 \->STR " " + +
x2 \->STR " " + +
y2 \->STR " " + +
x2 x1 - x2 + \->STR " " +
y2 y1 - y2 + \->STR " " + +
\>>
\>>
PSDRAW
\<< PPAR OBJ\-> 4 DROPN
0 0
\-> hm vm indp rs flop \Gdx
\<<
IF rs TYPE 10 ==
THEN rs # 0d 2 \->LIST PX\->C hm - RE
ELSE
IF rs 0 ==
THEN { # 1d # 0d } PX\->C hm - RE
ELSE rs
END
END
3 / '\Gdx' STO
'EQ' RCL 'vm' STO
\<< \-> vl
\<< vl \->NUM
indp \->NUM
\-> vlu indv
\<<
IF flop
THEN indv \Gdx - vl indp \.d \->NUM
\Gdx *
vlu SWAP - R\->C
'indp+vl*i' \->NUM PSCOPAIR
3 ROLLD + "c
"
+
PSADDTO
ELSE
'indp+vl*i' \->NUM
PSCO "m
"
+
indv \Gdx +
vl indp \.d \->NUM
\Gdx * vlu + R\->C PSCO +
1 'flop' STO
END
vlu
\>>
\>>
\>> 'hm' STO
IFERR vm {& 'hm(QUOTE(&))' } \|vMATCH DROP STEQ
DRAW vm STEQ
THEN vm STEQ ERRM DOERR
END "S
"
PSADDTO
\>>
\>>
PSCO
\<< 'PPAR(1)' EVAL - C\->R
'PPAR(2)-PPAR(1)' EVAL C\->R
ROT SWAP / 64 *
ROT ROT / 131 * \->STR
" " + SWAP \->STR
" " + +
\>>
PSLINE
\<< \-> C1 C2
\<< C1 PSCO
"m
"
+ C2 PSCO +
"l
S
"
+ PSADDTO
C1 C2 LINE
\>>
\>>
PSOUT
""
PSOUT&
""
PSOUT&&
""
PSOUT&&&
""
PSOUT&&&&
""
PSOUT&&&&&
""
PSOUT&&&&&&
""
END
END_RPL