/***************************************************************
 * PrVector3.cpp
 *
 * This implements a 3x1 vector class.
 *
 ****************************************************************/

/*
 * modification history
 *----------------------
 *
 * 11/20/97: K.C. Chang: added inline methods.
 * 11/05/97: K.C. Chang: created.
 */

#include "PrVector3.h"
#include "PrMatrix3.h"
#include <math.h>
#include <iostream.h>

PrVector3 PrVector3::operator-() const
{
    return PrVector3(-data_[0],-data_[1],-data_[2]);
}

void PrVector3::negate(PrVector3 &dest) const
{
    dest.data_[0] = -data_[0];
    dest.data_[1] = -data_[1];
    dest.data_[2] = -data_[2];
}

PrVector3 PrVector3::operator+(const PrVector3 &v) const
{
    return PrVector3(data_[0] + v.data_[0],
		     data_[1] + v.data_[1],
		     data_[2] + v.data_[2]);
}

void PrVector3::add(const PrVector3 &v,PrVector3 &dest) const
{
    dest.data_[0] = data_[0] + v.data_[0];
    dest.data_[1] = data_[1] + v.data_[1];
    dest.data_[2] = data_[2] + v.data_[2];
}

PrVector3 PrVector3::operator-(const PrVector3 &v) const
{
    return PrVector3(data_[0] - v.data_[0],
		     data_[1] - v.data_[1],
		     data_[2] - v.data_[2]);
}

void PrVector3::subtract(const PrVector3 &v,PrVector3 &dest) const
{
    dest.data_[0] = data_[0] - v.data_[0];
    dest.data_[1] = data_[1] - v.data_[1];
    dest.data_[2] = data_[2] - v.data_[2];
}


PrVector3 PrVector3::operator*(Float s) const
{
    return PrVector3(data_[0] * s,
		     data_[1] * s,
		     data_[2] * s);
}

void PrVector3::multiply(Float s,PrVector3 &dest) const
{
    dest.data_[0] = data_[0]*s;
    dest.data_[1] = data_[1]*s;
    dest.data_[2] = data_[2]*s;
}

PrVector3 PrVector3::operator*(const PrVector3 &v) const
{
    return PrVector3(data_[0] * v.data_[0],
		     data_[1] * v.data_[1],
		     data_[2] * v.data_[2]);
}

void PrVector3::multiply(const PrVector3 &v,PrVector3 &dest) const
{
    dest.data_[0] = data_[0] * v.data_[0];
    dest.data_[1] = data_[1] * v.data_[1];
    dest.data_[2] = data_[2] * v.data_[2];
}

PrVector3 &PrVector3::operator+=(const PrVector3 &v)
{
    data_[0] += v.data_[0];
    data_[1] += v.data_[1];
    data_[2] += v.data_[2];
    return (*this);
}

PrVector3 &PrVector3::operator-=(const PrVector3 &v)
{
    data_[0] -= v.data_[0];
    data_[1] -= v.data_[1];
    data_[2] -= v.data_[2];
    return (*this);
}

PrVector3 &PrVector3::operator*=(Float s)
{
    data_[0] *= s;
    data_[1] *= s;
    data_[2] *= s;
    return (*this);
}

// return mat = (*this) * v^T
PrMatrix3 PrVector3::multiplyTransposed(const PrVector3 &v) const
{
  return PrMatrix3(data_[0]*v.data_[0],
		   data_[0]*v.data_[1],
		   data_[0]*v.data_[2],

		   data_[1]*v.data_[0],
		   data_[1]*v.data_[1],
		   data_[1]*v.data_[2],

		   data_[2]*v.data_[0],
		   data_[2]*v.data_[1],
		   data_[2]*v.data_[2]);
}

void PrVector3::multiplyTransposed(const PrVector3 &v,PrMatrix3 &dest) const
{
    dest[0][0]=  data_[0]*v.data_[0];
    dest[0][1]=  data_[0]*v.data_[1];
    dest[0][2]=  data_[0]*v.data_[2];

    dest[1][0]=  data_[1]*v.data_[0];
    dest[1][1]=  data_[1]*v.data_[1];
    dest[1][2]=  data_[1]*v.data_[2];

    dest[2][0]=  data_[2]*v.data_[0];
    dest[2][1]=  data_[2]*v.data_[1];
    dest[2][2]=  data_[2]*v.data_[2];
}

Float PrVector3::dot(const PrVector3 &v) const
{
    return (data_[0]*v.data_[0]
	    + data_[1]*v.data_[1]
	    + data_[2]*v.data_[2]);
}

PrVector3 PrVector3::cross(const PrVector3 &v) const
{
    return PrVector3(data_[1]*v.data_[2] - data_[2]*v.data_[1],
		     data_[2]*v.data_[0] - data_[0]*v.data_[2],
		     data_[0]*v.data_[1] - data_[1]*v.data_[0]);
}

void PrVector3::cross(const PrVector3 &v,PrVector3 &dest) const
{
    dest.data_[0] = data_[1]*v.data_[2] - data_[2]*v.data_[1];
    dest.data_[1] = data_[2]*v.data_[0] - data_[0]*v.data_[2];
    dest.data_[2] = data_[0]*v.data_[1] - data_[1]*v.data_[0];
}

// [x y z] X = [0 -z y; z 0 -x; -y x 0]
PrMatrix3 PrVector3::cross() const
{
    return PrMatrix3(      0.0, -data_[2],  data_[1],
		      data_[2],       0.0, -data_[0],
		     -data_[1],  data_[0],       0.0);
}

void PrVector3::cross(PrMatrix3 &dest) const
{
    dest[0][0]=       0.0; dest[0][1]= -data_[2]; dest[0][2]=  data_[1];
    dest[1][0]=  data_[2]; dest[1][1]=       0.0; dest[1][2]= -data_[0];
    dest[2][0]= -data_[1]; dest[2][1]=  data_[0]; dest[2][2]=       0.0;
}

Float PrVector3::magnitude() const
{
    return sqrt(dot(*this));
}

void PrVector3::normalize()
{
    (*this) *= 1.0/magnitude();
}

void PrVector3::display(char *name)
{
    if (name != NULL)
      cout << name << '\n';

    cout << '(' << data_[0] << ", " << data_[1] << ", " << data_[2] << ')';
}
