/*************************************************************************** * Copyright (c) 2005 Imetric 3D GmbH * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library 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 Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ #include #endif #include #include #include "Vector3D.h" #include "Tools.h" using namespace Base; template Vector3::Vector3(float_type fx, float_type fy, float_type fz) : x(fx) , y(fy) , z(fz) {} template float_type& Vector3::operator[](unsigned short usIndex) { switch (usIndex) { case 0: return x; case 1: return y; case 2: return z; } return x; } template const float_type& Vector3::operator[](unsigned short usIndex) const { switch (usIndex) { case 0: return x; case 1: return y; case 2: return z; } return x; } template Vector3 Vector3::operator+(const Vector3& rcVct) const { Vector3 cVctRes; cVctRes.x = x + rcVct.x; cVctRes.y = y + rcVct.y; cVctRes.z = z + rcVct.z; return cVctRes; } template Vector3 Vector3::operator&(const Vector3& rcVct) const { Vector3 cVctRes; cVctRes.x = x * (float_type)fabs(rcVct.x); cVctRes.y = y * (float_type)fabs(rcVct.y); cVctRes.z = z * (float_type)fabs(rcVct.z); return cVctRes; } template Vector3 Vector3::operator-(const Vector3& rcVct) const { Vector3 cVctRes; cVctRes.x = x - rcVct.x; cVctRes.y = y - rcVct.y; cVctRes.z = z - rcVct.z; return cVctRes; } template Vector3 Vector3::operator-() const { return Vector3(-x, -y, -z); } template Vector3& Vector3::operator+=(const Vector3& rcVct) { x += rcVct.x; y += rcVct.y; z += rcVct.z; return *this; } template Vector3& Vector3::operator-=(const Vector3& rcVct) { x -= rcVct.x; y -= rcVct.y; z -= rcVct.z; return *this; } template Vector3& Vector3::operator*=(float_type fScale) { x *= fScale; y *= fScale; z *= fScale; return *this; } template Vector3& Vector3::operator/=(float_type fDiv) { x /= fDiv; y /= fDiv; z /= fDiv; return *this; } template Vector3 Vector3::operator*(float_type fScale) const { return Vector3(this->x * fScale, this->y * fScale, this->z * fScale); } template Vector3 Vector3::operator/(float_type fDiv) const { return Vector3(this->x / fDiv, this->y / fDiv, this->z / fDiv); } template float_type Vector3::operator*(const Vector3& rcVct) const { return (x * rcVct.x) + (y * rcVct.y) + (z * rcVct.z); } template float_type Vector3::Dot(const Vector3& rcVct) const { return (x * rcVct.x) + (y * rcVct.y) + (z * rcVct.z); } template Vector3 Vector3::operator%(const Vector3& rcVct) const { Vector3 cVctRes; cVctRes.x = (y * rcVct.z) - (z * rcVct.y); cVctRes.y = (z * rcVct.x) - (x * rcVct.z); cVctRes.z = (x * rcVct.y) - (y * rcVct.x); return cVctRes; } template Vector3 Vector3::Cross(const Vector3& rcVct) const { Vector3 cVctRes; cVctRes.x = (y * rcVct.z) - (z * rcVct.y); cVctRes.y = (z * rcVct.x) - (x * rcVct.z); cVctRes.z = (x * rcVct.y) - (y * rcVct.x); return cVctRes; } template bool Vector3::IsOnLineSegment(const Vector3& startVct, const Vector3& endVct) const { Vector3 vectorAB = endVct - startVct; Vector3 vectorAC = *this - startVct; Vector3 crossproduct = vectorAB.Cross(vectorAC); float_type dotproduct = vectorAB.Dot(vectorAC); if (crossproduct.Length() > traits_type::epsilon()) { return false; } if (dotproduct < 0) { return false; } if (dotproduct > vectorAB.Sqr()) { return false; } return true; } template bool Vector3::operator!=(const Vector3& rcVct) const { return !((*this) == rcVct); } template bool Vector3::operator==(const Vector3& rcVct) const { return (std::fabs(x - rcVct.x) <= traits_type::epsilon()) && (std::fabs(y - rcVct.y) <= traits_type::epsilon()) && (std::fabs(z - rcVct.z) <= traits_type::epsilon()); } template bool Vector3::IsEqual(const Vector3& rclPnt, float_type tol) const { return Distance(*this, rclPnt) <= tol; } template bool Vector3::IsParallel(const Vector3& rclDir, float_type tol) const { float_type angle = GetAngle(rclDir); if (boost::math::isnan(angle)) { return false; } return angle <= tol || traits_type::pi() - angle <= tol; } template bool Vector3::IsNormal(const Vector3& rclDir, float_type tol) const { float_type angle = GetAngle(rclDir); if (boost::math::isnan(angle)) { return false; } float_type diff = std::abs(traits_type::pi() / 2.0 - angle); // NOLINT return diff <= tol; } template Vector3& Vector3::ProjectToPlane(const Vector3& rclBase, const Vector3& rclNorm) { Vector3 clTemp(rclNorm); *this = *this - (clTemp *= ((*this - rclBase) * clTemp) / clTemp.Sqr()); return *this; } template void Vector3::ProjectToPlane(const Vector3& rclBase, const Vector3& rclNorm, Vector3& rclProj) const { Vector3 clTemp(rclNorm); rclProj = *this - (clTemp *= ((*this - rclBase) * clTemp) / clTemp.Sqr()); } template float_type Vector3::DistanceToPlane(const Vector3& rclBase, const Vector3& rclNorm) const { return ((*this - rclBase) * rclNorm) / rclNorm.Length(); } template float_type Vector3::Length() const { return static_cast(std::sqrt((x * x) + (y * y) + (z * z))); } template float_type Vector3::DistanceToLine(const Vector3& base, const Vector3& dir) const { // clang-format off return static_cast(std::fabs((dir % Vector3(*this - base)).Length() / dir.Length())); // clang-format on } template Vector3 Vector3::DistanceToLineSegment(const Vector3& rclP1, const Vector3& rclP2) const { float_type len2 = Base::DistanceP2(rclP1, rclP2); if (len2 == 0) { return rclP1; } Vector3 p2p1 = rclP2 - rclP1; Vector3 pXp1 = *this - rclP1; float_type dot = pXp1 * p2p1; float_type t = clamp(dot / len2, 0, 1); Vector3 dist = t * p2p1 - pXp1; return dist; } template Vector3& Vector3::ProjectToLine(const Vector3& rclPoint, const Vector3& rclLine) { return (*this = ((((rclPoint * rclLine) / rclLine.Sqr()) * rclLine) - rclPoint)); } template Vector3 Vector3::Perpendicular(const Vector3& rclBase, const Vector3& rclDir) const { float_type t = ((*this - rclBase) * rclDir) / (rclDir * rclDir); return rclBase + t * rclDir; } template float_type Vector3::Sqr() const { return (float_type)((x * x) + (y * y) + (z * z)); } template void Vector3::Set(float_type fX, float_type fY, float_type fZ) { x = fX; y = fY; z = fZ; } template void Vector3::ScaleX(float_type f) { x *= f; } template void Vector3::ScaleY(float_type f) { y *= f; } template void Vector3::ScaleZ(float_type f) { z *= f; } template void Vector3::Scale(float_type fX, float_type fY, float_type fZ) { x *= fX; y *= fY; z *= fZ; } template void Vector3::MoveX(float_type f) { x += f; } template void Vector3::MoveY(float_type f) { y += f; } template void Vector3::MoveZ(float_type f) { z += f; } template void Vector3::Move(float_type fX, float_type fY, float_type fZ) { x += fX; y += fY; z += fZ; } template void Vector3::RotateX(float_type f) { Vector3 cPt(*this); float_type fsin = static_cast(sin(f)); float_type fcos = static_cast(cos(f)); y = (cPt.y * fcos) - (cPt.z * fsin); z = (cPt.y * fsin) + (cPt.z * fcos); } template void Vector3::RotateY(float_type f) { Vector3 cPt(*this); float_type fsin = static_cast(sin(f)); float_type fcos = static_cast(cos(f)); x = (cPt.z * fsin) + (cPt.x * fcos); z = (cPt.z * fcos) - (cPt.x * fsin); } template void Vector3::RotateZ(float_type f) { Vector3 cPt(*this); float_type fsin = static_cast(sin(f)); float_type fcos = static_cast(cos(f)); x = (cPt.x * fcos) - (cPt.y * fsin); y = (cPt.x * fsin) + (cPt.y * fcos); } template Vector3& Vector3::Normalize() { float_type fLen = Length(); if (fLen != static_cast(0.0) && fLen != static_cast(1.0)) { x /= fLen; y /= fLen; z /= fLen; } return *this; } template bool Vector3::IsNull() const { float_type n {0.0}; return (x == n) && (y == n) && (z == n); } template float_type Vector3::GetAngle(const Vector3& rcVect) const { float_type len1 = Length(); float_type len2 = rcVect.Length(); if (len1 <= traits_type::epsilon() || len2 <= traits_type::epsilon()) { return std::numeric_limits::quiet_NaN(); // division by zero } float_type dot = Dot(rcVect); dot /= len1; dot /= len2; if (dot <= -1.0) { return traits_type::pi(); } if (dot >= 1.0) { return 0.0; } return float_type(acos(dot)); } template float_type Vector3::GetAngleOriented(const Vector3& rcVect, const Vector3& norm) const { float_type angle = GetAngle(rcVect); Vector3 crossProduct = Cross(rcVect); // Use dot product to determine the sign float_type dot = crossProduct.Dot(norm); if (dot < 0) { angle = 2 * traits_type::pi() - angle; } return angle; } template void Vector3::TransformToCoordinateSystem(const Vector3& rclBase, const Vector3& rclDirX, const Vector3& rclDirY) { Vector3 clVectX; Vector3 clVectY; Vector3 clVectZ; Vector3 clVectOld; clVectX = rclDirX; clVectY = rclDirY; clVectZ = rclDirX % rclDirY; clVectX.Normalize(); clVectY.Normalize(); clVectZ.Normalize(); clVectOld = *this - rclBase; x = clVectX * clVectOld; y = clVectY * clVectOld; z = clVectZ * clVectOld; } // explicit template instantiation namespace Base { template class BaseExport Vector3; template class BaseExport Vector3; } // namespace Base