diff --git a/orx-color/src/commonMain/kotlin/mixing/Spectral.kt b/orx-color/src/commonMain/kotlin/mixing/Spectral.kt index b81e1575d..54ceef747 100644 --- a/orx-color/src/commonMain/kotlin/mixing/Spectral.kt +++ b/orx-color/src/commonMain/kotlin/mixing/Spectral.kt @@ -13,6 +13,14 @@ import kotlin.math.sqrt Direct port of https://github.com/rvanwijnen/spectral.js */ +/** + * Represents spectral power distribution (SPD) coefficients for the cyan channel, + * spanning 38 wavelength samples. This array is used as part of the spectral upsampling + * process to convert a linear RGB color into a reflectance spectrum. + * + * The coefficients are predefined values that define the contribution of the cyan channel + * at specific wavelengths to the resulting reflectance spectrum. + */ private val SPD_C = doubleArrayOf( 0.96853629, 0.96855103, @@ -54,6 +62,11 @@ private val SPD_C = doubleArrayOf( 0.01435408 ) +/** + * Represents the spectral power distribution (SPD) data for the magenta color component. + * This array contains 38 predefined values corresponding to specific wavelengths. + * Used in the process of spectral upsampling to compute reflectance spectra from RGB color information. + */ private val SPD_M = doubleArrayOf( 0.51567122, 0.5401552, @@ -95,6 +108,11 @@ private val SPD_M = doubleArrayOf( 0.50083021 ) +/** + * Spectral power distribution (SPD) values for the Yellow primary in the spectral upsampling process. + * This array contains 38 precomputed reflectance values corresponding to specific wavelength samples. + * It is used to calculate the reflectance spectrum when converting a linear RGB color to its spectral representation. + */ private val SPD_Y = doubleArrayOf( 0.02055257, 0.02059936, @@ -136,6 +154,17 @@ private val SPD_Y = doubleArrayOf( 0.98350852 ) +/** + * A predefined spectral power distribution (SPD) array for the red channel, + * used in the spectral upsampling process to convert linear RGB colors into reflectance spectra. + * + * This array contains 38 values corresponding to specific wavelengths and represents + * the relative spectral contribution of the red channel in the conversion process. + * + * The SPD_R array is utilized in conjunction with other SPDs (e.g., SPD_C, SPD_M, SPD_Y, SPD_G, SPD_B) + * and the weights derived from spectral upsampling to calculate the reflectance spectrum + * for a given color. + */ private val SPD_R = doubleArrayOf( 0.03147571, 0.03146636, @@ -177,6 +206,16 @@ private val SPD_R = doubleArrayOf( 0.98551547 ) +/** + * Represents the predefined spectral power distribution (SPD) values for the green component + * used in spectral upsampling of linear RGB colors. + * + * This array contains 38 reflectance values corresponding to specific wavelengths and + * reflects the spectral characteristics of the green primary in the color model. + * + * It is utilized as one of the SPD datasets in the linearToReflectance function, which + * converts linear RGB colors into reflectance spectra. + */ private val SPD_G = doubleArrayOf( 0.49108579, 0.46944057, @@ -218,6 +257,12 @@ private val SPD_G = doubleArrayOf( 0.49889859 ) +/** + * Represents the spectral power distribution (SPD) values corresponding to the blue component + * of a linear RGB color. The array contains 38 precomputed reflectance values + * that span a specific range of wavelengths. These values are utilized in the spectral + * upsampling process to map an RGB color to its equivalent spectral reflectance distribution. + */ private val SPD_B = doubleArrayOf( 0.97901834, 0.97901649, @@ -259,6 +304,14 @@ private val SPD_B = doubleArrayOf( 0.0157002 ) +/** + * A pre-defined array representing the CIE 1931 Standard Observer's color matching function values for the X component. + * This data is used in color science calculations to transform spectral reflectance data into the CIE XYZ color space. + * The array contains 38 discrete samples corresponding to wavelengths within the visible spectrum. + * + * This constant is specifically used during computations involving spectral data to calculate the X component + * of the CIE XYZ color space via multiplication with a corresponding reflectance spectrum array. + */ private val CIE_CMF_X = doubleArrayOf( 0.00006469, 0.00021941, @@ -300,6 +353,17 @@ private val CIE_CMF_X = doubleArrayOf( 0.00002 ) +/** + * Represents the Y-component of the CIE 1931 color matching functions. + * + * The CIE 1931 color matching functions are used to convert spectral power distributions into + * CIE XYZ tristimulus values, which represent a color in a perceptually-uniform color space. + * These functions are defined over 38 discrete wavelength samples, typically covering + * the visible spectrum. + * + * The Y-component corresponds to the luminous efficiency function, + * which describes the sensitivity of human vision to different wavelengths of light. + */ private val CIE_CMF_Y = doubleArrayOf( 0.00000184, 0.00000621, @@ -341,6 +405,15 @@ private val CIE_CMF_Y = doubleArrayOf( 0.00000722 ) +/** + * Represents the Z component of the CIE 1931 2° Standard Observer Color Matching Function (CMF). + * + * This array contains precomputed values representing the spectral sensitivity of the human eye's Z cone. + * It is used in color science to convert spectral reflectance data into the Z component of the CIE XYZ color space. + * + * The values in this array correspond to sampling points across the visible light spectrum + * and are used in conjunction with `CIE_CMF_X` and `CIE_CMF_Y` to perform reflectance spectrum to XYZ color conversions. + */ private val CIE_CMF_Z = doubleArrayOf( 0.00030502, 0.00103681, @@ -382,6 +455,12 @@ private val CIE_CMF_Z = doubleArrayOf( 0.0 ) +/** + * Converts RGB color values into a form that represents spectral power distribution weights. + * + * @param rgb The RGB color in the form of a `ColorRGBa` object, which is to be converted to spectral weights. + * @return A `DoubleArray` representing the decomposed weights for white, cyan, magenta, yellow, red, green, and blue. + */ private fun spectralUpsampling(rgb: ColorRGBa): DoubleArray { var lrgb = rgb.toLinear() val w = min(min(lrgb.r, lrgb.g), lrgb.b) @@ -399,6 +478,14 @@ private fun spectralUpsampling(rgb: ColorRGBa): DoubleArray { } +/** + * Converts a linear RGB color into a reflectance spectrum represented as a `DoubleArray`. + * The resulting reflectance spectrum spans 38 wavelength samples + * and is computed using spectral upsampling based on predefined spectral distributions. + * + * @param rgb The linear RGB color to be converted, represented as a `ColorRGBa` object. + * @return A `DoubleArray` containing 38 reflectance values corresponding to the wavelengths. + */ internal fun linearToReflectance(rgb: ColorRGBa): DoubleArray { val eps = 0.00000001 val weights = spectralUpsampling(rgb) @@ -419,6 +506,20 @@ internal fun linearToReflectance(rgb: ColorRGBa): DoubleArray { return reflectance } +/** + * Computes the concentration of a component in a linear interpolation based on the specified parameters. + * + * The method calculates a concentration factor `c` using two linear values `l1` and `l2`, + * as well as a blend factor `t`. This can be used in scenarios such as spectral mixing + * or interpolation tasks where weights are dynamically computed. + * + * @param l1 The first linear value, typically derived from reflectance or intensity. + * @param l2 The second linear value, typically derived from reflectance or intensity. + * @param t The blending factor in the range [0.0, 1.0], where 0.0 represents full influence of `l1` + * and 1.0 represents full influence of `l2`. + * @return The computed concentration factor as a `Double`, representing the relative contribution + * of the components based on the blending factor. + */ private fun linearToConcentration(l1: Double, l2: Double, t: Double): Double { val t1 = l1 * (1 - t).pow(2.0) val t2 = l2 * t.pow(2.0) @@ -434,6 +535,16 @@ private fun DoubleArray.dot(other: DoubleArray): Double { return d } +/** + * Converts a reflectance spectrum represented as a `DoubleArray` to a color in the CIE XYZ color space. + * + * This method calculates the XYZ color by performing a dot product operation between the reflectance spectrum + * and the CIE color matching functions (CIE_CMF_X, CIE_CMF_Y, CIE_CMF_Z). The result is returned as a `ColorXYZa` object. + * + * @param reflectance An array of reflectance spectrum values, typically spanning the visible spectrum. + * This is represented as a `DoubleArray` with 38 wavelength samples. + * @return A `ColorXYZa` object representing the corresponding color in the CIE XYZ color space. + */ internal fun reflectanceToXYZ(reflectance: DoubleArray): ColorXYZa { val x = reflectance.dot(CIE_CMF_X) val y = reflectance.dot(CIE_CMF_Y) @@ -443,10 +554,34 @@ internal fun reflectanceToXYZ(reflectance: DoubleArray): ColorXYZa { private fun pow(x: Double, y: Double): Double = x.pow(y) +/** + * Applies the Saunderson correction to a reflectance value to account for surface reflectance effects. + * + * Saunderson correction adjusts the measured reflectance by considering front surface reflection + * and internal reflections in the material. The correction is based on two coefficients, `k1` and `k2`. + * + * @param rInf The measured reflectance value to be corrected. + * @param k1 The first Saunderson coefficient representing front surface reflection. + * @param k2 The second Saunderson coefficient representing internal reflection effects. + * @return The corrected reflectance value as a `Double`. + */ internal fun saundersonCorrection(rInf: Double, k1: Double, k2: Double): Double { return k1 + ((1 - k1) * (1 - k2) * rInf) / (1 - (k2 * rInf)) } +/** + * Blends two colors spectrally by interpolating their reflectance spectra and returns the resulting color. + * This method uses spectral upsampling, Saunderson correction, and concentration factors to compute + * the resulting color in the RGB color space. + * + * @param color1 The first color to be mixed, represented as a `ColorRGBa`. + * @param color2 The second color to be mixed, represented as a `ColorRGBa`. + * @param t The blending factor in the range [0.0, 1.0], where 0.0 represents full influence of `color1` + * and 1.0 represents full influence of `color2`. + * @param k1 The first Saunderson correction coefficient for surface reflection. Default is 0.0. + * @param k2 The second Saunderson correction coefficient for internal reflections. Default is 0.0. + * @return The resulting blended color as a `ColorRGBa`, maintaining the linearity of the first input color (`color1`). + */ fun mixSpectral(color1: ColorRGBa, color2: ColorRGBa, t: Double, k1: Double = 0.0, k2: Double = 0.0): ColorRGBa { val lrgb1 = color1.toLinear() val lrgb2 = color2.toLinear() diff --git a/orx-color/src/commonMain/kotlin/palettes/Classics.kt b/orx-color/src/commonMain/kotlin/palettes/Classics.kt index 5e4a67606..36c6fa2b7 100644 --- a/orx-color/src/commonMain/kotlin/palettes/Classics.kt +++ b/orx-color/src/commonMain/kotlin/palettes/Classics.kt @@ -6,10 +6,18 @@ import org.openrndr.color.HueShiftableColor import org.openrndr.extra.color.tools.shiftHue /** - * Generate an analogous palette - * @param T the color model to use - * @param hueShift Hue degrees between the first and the last color - * @param steps Number of colors to create + * Generates an analogous color palette based on the current color. + * + * This function creates a sequence of colors by shifting the hue of the current color + * gradually across a specified range of steps, using a particular color model that supports hue shifting. + * + * @param T The color model used for hue shifting. + * Must extend both `HueShiftableColor` and `ColorModel`. + * @param hueShift The total degree shift in hue between the first color and the last color. + * The hue shift is divided among the specified number of steps. + * @param steps The number of colors to include in the palette, including the starting color. + * Defaults to 5. + * @return A list of `ColorRGBa` instances forming the analogous palette. */ inline fun ColorRGBa.analogous(hueShift: Double, steps: Int = 5): List where T : HueShiftableColor, @@ -18,10 +26,21 @@ inline fun ColorRGBa.analogous(hueShift: Double, steps: Int = 5): Li } /** - * Generate a split complementary palette in which the receiver is the seed color - * @param T the color model to use - * @param splitFactor a value between 0 and 1 that indicates how much the complementary color should be split - * @param double should a double complementary palette be generated + * Generates a split complementary color palette based on the current `ColorRGBa`. + * + * The method calculates complementary colors that are spread around the complementary + * hue axis of the original color. Depending on the parameters, the result may include + * two or four additional colors in addition to the original color. + * + * @param T The color model and hue shifting capability of the colors to generate. + * @param splitFactor A value between 0.0 and 1.0 that controls the spread of the complementary colors + * around the complementary hue. A higher value increases the angle between + * the colors on the hue wheel, while a lower value decreases it. + * @param double If `true`, the method will generate two additional colors derived by more granular + * shifts within the complementary range. If `false`, a simpler complementary palette + * is returned. + * @return A list of `ColorRGBa` objects representing the split complementary palette, with the original + * color as the first element in the list. */ inline fun ColorRGBa.splitComplementary(splitFactor: Double, double: Boolean = false): List where T : HueShiftableColor, @@ -38,9 +57,16 @@ inline fun ColorRGBa.splitComplementary(splitFactor: Double, double: } } + /** - * Generate a triadic palette in which the receiver is the seed color. - * @param T the color model to use + * Generates a triadic color palette based on the current `ColorRGBa`. + * + * Triadic colors are evenly spaced on the color wheel, forming a triangle. + * This method generates two additional colors by evenly shifting the hue of the given color + * at 120° intervals around the hue circle. + * + * @param T The color model and hue shifting capability of the colors to generate. + * @return A list of `ColorRGBa` objects representing the triadic color palette. */ inline fun ColorRGBa.triadic(): List where T : HueShiftableColor, @@ -48,9 +74,14 @@ inline fun ColorRGBa.triadic(): List /** - * Generate a tetradic palette in which the receiver is the seed color. - * @param T the color model to use - * @param aspectRatio the aspect ratio between even and odd sides + * Generates a tetradic color scheme based on the current color. + * A tetradic color scheme consists of four colors that are equidistant on the color wheel. + * + * @param aspectRatio A double value representing the aspect ratio of the tetradic scheme. + * The aspect ratio determines the angular separation between the colors in the scheme. + * Default is 1.0, resulting in equidistant colors. + * @return A list of `ColorRGBa` instances representing the tetradic color scheme. + * The list includes the original color and three additional colors derived by shifting the hue. */ inline fun ColorRGBa.tetradic(aspectRatio: Double = 1.0): List where T : HueShiftableColor, diff --git a/orx-color/src/commonMain/kotlin/spaces/ColorHPLUVa.kt b/orx-color/src/commonMain/kotlin/spaces/ColorHPLUVa.kt index 13ec37420..e60dac93e 100644 --- a/orx-color/src/commonMain/kotlin/spaces/ColorHPLUVa.kt +++ b/orx-color/src/commonMain/kotlin/spaces/ColorHPLUVa.kt @@ -6,6 +6,16 @@ import org.openrndr.math.Vector4 import org.openrndr.math.mixAngle import kotlin.jvm.JvmRecord +/** + * Represents a color in the HPLUVa (Hue, Perceptual Lightness, Saturation, Alpha) color space. + * This color space is based on perceptual uniformity, making it suitable for operations + * like interpolation, shading, and manipulation of hue, saturation, and lightness values. + * + * @property h The hue component of the color, representing the angle on the color wheel in degrees [0, 360). + * @property s The saturation component of the color, representing the intensity of the color [0.0, 1.0]. + * @property l The lightness component of the color, representing the relative brightness [0.0, 1.0]. + * @property alpha The alpha (opacity) component of the color, ranging from fully transparent (0.0) to fully opaque (1.0). + */ @Serializable @JvmRecord data class ColorHPLUVa(val h: Double, val s: Double, val l: Double, override val alpha: Double = 1.0) : diff --git a/orx-color/src/commonMain/kotlin/spaces/ColorHSLUVa.kt b/orx-color/src/commonMain/kotlin/spaces/ColorHSLUVa.kt index ee562bc1a..617784491 100644 --- a/orx-color/src/commonMain/kotlin/spaces/ColorHSLUVa.kt +++ b/orx-color/src/commonMain/kotlin/spaces/ColorHSLUVa.kt @@ -78,8 +78,16 @@ private fun maxChromaForLH(L100: Double, H: Double): Double { return min } + /** - * HSLUV color space + * Represents a color in the HSLuv color space with an alpha transparency component. + * HSLuv is a perceptually uniform color space, where hues are uniformly distributed + * and the perception of color is consistent across the spectrum. + * + * @property h The hue of the color in degrees, ranging from 0.0 to 360.0. + * @property s The saturation of the color, ranging from 0.0 to 1.0. + * @property l The luminance of the color, ranging from 0.0 to 1.0. + * @property alpha The alpha transparency value, ranging from 0.0 (fully transparent) to 1.0 (fully opaque). */ @Serializable @JvmRecord diff --git a/orx-color/src/commonMain/kotlin/spaces/ColorOKHSLa.kt b/orx-color/src/commonMain/kotlin/spaces/ColorOKHSLa.kt index 021166273..b7e146f08 100644 --- a/orx-color/src/commonMain/kotlin/spaces/ColorOKHSLa.kt +++ b/orx-color/src/commonMain/kotlin/spaces/ColorOKHSLa.kt @@ -7,6 +7,16 @@ import org.openrndr.math.mixAngle import kotlin.jvm.JvmRecord import kotlin.math.* +/** + * Represents a color in the OKHSL (hue, saturation, lightness) color space with an alpha channel. + * This color model is based on perceptual uniformity and is useful for hue, saturation, and + * lightness manipulations while maintaining consistency with human vision. + * + * @property h The hue of the color, represented as a value in degrees [0.0, 360.0). + * @property s The saturation of the color, where 0.0 is fully desaturated (gray) and 1.0 is fully saturated. + * @property l The lightness of the color, where 0.0 is completely dark and 1.0 is completely light. + * @property alpha The opacity of the color, where 0.0 is fully transparent and 1.0 is fully opaque. + */ @Suppress("LocalVariableName") @Serializable @JvmRecord diff --git a/orx-color/src/commonMain/kotlin/spaces/ColorOKHSVa.kt b/orx-color/src/commonMain/kotlin/spaces/ColorOKHSVa.kt index 9dafc92d5..6fa61443e 100644 --- a/orx-color/src/commonMain/kotlin/spaces/ColorOKHSVa.kt +++ b/orx-color/src/commonMain/kotlin/spaces/ColorOKHSVa.kt @@ -7,6 +7,22 @@ import org.openrndr.math.mixAngle import kotlin.jvm.JvmRecord import kotlin.math.* +/** + * Represents a color in the OKHSVa color model. + * + * The OKHSVa color model is derived from OKLABa and provides a perceptually uniform representation + * of colors using hue (h), saturation (s), value (v), and alpha (opacity). + * + * This class supports operations and transformations such as conversion to and from RGBa, + * hue shifting, saturation adjustment, shading, and algebraic operations like addition, subtraction, + * and scaling. It is ideal for working with colors in contexts requiring accurate color mixing + * and perceptual results. + * + * @property h Hue value in degrees (0.0 - 360.0), representing the color's angle on the color wheel. + * @property s Saturation value (0.0 - 1.0), representing the intensity or purity of the color. + * @property v Value (0.0 - 1.0), representing the color's brightness. + * @property alpha Opacity value (0.0 - 1.0), with 1.0 being fully opaque. + */ @Suppress("LocalVariableName") @Serializable @JvmRecord diff --git a/orx-color/src/commonMain/kotlin/spaces/ColorOKLABa.kt b/orx-color/src/commonMain/kotlin/spaces/ColorOKLABa.kt index 3ef8dea18..6267e83c3 100644 --- a/orx-color/src/commonMain/kotlin/spaces/ColorOKLABa.kt +++ b/orx-color/src/commonMain/kotlin/spaces/ColorOKLABa.kt @@ -8,11 +8,16 @@ import kotlin.math.abs import kotlin.math.pow import kotlin.math.sign + /** - * Color in OKLab color space. - * [l] = lightness: black (0.0) to white (1.0), - * [a] = red (-1.0) to green (1.0), - * [b] = yellow (-1.0) to blue (1.0). + * Represents a color in the OKLAB color space with an optional alpha (transparency) value. + * OKLAB is a perceptual color space designed to represent colors in a way that aligns + * with human visual perception, offering an alternative to traditional color spaces like RGB. + * + * @property l The lightness component of the color. A value between 0 (black) and 1 (white). + * @property a The 'a' component in the OKLAB color space, representing the first chromatic axis. + * @property b The 'b' component in the OKLAB color space, representing the second chromatic axis. + * @property alpha The alpha (opacity) value of the color. A value between 0.0 (completely transparent) and 1.0 (completely opaque). */ @Suppress("LocalVariableName") @Serializable diff --git a/orx-color/src/commonMain/kotlin/spaces/ColorOKLCHa.kt b/orx-color/src/commonMain/kotlin/spaces/ColorOKLCHa.kt index 285ca0d71..1451b4fb9 100644 --- a/orx-color/src/commonMain/kotlin/spaces/ColorOKLCHa.kt +++ b/orx-color/src/commonMain/kotlin/spaces/ColorOKLCHa.kt @@ -6,8 +6,14 @@ import org.openrndr.math.* import kotlin.jvm.JvmRecord import kotlin.math.* + /** - * Color in cylindrical OKLab space + * Represents a color in the OKLCH color space, which is based on the OKLab color space with added polar coordinates for chroma and hue. + * + * @property l Lightness of the color. Range: 0.0 (black) to 1.0 (white). + * @property c Chroma, representing color intensity. Typically non-negative. + * @property h Hue angle in degrees. Range: 0.0 to 360.0. + * @property alpha Opacity of the color. Range: 0.0 (fully transparent) to 1.0 (fully opaque). Default is 1.0. */ @Serializable @JvmRecord diff --git a/orx-color/src/commonMain/kotlin/spaces/ColorXSLUVa.kt b/orx-color/src/commonMain/kotlin/spaces/ColorXSLUVa.kt index 815af22c7..f7b6a01c2 100644 --- a/orx-color/src/commonMain/kotlin/spaces/ColorXSLUVa.kt +++ b/orx-color/src/commonMain/kotlin/spaces/ColorXSLUVa.kt @@ -7,6 +7,16 @@ import org.openrndr.math.map import org.openrndr.math.mixAngle import kotlin.jvm.JvmRecord +/** + * Represents a color in the XSLUV color space with an optional alpha transparency value. + * XSLUV is a cylindrical representation of the HSLUV color space using an alternative X coordinate + * instead of the standard hue. It provides a perceptually uniform color representation. + * + * @property x The X coordinate representing the hue variation in the XSLUV color space. + * @property s The saturation of the color in the XSLUV color space. + * @property l The luminance of the color in the XSLUV color space. + * @property alpha The alpha transparency value of the color, ranging from 0.0 to 1.0. Defaults to 1.0. + */ @Serializable @JvmRecord data class ColorXSLUVa(val x: Double, val s: Double, val l: Double, override val alpha: Double = 1.0) : diff --git a/orx-color/src/commonMain/kotlin/spaces/OKHelpers.kt b/orx-color/src/commonMain/kotlin/spaces/OKHelpers.kt index ec7c35ed5..adfabfb39 100644 --- a/orx-color/src/commonMain/kotlin/spaces/OKHelpers.kt +++ b/orx-color/src/commonMain/kotlin/spaces/OKHelpers.kt @@ -14,6 +14,12 @@ internal fun max(a: Double, b: Double, c: Double, d: Double): Double { return max(max(a, b), max(c, d)) } +/** + * Computes a modified version of the Toe mapping function, used in color space transformations. + * + * @param x The input value for the function, representing a parameter in the transformation process. + * @return The transformed value after applying the Toe mapping function. + */ fun toe(x: Double): Double { val k1 = 0.206 val k2 = 0.03 @@ -24,6 +30,14 @@ fun toe(x: Double): Double { return 0.5 * (k3 * x - k1 + sqrt(d.coerceAtLeast(0.0))) } +/** + * Computes the toe inverse transformation of a given input value based on specific constants. + * This function is typically used for calculations involving perceptual transformations + * or non-linear scaling in color spaces or other mathematical models. + * + * @param x The input value for which the toe inverse transformation is calculated. + * @return A transformed value based on the toe inverse function. + */ fun toeInv(x: Double): Double { val k1 = 0.206 val k2 = 0.03 diff --git a/orx-color/src/commonMain/kotlin/statistics/DeltaE.kt b/orx-color/src/commonMain/kotlin/statistics/DeltaE.kt index 90488cdd8..af6d3b338 100644 --- a/orx-color/src/commonMain/kotlin/statistics/DeltaE.kt +++ b/orx-color/src/commonMain/kotlin/statistics/DeltaE.kt @@ -5,7 +5,12 @@ import org.openrndr.color.ConvertibleToColorRGBa import org.openrndr.math.Vector3 /** - * Computes delta E between two colors. + * Computes the CIE76 color difference (ΔE*76) between this color and another color. + * The method calculates the Euclidean distance between the two colors in the LAB color space. + * If either of the colors is not in LAB format, it will be converted to LAB before computation. + * + * @param other The second color to compare, which should implement the ConvertibleToColorRGBa interface. + * @return The calculated CIE76 color difference as a Double. */ fun T.deltaE76(other: T): Double { return if (this is ColorLABa && other is ColorLABa) { diff --git a/orx-color/src/commonMain/kotlin/tools/ColorRGBaExtensions.kt b/orx-color/src/commonMain/kotlin/tools/ColorRGBaExtensions.kt index eba7fbec9..3a4a41e97 100644 --- a/orx-color/src/commonMain/kotlin/tools/ColorRGBaExtensions.kt +++ b/orx-color/src/commonMain/kotlin/tools/ColorRGBaExtensions.kt @@ -3,10 +3,30 @@ package org.openrndr.extra.color.tools import org.openrndr.color.* import org.openrndr.extra.color.spaces.* +/** + * Indicates whether the color is out of the RGB gamut. + * + * This property evaluates if the color's red, green, or blue components are outside + * the valid range of [0.0, 1.0], accounting for a slight tolerance in the negative range (-1E-3). + * Additionally, it checks whether the alpha component is outside the range [0.0, 1.0]. + * + * This property is commonly used in color manipulation functions to detect and handle + * out-of-gamut colors, which may require adjustments (e.g., clipping or chroma adjustment) + * to fit within a valid color space. + */ val ColorRGBa.isOutOfGamut: Boolean get() { return (r !in -1E-3..1.0) || (g !in -1E-3..1.0) || (b !in -1E-3..1.0) || (alpha !in 0.0..1.0) } + +/** + * Matches the linearity of the current `ColorRGBa` instance with another `ColorRGBa` instance. + * If the linearity of `other` matches that of the current instance, the current instance is returned. + * Otherwise, it converts the current instance to match the linearity of `other`. + * + * @param other The `ColorRGBa` instance whose linearity is to be matched. + * @return A `ColorRGBa` instance with the same linearity as the `other` color. + */ fun ColorRGBa.matchLinearity(other: ColorRGBa): ColorRGBa { return if (other.linearity.isEquivalent(linearity)) { this @@ -36,6 +56,12 @@ inline fun ColorRGBa.blendWith(other: ColorRGBa, steps: Int): Sequen } +/** + * Converts the current `ColorRGBa` instance to the specified color model type `T`. + * + * @return An instance of the specified color model type `T` after conversion. + * @throws IllegalStateException if the specified color model is not supported. + */ inline fun > ColorRGBa.convertTo(): T { val converted = when (T::class) { ColorHSLa::class -> this.toHSLa() @@ -134,11 +160,27 @@ inline fun ColorRGBa.modulateChroma(factor: Double): ColorRGBa convertTo().modulateChroma(factor).toRGBa().matchLinearity(this) +/** + * Adjusts the saturation of the current `ColorRGBa` based on a given factor. + * + * @param T The target color model type that supports saturation adjustments. + * @param factor The saturation adjustment factor. A value of 1.0 keeps the saturation unchanged, + * values less than 1.0 decrease saturation, and values greater than 1.0 increase it. + * @return A new `ColorRGBa` instance with the adjusted saturation, maintaining the linearity of + * the original color. + */ inline fun ColorRGBa.saturate(factor: Double): ColorRGBa where T : SaturatableColor, T : ColorModel, T : ConvertibleToColorRGBa = convertTo().saturate(factor).toRGBa().matchLinearity(this) +/** + * Shifts the hue of the current `ColorRGBa` by the specified number of degrees. + * The method is only applicable to color models that support hue shifting and can be converted to `ColorRGBa`. + * + * @param degrees The amount of hue adjustment in degrees. Positive values shift the hue clockwise, while negative values shift it counterclockwise. + * @return A new `ColorRGBa` instance with the hue shifted by the specified degree, maintaining the same linearity as the input color. + */ inline fun ColorRGBa.shiftHue(degrees: Double): ColorRGBa where T : HueShiftableColor, T : ColorModel,