The Museum of HP Calculators

HP Forum Archive 21

[ Return to Index | Top of Index ]

WP-34S: Program for vector (3D) manipulation
Message #1 Posted by Marcel Samek on 4 Sept 2013, 4:25 p.m.

This is a slightly different approach to a program to do 3D vector operations. It is not really designed to be library subroutines used in other programs (although it could be used that way); it is intended as an interactive tool.

The problem that I was trying to solve is that I wanted to be able to do standard operations on 3D vectors but I didn't really want to hassle with stack management, especially when trying to intersperse random non-vector calculation between the vector operations.

So, I came up with this program which allows one to manipulate vectors without, for the most part, using the regular XYZT stack. The vector operations abuse STOS and RCLS to a fault to make sure that all 4 or 8 entries on the stack are preserved.

The program is document in the comments, but essentially it implements a little virtual mini-calculator that operates on an RPN type stack of vectors that live in memory away from the regular stack. The 4 hotkeys are used as push, pop, and shift - where shift essentially redefines the keyboard to be vector operations.

The neat thing is that even after you have pushed your triplets (vertices or vectors) onto the stack, you can do as many regular calculations as you like before operating on the vectors and you don't have to worry about what that does to the stack, since the vectors live in their own stack space.

The source below has a little example on how to use it. It might not stand out as particularly keystroke efficient, but after you have played with it for a while, I think that you will find it very easy to use and very practical.

When first playing with it, I highly recommend using the QT emulator so you can watch what it is doing with the memory - it will give you a much quicker understanding of what's happening until you get comfortable with it.

/*
	General concept:

Implements a virtual RPN calculator for manipulating 3D vectors/points/triangles. Instead of attempting to use the regular XYZT RPN stack for vector operations, a separate virtual stack for triplets is implemented. This allows the user to do regular RPN calculations in between vector operations without needing to worry about the vectors on the stack.

This vector stack is referred to as the vstack below and can contain up to 8 triplet values.

Using the vstack will be familiar to the user of an RPN calculator. There are operations to push values on the vstack, rotate the vstack up or down, duplicate values, switch positions, and off course a variety of vector and scalar operations. Operations pop their arguments off the vstack and push the results on. It is up to the user to use the standard RPN-like stack operators to manage the stack.

Summary of operations:

Hotkey A: pushes an XYZ triplet onto the vstack

Hotkey B: (analogous to a shift key) redefines the keyboard so that the next key press is a vector operations (e.g. +, -, x, DUP, etc) that operates on the values in the vstack

Hotkey C: (also analogous to a shift key) redefines the keyboard so that the next key press is a scalar operation (e.g. *, /) that operates on the values in the vstack.

Hotkey D: pops an XYZ triplet from the vstack to ZYX in the RPN stack.

Interaction with the regular stack:

The hotkey A, which pushes a new value on the vstack depends, of course, on the contents of the regular stack.

The operations which take a scalar as an input, (for example the scalar multiply), expect the scalar argument to be in X on the regular stack since the vstack only holds triplets.

The vector operations which return a scalar as the output, such as magnitude, for example, return that value in X on the regular stack.

None of the operations that operate solely on vectors and return vectors as results (e.g. vector add, cross product, etc) depend on the contents of the regular stack. They fully preserve the XYZT stack. It does not matter whether the stack size is 4 or 8. It will work with both.

Input (Hotkey A) Vectors are input via the regular XYZT RPN stack. The triplet should be pushed onto the stack in natural order, which means that that the triplet (x, y, z) representing a vector, or a 3D point will end up in the Z,Y,X registers respectively. Once a vector has been entered, or calculated on the RPN XYZT stack, the A subroutine (invoked by the A hotkey) will push it onto vstack.

Vector operations supported by Hotkey B:

+ Vector add - Vector subtract x Vector cross product . Vector dot product EEX Vector Magnitude Enter Duplicates the value at the bottom of the vstack R[v] Rotates the 8 value vstack down x<>y Exchange entries at bottom of stack (Any other key is a NoOp)

Vector operations supported by Hotkey C:

* Vector/scalar multiply / Vector/scalar divide R[v] Rotates the 8 value vstack up (Any other key is a NoOp)

Register: 00 through 23 The vstack (8 triplets)

Example Usage: Input three vertices v1, v2, v3 of a triangle and compute the area by computing half the cross product (v1-v2) X (v3-v2)

1, ENTER, 1, ENTER, 1 ; first vertex A ; push on the vstack 1, ENTER, -1, ENTER, 2 ; second vertex A ; push on the vstack 0, ENTER, 2, ENTER, 3 ; third vertex A ; push on the vstack B, x[<->] ; Exchange the bottom two values on the vstack B, ENTER ; Duplicate the entry on the bottom of the vstack B, R[v] ; Roll the vstack down B, x[<->] ; Exchange the bottom two values on the vstack C, R[v] ; Roll the vstack up B, - ; Vector subtract B, R[v] ; Roll the vstack down B, - ; Vector subtract C, R[v] ; Roll the vstack up B, [times] ; Vector cross product B, EEX ; Compute the magnitude 2 ; Going to divide by 2 / / Now we have the area

*/ LBL'VTL' STOP /* wait for input and a hotkey */ GTO'VTL' /* just loop if the person hits R/S */

/* Push a vector from the RPN stack to the Vstack. */ LBL A LocR 008 /* local register to save stack */ STOS .00 /* save stack */ . /* move the vstack up to make room at the bottom */ 2 1 0 0 3 R-COPY RCLS .00 /* restore the stack */ STO 00 /* copy Z from XYZT stack to vstack */ R[v] STO 01 /* copy Y from XYZT stack to vstack */ R[v] STO 02 /* copy X from XYZT stack to vstack */ R[^] /* restore the stack */ R[^] RTN

/* Prefix to executing a B-shiftted vector command on the Vstack */ LBL B LocR 009 /* a local register to get the keyboard input */ STOS .00 /* save the stack */ CL[alpha] /* clear out the alpha register for our message */ "V-V Op?" /* input prompt */ B1:: VIEW[alpha] /* display the input prompt */ PSE 99 /* pause as long as we can */ KEY? .08 /* if a key was hit, stuff it in a local register */ JMP B1 /* if no key was hit, wait some more */

# 75 /* "+" - vector addition */ x=? .08 GTO 10 # 65 /* "-" - vector subraction */ x=? .08 GTO 11 # 55 /* "x" - cross product */ x=? .08 GTO 12 # 73 /* "." - dot product */ x=? .08 GTO 13 # 34 /* "EEX" - Magnitude */ x=? .08 GTO 14 # 31 /* "ENTER" - DUP */ x=? .08 GTO 15 # 23 /* "R[v]" - R-DWN */ x=? .08 GTO 16 # 32 /* "x[<>y]" - EXCH */ x=? .08 GTO 17

RCLS .00 /* restore stack before returning */ RTN

/* Prefix to executing a C-shiftted vector command on the Vstack */ LBL C LocR 009 /* a local register to get the keyboard input */ STOS .00 /* save the stack */ CL[alpha] /* clear out the alpha register for our message */ "V-S Op?" /* input prompt */ C1:: VIEW[alpha] /* display the input prompt */ PSE 99 /* pause as long as we can */ KEY? .08 /* if a key was hit, stuff it in a local register */ JMP C1 /* if no key was hit, wait some more */

# 55 /* "x" - scalar multiply */ x=? .08 GTO 40 # 45 /* "/" - scalar divide */ x=? .08 GTO 41 # 23 /* "R[v]" - R-DWN */ x=? .08 GTO 42

RCLS .00 /* restore stack before returning */ RTN /* Push triplet from the vstack onto the RPN stack. Pops it off the vstack. */ LBL D RCL 02 /* copy the values onto the XYZT */ RCL 01 RCL 00 XEQ 01 /* drop the vstack */ RTN

/* Vector add operation - invoked by "B +". Pops the two arguments from the vstack and replaces them with the result of the addition. Preserves the regular XYZT stack. */ LBL 10 /* called by the shift key to restore stack first */ RCLS .00 LBL 30 /* public subroutine to do a vector + on the vstack */ LocR 008 /* local register to save stack */ STOS .00 /* save stack */ RCL 00 /* add the bottom of the vstack to the entry above it */ STO+ 03 RCL 01 STO+ 04 RCL 02 STO+ 05 XEQ 01 /* drop the vstack */ RCLS .00 /* restore the stack */ RTN

/* Vector subtract operation - invoked by "B -". Pops the two arguments from the vstack and replaces them with the result of the subtraction. Preserves the regular XYZT stack. */ LBL 11 /* called by the shift key to restore stack first */ RCLS .00 LBL 31 /* public subroutine to do a vector - on the vstack */ LocR 008 /* local register to save stack */ STOS .00 /* save stack */ RCL 00 /* subtract the bottom of the vstack from the entry above */ STO- 03 RCL 01 STO- 04 RCL 02 STO- 05 XEQ 01 /* drop the vstack */ RCLS .00 /* restore the stack */ RTN

/* Vector multiply operation - invoked by "B x". Pops the two arguments from the vstack and replaces them with the result of the cross product. Preserves the regular XYZT stack. */ LBL 12 /* called by the shift key to restore stack first */ RCLS .00 LBL 32 /* public subroutine to do a cross product on the vstack */ LocR 010 /* local register to save stack and working space*/ STOS .00 /* save stack */ RCL 02 /* z - Ax*By - Bx* Ay */ RCL[times] 04 RCL 05 RCL[times] 01 - STO .08 /* store in temp register (if stack is only 4) */ RCL 00 /* y = Az*Bx - Bz*Ax */ RCL[times] 05 RCL 03 RCL[times] 02 - STO .09 /* store in temp register */ RCL 01 /* x = Ay*Bz - By*Az */ RCL[times] 03 RCL 04 RCL[times] 00 - STO 05 /* store the resulting x in the vstack */ RCL .09 /* store the resulting y in the vstack */ STO 04 RCL .08 /* store the resulting z in the vstack */ STO 03 XEQ 01 /* drop the vstack */ RCLS .00 /* restore the stack */ RTN

/* Dot product operation - invoked by "B .". Pops the two arguments from the vstack and pushes the result of the dot product on the XYZT stack. */ LBL 13 /* called by the shift key to restore stack first */ RCLS .00 LBL 33 /* public subroutine to do a dot product on the vstack */ LocR 008 /* local register to save stack */ STOS .00 /* save stack */ RCL 00 /* do the dot product */ RCL 03 [times] RCL 01 RCL 04 [times] + RCL 02 RCL 05 [times] + STO 00 /* temporarily store in vstack */ RCLS .00 /* restore the stack */ RCL 00 /* push the dot product on the stack */ XEQ 01 /* drop the vstack two entries */ XEQ 01 RTN

/* Magnitude - invoked by "B EEX". Takes the magnitude of the value at the bottom of the vstack and pushes the result on the XYZT stack. Leaves the vstack unmodified. */ LBL 14 /* called by the shift key to restore stack first */ RCLS .00 LBL 34 /* public subroutine to calc vector magnitude */ LocR 009 /* local register to save stack */ STOS .00 /* save stack */

RCL 00 x[^2] RCL 01 x[^2] + RCL 02 x[^2] + SQRT STO .08 /* store in temp while restoring stack */ RCLS .00 /* restore the stack */ RCL .08 /* push the dot magnitude on the stack */ RTN

/* Dup the triplet at the bottom of the vstack [Enter] */ LBL 15 /* called by the shift key to restore stack first */ RCLS .00 LBL 35 /* public subroutine to DUP bottom of vstack */ LocR 008 /* local register to save stack */ STOS .00 /* save stack */ XEQ D /* pop the bottom of the vstack */ XEQ A /* push it back on twice */ XEQ A RCLS .00 /* restore stack */ RTN

/* Rotate the VStack down one triplet */ LBL 16 /* called by the shift key to restore stack first */ RCLS .00 LBL 36 LocR 008 /* local registers to save stack */ STOS .00 /* save stack */ RCL 00 /* copy the values that will rotate */ RCL 01 RCL 02 XEQ 01 /* drop the stack */ STO 23 /* move the bottom to the top */ R[v] STO 22 R[v] STO 21 RCLS .00 /* restore the XYZT stack */ RTN

/* Exchange the triplets at the bottom of the vstack [x[<->y] */ LBL 17 /* called by the shift key to restore stack first */ RCLS .00 LBL 37 LocR 008 /* local register to save stack and working space*/ STOS .00 /* save stack */ . 0 3 0 0 3 R-SWAP RCLS .00 /* restore the XYZT stack */ RTN

/* Vector by scalar multiply. */ LBL 40 /* called by the shift key to restore stack first */ RCLS .00 LBL 60 LocR 008 /* local register to save stack and working space*/ STO[times] 00 STO[times] 01 STO[times] 02 RTN

/* Vector by scalar divide. */ LBL 41 /* called by the shift key to restore stack first */ RCLS .00 LBL 61 LocR 008 /* local register to save stack and working space*/ STO/ 00 STO/ 01 STO/ 02 RTN

/* Rotate the VStack up one triplet */ LBL 42 /* called by the shift key to restore stack first */ RCLS .00 LBL 62 LocR 008 /* local registers to save stack */ STOS .00 /* save stack */ RCL 21 /* copy the values that will rotate */ RCL 22 RCL 23 . /* move the vstack up to make room at the bottom */ 2 1 0 0 3 R-COPY DROP STO 02 DROP STO 01 DROP STO 00 RCLS .00 /* restore the XYZT stack */ RTN

/* Drop the vstack by one entry (i.e. one triplet). Preserves XYZT stack completely. */ LBL 01 LocR 008 /* local register to save stack */ STOS .00 /* save stack */ 3 /* copy the vstack contents down one entry */ . 2 1 R-COPY RCLS .00 /* restore stack */ RTN

END

Edited: 4 Sept 2013, 4:30 p.m.

      
Re: WP-34S: Program for vector (3D) manipulation
Message #2 Posted by Marcus von Cube, Germany on 4 Sept 2013, 5:01 p.m.,
in response to message #1 by Marcel Samek

Thanks for the program which shows again that WP 34S is a different beast concerning keystroke programming. The sequence that interprets the shifted keyboard can be simplified by using indirect addressing. Look at the Matrix editor "MED" for an example.

Code fragment:

; Jump to label if it is defined
ignore::
        LBL?[->].08
        GTO[->].08
        JMP ignore
            
Re: WP-34S: Program for vector (3D) manipulation
Message #3 Posted by Marcel Samek on 4 Sept 2013, 5:25 p.m.,
in response to message #2 by Marcus von Cube, Germany

Thanks for the suggestion. I had actually started out using the indirect addressing exactly as you suggest. Then, however, I started playing around with using the same key for different functions (e.g. scalar multiply vs. cross product) and ending up moving away from it so that I could have different functions for different functionality instead of having conditionals buried in the functions that shared keycodes. In reality, there are only two keys that are overloaded that way and you are right, I would save a boatload of steps (especially if I add more functions) if I used the approach you suggest.

The rest of the program is a bit heavy right now too. It allocates 8 local registers to save the stack on every subroutine, but it should really check the stack size and only allocate as many as it needs to.

Also, I should change the vstack size to be configurable instead of hardwiring it to be 8.

And, I am sure that many of the actual vector operations could be coded much more efficiently but that was not really my intial focus. Right now I am much more focused on usability and now that I have been using it for a while, I have already made a number of usability changes in terms of which operations popped their operands off the vstack and which didn't etc. I'm hoping to get more input.

It is a different pattern for a calculator program and in the short time I have worked on it I have gotten quite fond of it.

                  
Re: WP-34S: Program for vector (3D) manipulation
Message #4 Posted by Paul Dale on 4 Sept 2013, 6:02 p.m.,
in response to message #3 by Marcel Samek

The assembler doesn't support it, but labels can be multiply defined in programs.

Thus,

        LBL B
        ...
        LBL?[->].08
        GTO[->].08
        JMP ignore

labels for B

LBL C ... LBL?[->].08 GTO[->].08 JMP ignore

labels for C

The assembler can deal with duplicate labels in separate programs so using END and global labels will also work but will require a tiny amount of duplication of the hot key code in each program (LBL B GTO'V3B' e.g.)

- Pauli

                  
Re: WP-34S: Program for vector (3D) manipulation
Message #5 Posted by Marcus von Cube, Germany on 5 Sept 2013, 5:29 a.m.,
in response to message #3 by Marcel Samek

Adding to Pauli's suggestion: If the key codes used for labels are far enough apart, just add INC .08 in the case of prefix C and use two consecutive label numbers for the functions.


[ Return to Index | Top of Index ]

Go back to the main exhibit hall