[Back to GRAPHICS SWAG index]  [Back to Main SWAG index]  [Original]

{
 -=> 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 }
      Degrees_Per_Radian  = 180.0/SYSTEM.Pi;
      Radians_Per_Degree  = SYSTEM.Pi/180.0;

{ 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
  Radians := Radians_Per_Degree * A;
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*****)

[Back to GRAPHICS SWAG index]  [Back to Main SWAG index]  [Original]