001/*
002 * Copyright (c) 2020-2021 REV Robotics
003 *
004 * Redistribution and use in source and binary forms, with or without
005 * modification, are permitted provided that the following conditions are met:
006 *
007 * 1. Redistributions of source code must retain the above copyright notice,
008 *    this list of conditions and the following disclaimer.
009 * 2. Redistributions in binary form must reproduce the above copyright
010 *    notice, this list of conditions and the following disclaimer in the
011 *    documentation and/or other materials provided with the distribution.
012 * 3. Neither the name of REV Robotics nor the names of its
013 *    contributors may be used to endorse or promote products derived from
014 *    this software without specific prior written permission.
015 *
016 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
017 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
018 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
019 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
020 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
021 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
022 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
023 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
024 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
025 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
026 * POSSIBILITY OF SUCH DAMAGE.
027 */
028
029package com.revrobotics;
030
031import edu.wpi.first.wpilibj.util.Color;
032
033public class CIEColor {
034  private double X;
035  private double Y;
036  private double Z;
037  private double magnitude;
038
039  // private final double IlluminantD65[] = {
040  //    95.0489, 100.0, 108.8840
041  // };
042
043  private final double XYZtoRGB[] = {
044    3.2404542,
045    -1.5371385,
046    -0.4985314,
047    -0.9692660,
048    1.8760108,
049    0.0415560,
050    0.0556434,
051    -0.2040259,
052    1.0572252
053  };
054
055  private static double CIERGB_f(double val) {
056    return (val > 0.0031308) ? (1.055 * Math.pow(val, 1 / 2.4) - 0.055) : (12.92 * val);
057  }
058
059  private static double clamp(double x, double min, double max) {
060    if (x > max) return max;
061    if (x < min) return min;
062    return x;
063  }
064
065  private Color ToRGB() {
066    double _X = clamp(X / 100, 0.0, 1.0);
067    double _Y = clamp(Y / 100, 0.0, 1.0);
068    double _Z = clamp(Z / 100, 0.0, 1.0);
069    double r = _X * XYZtoRGB[0] + _Y * XYZtoRGB[1] + _Z * XYZtoRGB[2];
070    double g = _X * XYZtoRGB[3] + _Y * XYZtoRGB[4] + _Z * XYZtoRGB[5];
071    double b = _X * XYZtoRGB[6] + _Y * XYZtoRGB[7] + _Z * XYZtoRGB[8];
072
073    r = CIERGB_f(r);
074    g = CIERGB_f(g);
075    b = CIERGB_f(b);
076
077    return new Color(r, g, b);
078  }
079
080  /**
081   * Get the X component of the color
082   *
083   * @return CIE X
084   */
085  public double getX() {
086    return X;
087  }
088
089  /**
090   * Get the Y component of the color
091   *
092   * @return CIE Y
093   */
094  public double getY() {
095    return Y;
096  }
097
098  /**
099   * Get the Z component of the color
100   *
101   * @return CIE Z
102   */
103  public double getZ() {
104    return Z;
105  }
106
107  /**
108   * Get the x calculated coordinate of the CIE 19313 color space
109   *
110   * <p>https://en.wikipedia.org/wiki/CIE_1931_color_space
111   *
112   * @return CIE Yx
113   */
114  public double getYx() {
115    return X / magnitude;
116  }
117
118  /**
119   * Get the y calculated coordinate of the CIE 19313 color space
120   *
121   * <p>https://en.wikipedia.org/wiki/CIE_1931_color_space
122   *
123   * @return CIE Yy
124   */
125  public double getYy() {
126    return Y / magnitude;
127  }
128
129  public CIEColor(double x, double y, double z) {
130    this.X = x;
131    this.Y = y;
132    this.Z = z;
133    this.magnitude = x + y + z;
134  }
135}