[comp.sys.handhelds] HP28S program: graphics, larger than life

#PSWHER@WMMVS.BITNET (03/22/90)

Recently, there have been a number of comments floating around the
network to the effect that "I have a 28S, not a 48SX--how about some
programs for MY calculator."  This article may contain just what you
are looking for.

I should point out, however, that my purchase of a 48SX is more-or-less
directly responsible for the following program (developed by Matt
McIrvin, my roommate [and new owner of a 28S]).  Remember this the
next time you fuss about the 48SX :-).

Phil Wherry
#PSWHER%WMMVS.BITNET@CUNYVM.CUNY.EDU    (BITNET)
psw@mitre.org                           (Internet)

---- Included article follows ----

Plots more than 32 pixels high on the HP-28S (a long article)
By Matt McIrvin (#MJMCIR%WMMVS.BITNET@CUNYVM.CUNY.EDU)

A major shortcoming of the HP-28S plot commands is the 28S's physical
display:  it's rather squat, and there's no way to handle a picture
larger than the size of the display.  The HP-48SX remedies this by
having a larger display and by allowing the user to scroll over a plot.
Some of us, however, still own the 28S and probably wish to get in on
the fun.  I got my 28S a couple of days ago from Phil Wherry,
who had just bought a 48SX, and we started talking about the possibility
of producing tall plots on the 28S with the ability to scroll vertically.
I had played around with the 28S a bit when Phil owned it, and had learned
just enough to be able, after hours of intense development, to produce
the following suite of programs.  Some inspiration was obtained from
Bill Wickes' utility, printed in _HP-28 Insights,_ to print an image
four screens high.  This set of programs, however, can produce plots up
to 20 screens high (an arbitrary limit I set to avoid ridiculous numbers
of screens) and will then let the user use something very similar to
interactive plot mode, with vertical scrolling added.

These programs are designed to live in two directories on an HP-28S, the
HOME directory and a subdirectory of HOME called TALL.  They will only
work on the 28S.  Type them all in and store them in the appropriate places,
and then, from any directory, execute the command TPLT.  This will put up
a custom menu greatly resembling the PLOT menu.  In fact, it's exactly
the same, except that DRAW and DRW& (pretend that last character is a sigma)
have been replaced with TDRW and TDR&, and the last six buttons (which
are irrelevant to interactive plotting) are not there.

TDRW and TDR& mimic as closely as possible the interactive plotting
buttons on the PLOT menu.  They use the current equation, current
parameters, and current statistics matrix in exactly the same way as
DRAW and DRW&.  The first difference between the new commands and their
predecessors is that TDRW and TDR& each take an argument off the stack,
equal to the height in screens of the plot.  For an example of how this
works, type

'PPAR' PURGE
'SIN(X)' STEQ
'X' INDEP
3 TDRW

The screen blanks, the BUSY annunciator comes on, and the HP-28S draws,
one after the other, three pictures which, together, make up a plot of a
sine wave three screens tall.  It's storing them in a big string
variable as it goes.  Then, the BUSY annunciator goes out, and you see
the first picture once again.  You are at the top of the tall plot.  The
cursor-up and cursor-down menu keys will scroll in quarter-screen
(eight-pixel) intervals up and down through the plot.  The right-arrow
key exits the program and returns you to the stack; don't use the ON key
to do this (more on that below).

You can even digitize points from a tall plot.  Press INSERT to turn on
the digitizing cursor.  It will then act exactly like it usually does;
the cursor keys move it around, the INSERT key digitizes a point, and
the DELETE key turns (the visible portion of) the picture into a string.
The ON key, as usual, gets you out of digitizing, but doesn't leave the
plot altogether; you can now use the up and down cursor keys to scroll
to somewhere else and digitize some more.  You should use the right
arrow rather than ON to leave scrolling because it terminates
gracefully; if you use ON, you'll end up in the TALL directory rather
than where you came in, and the stuff you digitized onto the stack won't
be there, having been replaced by garbage.  To sum up:

                        Scrolling                Digitizing (as usual)
                        ---------                ---------------------
        Up/down         Scroll up and down       Move the cursor up/down
        Left                                     Move the cursor left
        Right           Leave the plot           Move the cursor right
        INSERT          Go into digitizing mode  Digitize a point
        DELETE                                   Digitize the screen
        ON              Trash the stack          Leave digitizing mode

I apologize for the slight clunkiness in the user interface (it's really
only slight).  If you look closely, you may also be able to notice
slightly odd behavior of plotted curves at the boundaries between two
screens; sometimes they don't match exactly right.  This is due to the way
the standard drawing routines (which I use) handle PPAR, and with the
current implementation there's no graceful way to get rid of it.  This
also decreases marginally the accuracy of the vertical coordinate when
digitizing, but that usually doesn't matter much.

I encourage any improvements you might be able to make in the system; it
would be fairly simple, for instance, to superimpose a scatter plot and
a linear-regression line on the same tall picture.

The programs together take up somewhere between 2 and 3 kilobytes.  You
should probably type them in if you do anything even remotely graphical,
particularly if you haven't got a printer.  The ability to make and view
plots that don't look like they've been run over by a steamroller should
greatly enhance the utility of your calculator.

I should mention the roundabout path these programs are taking onto the
Internet.  They were sent via my HP-28S's infrared printer
transmitter to Phil Wherry's HP-48SX, from which (with the use of a
sort of serial cable knocked together from an RS-232 port tester)  Phil
KERMITed them into his PC.  I am now making them pretty with QEDIT, for
transfer onto the Internet via modem and mainframe.  Not bad for a glorified
pocket calculator keyboard macro...

Enjoy.

Matt McIrvin

-------------------- TALL:  tall plots for the HP-28S ------------------
Conventions:  & sigma   -> right arrow   << >> guillemets (angle quotes)
              >= greater than or equal to   <= less than or equal to
              != not equal to
              Checksums are given in square brackets next to the program
              name.  My comments are over on the right after a vertical
              line.
              Under each program name I have included a line showing what
              arguments the program takes and what it leaves on the stack:
              [ before | after ]
              Type in only the stuff between guillemets (don't type the
              comments), then STO it to the program name.

Store the following programs in the HOME directory:

TPLT [A6DA]                             | put up the custom menu
[ | ]
<< { STEQ RCEQ PMIN PMAX INDEP TDRW
     PPAR RES AXES CENTR *W *H
     STO& RCL& COL& SCL& TDR& }
     MENU
>>

TDRW [B8EA]                             | interactive function plot
[ #screens | ]
<< RCLF PATH -> flags userpath          | save the user's situation
  << 1 *H                               | make a PPAR if there is none
    IF DUP TYPE 0 !=                    | is the argument a real number?
      THEN
        "Needs real argument"
        1 DISP 1 WAIT ABORT
    END
    FLOOR                               | make it an integer
    IF DUP DUP 1 <                      | is it out of bounds?
      SWAP 20 > OR
      THEN
        "# of screens should"
        "be between 1 and 20"
        2 DISP 1 DISP 1.5
        WAIT ABORT
    END                                 | is there anything to plot?
    IF EQ TYPE 6 ==
      THEN
        "No current equation"
        1 DISP 1 WAIT ABORT
    END
    PPAR EQ                             | take the equation and params
    HOME TALL 'EQ' STO 'PPAR'           | and stuff them in the TALL dir.
    STO 11 CF                           | flag for equation plotting
    IFERR TDRAW                         | go for it...
      THEN
        "Undefined variable"            | if something's wrong, it's
        1 DISP 1 WAIT                   | probably an undefined name
    END
    userpath DUP                        | get back to where
    SIZE 1 SWAP                         | you once belonged
    FOR dir
      DUP dir
      GET EVAL
    NEXT
    DROP
    flags STOF                          | put the user's flags back
  >>
>>

TDR& [5482]                             | interactive scatter plotting
[ #screens | ]
<< RCLF PATH -> flags userpath          | save user's situation
  << 1 *H                               | make PPAR if there is none
    IF DUP TYPE 0 !=                    | is argument a real?
      THEN
        "Needs real argument"
        1 DISP 1 WAIT ABORT
    END
    FLOOR                               | make it an integer
    IF DUP DUP 1 < SWAP 20 > OR         | is it out of bounds?
      THEN
        "# of screens should"
        "be between 1 and 20"
        2 DISP 1 DISP 1.5
        WAIT ABORT
    END
    IF &DAT TYPE 6 ==                   | is there a statistics matrix?
      THEN
        "No current &DAT"
        1 DISP 1 WAIT ABORT
    END
    IF &PAR TYPE 6 ==                   | are there any stats parameters?
      THEN
        1 2 COL&                        | if not, make some default ones
    END
    PPAR &DAT &PAR                      | take user directory information...
    HOME TALL                           | ... and stuff it in HOME TALL
    '&PAR' STO '&DAT' STO 'PPAR' STO
    11 SF                               | flag indicates scatter plotting
    IFERR TDRAW                         | go for it, and if anything's wrong...
      THEN
        "Plotting error"                | ... admit puzzlement
        1 DISP 1 WAIT
    END
    userpath DUP                        | sneak back to the user's directory
    SIZE 1 SWAP
    FOR dir
      DUP dir GET EVAL
    NEXT
    DROP
    flags STOF                          | put the user's flags back
  >>
>>

Create a directory called TALL hanging from HOME, and put in it the following
programs, which are supposed to be invisible to the user:

TDRAW [283B]                            | perform a plot of either kind
[ #screens | ]
<< DUP TMAKE SWAP TSCROLL
>>

TMAKE [F9F0]                            | draw screens and concatenate
[ #screens | image ]
<<
  PGET
  SWAP DUP2 SWAP - 0 ""
    -> scrns miny maxy height inc image
  <<
    height scrns /
    'inc' STO                           | height of one screen in PPAR terms
    1 scrns FOR
      n maxy n 1 - inc * - DUP inc -    | figure out PPAR for this screen
      PPUT                              | and adjust it
      CLLCD                             | clear the screen
      IF 11 FS?                         | If this is a scatter plot...
        THEN DRW&                       | do a scatter plot
        ELSE DRAW                       | Otherwise do a function plot
      END
      LCD-> image                       | Concatenate onto multi-screen
      SWAP + 'image' STO                | image string
    NEXT
    image maxy miny PPUT                | restore the old PPAR
    CLMF
  >>
>>

TSCROLL [C34F]                          | keyboard interface for scroll mode
[ image #screens | stuff digitized by user ]
<< 4 * 4 - 0 1 { } ->
    maxoff offset continue outlist
  <<
    WHILE continue                      | go until user sez otherwise
      REPEAT
        DUP offset TDISP                | put currently visible view on LCD
        # 1F866h SYSEVAL                | turn off BUSY annunciator
      DO UNTIL KEY END                  | wait for a keystroke
      DUP
      IF "UP" ==                        | if it was an up arrow...
        THEN
          offset 1 - DUP                | move up one line,
          IF 0 < THEN DROP 0 END        | unless we're at the top already
          'offset' STO DROP
        ELSE
          DUP
          IF "DOWN" ==                  | if it was a down arrow...
            THEN
              offset 1 + DUP            | move down one line,
              IF maxoff >               | unless we're at the bottom
                THEN DROP maxoff END
              'offset' STO DROP
            ELSE
              DUP
              IF "RIGHT" ==             | if it was a right arrow...
                THEN
                  0 'continue' STO      | file a cease-and-desist order
                  DROP
                ELSE
                  IF "INS" ==           | if it was "INSERT"...
                    THEN
                      outlist           | digitize
                      maxoff
                      offset
                      TDIG
                      + 'outlist' STO   | and stick results onto a list
                  END
              END
          END
      END
    END
    DROP
    outlist LIST->                      | put output list back on the stack
    DROP                                | drop the number-of-elements number
    CLMF                                | don't retain this picture when done
  >>
>>

TDISP [F95E]                            | put a selected part of the image
[ image offset | ]                      | string onto the screen
<<
  137 * 1 + DUP 548 +                   | figure out character offsets
  SUB                                   | get the substring
  ->LCD                                 | blast it to the screen
>>

TDIG [FF41]                             | adjust PPAR and go to digitizing
[ maxoff offset | output_list_containing_stuff_digitized_by_user ]
<<
  SWAP DUP 4 +
  PGET DUP2 - 0
    -> offset maxoff lines maxy
       miny height stackd
  <<
    offset lines /
    height * maxy SWAP -                | find new maximum y
    DUP height lines / 4 * -            | find new minimum y
    PPUT                                | revise PPAR
    DEPTH 'stackd' STO                  | remember stack depth
    DGTIZ                               | digitize interactively
    DEPTH stackd -                      | how many new stack elements?
    ->LIST                              | put them in a list for output
    maxy miny PPUT                      | restore old PPAR
  >>
>>

PPUT [A5A7]                             | put new y limits into PPAR
[ maxy miny | ]
<<
  PPAR 1 GET RE                         | get minimum x
  SWAP R->C PMIN                        | stuff it and miny into PPAR
  PPAR 2 GET RE                         | get maximum x
  SWAP R->C PMAX                        | stuff it and maxy into PPAR
>>

PGET [4505]                             | get y limits from PPAR
[ | maxy miny ]
<<
  PPAR DUP 2 GET IM                     | get maximum y
  SWAP 1 GET IM                         | get minimum y
>>

---- End of included article ----

Have fun!