#include "Spherical.h" #include "Angle.h" #include "Quaternion.h" #include template SphericalOf::SphericalOf() { this->distance = 0.0f; this->direction = DirectionOf(); } template SphericalOf::SphericalOf(float distance, AngleOf horizontal, AngleOf vertical) { if (distance < 0) { this->distance = -distance; this->direction = -DirectionOf(horizontal, vertical); } else { this->distance = distance; this->direction = DirectionOf(horizontal, vertical); } } template SphericalOf::SphericalOf(float distance, DirectionOf direction) { if (distance < 0) { this->distance = -distance; this->direction = -direction; } else { this->distance = distance; this->direction = direction; } } template SphericalOf SphericalOf::FromPolar(PolarOf polar) { AngleOf horizontal = polar.angle; AngleOf vertical = AngleOf(); SphericalOf r = SphericalOf(polar.distance, horizontal, vertical); return r; } template SphericalOf SphericalOf::FromVector3(Vector3 v) { float distance = v.magnitude(); if (distance == 0.0f) { return SphericalOf(distance, AngleOf(), AngleOf()); } else { AngleOf verticalAngle = AngleOf::Radians((pi / 2 - acosf(v.Up() / distance))); AngleOf horizontalAngle = AngleOf::Radians(atan2f(v.Right(), v.Forward())); return SphericalOf(distance, horizontalAngle, verticalAngle); } } /** * @brief Converts spherical coordinates to a 3D vector. * * This function converts the spherical coordinates represented by the * SphericalOf object to a 3D vector (Vector3). The conversion is based * on the distance and direction (vertical and horizontal angles) of the * spherical coordinates. * * @tparam T The type of the distance and direction values. * @return Vector3 The 3D vector representation of the spherical coordinates. */ template Vector3 SphericalOf::ToVector3() const { float verticalRad = (pi / 2) - this->direction.vertical.InRadians(); float horizontalRad = this->direction.horizontal.InRadians(); float cosVertical = cosf(verticalRad); float sinVertical = sinf(verticalRad); float cosHorizontal = cosf(horizontalRad); float sinHorizontal = sinf(horizontalRad); float x = this->distance * sinVertical * sinHorizontal; float y = this->distance * cosVertical; float z = this->distance * sinVertical * cosHorizontal; Vector3 v = Vector3(x, y, z); return v; } template const SphericalOf SphericalOf::zero = SphericalOf(0.0f, AngleOf(), AngleOf()); template const SphericalOf SphericalOf::forward = SphericalOf(1.0f, AngleOf(), AngleOf()); template const SphericalOf SphericalOf::back = SphericalOf(1.0f, AngleOf::Degrees(180), AngleOf()); template const SphericalOf SphericalOf::right = SphericalOf(1.0f, AngleOf::Degrees(90), AngleOf()); template const SphericalOf SphericalOf::left = SphericalOf(1.0f, AngleOf::Degrees(-90), AngleOf()); template const SphericalOf SphericalOf::up = SphericalOf(1.0f, AngleOf(), AngleOf::Degrees(90)); template const SphericalOf SphericalOf::down = SphericalOf(1.0f, AngleOf(), AngleOf::Degrees(-90)); template SphericalOf SphericalOf::WithDistance(float distance) { SphericalOf v = SphericalOf(distance, this->direction); return SphericalOf(); } template SphericalOf SphericalOf::operator-() const { SphericalOf v = SphericalOf( this->distance, this->direction.horizontal + AngleOf::Degrees(180), this->direction.vertical + AngleOf::Degrees(180)); return v; } template SphericalOf SphericalOf::operator-(const SphericalOf &s2) const { // let's do it the easy way... Vector3 v1 = this->ToVector3(); Vector3 v2 = s2.ToVector3(); Vector3 v = v1 - v2; SphericalOf r = SphericalOf::FromVector3(v); return r; } template SphericalOf SphericalOf::operator-=(const SphericalOf &v) { *this = *this - v; return *this; } template SphericalOf SphericalOf::operator+(const SphericalOf &s2) const { // let's do it the easy way... Vector3 v1 = this->ToVector3(); Vector3 v2 = s2.ToVector3(); Vector3 v = v1 + v2; SphericalOf r = SphericalOf::FromVector3(v); return r; /* // This is the hard way... if (v2.distance <= 0) return Spherical(this->distance, this->horizontalAngle, this->verticalAngle); if (this->distance <= 0) return v2; float deltaHorizontalAngle = (float)Angle::Normalize(v2.horizontalAngle - this->horizontalAngle); float horizontalRotation = deltaHorizontalAngle < 0 ? 180 + deltaHorizontalAngle : 180 - deltaHorizontalAngle; float deltaVerticalAngle = Angle::Normalize(v2.verticalAngle - this->verticalAngle); float verticalRotation = deltaVerticalAngle < 0 ? 180 + deltaVerticalAngle : 180 - deltaVerticalAngle; if (horizontalRotation == 180 && verticalRotation == 180) // angle is too small, take this angle and add the distances return Spherical(this->distance + v2.distance, this->horizontalAngle, this->verticalAngle); Angle rotation = AngleBetween(*this, v2); float newDistance = Angle::CosineRuleSide(v2.distance, this->distance, rotation); float angle = Angle::CosineRuleAngle(newDistance, this->distance, v2.distance); // Now we have to project the angle to the horizontal and vertical planes... // The axis for the angle is the cross product of the two spherical vectors // (which function we do not have either...) float horizontalAngle = 0; float verticalAngle = 0; float newHorizontalAngle = deltaHorizontalAngle < 0 ? Angle::Normalize(this->horizontalAngle - horizontalAngle) : Angle::Normalize(this->horizontalAngle + horizontalAngle); float newVerticalAngle = deltaVerticalAngle < 0 ? Angle::Normalize(this->verticalAngle - verticalAngle) : Angle::Normalize(this->verticalAngle + verticalAngle); Spherical v = Spherical(newDistance, newHorizontalAngle, newVerticalAngle); */ } template SphericalOf SphericalOf::operator+=(const SphericalOf &v) { *this = *this + v; return *this; } template SphericalOf SphericalOf::operator*=(float f) { this->distance *= f; return *this; } template SphericalOf SphericalOf::operator/=(float f) { this->distance /= f; return *this; } #include "FloatSingle.h" #include "Vector3.h" const float epsilon = 1E-05f; template float SphericalOf::DistanceBetween(const SphericalOf &v1, const SphericalOf &v2) { // SphericalOf difference = v1 - v2; // return difference.distance; Vector3 vec1 = v1.ToVector3(); Vector3 vec2 = v2.ToVector3(); float distance = Vector3::Distance(vec1, vec2); return distance; } template AngleOf SphericalOf::AngleBetween(const SphericalOf &v1, const SphericalOf &v2) { // float denominator = v1.distance * v2.distance; // if (denominator < epsilon) // return 0.0f; Vector3 v1_3 = v1.ToVector3(); Vector3 v2_3 = v2.ToVector3(); // float dot = Vector3::Dot(v1_3, v2_3); // float fraction = dot / denominator; // if (isnan(fraction)) // return fraction; // short cut to returning NaN universally // float cdot = Float::Clamp(fraction, -1.0, 1.0); // float r = ((float)acos(cdot)) * Rad2Deg; Angle r = Vector3::Angle(v1_3, v2_3); return AngleOf::Degrees(r.InDegrees()); } template AngleOf Passer::LinearAlgebra::SphericalOf::SignedAngleBetween( const SphericalOf &v1, const SphericalOf &v2, const SphericalOf &axis) { Vector3 v1_vector = v1.ToVector3(); Vector3 v2_vector = v2.ToVector3(); Vector3 axis_vector = axis.ToVector3(); Angle r = Vector3::SignedAngle(v1_vector, v2_vector, axis_vector); return AngleOf::Degrees(r.InDegrees()); } template SphericalOf SphericalOf::Rotate(const SphericalOf &v, AngleOf horizontalAngle, AngleOf verticalAngle) { SphericalOf r = SphericalOf(v.distance, v.direction.horizontal + horizontalAngle, v.direction.vertical + verticalAngle); return r; } template SphericalOf SphericalOf::RotateHorizontal(const SphericalOf &v, AngleOf a) { SphericalOf r = SphericalOf(v.distance, v.direction.horizontal + a, v.direction.vertical); return r; } template SphericalOf SphericalOf::RotateVertical(const SphericalOf &v, AngleOf a) { SphericalOf r = SphericalOf(v.distance, v.direction.horizontal, v.direction.vertical + a); return r; } template class SphericalOf; template class SphericalOf;