File indexing completed on 2024-05-12 15:59:37

0001 /*
0002  *  SPDX-FileCopyrightText: 2006, 2007, 2010 Cyrille Berger <cberger@cberger.net>
0003  *  SPDX-FileCopyrightText: 2017, 2020 L. E. Segovia <amy@amyspark.me>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.1-or-later
0006 */
0007 
0008 #ifndef KOLABCOLORSPACEMATHS_H_
0009 #define KOLABCOLORSPACEMATHS_H_
0010 
0011 #include <cmath>
0012 #include <limits>
0013 
0014 #include "kritapigment_export.h"
0015 #include <KoIntegerMaths.h>
0016 #include "KoChannelInfo.h"
0017 #include "KoLut.h"
0018 
0019 #include <KoColorSpaceMaths.h>
0020 
0021 #undef _T
0022 
0023 /**
0024  * This is an empty mainWindow that needs to be "specialized" for each possible
0025  * numerical type (quint8, quint16...).
0026  *
0027  * It needs to defines some static constant fields :
0028  * - zeroValue : the zero for this numerical type
0029  * - unitValue : the maximum value of the normal dynamic range
0030  * - max : the maximum value
0031  * - min : the minimum value
0032  * - epsilon : a value close to zero but different of zero
0033  * - bits : the bit depth
0034  *
0035  * And some types :
0036  * - compositetype the type used for composite operations (usually one with
0037  *   a higher bit depth)
0038  *
0039  * This class is specialized to handle the floating point bounds of the Lab color space.
0040  */
0041 
0042 template<typename _T>
0043 class KoLabColorSpaceMathsTraits
0044 {
0045 public:
0046 };
0047 
0048 template<>
0049 class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits<quint8> : public KoColorSpaceMathsTraits<quint8>
0050 {
0051 public:
0052     static const quint8 zeroValueL = 0;
0053     static const quint8 unitValueL = 0x00FF;
0054     static const quint8 halfValueL = 0x00FF / 2;
0055     static const quint8 zeroValueAB = 0;
0056     static const quint8 unitValueAB = 0x00FF;
0057     static const quint8 halfValueAB = 0x0080;
0058 };
0059 
0060 template<>
0061 class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits<quint16> : public KoColorSpaceMathsTraits<quint16>
0062 {
0063 public:
0064     static const quint16 zeroValueL = 0;
0065     static const quint16 unitValueL = 0xFFFF;
0066     static const quint16 halfValueL = 0xFFFF / 2;
0067     static const quint16 zeroValueAB = 0;
0068     static const quint16 unitValueAB = 0xFFFF;
0069     static const quint16 halfValueAB = 0x8080;
0070 };
0071 
0072 template<>
0073 class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits<qint16> : public KoColorSpaceMathsTraits<qint16>
0074 {
0075 public:
0076     static const qint16 zeroValueL = 0;
0077     static const qint16 unitValueL = 32767;
0078     static const qint16 halfValueL = 32767 / 2;
0079     static const qint16 zeroValueAB = 0;
0080     static const qint16 unitValueAB = 32767;
0081     static const qint16 halfValueAB = 19549;
0082 };
0083 
0084 template<>
0085 class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits<quint32> : public KoColorSpaceMathsTraits<quint32>
0086 {
0087 public:
0088     static const quint32 zeroValueL = 0;
0089     static const quint32 unitValueL = 0xFFFFFFFF;
0090     static const quint32 halfValueL = 0xFFFFFFFF / 2;
0091     static const quint32 zeroValueAB = 0;
0092     static const quint32 unitValueAB = 0xFFFFFFFF;
0093     static const quint32 halfValueAB = 0x80808080;
0094 };
0095 
0096 #include <KoConfig.h>
0097 #ifdef HAVE_OPENEXR
0098 #include <half.h>
0099 
0100 template<>
0101 class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits<half> : public KoColorSpaceMathsTraits<half>
0102 {
0103 public:
0104     static const half zeroValueL;
0105     static const half unitValueL;
0106     static const half halfValueL;
0107     static const half zeroValueAB;
0108     static const half unitValueAB;
0109     static const half halfValueAB;
0110 };
0111 #endif
0112 
0113 template<>
0114 class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits<float> : public KoColorSpaceMathsTraits<float>
0115 {
0116 public:
0117     static const float zeroValueL;
0118     static const float unitValueL;
0119     static const float halfValueL;
0120     static const float zeroValueAB;
0121     static const float unitValueAB;
0122     static const float halfValueAB;
0123 };
0124 
0125 template<>
0126 class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits<double> : public KoColorSpaceMathsTraits<double>
0127 {
0128 public:
0129     static const double zeroValueL;
0130     static const double unitValueL;
0131     static const double halfValueL;
0132     static const double zeroValueAB;
0133     static const double unitValueAB;
0134     static const double halfValueAB;
0135 };
0136 
0137 //template<typename _T_>
0138 //struct KoIntegerToFloat {
0139 //  inline float operator()(_T_ f) const
0140 //  {
0141 //    return f / float(KoColorSpaceMathsTraits<_T_>::max);
0142 //  }
0143 //};
0144 
0145 //struct KoLuts {
0146 
0147 //  static KRITAPIGMENT_EXPORT const Ko::FullLut< KoIntegerToFloat<quint16>, float, quint16> Uint16ToFloat;
0148 //  static KRITAPIGMENT_EXPORT const Ko::FullLut< KoIntegerToFloat<quint8>, float, quint8> Uint8ToFloat;
0149 //};
0150 
0151 ///**
0152 // * This class defines some elementary operations used by various color
0153 // * space. It's intended to be generic, but some specialization exists
0154 // * either for optimization or just for being buildable.
0155 // *
0156 // * @param _T some numerical type with an existing trait
0157 // * @param _Tdst some other numerical type with an existing trait, it is
0158 // *              only needed if different of _T
0159 // */
0160 //template < typename _T, typename _Tdst = _T >
0161 //class KoColorSpaceMaths
0162 //{
0163 //    typedef KoColorSpaceMathsTraits<_T> traits;
0164 //    typedef typename traits::compositetype src_compositetype;
0165 //    typedef typename KoColorSpaceMathsTraits<_Tdst>::compositetype dst_compositetype;
0166 
0167 //public:
0168 //    inline static _Tdst multiply(_T a, _Tdst b) {
0169 //        return (dst_compositetype(a)*b) /  KoColorSpaceMathsTraits<_Tdst>::unitValue;
0170 //    }
0171 
0172 //    inline static _Tdst multiply(_T a, _Tdst b, _Tdst c) {
0173 //        return (dst_compositetype(a)*b*c) / (dst_compositetype(KoColorSpaceMathsTraits<_Tdst>::unitValue) * KoColorSpaceMathsTraits<_T>::unitValue);
0174 //    }
0175 
0176 //    /**
0177 //     * Division : (a * MAX ) / b
0178 //     * @param a
0179 //     * @param b
0180 //     */
0181 //    inline static dst_compositetype divide(_T a, _Tdst b) {
0182 //        return (dst_compositetype(a) *  KoColorSpaceMathsTraits<_Tdst>::unitValue) / b;
0183 //    }
0184 
0185 //    /**
0186 //     * Inversion : unitValue - a
0187 //     * @param a
0188 //     */
0189 //    inline static _T invert(_T a) {
0190 //        return traits::unitValue - a;
0191 //    }
0192 
0193 //    /**
0194 //     * Blending : (a * alpha) + b * (1 - alpha)
0195 //     * @param a
0196 //     * @param b
0197 //     * @param alpha
0198 //     */
0199 //    inline static _T blend(_T a, _T b, _T alpha) {
0200 //        src_compositetype c = ((src_compositetype(a) - b) * alpha) / traits::unitValue;
0201 //        return c + b;
0202 //    }
0203 
0204 //    /**
0205 //     * This function will scale a value of type _T to fit into a _Tdst.
0206 //     */
0207 //    inline static _Tdst scaleToA(_T a) {
0208 //        return _Tdst(dst_compositetype(a) * KoColorSpaceMathsTraits<_Tdst>::unitValue / KoColorSpaceMathsTraits<_T>::unitValue);
0209 //    }
0210 
0211 //    inline static dst_compositetype clamp(dst_compositetype val) {
0212 //        return qBound<dst_compositetype>(KoColorSpaceMathsTraits<_Tdst>::min, val, KoColorSpaceMathsTraits<_Tdst>::max);
0213 //    }
0214 
0215 //    /**
0216 //     * Clamps the composite type on higher border only. That is a fast path
0217 //     * for scale-only transformations
0218 //     */
0219 //    inline static _Tdst clampAfterScale(dst_compositetype val) {
0220 //        return qMin<dst_compositetype>(val, KoColorSpaceMathsTraits<_Tdst>::max);
0221 //    }
0222 //};
0223 
0224 ////------------------------------ double specialization ------------------------------//
0225 //template<>
0226 //inline quint8 KoColorSpaceMaths<double, quint8>::scaleToA(double a)
0227 //{
0228 //    double v = a * 255;
0229 //    return float2int(CLAMP(v, 0, 255));
0230 //}
0231 
0232 //template<>
0233 //inline double KoColorSpaceMaths<quint8, double>::scaleToA(quint8 a)
0234 //{
0235 //    return KoLuts::Uint8ToFloat(a);
0236 //}
0237 
0238 //template<>
0239 //inline quint16 KoColorSpaceMaths<double, quint16>::scaleToA(double a)
0240 //{
0241 //    double v = a * 0xFFFF;
0242 //    return float2int(CLAMP(v, 0, 0xFFFF));
0243 //}
0244 
0245 //template<>
0246 //inline double KoColorSpaceMaths<quint16, double>::scaleToA(quint16 a)
0247 //{
0248 //    return KoLuts::Uint16ToFloat(a);
0249 //}
0250 
0251 //template<>
0252 //inline double KoColorSpaceMaths<double>::clamp(double a)
0253 //{
0254 //    return a;
0255 //}
0256 
0257 ////------------------------------ float specialization ------------------------------//
0258 
0259 //template<>
0260 //inline float KoColorSpaceMaths<double, float>::scaleToA(double a)
0261 //{
0262 //    return (float)a;
0263 //}
0264 
0265 //template<>
0266 //inline double KoColorSpaceMaths<float, double>::scaleToA(float a)
0267 //{
0268 //    return a;
0269 //}
0270 
0271 //template<>
0272 //inline quint16 KoColorSpaceMaths<float, quint16>::scaleToA(float a)
0273 //{
0274 //    float v = a * 0xFFFF;
0275 //    return (quint16)float2int(CLAMP(v, 0, 0xFFFF));
0276 //}
0277 
0278 //template<>
0279 //inline float KoColorSpaceMaths<quint16, float>::scaleToA(quint16 a)
0280 //{
0281 //    return KoLuts::Uint16ToFloat(a);
0282 //}
0283 
0284 //template<>
0285 //inline quint8 KoColorSpaceMaths<float, quint8>::scaleToA(float a)
0286 //{
0287 //    float v = a * 255;
0288 //    return (quint8)float2int(CLAMP(v, 0, 255));
0289 //}
0290 
0291 //template<>
0292 //inline float KoColorSpaceMaths<quint8, float>::scaleToA(quint8 a)
0293 //{
0294 //    return KoLuts::Uint8ToFloat(a);
0295 //}
0296 
0297 //template<>
0298 //inline float KoColorSpaceMaths<float>::blend(float a, float b, float alpha)
0299 //{
0300 //    return (a - b) * alpha + b;
0301 //}
0302 
0303 //template<>
0304 //inline double KoColorSpaceMaths<float>::clamp(double a)
0305 //{
0306 //    return a;
0307 //}
0308 
0309 ////------------------------------ half specialization ------------------------------//
0310 
0311 //#ifdef HAVE_OPENEXR
0312 
0313 //template<>
0314 //inline half KoColorSpaceMaths<double, half>::scaleToA(double a)
0315 //{
0316 //    return (half)a;
0317 //}
0318 
0319 //template<>
0320 //inline double KoColorSpaceMaths<half, double>::scaleToA(half a)
0321 //{
0322 //    return a;
0323 //}
0324 
0325 //template<>
0326 //inline float KoColorSpaceMaths<half, float>::scaleToA(half a)
0327 //{
0328 //    return a;
0329 //}
0330 
0331 //template<>
0332 //inline half KoColorSpaceMaths<float, half>::scaleToA(float a)
0333 //{
0334 //    return (half) a;
0335 //}
0336 
0337 //template<>
0338 //inline quint8 KoColorSpaceMaths<half, quint8>::scaleToA(half a)
0339 //{
0340 //    half v = a * 255;
0341 //    return (quint8)(CLAMP(v, 0, 255));
0342 //}
0343 
0344 //template<>
0345 //inline half KoColorSpaceMaths<quint8, half>::scaleToA(quint8 a)
0346 //{
0347 //    return a *(1.0 / 255.0);
0348 //}
0349 //template<>
0350 //inline quint16 KoColorSpaceMaths<half, quint16>::scaleToA(half a)
0351 //{
0352 //    double v = a * 0xFFFF;
0353 //    return (quint16)(CLAMP(v, 0, 0xFFFF));
0354 //}
0355 
0356 //template<>
0357 //inline half KoColorSpaceMaths<quint16, half>::scaleToA(quint16 a)
0358 //{
0359 //    return a *(1.0 / 0xFFFF);
0360 //}
0361 
0362 //template<>
0363 //inline half KoColorSpaceMaths<half, half>::scaleToA(half a)
0364 //{
0365 //    return a;
0366 //}
0367 
0368 //template<>
0369 //inline half KoColorSpaceMaths<half>::blend(half a, half b, half alpha)
0370 //{
0371 //    return (a - b) * alpha + b;
0372 //}
0373 
0374 //template<>
0375 //inline double KoColorSpaceMaths<half>::clamp(double a)
0376 //{
0377 //    return a;
0378 //}
0379 
0380 
0381 //#endif
0382 
0383 ////------------------------------ quint8 specialization ------------------------------//
0384 
0385 //template<>
0386 //inline quint8 KoColorSpaceMaths<quint8>::multiply(quint8 a, quint8 b)
0387 //{
0388 //    return (quint8)UINT8_MULT(a, b);
0389 //}
0390 
0391 
0392 //template<>
0393 //inline quint8 KoColorSpaceMaths<quint8>::multiply(quint8 a, quint8 b, quint8 c)
0394 //{
0395 //    return (quint8)UINT8_MULT3(a, b, c);
0396 //}
0397 
0398 //template<>
0399 //inline KoColorSpaceMathsTraits<quint8>::compositetype
0400 //KoColorSpaceMaths<quint8>::divide(quint8 a, quint8 b)
0401 //{
0402 //    return UINT8_DIVIDE(a, b);
0403 //}
0404 
0405 //template<>
0406 //inline quint8 KoColorSpaceMaths<quint8>::invert(quint8 a)
0407 //{
0408 //    return ~a;
0409 //}
0410 
0411 //template<>
0412 //inline quint8 KoColorSpaceMaths<quint8>::blend(quint8 a, quint8 b, quint8 c)
0413 //{
0414 //    return UINT8_BLEND(a, b, c);
0415 //}
0416 
0417 ////------------------------------ quint16 specialization ------------------------------//
0418 
0419 //template<>
0420 //inline quint16 KoColorSpaceMaths<quint16>::multiply(quint16 a, quint16 b)
0421 //{
0422 //    return (quint16)UINT16_MULT(a, b);
0423 //}
0424 
0425 //template<>
0426 //inline KoColorSpaceMathsTraits<quint16>::compositetype
0427 //KoColorSpaceMaths<quint16>::divide(quint16 a, quint16 b)
0428 //{
0429 //    return UINT16_DIVIDE(a, b);
0430 //}
0431 
0432 //template<>
0433 //inline quint16 KoColorSpaceMaths<quint16>::invert(quint16 a)
0434 //{
0435 //    return ~a;
0436 //}
0437 
0438 ////------------------------------ various specialization ------------------------------//
0439 
0440 
0441 //// TODO: use more functions from KoIntegersMaths to do the computation
0442 
0443 ///// This specialization is needed because the default implementation won't work when scaling up
0444 //template<>
0445 //inline quint16 KoColorSpaceMaths<quint8, quint16>::scaleToA(quint8 a)
0446 //{
0447 //    return UINT8_TO_UINT16(a);
0448 //}
0449 
0450 //template<>
0451 //inline quint8 KoColorSpaceMaths<quint16, quint8>::scaleToA(quint16 a)
0452 //{
0453 //    return UINT16_TO_UINT8(a);
0454 //}
0455 
0456 
0457 //// Due to once again a bug in gcc, there is the need for those specialized functions:
0458 
0459 //template<>
0460 //inline quint8 KoColorSpaceMaths<quint8, quint8>::scaleToA(quint8 a)
0461 //{
0462 //    return a;
0463 //}
0464 
0465 //template<>
0466 //inline quint16 KoColorSpaceMaths<quint16, quint16>::scaleToA(quint16 a)
0467 //{
0468 //    return a;
0469 //}
0470 
0471 //template<>
0472 //inline float KoColorSpaceMaths<float, float>::scaleToA(float a)
0473 //{
0474 //    return a;
0475 //}
0476 
0477 //namespace Arithmetic
0478 //{
0479 //    const static qreal pi = 3.14159265358979323846;
0480 
0481 //    template<class T>
0482 //    inline T mul(T a, T b) { return KoColorSpaceMaths<T>::multiply(a, b); }
0483 
0484 //    template<class T>
0485 //    inline T mul(T a, T b, T c) { return KoColorSpaceMaths<T>::multiply(a, b, c); }
0486 
0487 ////     template<class T>
0488 ////     inline T mul(T a, T b) {
0489 ////         typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
0490 ////         return T(composite_type(a) * b / KoColorSpaceMathsTraits<T>::unitValue);
0491 ////     }
0492 ////
0493 ////     template<class T>
0494 ////     inline T mul(T a, T b, T c) {
0495 ////         typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
0496 ////         return T((composite_type(a) * b * c) / (composite_type(KoColorSpaceMathsTraits<T>::unitValue) * KoColorSpaceMathsTraits<T>::unitValue));
0497 ////     }
0498 
0499 //    template<class T>
0500 //    inline T inv(T a) { return KoColorSpaceMaths<T>::invert(a); }
0501 
0502 //    template<class T>
0503 //    inline T lerp(T a, T b, T alpha) { return KoColorSpaceMaths<T>::blend(b, a, alpha); }
0504 
0505 //    template<class TRet, class T>
0506 //    inline TRet scale(T a) { return KoColorSpaceMaths<T,TRet>::scaleToA(a); }
0507 
0508 //    template<class T>
0509 //    inline typename KoColorSpaceMathsTraits<T>::compositetype
0510 //    div(T a, T b) { return KoColorSpaceMaths<T>::divide(a, b); }
0511 
0512 //    template<class T>
0513 //    inline T clamp(typename KoColorSpaceMathsTraits<T>::compositetype a) {
0514 //        return KoColorSpaceMaths<T>::clamp(a);
0515 //    }
0516 
0517 //    template<class T>
0518 //    inline T min(T a, T b, T c) {
0519 //        b = (a < b) ? a : b;
0520 //        return (b < c) ? b : c;
0521 //    }
0522 
0523 //    template<class T>
0524 //    inline T max(T a, T b, T c) {
0525 //        b = (a > b) ? a : b;
0526 //        return (b > c) ? b : c;
0527 //    }
0528 
0529 //    template<class T>
0530 //    inline T zeroValue() { return KoColorSpaceMathsTraits<T>::zeroValue; }
0531 
0532 //    template<class T>
0533 //    inline T halfValue() { return KoColorSpaceMathsTraits<T>::halfValue; }
0534 
0535 //    template<class T>
0536 //    inline T unitValue() { return KoColorSpaceMathsTraits<T>::unitValue; }
0537 
0538 //    template<class T>
0539 //    inline T unionShapeOpacity(T a, T b) {
0540 //        typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
0541 //        return T(composite_type(a) + b - mul(a,b));
0542 //    }
0543 
0544 //    template<class T>
0545 //    inline T blend(T src, T srcAlpha, T dst, T dstAlpha, T cfValue) {
0546 //        return mul(inv(srcAlpha), dstAlpha, dst) + mul(inv(dstAlpha), srcAlpha, src) + mul(dstAlpha, srcAlpha, cfValue);
0547 //    }
0548 //}
0549 
0550 //struct HSYType
0551 //{
0552 //    template<class TReal>
0553 //    inline static TReal getLightness(TReal r, TReal g, TReal b) {
0554 //        return TReal(0.299)*r + TReal(0.587)*g + TReal(0.114)*b;
0555 //    }
0556 
0557 //    template<class TReal>
0558 //    inline static TReal getSaturation(TReal r, TReal g, TReal b) {
0559 //        return Arithmetic::max(r,g,b) - Arithmetic::min(r,g,b);
0560 //    }
0561 //};
0562 
0563 //struct HSIType
0564 //{
0565 //    template<class TReal>
0566 //    inline static TReal getLightness(TReal r, TReal g, TReal b) {
0567 //        return (r + g + b) * TReal(0.33333333333333333333); // (r + g + b) / 3.0
0568 //    }
0569 
0570 //    template<class TReal>
0571 //    inline static TReal getSaturation(TReal r, TReal g, TReal b) {
0572 //        TReal max    = Arithmetic::max(r, g, b);
0573 //        TReal min    = Arithmetic::min(r, g, b);
0574 //        TReal chroma = max - min;
0575 
0576 //        return (chroma > std::numeric_limits<TReal>::epsilon()) ?
0577 //            (TReal(1.0) - min / getLightness(r, g, b)) : TReal(0.0);
0578 //    }
0579 //};
0580 
0581 //struct HSLType
0582 //{
0583 //    template<class TReal>
0584 //    inline static TReal getLightness(TReal r, TReal g, TReal b) {
0585 //        TReal max = Arithmetic::max(r, g, b);
0586 //        TReal min = Arithmetic::min(r, g, b);
0587 //        return (max + min) * TReal(0.5);
0588 //    }
0589 
0590 //    template<class TReal>
0591 //    inline static TReal getSaturation(TReal r, TReal g, TReal b) {
0592 //        TReal max    = Arithmetic::max(r, g, b);
0593 //        TReal min    = Arithmetic::min(r, g, b);
0594 //        TReal chroma = max - min;
0595 //        TReal light  = (max + min) * TReal(0.5);
0596 //        TReal div    = TReal(1.0) - std::abs(TReal(2.0)*light - TReal(1.0));
0597 
0598 //        if(div > std::numeric_limits<TReal>::epsilon())
0599 //            return chroma / div;
0600 
0601 //        return TReal(1.0);
0602 //    }
0603 //};
0604 
0605 //struct HSVType
0606 //{
0607 //    template<class TReal>
0608 //    inline static TReal getLightness(TReal r, TReal g, TReal b) {
0609 //        return Arithmetic::max(r,g,b);
0610 //    }
0611 
0612 //    template<class TReal>
0613 //    inline static TReal getSaturation(TReal r, TReal g, TReal b) {
0614 //        TReal max = Arithmetic::max(r, g, b);
0615 //        TReal min = Arithmetic::min(r, g, b);
0616 //        return (max == TReal(0.0)) ? TReal(0.0) : (max - min) / max;
0617 //    }
0618 //};
0619 
0620 //template<class TReal>
0621 //TReal getHue(TReal r, TReal g, TReal b) {
0622 //    TReal min    = Arithmetic::min(r, g, b);
0623 //    TReal max    = Arithmetic::max(r, g, b);
0624 //    TReal chroma = max - min;
0625 
0626 //    TReal hue = TReal(-1.0);
0627 
0628 //    if(chroma > std::numeric_limits<TReal>::epsilon()) {
0629 
0630 ////         return atan2(TReal(2.0)*r - g - b, TReal(1.73205080756887729353)*(g - b));
0631 
0632 //        if(max == r) // between yellow and magenta
0633 //            hue = (g - b) / chroma;
0634 //        else if(max == g) // between cyan and yellow
0635 //            hue = TReal(2.0) + (b - r) / chroma;
0636 //        else if(max == b) // between magenta and cyan
0637 //            hue = TReal(4.0) + (r - g) / chroma;
0638 
0639 //        if(hue < -std::numeric_limits<TReal>::epsilon())
0640 //            hue += TReal(6.0);
0641 
0642 //        hue /= TReal(6.0);
0643 //    }
0644 
0645 ////     hue = (r == max) ? (b-g) : (g == max) ? TReal(2.0)+(r-b) : TReal(4.0)+(g-r);
0646 
0647 //    return hue;
0648 //}
0649 
0650 //template<class TReal>
0651 //void getRGB(TReal& r, TReal& g, TReal& b, TReal hue) {
0652 //    // 0 red    -> (1,0,0)
0653 //    // 1 yellow -> (1,1,0)
0654 //    // 2 green  -> (0,1,0)
0655 //    // 3 cyan   -> (0,1,1)
0656 //    // 4 blue   -> (0,0,1)
0657 //    // 5 maenta -> (1,0,1)
0658 //    // 6 red    -> (1,0,0)
0659 
0660 //    if(hue < -std::numeric_limits<TReal>::epsilon()) {
0661 //        r = g = b = TReal(0.0);
0662 //        return;
0663 //    }
0664 
0665 //    int   i = int(hue * TReal(6.0));
0666 //    TReal x = hue * TReal(6.0) - i;
0667 //    TReal y = TReal(1.0) - x;
0668 
0669 //    switch(i % 6){
0670 //        case 0: { r=TReal(1.0), g=x         , b=TReal(0.0); } break;
0671 //        case 1: { r=y         , g=TReal(1.0), b=TReal(0.0); } break;
0672 //        case 2: { r=TReal(0.0), g=TReal(1.0), b=x         ; } break;
0673 //        case 3: { r=TReal(0.0), g=y         , b=TReal(1.0); } break;
0674 //        case 4: { r=x         , g=TReal(0.0), b=TReal(1.0); } break;
0675 //        case 5: { r=TReal(1.0), g=TReal(0.0), b=y         ; } break;
0676 //    }
0677 //}
0678 
0679 //template<class HSXType, class TReal>
0680 //inline static TReal getLightness(TReal r, TReal g, TReal b) {
0681 //    return HSXType::getLightness(r, g, b);
0682 //}
0683 
0684 //template<class HSXType, class TReal>
0685 //inline void addLightness(TReal& r, TReal& g, TReal& b, TReal light)
0686 //{
0687 //    using namespace Arithmetic;
0688 
0689 //    r += light;
0690 //    g += light;
0691 //    b += light;
0692 
0693 //    TReal l = HSXType::getLightness(r, g, b);
0694 //    TReal n = min(r, g, b);
0695 //    TReal x = max(r, g, b);
0696 
0697 //    if(n < TReal(0.0)) {
0698 //        TReal iln = TReal(1.0) / (l-n);
0699 //        r = l + ((r-l) * l) * iln;
0700 //        g = l + ((g-l) * l) * iln;
0701 //        b = l + ((b-l) * l) * iln;
0702 //    }
0703 
0704 //    if(x > TReal(1.0) && (x-l) > std::numeric_limits<TReal>::epsilon()) {
0705 //        TReal il  = TReal(1.0) - l;
0706 //        TReal ixl = TReal(1.0) / (x - l);
0707 //        r = l + ((r-l) * il) * ixl;
0708 //        g = l + ((g-l) * il) * ixl;
0709 //        b = l + ((b-l) * il) * ixl;
0710 //    }
0711 //}
0712 
0713 //template<class HSXType, class TReal>
0714 //inline void setLightness(TReal& r, TReal& g, TReal& b, TReal light)
0715 //{
0716 //    addLightness<HSXType>(r,g,b, light - HSXType::getLightness(r,g,b));
0717 //}
0718 
0719 //template<class HSXType, class TReal>
0720 //inline static TReal getSaturation(TReal r, TReal g, TReal b) {
0721 //    return HSXType::getSaturation(r, g, b);
0722 //}
0723 
0724 //template<class HSXType, class TReal>
0725 //inline void setSaturation(TReal& r, TReal& g, TReal& b, TReal sat)
0726 //{
0727 //    int   min    = 0;
0728 //    int   mid    = 1;
0729 //    int   max    = 2;
0730 //    TReal rgb[3] = {r, g, b};
0731 
0732 //    if(rgb[mid] < rgb[min]) {
0733 //        int tmp = min;
0734 //        min = mid;
0735 //        mid = tmp;
0736 //    }
0737 
0738 //    if(rgb[max] < rgb[mid]) {
0739 //        int tmp = mid;
0740 //        mid = max;
0741 //        max = tmp;
0742 //    }
0743 
0744 //    if(rgb[mid] < rgb[min]) {
0745 //        int tmp = min;
0746 //        min = mid;
0747 //        mid = tmp;
0748 //    }
0749 
0750 //    if((rgb[max] - rgb[min]) > TReal(0.0)) {
0751 //        rgb[mid] = ((rgb[mid]-rgb[min]) * sat) / (rgb[max]-rgb[min]);
0752 //        rgb[max] = sat;
0753 //        rgb[min] = TReal(0.0);
0754 
0755 //        r = rgb[0];
0756 //        g = rgb[1];
0757 //        b = rgb[2];
0758 //    }
0759 //    else r = g = b = TReal(0.0);
0760 //}
0761 
0762 #endif