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

0001 // SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com>
0002 // SPDX-License-Identifier: BSD-2-Clause OR MIT
0003 
0004 // Own header
0005 #include "helpermath.h"
0006 
0007 #include <optional>
0008 #include <qgenericmatrix.h>
0009 #include <qmath.h>
0010 
0011 namespace PerceptualColor
0012 {
0013 
0014 /** @internal
0015  *
0016  * @brief Convenience constructor for @ref SquareMatrix3.
0017  *
0018  * @param r0c0 row 0, column 0
0019  * @param r0c1 row 0, column 1
0020  * @param r0c2 row 0, column 2
0021  * @param r1c0 row 1, column 0
0022  * @param r1c1 row 1, column 1
0023  * @param r1c2 row 1, column 2
0024  * @param r2c0 row 2, column 0
0025  * @param r2c1 row 2, column 1
0026  * @param r2c2 row 2, column 2
0027  *
0028  * @returns The corresponding @ref SquareMatrix3. */
0029 SquareMatrix3 createSquareMatrix3(double r0c0, double r0c1, double r0c2, double r1c0, double r1c1, double r1c2, double r2c0, double r2c1, double r2c2)
0030 {
0031     // clang-format off
0032     const double valueArray[] = {r0c0, r0c1, r0c2,
0033                                  r1c0, r1c1, r1c2,
0034                                  r2c0, r2c1, r2c2};
0035     // clang-format on
0036     return SquareMatrix3(valueArray);
0037 }
0038 
0039 /** @internal
0040  *
0041  * @brief Convenience constructor for @ref Trio.
0042  *
0043  * @param first first value
0044  * @param second second value
0045  * @param third third value
0046  *
0047  * @returns The corresponding @ref Trio. */
0048 Trio createTrio(double first, double second, double third)
0049 {
0050     const double valueArray[] = {first, second, third};
0051     return Trio(valueArray);
0052 }
0053 
0054 /** @internal
0055  *
0056  * @brief Try to find the inverse matrix.
0057  *
0058  * @param matrix The original matrix.
0059  *
0060  * @returns If the original matrix is invertible, its inverse matrix.
0061  * An empty value otherwise. */
0062 std::optional<SquareMatrix3> inverseMatrix(const SquareMatrix3 &matrix)
0063 {
0064     const double &a = matrix(0, 0);
0065     const double &b = matrix(0, 1);
0066     const double &c = matrix(0, 2);
0067     const double &d = matrix(1, 0);
0068     const double &e = matrix(1, 1);
0069     const double &f = matrix(1, 2);
0070     const double &g = matrix(2, 0);
0071     const double &h = matrix(2, 1);
0072     const double &i = matrix(2, 2);
0073     const auto determinant = a * e * i //
0074         + b * f * g //
0075         + c * d * h //
0076         - c * e * g //
0077         - b * d * i //
0078         - a * f * h;
0079     if (determinant == 0) {
0080         return std::nullopt;
0081     }
0082     // clang-format off
0083     const auto temp = createSquareMatrix3(
0084         e * i - f * h, c * h - b * i, b * f - c * e,
0085         f * g - d * i, a * i - c * g, c * d - a * f,
0086         d * h - e * g, b * g - a * h, a * e - b * d);
0087     // clang-format on
0088     return temp / determinant;
0089 }
0090 
0091 /** @brief Calculates the required number of decimals to achieve the requested
0092  * number of significant figures within the given range.
0093  *
0094  * @param rangeMax The maximum value of the range [0, rangeMax].
0095  * @param significantFigures The requested number of significant figures.
0096  *
0097  * | maxRange | decimalPlaces(maxRange, 2) | decimalPlaces(maxRange, 3) | decimalPlaces(maxRange, 4) |
0098  * | -------: | -------------------------: | -------------------------: | -------------------------: |
0099  * |        1 |                          1 |                          2 |                          3 |
0100  * |        2 |                          1 |                          2 |                          3 |
0101  * |      100 |                          0 |                          0 |                          1 |
0102  * |      255 |                          0 |                          0 |                          1 |
0103  * |      360 |                          0 |                          0 |                          1 |
0104  *
0105  * @returns The number of decimal places after the decimal point (in addition
0106  * to the whole number part) required to achieve the requested
0107  * number of significant figures within the given range. */
0108 int decimalPlaces(const int rangeMax, const int significantFigures)
0109 {
0110     const auto myLog10Value = std::log10(qAbs(rangeMax));
0111     const int wholeNumberDigits = (rangeMax == 0) //
0112         ? 1 // special case
0113         : qFloor(myLog10Value) + 1;
0114     return qMax(0, significantFigures - wholeNumberDigits);
0115 }
0116 
0117 } // namespace PerceptualColor