/*******************************************************************************
+
+  LEDA 3.5
+
+  _vector.c
+
+  This file is part of the LEDA research version (LEDA-R) that can be 
+  used free of charge in academic research and teaching. Any commercial
+  use of this software requires a license which is distributed by the
+  LEDA Software GmbH, Postfach 151101, 66041 Saarbruecken, FRG
+  (fax +49 681 31104).
+
+  Copyright (c) 1991-1997  by  Max-Planck-Institut fuer Informatik
+  Im Stadtwald, 66123 Saarbruecken, Germany     
+  All rights reserved.
+ 
*******************************************************************************/

//------------------------------------------------------------------------------
// Vectors of real numbers
//
// S. Naeher (1996)
//------------------------------------------------------------------------------

#include <LEDA/vector.h>
#include <math.h>



void vector::check_dimensions(const vector& vec) const
{ if (d!=vec.d)
   error_handler(1,"vector arguments have different dimensions.");
 }


vector::vector() 
{ d = 0; 
  v = nil;
 }


vector::vector(int n) 
{ 
 if (n<0) error_handler(1,"vector: negative dimension."); 
 d = n; 
 v = nil;
 if (d > 0)
 { v = (double*)std_memory.allocate_bytes(d*sizeof(double));
   while (n--) v[n] = 0.0;
  }
}


vector::~vector() 
{ if (v) std_memory.deallocate_bytes(v,d*sizeof(double)); }


vector::vector(const vector& p) 
{ d = p.d; 
  v = nil;
  if (d > 0)
  { v = (double*)std_memory.allocate_bytes(d*sizeof(double));
    for(int i=0; i<d; i++) v[i] = p.v[i];
   }
}



vector::vector(double x, double y) 
{ v = (double*)std_memory.allocate_bytes(2*sizeof(double));
  d = 2;
  v[0] = x;
  v[1] = y;
 }

vector::vector(double x, double y, double z) 
{ v = (double*)std_memory.allocate_bytes(3*sizeof(double));
  d = 3;
  v[0] = x;
  v[1] = y;
  v[2] = z;
 }


vector vector::rotate90() const
{ if (d !=2)  error_handler(1,"vector::rotate90: dimension must be two. ");
  return vector(-v[1],v[0]);
}

vector vector::rotate(double fi ) const
{ if (d !=2)  error_handler(1,"vector::rotate: dimension must be two. ");
  double sinfi = sin(fi);
  double cosfi = cos(fi);
  return vector(v[0]*cosfi-v[1]*sinfi,v[0]*sinfi+v[1]*cosfi);
}


double  vector::operator[](int i) const
{ if (i<0 || i>=d)  error_handler(1,"vector: index out of range ");
  return v[i]; 
}

double& vector::operator[](int i)
{ if (i<0 || i>=d)  error_handler(1,"vector: index out of range ");
  return v[i]; 
}


vector& vector::operator+=(const vector& vec)
{ check_dimensions(vec);
  int n = d;
  while (n--) v[n] += vec.v[n];
  return *this;
}

vector& vector::operator-=(const vector& vec)
{ check_dimensions(vec);
  int n = d;
  while (n--) v[n] -= vec.v[n];
  return *this;
}

vector vector::operator+(const vector& vec) const
{ check_dimensions(vec);
  int n = d;
  vector result(n);
  while (n--) result.v[n] = v[n]+vec.v[n];
  return result;
}

vector vector::operator-(const vector& vec) const
{ check_dimensions(vec);
  int n = d;
  vector result(n);
  while (n--) result.v[n] = v[n]-vec.v[n];
  return result;
}

vector vector::operator-() const  // unary minus
{ int n = d;
  vector result(n);
  while (n--) result.v[n] = -v[n];
  return result;
}


vector vector::operator*(double x) const
{ int n = d;
  vector result(n);
  while (n--) result.v[n] = v[n] * x;
  return result;
}

vector vector::operator/(double x) const
{ int n = d;
  vector result(n);
  while (n--) result.v[n] = v[n] / x;
  return result;
}

double vector::operator*(const vector& vec) const
{ check_dimensions(vec);
  double result=0;
  int n = d;
  while (n--) result = result+v[n]*vec.v[n];
  return result;
}

vector& vector::operator=(const vector& vec)
{ 
  if (d != vec.d)
  { if (v)
      std_memory.deallocate_bytes(v,d*sizeof(double));

    d = vec.d;

    if (d > 0)
      v = (double*)std_memory.allocate_bytes(d*sizeof(double));
    else
      v = 0;
   }

  for(int i=0; i<d; i++) v[i] = vec.v[i];

  return *this;
}


bool vector::operator==(const vector& vec)  const
{ if (vec.d != d) return false;
  int i = 0;
  while ((i<d) && (v[i]==vec.v[i])) i++;
  return (i==d) ? true : false;
 }


void vector::read(istream& is) 
{ for(int i=0;i<d;i++) is  >> v[i]; }

void vector::print(ostream& os) 
{ os << "(";
  for(int i=0;i<d;i++) os << string(" %6.2f",v[i]);
  os << " )";
}



ostream& operator<<(ostream& os, const vector& v)
{ os << v.d << " ";
  for (int i=0;i<v.d;i++) os << " " << v[i];
  return os;
}


istream& operator>>(istream& is, vector& v) 
{ int d;
  is >> d;
  vector w(d);
  for (int i=0;i<d;i++) is >> w[i];
  v = w;
  return is; 
} 


double vector::sqr_length() const { return *this * *this; }

double vector::length() const { return sqrt(sqr_length()); }


double vector::angle(const vector& y)  const
{ double l = length();
  double yl = y.length();

  if ( l==0 || yl==0)
    error_handler(1,"angle: zero argument\n");

  return  acos((*this)*y/(l*yl));  
}

