//  Vamos Automotive Simulator
//  Copyright (C) 2001--2002 Sam Varner
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#ifndef _THREE_VECTOR_H_
#define _THREE_VECTOR_H_

#include <iostream>
#include <cmath>

// A three-element vector.  Useful for representing physical quantites
// like position, veocity or force.

namespace Vamos_Geometry
{
  class Two_Vector;

  struct Three_Vector
  {
    // The components of the vector.
    double x;
    double y;
    double z;

    Three_Vector ();
    Three_Vector (double length, double angle);
    Three_Vector (double x_in, double y_in, double z_in);
    Three_Vector (const Two_Vector& xy_vector);

    // Set each element to zero.
    void zero ();
    // Return the magnitude of the vector.
    inline double magnitude () const;
    // True if all elements are zero.
    bool null () const;
    // Return the dot product with VEC.
    double dot (const Three_Vector& vec) const;
    // Return the cross product with VEC.
    Three_Vector cross (const Three_Vector& vec) const;
    // Return the projection onto VEC.
    Three_Vector project (const Three_Vector& vec) const;
    // Return the vector in the direction of the argument that would
    // yield this vector when projected.  This is the inverse of
    // project().
    Three_Vector back_project (const Three_Vector& vec) const;

    // Return the pependicular distance between vectors parallel to
    // this one passing through the given points.
    double perp_distance (const Three_Vector& point1,
                          const Three_Vector& point2) const;

    // The unit vector that points along this vector.
    Three_Vector unit () const;
    // The component of this vector projected onto another vector.
    double component (const Three_Vector& vec) const;
    // The angle between this vector and another.
    double angle (const Three_Vector& vec) const;

    Three_Vector& rotate (double x, double y, double z);
    Three_Vector rotate (double x, double y, double z) const;

    // These operators must be members of the class because they modify
    // class members.
    Three_Vector& operator += (const Three_Vector& vec);
    Three_Vector& operator -= (const Three_Vector& vec);
    Three_Vector& operator *= (double factor);
    Three_Vector& operator /= (double factor);

    static const Three_Vector X;
    static const Three_Vector Y;
    static const Three_Vector Z;
  };

  // Return the magnitude.
  double
  Three_Vector::magnitude () const
  {
    return sqrt (x*x + y*y + z*z);
  }

  // Addition operator.
  Three_Vector operator + (const Three_Vector& vec1, 
                                 const Three_Vector& vec2);
  // Subtraction operator.
  Three_Vector operator - (const Three_Vector& vec1, 
                                 const Three_Vector& vec2);
  // Negation operator.
  Three_Vector operator - (const Three_Vector& vec);
  // Scalar multiplication operators.
  Three_Vector operator * (const Three_Vector& vec1, double factor);
  Three_Vector operator * (double factor, const Three_Vector& vec1);
  // Scalar division operators.
  Three_Vector operator / (const Three_Vector& vec1, double factor);

  bool operator == (const Three_Vector& vec1, const Three_Vector& vec2);

  // Stream operators.
  std::istream& operator >> (std::istream& is, Three_Vector& vec);
  std::ostream& operator << (std::ostream& os, const Three_Vector& vec);
}

#endif
