File indexing completed on 2024-05-12 04:44:34

0001 // SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com>
0002 // SPDX-License-Identifier: BSD-2-Clause OR MIT
0003 
0004 #ifndef POLARPOINTF_H
0005 #define POLARPOINTF_H
0006 
0007 #include <qdebug.h>
0008 #include <qmetatype.h>
0009 #include <qpoint.h>
0010 
0011 namespace PerceptualColor
0012 {
0013 /** @internal
0014  *
0015  * @brief A point in a
0016  * <a href="https://en.wikipedia.org/wiki/Polar_coordinate_system">polar
0017  * coordinate system</a>
0018  *
0019  * Polar coordinates are important for color
0020  * handling because many color models use the
0021  * <a href="https://en.wikipedia.org/wiki/Cylindrical_coordinate_system">
0022  * cylindrical coordinate system</a> which extends the two-dimensional
0023  * polar coordinate system to three dimensions by adding a (linear)
0024  * <em>z</em> coordinate.
0025  *
0026  * Polar coordinate systems represent points by a radial coordinate
0027  * (<em>radius</em>, also called <em>r</em> or <em>ρ</em>) and an angular
0028  * coordinate (<em>angle</em>, also called <em>azimuth</em>, <em>φ</em>,
0029  * <em>θ</em> or <em>t</em>).
0030  *
0031  * Polar coordinates allow multiple representations for a single point:
0032  * - An angle of 0° is the same as 360° is the same as 720° is the same
0033  *   as −360°.
0034  * - A radius of 1 and an angle of 0° is the same as a radius of −1 and an
0035  *   angle of 180°.
0036  * - If the radius is 0, the angle is meaningless: A radius of 0 and an angle
0037  *   of 57° is the same as a radius of 0 and an angle of 233°.
0038  *
0039  * @invariant The polar coordinates are normalized. See @ref normalizePolar360
0040  * for details.
0041  *
0042  * To provide a clear API, there is no <em>equal</em> operator. Use
0043  * @ref isSamePoint() instead..
0044  *
0045  * This type is declared as type to Qt’s type system via
0046  * <tt>Q_DECLARE_METATYPE</tt>. Depending on your use case (for
0047  * example if you want to use for <em>queued</em> signal-slot connections),
0048  * you might consider calling <tt>qRegisterMetaType()</tt> for
0049  * this type, once you have a QApplication object.
0050  *
0051  * This data type can be passed to QDebug thanks to
0052  * @ref operator<<(QDebug dbg, const PerceptualColor::PolarPointF value)
0053  */
0054 class PolarPointF final
0055 {
0056 public:
0057     /** @brief Constructor
0058      *
0059      * Constructs an object with @ref radius() = 0 and @ref angleDegree() = 0 */
0060     explicit PolarPointF() = default;
0061 
0062     /** @brief Default copy constructor
0063      *
0064      * @param other the object to copy */
0065     PolarPointF(const PolarPointF &other) = default;
0066 
0067     /** @brief Default move constructor
0068      *
0069      * @param other the object to move */
0070     PolarPointF(PolarPointF &&other) noexcept = default;
0071 
0072     explicit PolarPointF(const double newRadius, const double newAngleDegree);
0073 
0074     explicit PolarPointF(const QPointF cartesianCoordiantes);
0075 
0076     /** @brief Default assignment operator
0077      *
0078      * @returns The default implementation’s return value.
0079      *
0080      * @param other the object to assign */
0081     // Clazy, our static code checker, complains about the next line of code
0082     // as follows:
0083     //     “Pass small and trivially-copyable type by value”
0084     // However, this is a copy constructor. We cannot pass the argument
0085     // by value, because the compiler would complain as follows:
0086     //     “the parameter for an explicitly-defaulted copy assignment
0087     //      operator must be an lvalue reference type”
0088     // Therefore, we exclude the following line from this specific clazy check,
0089     // by adding a magic comment after it.
0090     PolarPointF &operator=(const PolarPointF &other) = default; // clazy:exclude=function-args-by-value
0091 
0092     /** @brief Default move assignment operator
0093      *
0094      * @returns The default implementation’s return value.
0095      *
0096      * @param other the object to move-assign */
0097     PolarPointF &operator=(PolarPointF &&other) noexcept = default;
0098 
0099     [[nodiscard]] double angleDegree() const;
0100 
0101     [[nodiscard]] bool isSamePoint(const PolarPointF other) const;
0102 
0103     [[nodiscard]] double radius() const;
0104 
0105     QPointF toCartesian() const;
0106 
0107 private:
0108     /** @brief Holds the @ref angleDegree() value. */
0109     double m_angleDegree{0};
0110 
0111     /** @brief Holds the @ref radius() value. */
0112     double m_radius{0};
0113 };
0114 
0115 QDebug operator<<(QDebug dbg, const PerceptualColor::PolarPointF value);
0116 
0117 } // namespace PerceptualColor
0118 
0119 Q_DECLARE_METATYPE(PerceptualColor::PolarPointF)
0120 
0121 #endif // POLARPOINTF_H