You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

260 lines
5.9 KiB
C++

/**
* @file vector3d.cc
*
* @auhtor Remus Claudiu Dumitru <r.dumitru@jacobs-university.de>
* @date 16 Feb 2012
*
*/
//==============================================================================
// Includes
//==============================================================================
#include "model/vector3d.h"
#include "model/util.h"
#include <math.h>
using namespace model;
//==============================================================================
// Implementation
//==============================================================================
model::Vector3d::Vector3d() {
// nothing to do
}
model::Vector3d::Vector3d(const double& x, const double& y, const double& z) {
this->x = x;
this->y = y;
this->z = z;
}
// constructor for vector b - a, where a and b are points
model::Vector3d::Vector3d(const Point3d& a, const Point3d& b) {
this->x = b.x - a.x;
this->y = b.y - a.y;
this->z = b.z - a.z;
}
model::Vector3d::Vector3d(const Vector3d& other) {
this->x = other.x;
this->y = other.y;
this->z = other.z;
}
model::Vector3d& model::Vector3d::operator=(const model::Vector3d& other) {
if (this != &other) {
this->x = other.x;
this->y = other.y;
this->z = other.z;
}
return *this;
}
// normalizes the vector
void model::Vector3d::normalize() {
// squares
double sx = sqr(this->x);
double sy = sqr(this->y);
double sz = sqr(this->z);
double len = sqrt(sx + sy + sz);
// avoid a division by zero
if (len == 0.0) {
len = 1.0;
}
// normalize the values
this->x /= len;
this->y /= len;
this->z /= len;
// increase precision, this accounts for the lost digits
this->x = round(this->x * 10000) / 10000;
this->y = round(this->y * 10000) / 10000;
this->z = round(this->z * 10000) / 10000;
}
// inverses the vector
void model::Vector3d::invert() {
this->x *= (-1);
this->y *= (-1);
this->z *= (-1);
}
// get the length
double model::Vector3d::length() const {
return sqrt(sqr(this->x) + sqr(this->y) + sqr(this->z));
}
// rotation of a vector is like a point around 0 0 0
void model::Vector3d::rotate(const Rotation3d& rot) {
// create rotation matrices
double Rx[3][3] = {
{1.0, 0.0, 0.0},
{0.0, +cos(rot.x), -sin(rot.x)},
{0.0, +sin(rot.x), +cos(rot.x)}
};
double Ry[3][3] = {
{+cos(rot.y), 0.0, +sin(rot.y)},
{0.0, 1.0, 0.0},
{-sin(rot.y), 0.0, +cos(rot.y)}
};
double Rz[3][3] = {
{+cos(rot.z), -sin(rot.z), 0.0},
{+sin(rot.z), +cos(rot.z), 0.0},
{0.0, 0.0, 1.0}
};
// convert to something easier to use
double point[3];
point[0] = this->x;
point[1] = this->y;
point[2] = this->z;
// somewhere to save the result
double temp[3];
// do rotation around z axis
for (int i = 0; i < 3; ++i) {
// reset the sum
double sum = 0.0;
for (int j = 0; j < 3; ++j) {
sum += (Rz[i][j] * point[j]);
}
// save the result
temp[i] = sum;
}
// move results for next rotation
for (int i = 0; i < 3; ++i) {
point[i] = temp[i];
}
// do rotation around y axis
for (int i = 0; i < 3; ++i) {
// reset the sum
double sum = 0.0;
for (int j = 0; j < 3; ++j) {
sum += (Ry[i][j] * point[j]);
}
// save the result
temp[i] = sum;
}
// move results for next rotation
for (int i = 0; i < 3; ++i) {
point[i] = temp[i];
}
// do rotation around z axis
for (int i = 0; i < 3; ++i) {
// reset the sum
double sum = 0.0;
for (int j = 0; j < 3; ++j) {
sum += (Rx[i][j] * point[j]);
}
// save the result
temp[i] = sum;
}
// move results for next rotation
for (int i = 0; i < 3; ++i) {
point[i] = temp[i];
}
// save the results
this->x = point[0];
this->y = point[1];
this->z = point[2];
}
// computes the cross product between this vector and another given one
model::Vector3d model::Vector3d::crossProduct(const Vector3d& other) const {
Vector3d ret;
double a1 = this->x;
double a2 = this->y;
double a3 = this->z;
double b1 = other.x;
double b2 = other.y;
double b3 = other.z;
ret.x = a2 * b3 - a3 * b2;
ret.y = a3 * b1 - a1 * b3;
ret.z = a1 * b2 - a2 * b1;
return ret;
}
// computes the dot product between this vector and another given one
double model::Vector3d::dotProduct(const Vector3d& other) const {
return this->x * other.x +
this->y * other.y +
this->z * other.z;
}
// FIXME use atan2, computes the angle between two vectors
double model::Vector3d::angle(const Vector3d& other) {
double len1 = this->length();
double len2 = other.length();
if (len1 == 0 || len2 == 0) {
return 0;
}
return acos(
this->dotProduct(other) / (len1 * len2)
);
}
void model::Vector3d::operator+=(const Vector3d& other) {
this->x += other.x;
this->y += other.y;
this->z += other.z;
}
model::Vector3d model::Vector3d::operator+(const Vector3d& other) {
Vector3d result;
result.x = this->x + other.x;
result.y = this->y + other.y;
result.z = this->z + other.z;
return result;
}
model::Vector3d model::Vector3d::operator*(const double& val) {
Vector3d result;
result.x = this->x * val;
result.y = this->y * val;
result.z = this->z * val;
return result;
}
void model::Vector3d::operator/=(const double& div) {
this->x /= div;
this->y /= div;
this->z /= div;
}
std::ostream& model::operator<<(std::ostream& os, const model::Vector3d& vect) {
os << vect.x << " " << vect.y << " " << vect.z;
return os;
}