///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2025 Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // ResInsight 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 General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #pragma once #include "cvfMath.h" #include "cvfVector3.h" #include namespace Ria { //================================================================================================== // // Type-safe angle representation classes // //================================================================================================== template class Radians; template class Degrees { public: constexpr Degrees() : m_value( T{} ) { } constexpr explicit Degrees( T value ) : m_value( value ) { } constexpr Degrees( const Degrees& other ) : m_value( other.m_value ) { } constexpr Degrees( const Radians& radians ); constexpr T value() const { return m_value; } constexpr operator T() const { return m_value; } constexpr Degrees& operator=( const Degrees& other ) { m_value = other.m_value; return *this; } constexpr Degrees& operator=( const Radians& radians ); constexpr Degrees operator+( const Degrees& other ) const { return Degrees( m_value + other.m_value ); } constexpr Degrees operator-( const Degrees& other ) const { return Degrees( m_value - other.m_value ); } constexpr Degrees operator*( T scalar ) const { return Degrees( m_value * scalar ); } constexpr Degrees operator/( T scalar ) const { return Degrees( m_value / scalar ); } constexpr Degrees operator-() const { return Degrees( -m_value ); } constexpr Degrees& operator+=( const Degrees& other ) { m_value += other.m_value; return *this; } constexpr Degrees& operator-=( const Degrees& other ) { m_value -= other.m_value; return *this; } constexpr Degrees& operator*=( T scalar ) { m_value *= scalar; return *this; } constexpr Degrees& operator/=( T scalar ) { m_value /= scalar; return *this; } constexpr bool operator==( const Degrees& other ) const { return m_value == other.m_value; } constexpr bool operator!=( const Degrees& other ) const { return m_value != other.m_value; } constexpr bool operator<( const Degrees& other ) const { return m_value < other.m_value; } constexpr bool operator<=( const Degrees& other ) const { return m_value <= other.m_value; } constexpr bool operator>( const Degrees& other ) const { return m_value > other.m_value; } constexpr bool operator>=( const Degrees& other ) const { return m_value >= other.m_value; } Degrees normalized() const; private: T m_value; }; template class Radians { public: constexpr Radians() : m_value( T{} ) { } constexpr explicit Radians( T value ) : m_value( value ) { } constexpr Radians( const Radians& other ) : m_value( other.m_value ) { } constexpr Radians( const Degrees& degrees ); constexpr T value() const { return m_value; } constexpr operator T() const { return m_value; } constexpr Radians& operator=( const Radians& other ) { m_value = other.m_value; return *this; } constexpr Radians& operator=( const Degrees& degrees ); constexpr Radians operator+( const Radians& other ) const { return Radians( m_value + other.m_value ); } constexpr Radians operator-( const Radians& other ) const { return Radians( m_value - other.m_value ); } constexpr Radians operator*( T scalar ) const { return Radians( m_value * scalar ); } constexpr Radians operator/( T scalar ) const { return Radians( m_value / scalar ); } constexpr Radians operator-() const { return Radians( -m_value ); } constexpr Radians& operator+=( const Radians& other ) { m_value += other.m_value; return *this; } constexpr Radians& operator-=( const Radians& other ) { m_value -= other.m_value; return *this; } constexpr Radians& operator*=( T scalar ) { m_value *= scalar; return *this; } constexpr Radians& operator/=( T scalar ) { m_value /= scalar; return *this; } constexpr bool operator==( const Radians& other ) const { return m_value == other.m_value; } constexpr bool operator!=( const Radians& other ) const { return m_value != other.m_value; } constexpr bool operator<( const Radians& other ) const { return m_value < other.m_value; } constexpr bool operator<=( const Radians& other ) const { return m_value <= other.m_value; } constexpr bool operator>( const Radians& other ) const { return m_value > other.m_value; } constexpr bool operator>=( const Radians& other ) const { return m_value >= other.m_value; } Radians normalized() const; private: T m_value; }; // Cross-conversions between Degrees and Radians template constexpr Degrees::Degrees( const Radians& radians ) : m_value( cvf::Math::toDegrees( radians.value() ) ) { } template constexpr Degrees& Degrees::operator=( const Radians& radians ) { m_value = cvf::Math::toDegrees( radians.value() ); return *this; } template constexpr Radians::Radians( const Degrees& degrees ) : m_value( cvf::Math::toRadians( degrees.value() ) ) { } template constexpr Radians& Radians::operator=( const Degrees& degrees ) { m_value = cvf::Math::toRadians( degrees.value() ); return *this; } // Scalar multiplication (scalar * angle) template constexpr Degrees operator*( T scalar, const Degrees& degrees ) { return degrees * scalar; } template constexpr Radians operator*( T scalar, const Radians& radians ) { return radians * scalar; } // Type aliases using Degreesf = Degrees; using Degreesd = Degrees; using Radiansf = Radians; using Radiansd = Radians; //================================================================================================== // // Trigonometric functions for typed angles // //================================================================================================== template T sin( const Degrees& angle ) { return cvf::Math::sin( cvf::Math::toRadians( angle.value() ) ); } template T sin( const Radians& angle ) { return cvf::Math::sin( angle.value() ); } template T cos( const Degrees& angle ) { return cvf::Math::cos( cvf::Math::toRadians( angle.value() ) ); } template T cos( const Radians& angle ) { return cvf::Math::cos( angle.value() ); } template T tan( const Degrees& angle ) { return cvf::Math::tan( cvf::Math::toRadians( angle.value() ) ); } template T tan( const Radians& angle ) { return cvf::Math::tan( angle.value() ); } template Radians asin( T value ) { return Radians( cvf::Math::asin( value ) ); } template Radians acos( T value ) { return Radians( cvf::Math::acos( value ) ); } template Radians atan( T value ) { return Radians( cvf::Math::atan( value ) ); } template Radians atan2( T y, T x ) { return Radians( std::atan2( y, x ) ); } //================================================================================================== // // Coordinate system conversion utilities // //================================================================================================== struct CylindricalCoordinate { template CylindricalCoordinate( T radius, const Radians& angle, T height ) : radius( radius ) , angle( angle.value() ) , height( height ) { } template CylindricalCoordinate( T radius, const Degrees& angle, T height ) : radius( radius ) , angle( cvf::Math::toRadians( angle.value() ) ) , height( height ) { } double radius; double angle; // In radians double height; }; class CoordinateConverter { public: template static cvf::Vector3 cylindricalToCartesian( T radius, const Radians& angle, T height ); template static cvf::Vector3 cylindricalToCartesian( T radius, const Degrees& angle, T height ); template static cvf::Vector3 cylindricalToCartesian( const CylindricalCoordinate& coord ); template static CylindricalCoordinate cartesianToCylindrical( const cvf::Vector3& cartesian ); template static CylindricalCoordinate cartesianToCylindrical( T x, T y, T z ); }; //================================================================================================== // // Convenience functions for creating angle literals // //================================================================================================== constexpr Degreesd operator"" _deg( long double value ) { return Degreesd( static_cast( value ) ); } constexpr Degreesf operator"" _degf( long double value ) { return Degreesf( static_cast( value ) ); } constexpr Radiansd operator"" _rad( long double value ) { return Radiansd( static_cast( value ) ); } constexpr Radiansf operator"" _radf( long double value ) { return Radiansf( static_cast( value ) ); } } // namespace Ria #include "RiaAngleUtils.inl"