Monday, November 12, 2007

Fixing the HP-41CV - IV : More HP calculator stuff from the past recovered

After got back the HP-41CV in as good as new condition I got motivated to dig into the old stuff stored away at my parents place to see what else could be found from the good old days. After this time's digging my HP inventory (not counting the 35s) is:

Machines

One working HP-41CV (thanks to FixThatCalc).

One not working HP-29C (details at the end of this blog entry) with manuals (in Swedish).

HP-41 manuals

Instruktionsbok Och Programmeringshandledning - The instruction and programming manual in Swedish! Apperently they did not bother to do a translation to Norwegian!

Hur man använder kalkulatorer från HP - Small booklet explaining the RPN paradigm, also in sweedish.

HP-41C Standard Applications

HP-41 accessories

Modules:
  • Math I, with manual, quick reference card and keyboard overlays.
  • X Functions, manual missing.
  • Games, with manual and keyboard overlays.
A card reader (with (in swedish ofcourse!) manual) that propably is not working that great anymore (details at the end of this blog entry).

Miscellaneous

A module holder with my two missing port 'protectors' :-)

Keyboard layovers for the modules AND two blank ones and one unidentified one!

Comments

I know I got magnetic cards laying around somewhere so I would be interesting in using the card reader. Actual found some cards that I remembered put aside because damaged. However, still the way reader behaved on them may suggest it is suffering from old age (that and the fact they usual do). The good news (yep been chating with FixThatCalc) is that it can fixed, may very well soon be another package on it's way...

The 29C sadly is not for any practical reasons repairable I have been assured. It look brand new (did not have a long and active life), it may have a future as spare parts!

It bugs me that manual for the X functions is missing. I never got much time to play around with those and there is some I would like to utilize in my nowadays programming. Well, it may still turn up and anyway eventual I am going to get the museum's dvd set which includes the manual.

Saturday, November 10, 2007

Fixing the HP-41CV - III : An old machine reports for duty again!

Got it (HP-41CV serial nr. 2103A07854) back from FixThatCalc!

Belive they did a great job, seems to be working just fine AND they do a fantastic job cleaning the machines: Can not remember it have looked this good. Sure it must have when I got it, but that is 26 years ago!

There is a note returned with the machine telling me I should not put it back in it's pouch since it has started to deteriorate and it may harm the calculator. It has the undertone of a caring mother telling children to take good care of their fine toys... I belive we who cares for these devices are very lucky that FixThatCalc exists!

Thursday, November 8, 2007

Got my hands on a HP-48GX

A co-worker discovered my interest for HP calculators and remembered he had some kind of graphing calculator while at engineering shool. Belived it was some kind of a TI model. Turned out he had a HP-48GX collecting dust home!

To cut a short story shorter, he has kindly borrowed me the machine. Later this year I will get my self a HP-50g and this will allow me to learn the RPL language up front!

I may do a RPL port of the HP-35s Euclid Pack implementation...

Resources related to getting to know the RPL series of machines:

Manuals downloadable from Educalc.net here.
HP 48G Series Advanced User's Reference Manual available here at hpcalc.org.
Short but good introduction to RPL at the museum.
UserRPL stack commands, article at the museum.
The usenet group ofcourse.
FAQs found at the Internet FAQ Archieves.

Tuesday, November 6, 2007

A HP-35s hacker

Stefan is a HP calculator enthusiast that got himself a HP-35s and have a done a man's work providing two (so fare) rather lengthy programs for Curve Fitting and Matrix Operations on the HP-35s.

Mind you, as this thread (about Stefan's matrix program) at the MoHPC forum shows: If you need to do serious matrix work, clearly you should consider a RPL machine.

By the way, do check out Stefan web content, he is an inspiration to any kind of web author and also he turns out to be a norgesvenn!

Monday, October 22, 2007

A programmer's HP-35s review

Some thoughts on the HP-35s after been programming it for a while: Doing the HP-35s Euclid Pack implementation.

Two features I learned to love when programming the 35s: Vector type and equations.

Vector type

The vector type has been critizised for missing key features:
  1. No cross product. Must make a program.
  2. No native way to unpack or address vector components. Must use 'dot product mask vectors'.
  3. No operation to tell a vector's dimension (dim or size).
Despite these drawbacks (of which the two first can be worked around), I find the vector type a very valuable feature because of it's data packing capabilities.

Some focus has been on using 3D vectors to augment the machine's 800 indirect registers. For the things I do and the fact that it is a closed system (no I/O), I can't imagine applications using a large fraction of the 800 registers even without packing 3 real numbers in one register!

But, I find the data packing offered by 3D vectors to be very valuable in the 'more valuable real estate territories' of near end user variable registers (A-Z) and working registers (stack and lastx).

For example, for the design of the euclid pack project I ended up with wanting to store definition of two lines (four 2D or 3D points), two planes (two 3D points and two normal vectors) and one triangle (three 3D points) in variables.

If all data entered is in 3D, that would require minimum use 33 registers! And this is data I would like to be close to the end user, so I would like to use variables: Unless had vector type would not have room. Since have the vector type minimum register use is 11.

And implementation actual ended up storing additional data in variables to make certain computations easy and results handy. And I still did not use up all variable registers...

Also now we can have 12 real numbers on the stack! That becomes usefull when using programs that take more than 4 numbers as input. For example to define a 3D triangle (the T program) end user must give in nine numbers (three 3D numbers), without the ability to just put the points on the stack and run the program, the program would had to prompt for the data.

Also the vector type, RPN paradigm and the use of equation is very powerfull when programming:

Equations in programs

I find programming complex calculations in need of much intermediate results to be easy on the 35s by combining the RPN paradigm, vector type and equations:
  • The vector type allows 12 values to be stored on the stack.
  • Equations in programs can use all these number while being evaluated, only when done is maximum three numbers lost on the stack: A 3D vector in the T stack register.
  • The result of evaluating an equation may very well be a 3D vector: A single line in a program may execute three equation which result raises the stack only once.
I think second half of the last program (lines 28 to 35) I made in this series realy utilize this programming style, there is eight lines of equations in sequence!

A very nice feature of the HP 35s that helps programming this way is that when in programming mode and to insert a stack register as a variable in an equation using the RDN key one sees the content of the registers user side. If one has a worked example of the problem being programmed and is programming equation by equation and running the program before programming a new equation then when programming the equation it is easy to see where on the stack needed numbers are.

One drawback of this style of programming is that the evaluation of equation makes for much slower execution then a pure RPN version. For programs that intention is to be called a large (or small...) number of times as subroutines by other programs this style of programming may not be appropiate.

On an improved HP 35s (HP 35s+ :-) perhaps one could have some kind of equation compilation?

No need for me to get into any of the now well known short commings or bugs of the device documented by the community of the MoHPC here, except to say that the reported vector syntax bug is indeed real on some machines and makes this type of programming much harder than needed. I know, I got one... Still I have been able to do whatever I did without ever needing to reset the thing.

Sunday, October 21, 2007

HP-35s Euclid Implementation - XV : The inscribed and circumscribed circle of a triangle

The final program to fullfill the requirements! Problem 16 and 17: Finding the inscribed (incircle) and circumscribed (circumcircle) circles of a triangle.

Finding the inscribed circle is the same as solving the problem of finding the circle tangent to three lines (lines defined by the triangle edges) and finding the circumscribed circle is the same as solving the problem of finding the circle that passes through three points (triangle's vertexes).

The triangle in question has been entered using the T program.

v3
/ \
/ \
/ \
v1------v2
Refering to the above triangle I give the formulas used in the HP-35s program presented here:

Inscribed circle:

The barycentric coordinates for the incenter are:
(l1/p, l2/p, l3/p)
Where p is the perimeter of the triangle (sum of all edges lengths) and l1 is the length of the edge v3-v2, l2 is the length of the edge v1-v3 and l3 is the length of the edge v2-v1.

The radius of the inscribed circle is:
(2A)/p
Where A is the area of the triangle.

Circumscribed circle:

With the intermediate results
d1=-e2*e3
d2=-e3*e1
d3=-e1*e2

(e1=v3-v2, e2=v1-v3, e3=v2-v1, * is the dot product)

c1=d2d3
c2=d3d1
c3=d1d2

c=c1+c2+c3
the barycentric coordinates for the circumcenter are:
((c2+c3)/2c, (c3+c1)/2c, (c1+c2)/2c)
The radius of the circumscribed circle is:
sqrt((d1+d2)(d2+d3)(d3+d1)/c)/2
These formulas are taken from the excelent book 3D Math Primer for Graphics and Game Development that also provide background for much of the geometric problems in the Euclid Pack specification.

Stack Input/Output:
No input on stack-> XEQ O ->[[bc1, bc2, bc3], cr, [bi1, bi2, bi3], ir | L]
Where (bc1, bc2, bc3) are the barycentric coordinates for the circumscribed circle's center (circumcenter) , cr is its radius, (bi1, bi2, bi3) are the barycentric coordinates for the inscribed circle's center (incenter) and ir is its radius.

Variables:

Reads:
K : First vertex (3D vector). Populated by the T program.
L : Second vertex (3D vector). Populated by the T program.
M : Third vertex (3D vector). Populated by the T program.
Writes:
Z : Scratch data.
Program:
O001 LBL O
O002 5
O003 STO I
O004 STO(I)
O005 4
O006 STO I
O007 LASTX
O008 STO(I)
O009 eq M-L
0O10 eq M-K
O011 eq [ABS(REGY),ABS(REGX),ABS(L-K)]
O012 STO Z
O013 eq REGX/([1,0,0]xREGX+[0,1,0]xREGX+[0,0,1]xREGX)
O014 R^
O015 R^
O016 XEQ X001
O017 R^
O018 X<>Y
O019 ABS
O020 eq REGX/([1,0,0]xZ+[0,1,0]xZ+[0,0,1]xZ)
O021 X<>Y
O022 RDN
O023 X<>Y
O024 RCL(I)
O025 ABS
O026 RDN
O027 XEQ U001
O028 eq M-L
O029 eq K-M
O030 eq L-K
O031 eq [-REGYxREGX,-REGXxREGZ,-REGZxREGY]
O032 eq [([0,1,0]xREGX)x([0,1,0]xREGX),
([0,0,1]xREGX)x([1,0,0]xREGX),
([1,0,0]xREGX)x([0,1,0]xREGX)]
O033 eq [1,0,0]xREGX+[0,1,0]xREGX+[0,0,1]xREGX
O034 eq 0.5xSQRT((([1,0,0]xREGZ+[0,1,0]xREGZ)x
([0,1,0]xREGZ+[0,0,1]xREGZ)x
([0,0,1]xREGZ+[1,0,0]xREGZ))/REGX)
O035 eq [([0,1,0]xREGZ)+([0,0,1]xREGZ),
([0,0,1]xREGZ)+([1,0,0]xREGZ),
([1,0,0]xREGZ)+([0,1,0]xREGZ)]/(2xREGY)
O036 XEQ U079
O037 RTN
Comments:

Terms of use.

Mnemonics: O since letter is a circle (or more or less depeding on font, rather circular on the 35s).

Reason for not converting to cartesian coordinates is that since the barycentric coordinates are relative to the vertices it is much easier to 'see' where the center points are relative to the triangle. If one where to be presented the cartesian coordinates one must remember the nine vertex coordinates to know where (relative to triangle) the center points are. Particular one see at once if the circumscribed circle's center is inside or outside the triangle.

Cartesian coordinates are easily obtained using the A program by the following key sequence:
XEQ A
RDN
RDN
XEQ A
RDN
RDN
The last two RDN are only provided to get content of stack in same order as before except that barycentric positional vectors are now replaced with cartesian ones.

Thursday, October 18, 2007

HP-35s Euclid Implementation - XIV : Barycentric to Cartesian coordinates

Going from barycentric to cartesian coordinates (problem 15 in the requirements) is the easy part of Cartesian<->Barycentric 2D/3D conversion, this will be a much shorter blog entry than this one!

Stack Input/Output:
3D case: [[b1, b2, b3], Y, Z, T | L]-> XEQ A ->[[x, y, z], Y, Z, T | [b1, b2, b3]]

2D case: [[b1, b2, b3], Y, Z, T | L]-> XEQ A ->[[x, y], Y, Z, T | [b1, b2, b3]]
Variables:

Reads:
K : First vertex (3D vector), in 3D case. Populated by the T program.
L : Second vertex (3D vector), in 3D case. Populated by the T program.
M : Third vertex (3D vector), in 3D case. Populated by the T program.
U : First vertex of triangle projected to 2D (2D vector), in 2D case. Populated by the T program.
V : Second vertex of triangle projected to 2D (2D vector), in 2D case. Populated by the T program.
W : Third vertex of triangle projected to 2D (2D vector), in 2D case. Populated by the T program.
Program:
A001 LBL A
A002 ABS
A003 RDN
A004 FS? 2
A005 GTO A008
A006 eq Kx([1,0,0]xLASTX)+Lx([0,1,0]xLASTX)+Mx([0,0,1]xLASTX)
A007 RTN
A008 eq Ux([1,0,0]xLASTX)+Vx([0,1,0]xLASTX)+Wx([0,0,1]xLASTX)
A009 RTN
Comments:

Terms of use.

Mnemonics: None realy, but letter is left to B, the program label for Barycentric to Cartesian conversion.

If we are working in 2D (flag 2 set) we are applying the weights (barycentric coordinates) to the 2D coordinate's of the projected triangle (line A008) else applying the weights to the vertexes 3D coordinates (line A006).

Wednesday, October 17, 2007

Fixing the HP-41CV - II : Sending it

Finaly got around to post the HP-41CV to Fix That Calc!

Monday, October 15, 2007

HP-35s Euclid Implementation - XIII : Cartesian to Barycentric coordinates

Arrived at problem 14 of the requirements: Computing barycentric coordinates given cartesian coordinates.

Barycentric coordinates [b1, b2, b3] of a point in a plane are coordinates defined by a triangle in the plane (defines the plane) where the triangle's first vertex's barycentric coordinates are [1,0,0], second vertex's are [0,1,0], third vertex's are [0,0,1] and one have that b1+b2+b3=1.

Coordinates of any point in the plane can be expressed as the weighted average of the triangle's vertices coordinates, these weights are the barycentric coordinates:
 Barycentric     Cartesian
(b1, b2, b3)<=>b1v1+b2v2+b3v3
Where vi is the positional vector for vertex i.

Barycentric coordinates has several uses and are of theoretical importance outside the scope of this blog entry. Here I give two practical uses:
  1. Provides a robust test for if a point in triangle's plane with barycentric coordinates [b1, b2, b3] is inside the triangle, on one of the triangle's edge or outside the triangle: If all components are in the range[0,1] point is inside, if bi is 0 and the two others are in the [0,1] range then the point is on the edge oposite of triangle's vertice i, and finaly if at least one component is not in the [0,1] range then point is outside triangle.
  2. If a function's values is known at the triangle's vertices one can perform linear interpolation inside the triangle at the point: v1*b1+v2*b2+v3*b3. Where vi is the value at vertex i and [b1, b2, b3] is the barycentric coordinates for point to evaluate at. Note that converting from barycentric coordinates to cartesian coordinates is a special case of this.
I choose to convert from cartesian coordinates to barycentric by programming the solution to the equations for the 2D cartesian to barycentric coordinates case:
Q=(y1-y3)*(x2-x3)+(y2-y3)*(x2-x1)

b1=((y-y3)*(x2-x3)+(y2-y3)*(x3-x))/Q
b2=((y-y1)*(x3-x1)+(y3-y1)*(x1-x))/Q
b3=((y-y2)*(x1-x2)+(y1-y2)*(x2-x))/Q
Where (xi, yi) are cartesian coordinates for triangle's i'th vertex and (x, y) is the cartesian coordinates of the point in question. This is the solution to the equation set of three uknown (b1, b2, b3):
x=b1*x1+b2*x2+b3*x3
y=b1*y1+b2*y2+b3*y3
1=b1+b2+b3
To solve 3D cartesian to barycentric I project the triangle and point in question to 2D and solve as a 2D problem.

Implementation is done in two steps:
  1. Modify the T program so it: A) Also accept a 2D triangle (flag 2 set='2D mode'. B) Project the triangle to the cardinal plane that gives the largest area, this is the triangle used for computing barycentric coordinates. C) Computes the quotient Q in the above equations.
  2. Implement a program labeled B to accepts a 2D or 3D cartesian tuple and use result from B and C above to compute barycentric coordinates.
Step 1 : The modified T program

Stack Input/Output:
2D case: [[x2, y2], [x1, y1], [x0, y0] | L]->XEQ T->[[nx, ny, nz], [x2, y2], [x1, y1], [x0, y0] | L]

3D case: [[x2, y2, z2], [x1, y1, z1], [x0, y0, z0] | L]->XEQ T->[[nx, ny, nz], [x2, y2, z2], [x1, y1, z1], [x0, y0, z0] | L]
Where v0=(x0, y0, z0) is first, v1=(x1, y1, z1) is second, v2=(x2, y2, z2) is the third triangle vertex and [nx, ny, nz] is the cross product (v1-v0)x(v2-v0).

Variables:

Writes:
K : First vertex (3D vector).
L : Second vertex (3D vector).
M : Third vertex (3D vector).
Q : Quotient (y1-y3)*(x2-x3)+(y2-y3)*(x2-x1).
U : First vertex of triangle projected to 2D (2D vector).
V : Second vertex of triangle projected to 2D (2D vector).
W : Third vertex of triangle projected to 2D (2D vector).
X : Index of coordinate discarded in 3D->2D projection.
Program:
T001 LBL T
T002 XEQ U001
T003 FS? 2
T004 XEQ X068
T005 STO M
T006 RDN
T007 FS? 2
T008 XEQ X068
T009 STO L
T010 RDN
T011 FS? 2
T012 XEQ X068
T013 STO K
T014 R^
T015 X<>Y
T016 -
T017 RDN
T018 RDN
T019 LASTX
T020 -
T021 X<>Y
T022 RDN
T023 XEQ X001
T024 ABS
T025 1E-6
T026 X>Y?
T027 GTO T065
T028 LASTX
T029 XEQ X025
T030 STO X
T031 RCL K
T032 X<>Y
T033 XEQ X052
T034 STO U
T035 RDN
T036 RCL L
T037 X<>Y
T038 XEQ X052
T039 STO V
T040 RDN
T041 RCL M
T042 X<>Y
T043 XEQ X052
T044 STO W
T045 eq ([0,1]xU-[0,1]xW)x([1,0]xV-[1,0]xW)+
([0,1]xV-[0,1]xW)x([1,0]xW-[1,0]xU)
T046 STO Q
T047 LASTX
T048 4
T049 STO I
T050 RDN
T051 RCL(I)
T052 ABS
TO53 RDN
T054 FS? 2
T055 GTO T060
T056 RCL K
T057 RCL L
T058 RCL M
T059 GTO T063
T060 RCL U
T061 RCL V
T062 RCL W
T063 R^
T064 RTN
T065 SF 10
T066 eq DEGENERATED
T067 PSE
T068 CF 10
T069 XEQ U029
T070 RTN
Comments:

Terms of use.

Mnemonics: T for Triangle.

Uses the X068 subroutine to place 2D triangle in th XZ plane if flag 2 set and the X025 routine to find out which coordinate to discard for the 3D to 2D projection and finaly the X052 routine to actual do the 3D to 2D conversion. In the 2D case this is a rather roundabout way to get end user's input into the variables U, V and W! But I think this worked out quite well in order to have one program for both the 2D and 3D case:

One can compute barycentric coordinates in 3D using four cross product, four dot product and three scalar division operations avoiding projection from 3D to 2D, but involves more scalar math operations than the implemented method. On a vector architecture it may be a better choice, on the HP-35s architecture I think this is a good solution!

The index of the coordinate discarded to do the 3D to 2D projection is remembered in variabe X so the next program to actual compute barycentric coordinates know which coordinate to discard from input.

An unrelated change done to the T program is that it now check if the computed plane normal vector is considered to be of zero length: Then all points are the same or colinear, the message "DEGENERATED" is then shortly displayed and stack registers restored.

Note that one get a cross product calculated normal vector also in the 2D case (direction
[0, 1, 0]), length still twice triangle's area.

Step 2 : Program to convert from Cartesian to Barycentric Coordinates

Stack Input/Output:
[[x, y, z], Y, Z, T | L]->XEQ B->[[b1, b2, b3], Y, Z, T | [x, y, z]]
Where (x, y, z) are cartesian coordinates for point in question and (b1, b2, b3) are computed barycentric coordinates.

Variables:

Reads:
Q : Quotient (y1-y3)*(x2-x3)+(y2-y3)*(x2-x1). Populated by the P program.
U : First vertex of triangle projected to 2D (2D vector). Populated by the P program.
V : Second vertex of triangle projected to 2D (2D vector). Populated by the P program.
W : Third vertex of triangle projected to 2D (2D vector). Populated by the P program.
X : Index of coordinate discarded in 3D->2D projection. Populated by the P program.
Program:
B001 LBL B
B002 XEQ U001
B003 FS? 2
B004 GTO B007
B005 RCL X
B006 XEQ X052
B007 eq [([0,1]xREGX-[0,1]xW)x([1,0]xV-[1,0]xW)+
([0,1]xV-[0,1]xW)x([1,0]xW-[1,0]xREGX),

([0,1]xREGX-[0,1]xU)x([1,0]xW-[1,0]xU)+
([0,1]xW-[0,1]xU)x([1,0]xU-[1,0]xREGX),

([0,1]xREGX-[0,1]xV)x([1,0]xU-[1,0]xV)+
([0,1]xU-[0,1]xV)x([1,0]xV-[1,0]xREGX)]/Q
B008 XEQ U050
B009 RTN
Comments:

Terms of use.

Mnemonics: B for Barycentric.

If the input is a 2D (flag 2 set) then goes straight to the equation that calculates baycentric coordinates using the data precomputed by the modified T program, else first project the 3D input to 2D using subroutine X052 and information found in the X variable.

HP-35s 2D to 3D vector conversion

Short program to convert a 2D vector to a 3D by placing it in the z=0 plane. Usefull when want to utilize 3D solutions to 2D data, for example taking cross product of two 2D vectors.

Stack Input/Output:
[[u, v], Y, Z, T | L]-> XEQ 068 ->[[u, v, 0], Y, Z, T | [u, v]]
Program:
X068 ABS
X069 RDN
X070 eq [[1,0]xLASTX,[0,1]xLASTX,0]
X071 RTN
Comments:

Terms of use.

Placed in the X 'library' since a vector utlity, from before have projecting to a cardinal plane, finding the component of a 3D vector with max absolute value, vector unpack routines, cross product and normalization.

Sunday, October 14, 2007

HP-35s 3D to 2D projection utility subroutines - II

Subroutine to project a 3D vector to 2D by paralell projection to one of the cardinal planes; discards one coordinate.

Stack Input/Output
[n, [u,v,w], Z, T | L]-> X047 ->[[x,y], n, [u,v,w], Z | L]
Where n tells which coordinate to discard: [x=v, y=w] if n=1, [x=u, y=w] if n=2 and [x=u, y=v] if n=3.

Program:
X052 1
X053 X=Y?
X054 GTO X062
X055 RDN
X056 2
X057 X=Y?
X058 GTO X065
X059 RDN
X060 eq [[1,0,0]xREGY,[0,1,0]xREGY]
X061 RTN
X062 RDN
X063 eq [[0,1,0]xREGY,[0,0,1]xREGY]
X064 RTN
X065 RDN
X066 eq [[1,0,0]xREGY,[0,0,0]xREGY]
X067 RTN
Comments:

Terms of use.

The parameter n is typical found using the X025 subroutine.

Placed in the X 'library' since a vector utlity, from before have finding the component of a 3D vector with max absolute value, vector unpack routines, cross product and normalization.

Change history:

20071014:1723UTC : Because of change in the X025 subroutine line numbers changed here. Entry point used to be X047 but is now X052.

Friday, October 12, 2007

HP-35s 3D to 2D projection utility subroutines - I

Utility 3D vector subroutine to tell which component that has the largest absolute value.

This is of use when projecting points in an arbitary plane to one of the three cardinal planes in order to reduce a 3D problem to a 2D problem (when possible). Use this subroutine on the arbitary plane's normal vector in order to decide which 3D coordinate to discard in order to avoid all points to be projected on a line if arbitary plane is perpendicular to the choosen cardinal plane or to avoid floating precision problems in case they are nearly perpendicular:

Examine the arbitary plane's normal vector (using this subroutine) and discard the coordinate that has the maximum absolute value.

Stack Input/Output:
[[u, v, w], Y, Z, T | L]-> XEQ X025 ->[n, -, -, - | [u, v, w]]
Where [u, v, w] is the vector in question and n is 1 if u has largest absolute value, 2 if v has and 3 if w has.

Program:
X025 XEQ X008
X026 LASTX
X027 RDN
X028 ABS
X029 RDN
X030 ABS
X031 RDN
X032 ABS
X033 X<>Y
X034 ABS
X035 X<>Y
X036 R^
X037 X>=Y?
X038 GTO X047
X039 X<>Y
X040 R^
X041 X<Y?
X042 GTO X045
X043 3
X044 RTN
X045 1
X046 RTN
X047 R^
X048 X>=Y?
X049 GTO X043
X050 2
X051 RTN
Comments:

Terms of use.

Placed in the X 'library' since a vector utlity, from before have vector unpack routines, cross product and normalization.

Change history:

20071014:1723UTC : Problem that vector lost, changed so vector now can be found in LASTX register. This also effects the X047 subroutine now X052 subroutine and those using that: Entry point address changed to X052.

Thursday, October 11, 2007

HP-35s Euclid Implementation - XII : Plane Plane Intersection

The intersection between two non paralell planes is a line (problem 13 of the requirements).

The program here computes two points that defines the intersection line between the plane defined by the P program and a second plane given as input to this program.

Stack Input/Output:
[[nx, ny, nz], [px, py, pz], Z, T | L]-> XEQ V ->[[x1, y1, z1], [x0, y0, z0], [nx, ny, nz], [px, py, pz] | L]
The input of the second plane is similar to defining the first plane using the P program: [nx, ny, nz] in X stack register is a vector normal to the second plane and (px, py, pz) in Y stack register is a point in the second plane. The result in the case the planes are not paralell is two points defining the line: (x0, y0, z0) and (x1, y1, z1).

In the case the planes are paralell the message "PARALELL" is displayed shortly, stack and LASTX registers are then left unchanged.

Variables:

Writes:
R : Normalized normal vector.
S : Distance from origo (0,0,0) to plane.
T : Defining point in the plane.
Z : Scratch data.
Program:
V001 LBL V
V002 XEQ U001
V003 XEQ X004
V004 STO R
V005 X<>Y
V006 STO T
V007 X<>Y
V008 x
V009 +/-
V010 STO S
V011 RCL N
V012 LASTX
V013 XEQ X001
V014 STO Z
V015 ABS
V016 1E-6
V017 X>Y?
V018 GTO M041
V019 LASTX
V020 XEQ X025
V021 1
V022 X=Y?
V023 GTO V032
V024 RDN
V025 2
V026 X=Y?
V027 GTO V036
V028 eq (Sx([0,1,0]xN)-Ox([0,1,0]xR))/([0,0,1]xZ)
V029 eq (Ox([1,0,0]xR)-Sx([1,0,0]xN))/([0,0,1]xZ)
V030 0
V031 GTO VO39
V032 0
V033 eq (Sx([0,0,1]xN)-Ox([0,0,1]xR))/([1,0,0]xZ)
V034 eq (Ox([0,1,0]xR)-Sx([0,1,0]xN))/([1,0,0]xZ)
V035 GTO V039
V036 eq (Ox([0,0,1]xR)-Sx([0,0,1]xN))/([0,1,0]xZ)
V037 0
V038 eq (Sx([1,0,0]xN)-Ox([1,0,0]xR))/([0,1,0]xZ)
V039 eq [REGZ,REGY,REGX]
V040 ENTER
V041 ENTER
V042 RCL+ Z
V043 XEQ U079
V044 RTN
Comments:

Terms of use.

Mnemonic: None.

The program stores the normalized implicit equation for the second plane and it's defining point in the calculator the same way as the P program does for the first plane: The normalized normal vector is stored in variable R, distance to origo in variable S and defining point in variable T. Mnemonics for these are that the keys associated with these variables are below and to the left of the keys assigned to the variables N, O and P where the same values are stored for the plane defined using the program P. This makes the relation between the P program and V program similar to the relation between the L program and the M program.

This program needs to compute and store the cross product of the two plane's normal vector: If this vector is of zero length the planes are paralell else it is a directional vector for the intersection line. This vector is stored in the Z variable.

This shares the show "PARALELL" message and stack restore code with the M program in the no solution case.

Change history:

20071013:1415UTC : This program was implemented before the X025 routine that finds the component of a 3D vector with largest absolute value. This program did that inline, now gone back and modified this program to use X025.

Addition to the HP-35s stack save/restore program - III

Addition to the U program when in need to restore LASTX register and push two new values on the stack:
[X, Y, Z, T | L]-> Program invoking U001 first and U070 last ->[X', Y', X, Y | L]
Where X' is new content of X stack register present in the X stack register before U079 is executed and Y' is new content of Y stack register present in Y stack register before U079 is executed.

Of interest for programs that do not take stack register input but produces a result in the X and Y stack register.

Program:
U079 4
U080 STO I
U081 RDN
U082 RCL(I)
U083 ABS
U084 RDN
UO85 XEQ U041
U086 R^
U087 R^
U088 RTN
Comments:

Terms of use.

So now we have the subroutines:
  1. XEQ U001 to save the stack and LASTX.
  2. XEQ U029 to restore the stack and LASTX given U001 has been used to save.
  3. XEQ U050 to implement operation native unary operation stack and LASTX behaviour given U001 has been used to save.
  4. XEQ U070 to push single value on the stack and preserve LASTX given U001 has been used to save.
  5. XEQ U079 to push two values on the stack and preserve LASTX given U001 has been used to save.

Tuesday, October 9, 2007

Communicating RPN stack and LASTX register transitions, a notation

I will try using the following notation to communicate program's effect on the stack and LASTX register:
[X, Y, Z, T | L]-> opr. desc. ->[X', Y', Z', T' | L']
So for example to describe sqrt:
[X, Y, Z, T | L]-> sqrt ->[sqrt(X), Y, Z, T | X]
and addition:
[X, Y, Z, T | L]-> + ->[Y+X, Z, T, T | X]

Sunday, October 7, 2007

HP-35s 3D and 2D vector unpack subroutines

Subroutines to unpack 3D and 2D vectors when need to work on individual components.

Stack Input/Output:
3D case: [[u0, u1, u2], Y, Z, T | L]-> X008 ->[u2, u1, u0, u0 | [u0, u1, u2]]

2D case: [[u0, u1], Y, Z, T | L]-> X018 ->[u1, u0, Y, Y | [u0, u1]]
Program:
XOO8 [1,0,0]
X009 X<>Y
X010 x
X011 [0,1,0]
X012 LASTX
X013 x
X014 [0,0,1]
X015 LASTX
X016 x
X017 RTN
X018 [1,0]
X019 X<>Y
X020 x
X021 [0,1]
X022 LASTX
X023 x
X024 RTN
Comments:

Terms of use.

Uses the X label for vector utility programs/routines, from before have cross product and normalization.

Wednesday, October 3, 2007

HP-35s Euclid Implementation - XI : Line Plane Intersection

The point of intersection between a line and a plane (problem 12 in the requirements) is given by the parameter (to it's parametric equation) t=-(ax0+by0+cz0+d)/n*(p1-p0) (* is here the dot product) where p0=(x0, y0, z0) and p1 are the two points defining the line.

The following program finds the intersection between the 3D line defined using the L program (p0 stored in variable A and p1 stored in variable B) and the plane defined using the P program ([a, b, c] stored in variable N and d stored in variable O).

Stack Input/Output:
No input on stack-> XEQ R ->[t, X, Y, Z | L]
Where t is the parameter defining intersection point using line l's parametric equation.

If n*(p1-p0)=0 then the line and the plane are paralell and there is no intersection point. In that case the message "PARALELL" is displayed shortly, stack and LASTX registers are then left unchanged.

Variables:

Reads:
A : Line's first defining point. Populated by the L program.
B : Line's second defining point. Populated by the L program.
N : Plane's normalized normal vector. Populated by the P program.
O : Plane's distance to origo (0, 0, 0). Populated by the P program.
Program:
R001 LBL R
R002 XEQ U001
R003 RCL N
R004 RCL B
R005 RCL A
R006 -
ROO7 x
R008 ABS
R009 1E-6
R010 X>Y?
R011 GTO M041
R012 RDN
R013 LASTX
R014 eq -(AxN+0)/REGX
R015 XEQ U070
R016 RTN
Comments:

Terms of use.

Mnemonic: None.

Again when the result is a point on a line we produce the parameter giving the point, not the coordinates. So for example one learns that the line segment A, B intersect the plane if result is in the range [0, 1]. To get the coordinates end user does XEQ E.

Uses the new subroutine U070 to raise the stack and preserve LASTX register content in the case there is a solution (line and plane not paralell).

This shares the show "PARALELL" message and stack restore code with the M program in the no solution case.

Change history:

20071004:1835UTC : Fixed typo in line R011, was GTO M014!

Addition to the HP-35s stack save/restore program - II

Extenstion to the U program for the case when a result has been produced and should be pushed on the stack:
[X, Y, Z, T | L]->Program invoking U001 first and U070 last ->[X', X, Y, Z | L]
Where X' is new content of X stack register present in the X stack register before U070 is executed.

Of interest for programs that do not take stack register input but produces a result in the X stack register.

Program:
U070 4
U071 STO I
U072 RDN
U073 RCL(I)
U074 ABS
U075 RDN
U076 XEQ U037
U077 R^
U078 RTN
Comments:

Terms of use.

So now we have the subroutines:
  1. XEQ U001 to save the stack and LASTX.
  2. XEQ U029 to restore the stack and LASTX given U001 has been used to save.
  3. XEQ U050 to implement operation native unary operation stack and LASTX behaviour given U001 has been used to save.
  4. XEQ U070 to push single value on stack and preserve LASTX given U001 has been used to save.

Tuesday, October 2, 2007

Disclaimer

Oh, since I'am posting code I guess I should have one of these....

You are welcome to use the programs you find on this site free of charge. While I hope these programs become rather bug free and robust I make no claim that they are. I am not liable for any damages, injuries, or losses that may result in using any of these programs. By using these programs or ones that you create based on them, you agree to these terms.

HP-35s Euclid Implementation - X : Closest point on a plane to a point

The closest point on a plane to a point P is P-(P*N+d)*N where N is the plane's normalized normal vector and d is the plane's distance to origo (* is here the dot product).

Since the program P stores N in variable N and d in variable O the following short program computes the closest point on the plane entered using program P if the point's positional vector is in the X stack register (problem 11 in the requirements).

Stack Input/Output:
[[x, y, z], Y, Z, T | L]-> XEQ Q ->[[cx, cy, cz], [x, y, z], Y, Z | L]
Where (x, y, z) is point p and (cx, cy, cz) is closest point in plane to p.

Variables:

Reads:
N : Plane's normalized normal vector. Populated by the P program.
O : Plane's distance to origo (0, 0, 0). Populated by the P program.
Program:
Q001 LBL Q
Q002 eq REGX-(REGXxN+O)xN
Q003 RTN
Comments:

Terms of use.

Mnemonic: Sorry, run out :-(

Unless the input is a point in the plane (if this is the case the vectors in Y and X stack register are the same after execution) the line defined by the point in Y stack register and the point in X stack register defines the perpendicular line from point now in the Y stack register onto the plane entered using the program P. May be used as input to the L program or M program.

Monday, October 1, 2007

HP-35s Euclid Implementation - IX : Signed distance from a plane to a point

The plane is the hyperplane of 3D (like a line in 2D divides the space a plane divide 3D space) so since program P stores the plane's normalized implicit equation point p=(x, y, z)'s signed distance to the plane is ax+by+cz+d or (since [a, b, c] is stored in variable N and d is stored in variable O) N*p+O where * here is the dot product operator.

I choose to modify the S program so that it computes the signed distance in 2D (as before) if flag 2 is set and else computes signed distance in 3D (to the plane defined by the P program); problem 10 of the requirements.

Stack Input/Output:

2D case:
[[x, y], Y, Z, T | L]-> XEQ S ->[d, Y, Z, T | [x, y]]
3D case:
[[x, y, z], Y, Z, T | L]-> XEQ S ->[d, Y, Z, T | [x, y, z]]
Where (x, y) or (x, y, z) is point to find distance to and d is the signed distance.

Variables:

Reads:
C : [a, b, c], constants of line's normalized implicit equation. Populated by the L program. Reads in 2D case (flag 2 set).
N : Plane's normalized normal vector. Populated by the P program. Reads in 3D case.
O : Plane's distance to origo (0, 0, 0). Populated by the P program. Reads in 3D case.
Program:
S001 LBL S
S002 ABS
S003 RDN
S004 FS? 2
S005 GTO 008
S006 eq LASTXxN+O
S007 RTN
S008 eq (([1,0,0]xC)x([1, 0]xLASTX))+(([0,1,0]xC)x([0,1]xLASTX))+[0,0,1]xC
S009 RTN
Comments:

Terms of use.

As before point to find signed distance to in the X stack register: Again, if had an dim operator for vectors would not need for the end user to toggle the 2 flag, could branch on dimension of argument in the X stack register.

Sunday, September 30, 2007

HP-35s Euclid Implementation - VIII : Defining a triangle

Yet another 'data entry' program, this one for defining a triangle in 3D space. It will be needed for solving triangle problems (14-17 of the requirements) but is also usefull to solve plane problems when the plane is defined by three points (problem 9 A of the requirements), so introducing it now.

The program accepts triangle's first point in the Z stack register, second point in Y stack register and third point in the X stack register, all expected to be 3D vectors. Program performs two tasks:
  1. Store the points in the variables K (first point), L (second point) and M (third point). These variables will be used later in solving triangle problems.
  2. Returns in the X stack register a vector normal to the plane defined by the triangle computed as (L-K)x(M-K) (x is here the cross product). This gives the area of the triangle since the length of this vector is twice the area (keystrokes: ABS, 2, /).
Stack Input/Output:
[[x2, y2, z2], [x1, y1, z1], [x0, y0, z0] | L]->XEQ T->[[nx, ny, nz], [x2, y2, z2], [x1, y1, z1], [x0, y0, z0] | L]
Where v0=(x0, y0, z0) is first, v1=(x1, y1, z1) is second, v2=(x2, y2, z2) is the third triangle vertex and [nx, ny, nz] is the cross product (v1-v0)x(v2-v0).

Variables:

Writes:
K : First vertex.
L : Second vertex.
M : Third vertex.
Program:
T001 LBL T
TOO2 5
T003 STO I
T004 STO(I)
T005 RDN
T006 4
T007 STO I
T008 RDN
T009 LASTX
T010 STO(I)
T011 RDN
T012 STO M
T013 RDN
T014 STO L
T015 RDN
T016 STO K
T017 R^
T018 X<>Y
T019 -
T020 RDN
T021 RDN
T022 LASTX
T023 -
T024 X<>Y
T025 RDN
T026 XEQ X001
T027 RCL(I)
T028 ABS
T029 RDN
T030 RCL K
T031 RCL L
T032 RCL M
T033 R^
T034 RTN
Comments:

Terms of use.

Mnemonic: T for triangle.

If end user need to compute the plane's normalized implicit equation she may simply do XEQ P since X stack register contains a vector normal to the plane and Y register a point in the plane (triangle's third vertex).

Change history:

20071018:1950UTC : This program has been modified as a part of providing for Cartesion to Barycentric coordinate transformation.

Saturday, September 29, 2007

Allocate memory on the HP-35s or Zero is also a number to remember!

Found errors in my hp-35s programs due to the stupid way memory is managed on it, yea, yea, it's my fault, but still:

While not a bug I think the 35s indirect register handling is pretty ..... stupid ....

Say you want to store N numbers in register 0...N-1, god forbid some or your last numbers happens to be 0 (a perfectly okey number) AND register N,... hapens not to be allocated. You get an INVALID when trying to learn that number N-1 was 0!

What you must do is to allocate your N registers by putting a 'watermark' non zero in register N.

I do not mind allocating and deallocating memory, but this reality of hp-35s is: a) implication not well documented, b) error prone. What I think should been here is commands to allocate registers and to free registers!

Wednesday, September 26, 2007

HP-35s Euclid Implementation - VII : Defining a plane

Time to start working with the plane: First a data entry program to define a plane given a point in the plane and a vector normal to it.

This program is similar to the L program in that it computes a hyperplane's (now of 3D space) implicit equation (problem 9A of the specification).

The program accepts the defining point in the Y stack register and a vector normal to the plane in X stack register.

It stores the point that defines the plane in variable P (mnemonic: plane's point), the normalized normal vector in variable N (mnemonic: plane's normal) and the constant d of the plane's implicit equation ax+by+cz+d=0 in variable O (mnemonic: distance from origo to plane, true since equation normailized; see comments section). Since [a, b, c] is the plane's normal (stored in variable N) the computation of d=-(N*P) (* is here the dot product) is what is to be done to compute the plane's implicit equation.

Stack Input/Output:
[[nx, ny, nz], [x, y, z], Z, T | L]-> XEQ P->[d, [a, b, c], [x, y, z], Z | [nx, ny, nz]]
Where [nx, ny, nz] is a vector normal to the plane and (x, y, z) is a point in the plane. Output is the constants of the normalized implicit plane equation ax+by+cz+d=0. Content of Y stack register [a, b, c] is [nx, ny, nz] normalized, orginal vector can be found in LASTX register.

Variables:

Writes:
N : Plane's normalized normal vector.
O : Signed distance to origo (0, 0, 0).
P : Defining point in plane.
Program:
POO1 LBL P
P002 XEQ X004
P003 STO N
P004 X<>Y
P005 STO P
P006 eq -(PxN)
P007 STO O
P008 RDN
P009 X<>Y
P010 R^
P011 RTN
Comments:

Terms of use.

Mnemonics: P for Plane.

Importent to remember when entering line P006: Stroke the +/- key not the - operation key to get the equation's sign. Using the - operator key will result in a program that looks fine but causes a SYNTAX error when line P006 is executed.

Reason for normalizing the normal vector defining the plane are:
  • Because it is often done. For example planes defined by a triangles found in the dataset of a Computer Graphics application's polygon model typical has normalized normal vectors associated with it's triangles.
  • When the normal vector defining the plane is normalized the plane's implicit equation is said to be normalized. Representing the plane using the normalized implicit equation has the advantage that some formulas for plane problems becomes simplified.
Since the implicit equation is normalized the d term of ax+by+cd+d, the value in the X stack register is the signed distance from the origo (0, 0, 0) to the plane.

Tuesday, September 25, 2007

Cross product and normalizing a vector on the HP-35s

NOTE: An error has been corrected in this program listing around 20070927 16:30 UTC.

Now need to calculate the cross product of two 3D vector in the HP-35s Euclid Pack implementation. One should think that the cross product would have been a build in function on th 35s, but no, we need to roll our own: Line 001-003 in the following program.

Normalizing a vector (keeping direction but making it of unit length) is a common operation performed on directional only vectors. Subroutine X006 performs normalization.

Stack Input/Output:

Cross product:
[[ux, uy, uz], [vx, vy, vz], Z, T | L]-> XEQ X001 ->[[wx, wy, wz], [ux, uy, uz], [vx, vy, vz], Z | L]
Where the w vector is the result of u*v.

Normalization:
[u, Y, Z, T | L]-> XEQ U004 ->[u/|u|, Y, Z, T | u]
Where u is a 2D or 3D.

Program:
X001 LBL X
X002 eq [([0,1,0]xREGY)x([0,0,1]xREGX)-([0,0,1]xREGY)x([0,1,0]xREGX),
([0,0,1]xREGY)x([1,0,0]xREGX)-([1,0,0]xREGY)x([0,0,1]xREGX),
([1,0,0]xREGY)x([0,1,0]xREGX)-([0,1,0]xREGY)x([1,0,0]xREGX)]
X003 RTN
X004 ABS
X005 RDN
X006 eq LASTX/REGT
X007 RTN
Comments:

Terms of use.

Sunday, September 23, 2007

HP-35s Euclid Implementation - VI : Closest points on two lines

The following program addresses problem 7 and 8 in the requirements, it finds the closest points on two non paralell lines or tells if the lines are paralell. In 2D non paralell lines intersect so if working in 2D this finds the intersection point. For 3D lines the two points found defines the shortest line segment between two non paralell lines. The length of this line segment is the shortest distance between the lines. Ofcourse 3D lines can intersect: The two points found are then the same point.

The first line has been entered using the L program (refered to as l) and the second is given as first point in the Y stack register and the second in the X stack register (refered to as m).

Stack Input/Output:
[[x1, y1, z1], [x0, y0, z0], Z, T | L]-> XEQ M ->[s, t, [x1, y1, z1], [x0, y0, z0] | L]
Where (x0, y0, z0) is the first point defining m, (x1, y1, z1) is the second point defining m, s is the parameter defining the closest point on l to m and t is the parameter defining the closest point on m to l.

If the lines are paralell the message PARALELL is shortly displayed. The stack and LASTX registers are left unchanged in this case.

Variables:

Reads:
A : 'First' line l's first defining point.
B : 'Second' line l's first defining point.
Writes:
D : 'Second' line m's first defining point.
E : 'Second' line m's second defining point.
Z : Scratch data.
Program:
M001 LBL M
M002 XEQ U001
M003 STO E
M004 X<>Y
M005 STO D
M006 -
M007 RCL B
M008 RCL- A
M009 eq [REGXxREGX,REGXxREGY,REGYxREGY]
M010 STO Z
M011 RDN
M012 RCL A
M013 RCL- D
M014 eq [REGYxREGX,REGZxREGX]
M015 eq ([1,0,0]xZ)x([0,0,1]xZ)-([0,1,0]xZ)x([0,1,0]xZ)
M016 eq ([0,1,0]xZ)x([0,1]xREGY)-([0,0,1]xZ)x([1,0]xREGY)
M017 X<>Y
M018 ABS
M019 1E-6
MO20 X>Y?
M021 GOTO M041
M022 RDN
M023 RDN
M024 LASTX
M025 /
M026 eq ([1,0,0]xZ)x([0,1]xREGY)-([0,1,0]xZ)x([1,0]xREGY)
M027 LASTX
MO28 /
M029 X<>Y
M030 4
M031 STO I
M032 RDN
M033 RCL(I)
M034 ABS
M035 RDN
M036 RCL D
M037 RCL E
M038 RDN
M039 RDN
M040 RTN
M041 SF 10
M042 eq PARALELL
M043 PSE
M044 CF 10
M045 XEQ U029
M046 RTN
Comments:

Terms of use.

If end user needs the coordinates for the closest point on l to m she need only do XEQ E. The M program actual stores the defining points for the m line in variables D (first point) and E (second point) so that with the following short program similar to the E program the coordinate for the closest point on line m to line l can be calculated by moving the parameter for the m line to the X register and do XEQ F:

Stack Input/Output:
3D case: [t, Y, Z, T | L]-> XEQ F ->[[x, y, z], Y, Z, T | t]

2D case: [t, Y, Z, T | L]-> XEQ F ->[[x, y], Y, Z, T | t]
Where t is the parameter and (x, y, z) is the evaluated point if a 3D line has been entered using the M program and (x, y) is the evaluated point if a 2D line has been entered using the M program.

Variables:

Reads:
D: First point defining the line, populated by the M program.
E: Second point defining the line, populated by the M program.
Program:
F001 LBL F
F002 ABS
F003 RDN
F004 (1-LASTX)xD+LASTXxE
F005 RTN
Mnemonics: Like the L program the program M stores a line (but the implicit equation constants are not computed for this 'secondary' line) so is put next to the L key. Same for the F program: Put next to the E program (that compute coordinates on l).

Allowed one variable to be used for scratch data: The Z variable register.

Change history:

20070929:2035UTC : Change because of fix in U program.
20071002:1835UTC : Bug fix: Did not take absolute value of denominator value when doing epsilon-zero test!.

Addition to the HP-35s stack save/restore program - I

The following extension to the U001 subroutine allow for simulating unary operation (one that only operates on value in X stack register and saves old value in LASTX register): Get what was in the X register to LASTX, leave what is in X register in X (this is your new operation's result) and restore Y, Z and T registers.

Program:
U050 0
U051 STO I
U052 RDN
U053 RCL(I)
U054 ABS
U055 RDN
U056 3
UO57 STO I
U058 RDN
U059 RCL(I)
U060 2
U061 STO I
UO62 RDN
U063 RCL(I)
U064 1
U065 STO I
U066 RDN
U067 RCL(I)
U068 R^
U069 RTN
Comments:

Terms of use.

So now we have the subroutines:
  1. XEQ U001 to save the stack and LASTX.
  2. XEQ U029 to restore the stack and LASTX given U001 has been used to save.
  3. XEQ U050 to implement operation native unary operation stack and LASTX behaviour given U001 has been used to save.
Change history:

20070929:2035UTC : Change because of fix in U program.

HP-35s Euclid Implementation - V : Closest point on a line to a point

The following program finds the parameter giving the closest point (problem 6 (and 5) in the requirements) on the line entered by the L program to a given point.

Remembering that the positional vector for first point defining the line is in variable A, second point is in variable B and saying that the point in question's positional vector is in the X stack register the formula for the parameter is: t=((X-A)*(B-A))/((B-A)*(B-A)).

Stack Input/Output:
[[x, y, z], Y, Z, T | L]-> XEQ C ->[t, Y, Z, T | [x, y, z]]
Where (x, y, z) is the point p in question and t is the parameter defining the closest point on the line to p.

Variables:

Reads:
A: First point defining the line, populated by the L program.
B: Second point defining the line, populated by the L program.
Program:
C001 LBL C
C002 XEQ U001
C003 RCL A
C004 -
C005 RCL B
C006 RCL A
C007 -
C008 x
C009 LASTX
C010 ENTER
C011 x
C012 /
C013 XEQ U050
C014 RTN
Comments:

Terms of use.

Mnemonic: C for closest point.

The program does not calculate the coordinates for the closest point on line since end user may only be interested in the parameter that tells if point is on the defining line segment or on which ray. The coordinates are only one program away: XEQ E.

I decide not to implement a program for problem 5 (distance from a 3D line to a point) in the requirements since end user easily now can find the perpendicular line from the point to the line, and length of it's defining line segment is the distance from line to the point. The operation sequence after this program is run:

LASTX // Get back point which to find perpendicular line on stored line or distance.
X<>Y // Parameter back in X stack register.
XEQ E // Find coordinates to closest point on line.
// Now Y and X stack registers contains two points defining the perpendicular
// line, one could now run program L to store this line for further
// computation relating to that line.
- // Continuing to find distance: Get perpendicular line segment directional
// vector of segment's length in X and
ABS // the length.
This program works for both 2D and 3D data so do not need to check the 2 flag, but if one are to enter the perpendicular line as computed in above paragraph one should remember to have it set if working in 2D so the implicit equation is computed.

Change history:

20070929:2035UTC : Change because of fix in U program.

Saturday, September 22, 2007

HP-35s Euclid Implementation - IV : Normalizing a line definition

The following program adjust second point (in register B) so that the line segment defining the line entered using the program L is of unit length (problem 4 of the requirements).

It then becomes easy to produce coordinates of a given distance from the defining segments first point (in register A) using program E since the distance then is the given parameter.

Stack Input/Output:

This program does not take any stack register input, stack register and LASTX register is left unchanged by this program.

Variables:

Reads:
A: First point defining the line, populated by the L program.
B: Second point defining the line, populated by the L program.
Writes:
B: Adjust so line segment becomes of unit length.
Program:
N001 LBL N
N002 XEQ U001
N003 RCL A
N004 eq 1/ABS(B-A)
N005 STOx A
N006 STOx B
N007 RDN
N008 RCL A
N009 -
N010 STO+ A
N011 STO+ B
N012 XEQ U029
N013 RTN
Comments:

Terms of use.

Mnemonic: N for Normal since normalize the vector B-A.

Since this program does not take any input from the stack registers but messes up the stack and LASTX registers it uses the U program to hide this from the end user; line 2 saves stack and LASTX registers and line 14 restores the working registers.

Change history:

20070929:2035UTC : Change because of fix in U program.
20071001:2040UTC : Do no longer recompute implicit equation of 2D line (used to check flag 2) since program L now stores the normalized implicit equation.

Modified HP-35s stack save/restore program

Decided wanted the U program to also save/restore the LASTX register.

Modified program:
U001 LBL U
U002 X<> I
U003 RDN
U004 0
U005 X<> I
U006 STO(I)
U007 RDN
U008 1
U009 STO I
U010 RDN
U011 STO(I)
U012 RDN
U013 2
U014 STO I
U015 RDN
U016 STO(I)
U017 RDN
U018 3
U019 STO I
U020 RDN
U021 STO(I)
U022 4
U023 STO I
U024 LASTX
U025 STO(I)
U026 5
U027 STO I
U028 STO(I)
U029 4
U030 STO I
U031 RCL(I)
U032 ABS
U033 3
U034 STO I
U035 RDN
U036 RCL(I)
U037 2
U038 STO I
U039 RDN
U040 RCL(I)
U041 1
U042 STO I
U043 RDN
U044 RCL(I)
U045 0
U046 STO I
U047 RDN
U048 RCL(I)
U049 RTN
Comments:

Terms of use.

LASTX is saved to register 4 and register 5 gets a non zero to allocate registers for sure.

Recall soubroutine is now U029.

Change history:

20070929:2035UTC : An error has been corrected: The error had to do with not properly allocating indirect registers if happen to store zeros in reg. 4 and downwards in sequence... See here for more on this topic.

Saving HP-35s' stack in indirect registers

NOTE: Program here has bugs and is no longer maintained, use program listed here.

The method of imitating native operations stack and lastx behaviour used here and here is perfect for cases when job can be done with a single equation. For longer and more traditional rpn type of programs one may want to save the stack.

The following program stores X stack register content in register 0, Y stack register in 1, Z stack register in 2 and T stack register in 3.

Program:
U001 LBL U
U002 X<> I
U003 RDN
U004 0
U005 X<> I
U006 STO(I)
U007 RDN
U008 1
U009 STO I
U010 RDN
U011 STO(I)
U012 RDN
U013 2
U014 STO I
U015 RDN
U016 STO(I)
U017 RDN
U018 3
U019 STO I
U020 RDN
U021 STO(I)
U022 3
U023 STO I
U024 RDN
U025 RCL(I)
U026 2
U027 STO I
U028 RDN
U029 RCL(I)
U030 1
U031 STO I
U032 RDN
U033 RCL(I)
U034 0
U035 STO I
U036 RDN
U037 RCL(I)
U038 RTN
Comments:

Terms of use.

The start is a bit tricky since we are storing in indirect registers (do not want to use high valuable variable registers for this) and need to enter index 0 in I but stack is full of stuff not to be lost. Rescue operator is X<> I: Swaps content in I with X, get old I content to T and put index O in X, swap it with old X content which then is stored in register 0. From then on it is straight forward.

This program restore the stack after it is saved (program calling propably would like that...), that is what lines 22-38 does. Note that when 22-38 execute in context of last part of saving the stack there are some redundant lines, but wrote it like this so XEQ U022 can be used in general to recall saved stack.

NOTE: I made a modification and an extension to this program.

Friday, September 21, 2007

HP-35s Euclid Implementation - III : Evaluating points on a line

A simple but important operation is to evaluate points on a line using it's parametric equation (item 3 in the specification); (1-t)p+tq (linear interpolation/extrapolation) where t is the scalar parameter and p is the position vector for first point defining the line and q the position vector for the second point.

The importance of this operation is:
  1. More practical to produce points of the line than the implicit equation.
  2. Works in any dimension.
  3. It is more usefull to have programs that solves problems where the solution is a point on a line produce the parameter giving the point then the actual coordinates: The parameter tells if the point is on the line segment defining the line (0<=t<=1), on the ray starting at first point and traveling away from second point (t<0) or on other ray if t>1. Use this program if want coordinates after parameter inspection.
Stack Input/Output:
3D case: [t, Y, Z, T | L]-> XEQ E ->[[x, y, z], Y, Z, T | t]

2D case: [t, Y, Z, T | L]-> XEQ E ->[[x, y], Y, Z, T | t]
Where t is the parameter and (x, y, z) is the evaluated point if a 3D line has been entered using the L program and (x, y) is the evaluated point if a 2D line has been entered using the L program.

Variables:

Reads:
A: First point defining the line, populated by the L program.
B: Second point defining the line, populated by the L program.
Program:
E001 LBL E
E002 ABS
E003 RDN
E004 eq (1-LASTX)xA+LASTXxB
E005 RTN
Comments:

Terms of use.

Mnemonic: E for evaluate.

HP-35s Euclid Implementation - II : Signed distance from a 2D line to a 2D point

NOTE: This program has been modified.

The 2D line is the hyperplane of 2D space meaning a line divide the space (a point is the hyperplane of 1D space and plane the is the hyperplane of 3D space). This manifest itself in that if we use the left side of the implicit equation ax+by+c=0 as a function we get out a number that is 0 if (x, y) is on the line, negative sign if on one side and positive sign if on the other.

In the case that |[a, b]|=1, the implicit equation is said to be normalized and ax+by+c is in fact the (signed) distance from the point (x, y) to the line. Since the program L do store the normalized line equation this program simply computes ax+by+c.

Stack Input/Output:
[[x, y], Y, Z, T | L]-> XEQ S ->[d, Y, Z, T | [x, y]]
Where (x, y) is point to find distance to and d is the signed distance.

Variables:

Reads:
C : [a, b, c], constants of line's normalized implicit equation. Populated by the L program.
Program:
S001 LBL S
S002 ABS
S003 RDN
S004 eq (([1,0,0]xC)x([1, 0]xLASTX))+(([0,1,0]xC)x([0,1]xLASTX))+[0,0,1]xC
S005 RTN
Comments:

Terms of use.

Mnemonic: S for signed distance.

The line distance is computed from is entered using the program L and the point is in the X stack register as a 2D vector.

This program does not test for the 2 flag since it only work on a 2D problem.

An important feature I wanted from this program is that it behaves like a build in function: The argument in the X stack register (the point) goes to LASTX register, result (signed distance) appears in the X stack register and Y, Z and T stack registers are left unchanged. First version fooled around saving stack content in indirect registers, but then I found Valentin Albillo (VA) trick in a MoHPC forum post used here: Thanks VA, expects that to be utilized more!

Change history:

20071001:2010UTC : No longer divide ax+by+c by |[a, b]| since now the normalized implicit equation is stored.
20071001:2210UTC : New version of program.

HP-35s Euclid Implementation - I : Defining a line

The first program in the HP-35s Euclid Pack implementation is one to accept a line defined by two points to be used for further calculations. The program stores first point in variable A and second point in variable B.

What I realy would like is if this program could tell the dimension of vectors or if input is scalar, this could be used for:

1. Check if gets what is expected (vectors). As it is now the program will do nothing more for 3D lines but to store points in correct variables, might as well use STO commands directly in 3D case.

2. For 2D lines I would like it to compute the constants of the lines implicit equation ax+by+c=0 and store it in variable C as a 3D vector [a, b, c] (problem 1 in the specification). Since this is not possible I am introducing a 2D mode: If flag 2 is set then user is working in 2D, programs that need do perform different based on dimension of input will check this flag.

Stack Input/Output:
2D case: [[x1, y1], [x0, y0], Z, T | L]-> XEQ L ->[[a, b, c], [x1, y1], [x0, y0], Z | L]

3D case: [[x1, y1, z1], [x0, y0, z0], Z, T | L]-> XEQ L -> No change.
Where x0, y0, z0 are coordinates for first point defining the line, x1, y1, z1 are coordinates for second point defining the line and in the 2D case a, b, and c are the constants of line's implicit equation ax+by+c.

Variables:

Writes:
A : First point defining line.
B : Second point defining the line.
C : [a, b, c] the constants of 2D line's normalized implicit equation ax+by+c. Not populated if input is a 3D line.
Program:
L001 LBL L
L002 STO B
L003 x<>y
L004 STO A
L005 x<>y
L006 FS? 2
L007 GTO L009
L008 RTN
L009 eq [[0,1]xA+[0,-1]xB,
[1,0]xB+[-1,0]xA,
([1,0]xA)x([0,1]xB)-([1,0]xB)x[0,1]xA)]/(ABS(B-A))
L010 STO C
L011 RTN
Comments:

Terms of use.

Mnemonic: L for line.

The implicit equation (2D case) stored is normalized since the vector [a, b] is made to be of length 1, which means that for a point x, y not on the line ax+by+c is the signed distance to the line (two 2D points has opposite distance sign if not on same side of the 2D line). The program S computes the signed distance. One piece of information one get right away is the line's distance to origo (0, 0): |c|.

I realy like that one can use equations in programs.

All those vectors with signed 1s and 0s elements are mask vectors to get out a vector's components needed since no operation to do so is provided. I knew about that trick long before getting my hands on machine reading MoHPC forum posts...

I actual did ask about the runtime type problem at MoHPC in this thread, if there was a solution I'am sure Katie would have found it...

For all its shortcomings I still find the vector type very usefull because it lets us store vectors of 2D and 3D space in a single register. Sure I got 800 registers, but this type of data I would like to use the A-H, K-Z variable registers for easy access: Without the vector type I would have used 9 variables not 3, also the stack would not been high enough for non prompt input.

Change history:

20071001:2010UTC : Changed to store normalized implicit equation.

Got the HP-35s

Got the HP-35s day before yesterday.

Total cost: Calculator and shipping: 568.74 nok
Custom (tax and handling): 233.00 nok
Total cost: 801.74 nok

Samson Cables told me I did not have to pay taxes, but I had to. Still think my total cost is not that different from what it will cost here when to be had next year, so I am happy.

Actual like it a lot so fare, wrote a first impression post on the MoHPC site's forum.

Serial: CNA 72800529, may be the first 35s in Norway :-)

Tuesday, September 11, 2007

Euclid Pack - The Geometric Calculator

The idea of this programming project come from my day time job that also include computer graphics (3D visualization and CAD type of problems).

An important module in our software is an API we call Euclid. It do 2D and 3D geometric calculations and is well tested. I think it might be of use to have a version of it on a calculator when testing and debug code that is using the Euclid API. I name the calculator version Euclid Pack.

Initial specification for the problems to solved by the Euclid Pack:
  1. Compute the implicit equation for a 2D line given two 2D points. HP-35s
  2. Find the signed distance from a 2D line to a 2D point. HP-35s
  3. Evaluate points on a lines (2D or 3D) using their parametric equations. HP-35s
  4. "Normalize" the segment defining a line (2D or 3D). HP-35s
  5. Find the distance from a 3D line to a 3D point. HP-35s
  6. Compute the closest point on a line to a point (2D or 3D). HP-35s
  7. Find the point of intersection of two 2D lines or learn that the lines are paralell. HP-35s
  8. Find the unique shortest line between two 3D lines or learn that the lines intersect or are paralell. HP-35s
  9. Compute the implicit equation for a plane given A) a point and normal vector or B) three points. HP-35s (A, B)
  10. Find the signed distance from a plane to a point. HP-35s
  11. Compute the closest point on a plane to a point. HP-35s
  12. Find the point of intersection of a plane and a line or learn that the plane and line are paralell. HP-35s
  13. Find the line of intersection between two planes. HP-35s
  14. Cartesian coordinates to Barycentric coordinates. HP-35s
  15. Barycentric coordinates to Cartesian coordinates. HP-35s
  16. Compute a triangle's inscribed circle. HP-35s
  17. Compute a triangle's circumscribed circle. HP-35s
The plan is to implement this on the HP-35s once it is available to me. If I managed to get my old HP-41CV repaired I might try to implement it on that as well.

On paper the HP-35s should be a good machine for this since it has 2D and 3D vectors.

Saturday, September 8, 2007

Fixing the HP-41CV - I

Had nice e-mail exchanges with Randy at FixThatCalc, discussed the patient (seems there is good hope) and details around getting it to them. Propably will not be to long before send it.

Wednesday, September 5, 2007

HP Calculator links

The Museum of HP Calculators (MoHPC)

I would say the most important HP calculator site, a virtual museum of vintage HP calculators from the HP-9100s to the HP-48s. Beside presentations of the machines here is a *lot* of information on programming, collecting and more... What nails this as the HP calculator site is the forum. It seems to be the Rick's cafe for HP calculator crowd. Hanging out here and explore it's archive may be the best way to discover the HP calculator online universe.

FixThatCalc

The place that give me hopes my old pal the HP-41CV and me once again will hack together.

Speaking about the HP-41...

Fantastic scan of HP-41's user's manual and card reader manual by this site.

HP-41 machines flew on the early space shuttle missions, here is an article from the Smithsonian Institution's National Air and Space Museum web site about it.

However it must be mention that the HP-41C was not the first hp calculator to go to space, as told by this old HP press release the HP-35 (first scientific handheld calculator) and HP-65 (first magnetic card-programmable handheld calculator) had been there before: A museum visitor's picture and a cool picture from a HP poster.

Tuesday, September 4, 2007

About

Long time ago before learned high level programming languages such at Pascal, FORTRAN, C, C++ and Java I made my first programs on HP calculators, first on a 33C, then on a 41CV.

My hobby ended when the 41CV stopped working after a short periode of being weightless... I never bought a calculator again, before now...

Lately my work has been of such a nature that I do like to use a calculator now and then, and not wanting to use any other than a rpn calculator I was delighted to learn that HP had made a new reasonable priced RPN calculator: The HP-35s. I ordered it and as I write it should be on it's way to me.

I have been thinking that it's programmable feature will be wasted on me; I was not looking to get back to my old hobby of 'key stroke programming'. But who am I kidding? I am a programmer who love to program, if I am getting something programmable I am gonna program it...

The first programming project for it I have tagged Euclid.

All this excitement of buying a brand new RPN classic type HP calculator got me to hunt down my old pal, the defunced HP-41CV. Well, to get cut a short story shortere: I am going to get it fixed, I tag that project HP41RP (HP-41 Repair Project).

Well, that is what this blog is about, all thing HP Calculator activities I may wanna blog about!