(*-------------------------------------------------------------------------*)
(*                                                                         *)
(*  Amiga Oberon Interface Module: VECTOR             Date: 02-Nov-92      *)
(*                                                                         *)
(*   © 1992 by Fridtjof Siebert                                            *)
(*                                                                         *)
(*-------------------------------------------------------------------------*)

MODULE VECTOR;

IMPORT BT * := BasicTypes, MATHLIB;

TYPE
  VECTOR * = POINTER TO VECTORDesc;

  VECTORDesc * = RECORD (BT.GROUPDesc)
    elements: POINTER TO ARRAY OF LONGREAL;
  END;


PROCEDURE Create * (dim: LONGINT): VECTOR;
(*
 * require
 *   dim>0
 *
 * ensure
 *   Result.Dimension()=len
 *)

VAR
  v: VECTOR;
BEGIN
  NEW(v);
  NEW(v.elements,dim);
  RETURN v;
END Create;


PROCEDURE (v: VECTOR) Get * (n: LONGINT): LONGREAL;
(*
 * require
 *   v.Dimension()>n;
 *   n>0
 *)
BEGIN
  RETURN v.elements[n];
END Get;


PROCEDURE (v: VECTOR) Put * (n: LONGINT; x: LONGREAL);
(*
 * require
 *   v.Dimension()>n;
 *   n>0
 * ensure
 *   v.Get(n)=x
 *)
BEGIN
  v.elements[n] := x;
END Put;


PROCEDURE (v: VECTOR) Dimension * (): LONGINT;

BEGIN
  RETURN LEN(v.elements^);
END Dimension;


PROCEDURE (v: VECTOR) Add   * (n: BT.GROUP): BT.GROUP;
(*
 * require
 *   v.Dimension = n(VECTOR).Dimension
 *)
VAR
  new: VECTOR;
  i: LONGINT;

BEGIN
  WITH n: VECTOR DO
    new := Create(v.Dimension());
    FOR i := 0 TO v.Dimension()-1 DO
      new.elements[i] := v.elements[i] + n.elements[i]
    END;
  END;
  RETURN new;
END Add;


PROCEDURE (v: VECTOR) Neg   * (): BT.GROUP;

VAR
  new: VECTOR;
  i: LONGINT;

BEGIN
  new := Create(v.Dimension());
  FOR i := 0 TO v.Dimension()-1 DO
    new.elements[i] := - v.elements[i];
  END;
  RETURN new;
END Neg;


PROCEDURE (v: VECTOR) Sub   * (n: BT.GROUP): BT.GROUP;
(*
 * require
 *   v.Dimension = n(VECTOR).Dimension
 *)
VAR
  new: VECTOR;
  i: LONGINT;

BEGIN
  WITH n: VECTOR DO
    new := Create(v.Dimension());
    FOR i := 0 TO v.Dimension()-1 DO
      new.elements[i] := v.elements[i] - n.elements[i]
    END;
  END;
  RETURN new;
END Sub;


PROCEDURE (v: VECTOR) Norm * (): LONGREAL;

VAR
  i: LONGINT;
  l: LONGREAL;

BEGIN
  l := 0;
  FOR i := 0 TO v.Dimension()-1 DO
    l := l + MATHLIB.SQR(v.elements[i])
  END;
  RETURN MATHLIB.SQRT(l);
END Norm;


PROCEDURE (v: VECTOR) Mul3  * (n: VECTOR): VECTOR;
(*
 * require
 *   v.Dimension = 3
 *   v.Dimension = 3
 *
 *)

VAR
  new: VECTOR;
  i,j: LONGINT;

BEGIN
  WITH n: VECTOR DO
    new := Create(3);
    new.elements[0] := v.elements[1] * n.elements[2] - v.elements[2] * n.elements[1];
    new.elements[1] := v.elements[2] * n.elements[0] - v.elements[0] * n.elements[2];
    new.elements[2] := v.elements[0] * n.elements[1] - v.elements[1] * n.elements[0];
  END;
  RETURN new;
END Mul3;


PROCEDURE (v: VECTOR) isEqual * (n: BT.COMPAREABLE): BOOLEAN; (* a = b *)
(*
 * require
 *   v.Dimension = n(VECTOR).Dimension
 *)
VAR
  i: LONGINT;

BEGIN
  WITH n: VECTOR DO
    FOR i := 0 TO v.Dimension()-1 DO
      IF v.elements[i] # n.elements[i] THEN RETURN FALSE END;
    END;
  END;
  RETURN TRUE;
END isEqual;


PROCEDURE (a: VECTOR) Compare * (b: BT.COMPAREABLE): LONGINT;
(*
 * Compares the lengths of a and b.
 *
 * require
 *   a.Dimension = b(VECTOR).Dimension;
 *)
VAR
  an,bn: LONGREAL;
BEGIN
  an := a.Norm(); bn := b(VECTOR).Norm();
  IF    an = bn THEN RETURN  0
  ELSIF an > bn THEN RETURN  1
  ELSE               RETURN -1 END;
END Compare;


PROCEDURE (a: VECTOR) ScalarProduct * (b: VECTOR): LONGREAL;
(*
 * Determine scalar product a × b.
 *
 * require
 *   b#NIL;
 *   a.Dimension = b.Dimension;
 *)

VAR
  result: LONGREAL;
  i: LONGINT;
BEGIN
  result := 0;
  FOR i := 0 TO a.Dimension()-1 DO
    result := result + a.elements[i]*b.elements[i];
  END;
  RETURN result;
END ScalarProduct;


PROCEDURE (a: VECTOR) Angle * (b: VECTOR): LONGREAL;
(*
 * Determine angle between by a and b.
 *
 *)

BEGIN
  RETURN MATHLIB.ACOS(a.ScalarProduct(b) / (a.Norm() * b.Norm()));
END Angle;


PROCEDURE (a: VECTOR) SMul * (r: LONGREAL): VECTOR;
(*
 * multiply a by r.
 *
 * ensure
 *   a.Norm() = r * OLD a.Norm();
 *)

VAR
  new: VECTOR;
  i: LONGINT;

BEGIN
  new := Create(a.Dimension());
  FOR i := 0 TO a.Dimension()-1 DO
    new.elements[i] := r * a.elements[i];
  END;
  RETURN new;
END SMul;


END VECTOR.


