``````{
-=> Quoting Sean Graham to All on 22 Jun 94 <=-
SG> some  (efficient, I would hope) code in pascal that will allow me to
SG> move in a 2D or  3D 'universe' (or more correctly, grid-system). Let me

SG> Let's start out easy.  For example, how would I write code to draw a
SG> line on  a 50x80 (yes, ascii chars) screen from pos A(10,5) to pos
SG> B(47,56)?
SG> Now imagine that my screen has magically grown a third dimention.  So
SG> I now  want to draw a line from pos A(47,34,7) to pos B(21,11,33).  How
SG> would I write  code to do that?

SG> Now picture this, I no longer have a screen, but a grid that works
SG> along the same principles as the screen did, except the points range
SG> from -20 to +20 on (x,y,z).  (That gives me a total of 68,921 (41^3)
SG> possible co-ordinates.)
SG> Pretend that Is a universe in space.  I'm in a tiny escape pod and
SG> must get from co-ordinate (-10,+05,+12) to co-ordinate (+07,+02,-11)

If you want to create an actual space, try :
}

UNIT space;
{ Author: John Howard }
{
Define a two-dimensional space representation which is used for Cartesian and
Polar coordinate systems.  A three-dimensional space is for Spherical and
Azimuth-Elevation coordinate systems.
}
{ A vector is a one-dimensional array of real numbers.  A matrix has two
dimensions m by n with m rows and n columns.  Notice the row number always
comes first in the dimensions and the indices.  Example square matrix A33 =
[ a11  a12  a13 ]    or generally  A[i, j]; i=rows, j=columns.
[ a21  a22  a23 ]
[ a31  a32  a33 ]
A matrix can be operated upon with appropriate column or row vectors.
}
INTERFACE
{.\$DEFINE D2}                            {remove period to use 2D}
{\$IFNDEF D2}
const N = 3;                             { Cardinality for Three_Vector}
M = 3;                             { Square matrix for invert routine}
{\$ELSE}
const N = 2;                             { Cardinality for Two_Vector}
M = 2;                             { Square matrix for invert routine}
{\$ENDIF}
Size = M;
type
Vector = array [1..N] of real;        { 3D vector is the most common! }
Matrix = array [1..M, 1..N] of real;  { 3x3 matrix is the most common! }

{Store all the components into a vector}
{\$IFNDEF D2}
procedure Set_Value( var a: Vector; x_value, y_value, z_value: real);
{\$ELSE}
procedure Set_Value( var a: Vector; x_value, y_value: real);
{\$ENDIF}

{Retrieve the value of s from the ith element of a vector}
function Element( var a: Vector; i: integer): real;

{Retrieve the first element from a vector}
function  X_Component( var a: Vector): real;

{Retrieve the second element from a vector}
function  Y_Component( var a: Vector): real;

{Retrieve the third element from a vector}
{\$IFNDEF D2}
function  Z_Component( var a: Vector): real;
{\$ENDIF}

IMPLEMENTATION

procedure Set_Value;          { Note: parameter list intentionally left off}
begin
a[1] := x_value;
a[2] := y_value;
{\$IFNDEF D2}
a[3] := z_value;
{\$ENDIF}
end;

function Element( var a: Vector; i: integer): real;
begin
Element := a[i];
end;

function  X_Component( var a: Vector): real;
begin
X_Component := a[1];
end;

function  Y_Component( var a: Vector): real;
begin
Y_Component := a[2];
end;

{\$IFNDEF D2}
function  Z_Component( var a: Vector): real;
begin
Z_Component := a[3];
end;
{\$ENDIF}
BEGIN
END.

(**********
If you do not want to create an actual 3d space, just convert coordinates :

You could use a two dimensional X_Component and Y_Component calculation to get
you to an approximate region based upon Z_Component.  Example:

From point A(x1,y1) to B(x2,y2) you travel a distance = sqrt(sqr(x2-x1) +
sqr(y2-y1)) at a slope of (y2-y1)/(x2-x1).  That slope is called the Tangent
of the angle of inclination of the line AB.

Now that you know where you are heading and how far away it is you can divide
the total distance into sections say of unit length.  That means a distance of
10 would have ten units.  Every time your spaceship moves one unit in the known
direction you can reverse the calculation to find out where you are at.  When
you reach the final distance, you'd take approximations using the third
component.  This idea is simple but not very accurate in the interum space.

You can use the same idea but implement it with a proper coordinate conversion.
**********)

UNIT coord;
{ Author: John Howard }
{ Original source: Jack Crenshaw, 1992 Embedded Systems Programming }
{ Space Conversion -- Angles are capitalized }
{ All axes are perpendicular to each other }
INTERFACE
const
Zero = 0.0;
One  = 1.0;
TwoPi               = Two * SYSTEM.Pi;
Pi_Over_Two         = SYSTEM.Pi/Two;

{ 1 binary angular measure = 1 pirad = Pi radians = 180 degrees }

{ X-axis points east, y-axis north, and angle Theta is the heading measured
north of due east.  If Theta is zero that corresponds to a line running
along the x-axis a radial distance of r.
}
Procedure To_Polar ( x, y: real; Var r, Theta: real);
Procedure From_Polar ( r, Theta: real; Var x, y: real);

{ X-axis points toward you, y-axis right, z-axis upward, angle Phi measures
directions in the horizontal (x-y plane) from the x-axis, and angle Theta
measures the direction in the vertical from the z-axis downward.  If Theta
is zero that corresponds to a line pointed up the z-axis.
}
Procedure To_Spherical ( x, y, z: real; Var r, Phi, Theta: real);
Procedure From_Spherical ( r, Phi, Theta: real; Var x, y, z: real);

{ X-axis points east, y-axis north, z-axis upward, angle Phi corresponds to an
azimuth measured clockwise from due north, and angle Theta is the elevation
measured upwards from the horizon (x-y plane).
}
Procedure To_Azimuth_Elevation ( x, y, z: real; Var r, Phi, Theta: real);
Procedure From_Azimuth_Elevation ( r, Phi, Theta: real; Var x, y, z: real);

Function Sign ( x, y: real): real;
Function Degrees ( A: real): real;
Function Radians ( A: real): real;

Function Atan ( x: real): real;           {ArcTangent}
Function Atan2 ( s, c: real): real;

IMPLEMENTATION

{ Convert from Cartesian to polar coordinates }
Procedure To_Polar ( x, y: real; Var r, Theta: real);
Begin
r := Sqrt(Sqr(x) + Sqr(y));
Theta := Atan2(y, x);
End;

{ Convert from polar to Cartesian coordinates }
Procedure From_Polar ( r, Theta: real; Var x, y: real);
Begin
x := r * Cos(Theta);
y := r * Sin(Theta);
End;

{ Convert from Cartesian to spherical polar coordinates }
Procedure To_Spherical ( x, y, z: real; Var r, Phi, Theta: real);
var  temp: real;
Begin
To_Polar(x, y, temp, Phi);
To_Polar(z, temp, r, Theta);
End;

{ Convert from spherical polar to Cartesian coordinates }
Procedure From_Spherical ( r, Phi, Theta: real; Var x, y, z: real);
var  temp: real;
Begin
From_Polar(r, Theta, z, temp);
From_Polar(temp, Phi, x, y);
End;

{ Convert from Cartesian to Az-El coordinates }
Procedure To_Azimuth_Elevation ( x, y, z: real; Var r, Phi, Theta: real);
var  temp: real;
Begin
To_Polar(y, x, temp, Phi);
To_Polar(temp, z, r, Theta);
End;

{ Convert from Az-El to Cartesian coordinates }
Procedure From_Azimuth_Elevation ( r, Phi, Theta: real; Var x, y, z: real);
var  temp: real;
Begin
From_Polar(r, Theta, temp, z);
From_Polar(temp, Phi, y, x);
End;

{ Returns Absolute value of x with Sign of y }
Function Sign ( x, y: real): real;
Begin
if y >= Zero then
Sign := Abs(x)
else
Sign := -Abs(x);
End;

{ Convert angle from radians to degrees }
Function Degrees ( A: real): real;
Begin
Degrees := Degrees_Per_Radian * A;
End;

{ Convert angle from degrees to radians }
Function Radians ( A: real): real;
Begin
End;

{ Inverse Trigonometric Tangent Function }
Function Atan ( x: real): real;
{  Arctangent algorithm uses fifth-order rational fraction with optimized
coefficients
}
function _Atan ( x: real): real;
const
a = 0.999999447;
b = 0.259455937;
c = 0.592716128;

var  y: real;
begin
y := x*x;
_Atan := a*x*( One + b*y) / ( One + c*y);
end;

var  a, y: real;
Begin
y := Abs(x);
if y <= One then
a := _Atan(y)
else
a := Pi_Over_Two - _Atan( One / y);
if x <= Zero then
a := -a;
Atan := a;
End;

{ Four-Quadrant Inverse Trigonometric Tangent Function }
Function Atan2 ( s, c: real): real;
var  s1, c1, Theta: real;
Begin
s1 := Abs(s);
c1 := Abs(c);
if c1 + s1 = Zero then
Theta := Zero
else if s1 <= c1 then
Theta := ArcTan(s1 / c1)
else
Theta := Pi_Over_Two - ArcTan(c1 / s1);
if c < Zero then
Theta := Pi - Theta;
Atan2 := Sign(Theta, s);
End;
BEGIN
END.
(*****END*****)

``````