-- Copyright (C) 1983  by Xerox Corporation. All rights reserved. 
-- IVector.mesa - last edited by
-- Poskanzer 	23-May-83 20:02:37

DIRECTORY
  Window USING [Place];

IVector: DEFINITIONS =
  BEGIN

  -- These procedures are intended to abstract the concepts of point and vector.  The purpose of this is to make simple geometric manipulations in Mesa easier and more reliable (by virture of type checking).  A Vector can be thought of as a distance between points, or a translation that can be added to a point.  A point is a fixed location on the plane.  

  IPoint: TYPE = Window.Place;
  IVec: TYPE = RECORD [x, y: INTEGER];
  Angle: TYPE = REAL;

  -- The constants, Up and Right are provided so the user can orient things on the screen when necessary.  With these constants defined the user shouldn't have to ever access the internal representation of a Vector or a point.  In fact the defintion of these data types should be PRIVATE if that's possible.

  Right: IVec = [1, 0];
  Up: IVec = [0, 1];
  Zero: IVec = [0, 0];

  -- functions
  ArcTan: PROCEDURE [y, x: INTEGER] RETURNS [Angle];
  Sqrt: PROCEDURE [LONG INTEGER] RETURNS [INTEGER];
  Sign: PROCEDURE [INTEGER] RETURNS [INTEGER];  -- returns 1 if >= 0, else -1

  -- vector

  -- Go: makes a vector out of two points
  Go: PROCEDURE [from, to: IPoint] RETURNS [IVec];

  -- It makes sense to add IVecs to IPoints or IVecs to IVecs but not IPoints to Places.  This is becuase if you added points, as if they were IVecs, the result would depend on the position of the origin with respect to those points, and the user (of the interface) should know nothing about the origin or anything about the coordinate system.  For similar reasons you cannot take the dot product of a IVec and a IPoint, only dot products of IVecs are  allowed.

  -- Add: adds two vectors
  Add: PROCEDURE [v1, v2: IVec] RETURNS [IVec];

  -- Dot: the dot product of two vectors. Useful facts about dot products: If one of the vectors has a length of one the dot product is the length of the other vector projected orthogonally onto it.  The dot product of two vectors increases linearly as the length of one of the vectors is increased.  Dot[A,B] = Length[A] * Length[B] * Cos[angle between A and B].
  Dot: PROCEDURE [v1, v2: IVec] RETURNS [LONG INTEGER];

  -- Sub: The second argument is subtracted from the first
  Sub: PROCEDURE [v1, v2: IVec] RETURNS [IVec];

  -- AngleOf: Returns real angle of a vector.
  AngleOf: PROCEDURE [v: IVec] RETURNS [REAL];

  -- checks whether test is between ccw and cw.
  BetweenVector: PROCEDURE [cw, ccw, test: IVec] RETURNS [BOOLEAN];

  -- returns TRUE if test is to the "left" of ref when ref is viewed as going up
  LeftOf: PROCEDURE [ref, test: IVec] RETURNS [BOOLEAN];

  -- returns TRUE if test is to the "right" of ref when ref is viewed as going up
  RightOf: PROCEDURE [ref, test: IVec] RETURNS [BOOLEAN];

  -- returns TRUE if angle bewteen v1 anf v2 is less than 90
  SameDirection: PROCEDURE [v1, v2: IVec] RETURNS [BOOLEAN];

  -- Length: length of a vector
  Length: PROC [v: IVec] RETURNS [INTEGER];

  -- LenSqrd: returns the length of a vector squared
  LenSqrd: PROCEDURE [v: IVec] RETURNS [LONG INTEGER];

  -- Scale: scales a vector by a scalar
  Scale: PROCEDURE [v: IVec, scale: REAL] RETURNS [IVec];

  -- VectorOfLength: returns a vector of length l in the same direction as v
  VectorOfLength: PROCEDURE [v: IVec, l: INTEGER] RETURNS [IVec];

  -- Minus: negates a vector
  Minus: PROCEDURE [v: IVec] RETURNS [IVec];

  -- Rotate90CCW: rotates a vector 90 degrees counterclockwise.
  Rotate90CCW: PROCEDURE [v: IVec] RETURNS [IVec];

  -- Rotate90CW: rotates a vector 90 degrees clockwise.
  Rotate90CW: PROCEDURE [v: IVec] RETURNS [IVec];

  -- SubPoint, and AddPoint: Used to subtract or add a IVec to a IPoint, returns a IPoint.
  AddPoint: PROCEDURE [p: IPoint, v: IVec] RETURNS [IPoint];
  SubPoint: PROCEDURE [p: IPoint, v: IVec] RETURNS [IPoint];

  -- Between: takes three vectors as arguments.  If test or Minus[test] is between cw and ccw (going clockwise) then TRUE is returned.
  Between: PROCEDURE [cw, ccw, test: IVec] RETURNS [BOOLEAN];

  -- Combine: multiplies the vectors by their respective scalars and adds them together.
  Combine: PROCEDURE [v1: IVec, s1: INTEGER, v2: IVec, s2: INTEGER]
    RETURNS [IVec];

  -- Det: The determinant of two vectors is equal to: SIN[angle between the vectors]*length1*length2. If the arc going counter clockwise from "cw" to "ccw" is less than 180 degrees then the result will be positive.   
  Det: PROCEDURE [cw, ccw: IVec] RETURNS [LONG INTEGER];

  -- Colinear: checks to see if the three points are on a line.
  Colinear: PROCEDURE [p1, p2, p3: IPoint] RETURNS [BOOLEAN];

  -- Parallel: checks to see if the two vectors are parallel.
  Parallel: PROCEDURE [v1, v2: IVec] RETURNS [BOOLEAN];

  -- Coeffs: computes c1 and c2 such that v = c1*basis1 + c2*basis2.
  Coeffs: PROCEDURE [basis1, basis2, v: IVec] RETURNS [c1, c2: REAL];

  -- Intersect: finds the intersection point of two rooted vectors.
  Intersect: PROCEDURE [v1: IVec, p1: IPoint, v2: IVec, p2: IPoint]
    RETURNS [p: IPoint];

  END.