[comp.sys.handhelds] Airfoil Plotter for HP48sx

nelson@ (Matt Nelson) (10/30/90)

     This is for all of the R/C model airplane/sailplane enthusiasts out there,
especially if you are into designing and building. If you have no interest in
model aircraft, you might as well hit 'n' now.

     Here is the latest version of my airfoil section plotter.  I needed to
plot  some ribs for a glider project, and realized that I had sold my trusty 
HP-28s.  I quickly re-wrote my original program to run on the HP-48sx,  and
came up with something MUCH prettier, and MUCH MUCH faster.  This  thing is
really quite painless to use now (the 28s version was slooooow).

     The speedup came from creating a PICT that is big enough to contain  the
entire airfoil section.  The airfoil data is plotted only once, and then sent
to the printer, one screen at a time, through successive PVIEW and PRLCD
commands.  BE WARNED... although this is a very fast way to print out large
objects, it is also a memory-hungry way to do it. for example, a 10" SD7003
required a PICT that was 131 by 832.  When I saved this PICT to the stack and
BYTESed it, it was 14,154 bytes big.  On top of that, just the data for the
SD7003 (as listed below) is 988.5 bytes long.  All I am saying is that this
program DOES use a lot of memory, but is very handy, and serves my purposes
very well; if you don't like it, feel free to use something else.

     To use this program, simply download the listing below, get into the new
directory, and hit [AIRFOI].  It will ask for an airfoil.  Just hit the menu
button corresponding to the airfoil data you wish to use  (you can hit [SD700]
to try it out), then [ENTER].  It will then ask for  a chord.  Give it a number
corresponding to the desired chord, in centimeters, then [ENTER].  The program
will handle other units, and in fact presents you with the UNITS LENG menu, so
you can give it a chord size in any unit you wish.  Just be sure to give it a
valid unit object (you have to supply the underscore manually, since the
calculator is in program entry mode at this point).  You should be greeted by a
"working..." message.  Point the calculator at your 82240A/B printer, and watch
the airfoil section print out.

     The airfoil data is assumed to be in a complex vector, where each element
corresponds to a point (x,y) on the airfoil.  The points should be arranged so
that if you were to draw lines sequentially from one point to the next,  you
would trace out a closed outline of the airfoil section.  The sample airfoil in
this posting, the SD7003, should help illustrate this.  For those who are
interested, the SD7003 is an airfoil designed specifically for use at very low
Reynolds numbers, such as those encountered by model sailplanes.

     There are two parameters which control the absolute size of the printed
output.  These are the global variables ycmps and xcmps.  These represent the
number of centimeters per screen OF PRINTED OUTPUT for the y and x directions,
respectfully.  One arrives at these values by printing a screenfull of
anything, and measuring the size of the printed output in centimeters.  The
numbers supplied below are for the 82240A printer; I have never used a 'B'
version of the printer, and don't know whether these numbers will have to be
changed in order to work properly with that printer.  The only reason I left
these numbers as global variables is so that the user could have some control
over the aspect ratio of the output, without diving into the program itself.

     Please direct any comments/suggestions/questions etc. to:

     Matt Nelson     		internet:  nelson@psroot.ps.uci.edu
     Physics Dept.		bitnet:    mnelson@uci
     University of California   phone:     (714) 725-2629
     Irvine, CA 92717

---snip----snip----snip----snip----snip----snip----snip----snip----snip----snip

%%HP: T(3)A(R)F(.);
DIR
                                                    
AIRFOIL                                                                  
\<<  
  "Airfoil?"			@ prompt for airfoil name
  {1}
  INPUT
  OBJ\->			@ get the data array on the stack
  DUP IF TYPE 4 \=/ THEN	@ check to see if this is a complex
    "Not airfoil data"		@ array; assumes any complex array
    DOERR			@ in this directory IS airfoil data
    DROP
    KILL			@ if not, kill the program
  END
  43 MENU			@ select UNITS LENG menu
  "Chord?"			@ prompt for desired chord             
  {1}
  INPUT
  OBJ\->			@ put chord on stack
  0 MENU			@ return to previous menu
  CLLCD
  "   working..." 3 DISP	@ display info message
  DUP				@ get type of argument 
  IF TYPE 13 == THEN		@ it is a unit object 
    '1_cm' CONVERT		@ assume unit is length, so convert to cm 
    OBJ\-> DROP			@ get rid of its unit
  END
  PPAR				@ get current PPAR so we can save it
  \-> chord ppar		@ save desired chord, in cm, and PPAR
  \<<
    # 64d			@ eventual width of PICT we will want 
    chord ycmps /		@ required height of PICT, in screens
    CEIL			@ required height of PICT, in integer screens
    \-> nscreen			@ we will need number of screens later 
    \<<  {
      (-1.82,0) (1.82,2.11)	@ put a PPAR on stack, so that we have
      X 0 (0,0) FUNCTION Y }	@ something to work with...
      1				@ PUT index for pmin
      xcmps 2 / NEG		@ get xmin from the real width of output
      0 R\->C PUT		@ put (xmin,0) into our PPAR
      2				@ PUT index for below...
      xcmps 2 /			@ get xmax from the real width of output
      nscreen ycmps *		@ new ymax = #screens * (cm/screen)
      R\->C PUT			@ make it complex, and shove it into PPAR
      'PPAR' STO		@ store it for use
      nscreen 64 * R\->B PDIM	@ make PICT the appropriate size               
@                                                 
@ at this point, we still have the array of coordinates on the stack,
@ so re-scale them into cm
@
      DUP SIZE OBJ\-> DROP	@ get size of array
      -100 100 -100 100		@ initialize xmax=ymax=-100, xmin=ymin=100
      \-> size xmax xmin ymax ymin
      \<< 
        1 1 size
        START			@ scan the array looking for max & min x
          GETI C\->R		@ get the x and y coord
          \-> x y
          \<<
            x xmin MIN		@ put minimum of x and xmin in xmin
            'xmin' STO
            x xmax MAX		@ put maximum of x and xmax in xmax
            'xmax' STO
            y ymin MIN		@ put minimum of y and ymin in ymin
            'ymin' STO
            y ymax MAX		@ put maximum of y and ymax in ymax
            'ymax' STO
          \>>
        NEXT                        
        DROP			@ get rid of the GETI index
        1 1 size 1 -
        START DUP NEXT		@ make two arrays of 1's, size of data
        size 1 \->LIST \->ARRY DUP       
        ROT C\->R			@ get y-coordinates
        4 ROLL ymax ymin + 2 / *	@ make array of average y value
        -				@ shift y values by subtracting average
        3 ROLLD SWAP xmin * -	@ subtract xmin from all x values
        SWAP R\->C		@ re-pack complex array, now has [0,1] x-range
        chord *			@ multiply by chord for proper scale
@   
@ we now have a properly scaled array of coordinates on the stack, so
@ connect the dots between adjacent points
@
        ERASE			@ clear PICT
        1 size 1 -		@ need one less than size of the array
        FOR i
          DUP i GETI
          4 ROLLD GET ROT	@ put the first pair of points on the stack
          C\->R SWAP R\->C	@ swap x and y so foil comes out long-wise
          SWAP
          C\->R SWAP R\->C	@ do same with 2nd point
          LINE			@ draw a line between the two points
        NEXT
        DROP			@ don't need the array of points anymore
      \>>
@
@ now PICT has the airfoil drawn on it, so display it screen
@ by screen, dumping it to the printer
@
      CR			@ put print head over to right
      1 nscreen			@ there will be nscreen dumps
      FOR i
        # 0d			@ upper left hand x-pixel coordinate to display
        i 1 - 64 * R\->B	@ upper right hand y-pixel coordinate "
        2 \->LIST		@ put pixel coordinates in a list
        PVIEW			@ and display PICT
        PRLCD			@ send display to printer
      NEXT
    \>>
@
@ we is done, so clean up
@
    ppar DUP                                                  
    IF TYPE 6 == THEN		@ there was no PPAR, and we just saved a name
      DROP			@ at top of program; just drop it
      'PPAR' PURGE		@ and get rid of the one we created
    ELSE
      'PPAR' STO		@ there was a PPAR, so restore it
    END
    PICT PURGE			@ get back the memory used by PICT
  \>>
\>>


ycmps				@ height of one screen of PRINTED OUTPUT, cm
  2.096

xcmps				@ width of one screen of PRINTED OUTPUT, cm
  3.60
  
SD7003				@ sample airfoil, the Selig-Donovan 7003
  [ (1.00000,0.0)
    (0.99681,0.00031)
    (0.98745,0.00132)
    (0.97235,0.00310)
    (0.95193,0.00547)
    (0.92639,0.00824)
    (0.89600,0.01139)
    (0.86112,0.01494)
    (0.82224,0.01884)
    (0.77985,0.02304)
    (0.73449,0.02744)
    (0.68673,0.03197)
    (0.63717,0.03649)
    (0.58641,0.04086)
    (0.53499,0.04494)
    (0.48350,0.04859)
    (0.43249,0.05171)
    (0.38250,0.05415)
    (0.33405,0.05581)
    (0.28760,0.05658)
    (0.24358,0.05639)
    (0.20240,0.05518)
    (0.16442,0.05292)
    (0.12993,0.04961)
    (0.09921,0.04526)
    (0.07244,0.03993)
    (0.04978,0.03372)
    (0.03130,0.02677)
    (0.01702,0.01932)
    (0.00697,0.01172)
    (0.00127,0.00438)
    (0.00025,-0.00186)
    (0.00457,-0.00741)
    (0.01408,-0.01285)
    (0.02839,-0.01759)
    (0.04763,-0.02141)
    (0.07182,-0.02438)
    (0.10073,-0.02660)
    (0.13407,-0.02809)
    (0.17150,-0.02888)
    (0.21268,-0.02900)
    (0.25719,-0.02852)
    (0.30456,-0.02752)
    (0.35426,-0.02608)
    (0.40572,-0.02428)
    (0.45837,-0.02217)
    (0.51161,-0.01980)
    (0.56484,-0.01723)
    (0.61748,-0.01450)
    (0.66898,-0.01167)
    (0.71883,-0.00887)
    (0.76644,-0.00628)
    (0.81118,-0.00403)
    (0.85241,-0.00220)
    (0.88957,-0.00082)
    (0.92210,0.00008)
    (0.94952,0.00052)
    (0.97134,0.00057)
    (0.98718,0.00037)
    (0.99679,0.00011)
    (1.00001,-0.00000) ]                                           

END