WP-34S: Program for vector (3D) manipulation



#2

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.


#3

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

#4

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.


#5

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

#6

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.


Possibly Related Threads…
Thread Author Replies Views Last Post
  [WP-34S] Unfortunate key damage with update to V3 :( svisvanatha 5 3,255 12-10-2013, 11:37 PM
Last Post: Les Bell
  WP-34S (Emulator Program Load/Save) Barry Mead 1 1,833 12-09-2013, 05:29 PM
Last Post: Marcus von Cube, Germany
  DIY HP 30b WP 34s serial flash/programming cable Richard Wahl 2 2,572 12-04-2013, 11:14 AM
Last Post: Barry Mead
  HP Prime: adding an entry to a vector Alberto Candel 12 4,084 12-02-2013, 01:18 PM
Last Post: Alberto Candel
  HP Prime - vector question bluesun08 3 1,834 11-18-2013, 07:26 PM
Last Post: Han
  HP Prime: run a program in another program Davi Ribeiro de Oliveira 6 2,738 11-11-2013, 08:28 PM
Last Post: Davi Ribeiro de Oliveira
  3D graphing planned for HP Prime Mic 5 2,097 11-11-2013, 10:17 AM
Last Post: Tim Wessman
  WP 34S/43 ?'s Richard Berler 3 2,099 11-10-2013, 02:27 AM
Last Post: Walter B
  My FrankenCulator (wp-34s) FORTIN Pascal 4 2,225 11-09-2013, 06:18 PM
Last Post: FORTIN Pascal
  WP 34S Owner's Handbook Walter B 5 2,723 11-09-2013, 05:34 PM
Last Post: Harald

Forum Jump: