File indexing completed on 2024-05-19 04:45:53
0001 // SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com> 0002 // SPDX-License-Identifier: BSD-2-Clause OR MIT 0003 0004 // Own header 0005 #include "polarpointf.h" 0006 0007 // Other includes 0008 #include "helpermath.h" 0009 #include "helperposixmath.h" 0010 #include <cmath> 0011 #include <qdebug.h> 0012 #include <qmath.h> 0013 #include <type_traits> 0014 0015 namespace PerceptualColor 0016 { 0017 /** @brief Constructor 0018 * 0019 * Normalizes the given polar coordinates and constructs an object with 0020 * the <em>normalized</em> polar coordinates. See the general class 0021 * description for details about the normalization. 0022 * 0023 * @param newRadius the @ref radius() value 0024 * @param newAngleDegree the @ref angleDegree() value */ 0025 PolarPointF::PolarPointF(const double newRadius, const double newAngleDegree) 0026 : m_angleDegree(newAngleDegree) 0027 , m_radius(newRadius) 0028 { 0029 normalizePolar360(m_radius, m_angleDegree); 0030 } 0031 0032 /** @brief Constructor 0033 * 0034 * Constructs an object converting from the given Cartesian coordinates. 0035 * 0036 * If the Cartesian coordinates are (0, 0) than the @ref angleDegree (which is 0037 * meaningless for a @ref radius of 0) is set to 0°. 0038 * 0039 * @param cartesianCoordiantes the Cartesian coordinates */ 0040 PolarPointF::PolarPointF(const QPointF cartesianCoordiantes) 0041 { 0042 m_radius = sqrt( // 0043 pow(cartesianCoordiantes.x(), 2) + pow(cartesianCoordiantes.y(), 2)); 0044 if (m_radius == 0) { 0045 m_angleDegree = 0; 0046 return; 0047 } 0048 // NOTE As explained in https://en.wikipedia.org/wiki/Atan2 0049 // the function std::atan2() can be used to calculate the angle without 0050 // an “if” statement. However, it returns angles in the interval [-π, +π] 0051 // while we need [0°, 360°], so finally we could avoind an “if” statement 0052 // but need to add code for the range correction. Therefore, the current 0053 // approach seems fine. 0054 if (cartesianCoordiantes.y() >= 0) { 0055 m_angleDegree = qRadiansToDegrees( // 0056 acos(cartesianCoordiantes.x() / m_radius)); 0057 } else { 0058 m_angleDegree = qRadiansToDegrees( // 0059 2 * pi - acos(cartesianCoordiantes.x() / m_radius)); 0060 } 0061 } 0062 0063 /** @brief Compares with another @ref PolarPointF 0064 * 0065 * @param other the polar coordinates to compare with 0066 * 0067 * @returns <tt>true</tt> if both, <tt>this</tt> and <tt>other</tt>, 0068 * are the same point in the coordinate space. <tt>false</tt> otherwise. 0069 * Therefore <tt>[@ref radius() 0, @ref angleDegree() 50]</tt> is considered 0070 * to be the same point as <tt>[@ref radius() 0, @ref angleDegree() 80]</tt> 0071 because the @ref angleDegree() is meaningless if the @ref radius() is 0.*/ 0072 bool PolarPointF::isSamePoint(const PolarPointF other) const 0073 { 0074 return ( 0075 // radius has to be identical 0076 (m_radius == other.m_radius) && 0077 // angle has to be identical (except when radius is 0, because 0078 // then angle is meaningless) 0079 ((m_angleDegree == other.m_angleDegree) || (m_radius == 0))); 0080 } 0081 0082 /** @brief Normalized radius 0083 * 0084 * @returns the normalized radius value, guaranteed to be ≥ 0. */ 0085 double PolarPointF::radius() const 0086 { 0087 return m_radius; 0088 } 0089 0090 /** @brief Normalized angle 0091 * 0092 * @returns the normalized angle value (coordinates in degree), guaranteed to 0093 * be 0° ≤ value < 360° */ 0094 double PolarPointF::angleDegree() const 0095 { 0096 return m_angleDegree; 0097 } 0098 0099 /** @brief Convert to Cartesian coordinates 0100 * 0101 * @returns the corresponding Cartesian coordinates */ 0102 QPointF PolarPointF::toCartesian() const 0103 { 0104 return QPointF(m_radius * cos(qDegreesToRadians(m_angleDegree)), // 0105 m_radius * sin(qDegreesToRadians(m_angleDegree))); 0106 } 0107 0108 /** @internal 0109 * 0110 * @brief Adds QDebug() support for data type 0111 * @ref PerceptualColor::PolarPointF 0112 * 0113 * @param dbg Existing debug object 0114 * @param value Value to stream into the debug object 0115 * @returns Debug object with value streamed in */ 0116 QDebug operator<<(QDebug dbg, const PerceptualColor::PolarPointF value) 0117 { 0118 dbg.nospace() // 0119 << "PolarPointF(radius: " // 0120 << value.radius() // 0121 << ", angleDegree: " // 0122 << value.angleDegree() // 0123 << "°)"; 0124 return dbg.maybeSpace(); 0125 } 0126 0127 static_assert(std::is_trivially_copyable_v<PolarPointF>); 0128 // static_assert(std::is_trivial_v<PolarPointF>); 0129 0130 static_assert(std::is_standard_layout_v<PolarPointF>); 0131 0132 static_assert(std::is_default_constructible_v<PolarPointF>); 0133 // static_assert(std::is_trivially_default_constructible_v<PolarPointF>); 0134 static_assert(std::is_nothrow_default_constructible_v<PolarPointF>); 0135 0136 static_assert(std::is_copy_constructible_v<PolarPointF>); 0137 static_assert(std::is_trivially_copy_constructible_v<PolarPointF>); 0138 static_assert(std::is_nothrow_copy_constructible_v<PolarPointF>); 0139 0140 static_assert(std::is_move_constructible_v<PolarPointF>); 0141 static_assert(std::is_trivially_move_constructible_v<PolarPointF>); 0142 static_assert(std::is_nothrow_move_constructible_v<PolarPointF>); 0143 0144 } // namespace PerceptualColor