[orx-color] Fix ColorXSLUV

This commit is contained in:
Edwin Jakobs
2023-12-07 14:38:22 +01:00
parent 3dd29f5128
commit 0b87c9687d
4 changed files with 90 additions and 18 deletions

View File

@@ -151,20 +151,20 @@ internal fun map(x: Double, a: Double, b: Double, c: Double, d: Double): Double
return ((x - a) / (b - a)) * (d - c) + c
}
private fun hueToX(hue:Double): Double {
val h = ((hue % 360.0) + 360.0) % 360.0
fun hueToX(hue:Double): Double {
val h = hue.mod(360.0)
return if (0 <= h && h < 35) {
map(h, 0.0, 35.0, 0.0, 60.0)
h.map(0.0, 35.0, 0.0, 60.0)
} else if (35 <= h && h < 60) {
map(h, 35.0, 60.0, 60.0, 120.0)
h.map(35.0, 60.0, 60.0, 120.0)
} else if (60 <= h && h < 135.0) {
map(h, 60.0, 135.0, 120.0, 180.0)
h.map(60.0, 135.0, 120.0, 180.0)
} else if (135.0 <= h && h < 225.0) {
map(h, 135.0, 225.0, 180.0, 240.0)
h.map(135.0, 225.0, 180.0, 240.0)
} else if (225.0 <= h && h < 275.0) {
map(h, 225.0, 275.0, 240.0, 300.0)
h.map( 225.0, 275.0, 240.0, 300.0)
} else {
map(h, 276.0, 360.0, 300.0, 360.0)
h.map( 275.0, 360.0, 300.0, 360.0)
}
}

View File

@@ -3,6 +3,7 @@ package org.openrndr.extra.color.spaces
import kotlinx.serialization.Serializable
import org.openrndr.color.*
import org.openrndr.math.Vector4
import org.openrndr.math.map
import org.openrndr.math.mixAngle
@Serializable
@@ -28,9 +29,11 @@ data class ColorXSLUVa(val x: Double, val s: Double, val l: Double, override val
override fun opacify(factor: Double) = copy(alpha = alpha * factor)
override fun minus(right: ColorXSLUVa) = copy(x = x - right.x, s = s - right.s, l = l - right.l, alpha = alpha - right.alpha)
override fun minus(right: ColorXSLUVa) =
copy(x = x - right.x, s = s - right.s, l = l - right.l, alpha = alpha - right.alpha)
override fun plus(right: ColorXSLUVa) = copy(x = x + right.x, s = s + right.s, l = l + right.l, alpha = alpha + right.alpha)
override fun plus(right: ColorXSLUVa) =
copy(x = x + right.x, s = s + right.s, l = l + right.l, alpha = alpha + right.alpha)
override fun times(scale: Double) = copy(x = x * scale, s = s * scale, l = l * scale, alpha = alpha * scale)
@@ -39,20 +42,20 @@ data class ColorXSLUVa(val x: Double, val s: Double, val l: Double, override val
override fun toVector4(): Vector4 = Vector4(x, s, l, alpha)
}
private fun xToHue(x:Double) : Double {
fun xToHue(x: Double): Double {
@Suppress("NAME_SHADOWING") val x = x.mod(360.0)
return if (0.0 <= x && x < 60.0) {
map(x, 0.0, 60.0, 0.0, 35.0)
x.map(0.0, 60.0, 0.0, 35.0)
} else if (60.0 <= x && x < 120.0) {
map(x, 60.0, 120.0, 35.0, 60.0)
x.map(60.0, 120.0, 35.0, 60.0)
} else if (120.0 <= x && x < 180.0) {
map(x, 120.0, 180.0, 60.0, 135.0)
x.map(120.0, 180.0, 60.0, 135.0)
} else if (180.0 <= x && x < 240.0) {
map(x, 180.0, 240.0, 135.0, 225.0)
x.map(180.0, 240.0, 135.0, 225.0)
} else if (240.0 <= x && x < 300.0) {
map(x, 240.0, 300.0, 225.0, 275.0)
x.map(240.0, 300.0, 225.0, 275.0)
} else {
map(x, 300.0, 360.0, 276.0, 360.0)
x.map( 300.0, 360.0, 275.0, 360.0)
}
}
@@ -62,7 +65,8 @@ fun mix(left: ColorXSLUVa, right: ColorXSLUVa, x: Double): ColorXSLUVa {
mixAngle(left.x, right.x, sx),
(1.0 - sx) * left.s + sx * right.s,
(1.0 - sx) * left.l + sx * right.l,
(1.0 - sx) * left.alpha + sx * right.alpha)
(1.0 - sx) * left.alpha + sx * right.alpha
)
}
fun ColorRGBa.toXSLUVa() = toHSLUVa().toXSLUVa()

View File

@@ -0,0 +1,24 @@
package spaces
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.color.spaces.toHSLUVa
import kotlin.test.Test
import kotlin.test.assertTrue
class TestHSLUVa {
@Test
fun testConversions() {
val testColors = listOf(ColorRGBa.RED, ColorRGBa.BLUE, ColorRGBa.GREEN, ColorRGBa.GRAY, ColorRGBa.YELLOW)
val error = (-1E-3 .. 1E-3)
testColors.forEach {
val testColor = it
val toColor = it.toHSLUVa()
val restoreColor = toColor.toRGBa().toSRGB()
assertTrue("color $testColor, $toColor, $restoreColor") {
testColor.r - restoreColor.r in error && testColor.g - restoreColor.g in error && testColor.b - restoreColor.b in error
}
}
}
}

View File

@@ -0,0 +1,44 @@
package spaces
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.color.spaces.hueToX
import org.openrndr.extra.color.spaces.toHSLUVa
import org.openrndr.extra.color.spaces.toXSLUVa
import org.openrndr.extra.color.spaces.xToHue
import kotlin.math.abs
import kotlin.test.Test
import kotlin.test.assertTrue
class TestXSLUVa {
@Test
fun testHueConversions() {
for (i in 0 until 3600) {
val inputHue = i/10.0
val x = hueToX(inputHue)
val recoveredHue = xToHue(x)
assertTrue( abs(recoveredHue-inputHue) < 1E-8, "$inputHue $recoveredHue")
}
}
@Test
fun testConversions() {
val testColors = listOf(ColorRGBa.RED, ColorRGBa.BLUE, ColorRGBa.GREEN, ColorRGBa.GRAY, ColorRGBa.YELLOW)
val error = (-1E-3..1E-3)
testColors.forEach {
val testColor = it
val hsluvColor = it.toHSLUVa()
val xsluvColor = it.toXSLUVa()
val restoredHsluvColor = xsluvColor.toHSLUVa()
val dh = restoredHsluvColor.h - hsluvColor.h
val dl = restoredHsluvColor.l - hsluvColor.l
val ds = restoredHsluvColor.s - hsluvColor.s
assertTrue(abs(dh) < 1E-7)
}
}
}