[orx-color] Match new HueShiftableColor / SaturatableColor interfaces

This commit is contained in:
Edwin Jakobs
2023-12-09 10:49:46 +01:00
parent 10ffb7ce59
commit 7413bcacc3
9 changed files with 116 additions and 61 deletions

View File

@@ -26,11 +26,15 @@ data class ColorHPLUVa(val h: Double, val s: Double, val l: Double, override val
return ColorLCHUVa(l100, c100, h)
}
override fun shiftHue(shiftInDegrees: Double): ColorHPLUVa = copy(h = h + (shiftInDegrees))
override val hue: Double = h
override fun withHue(hue: Double) = copy(h = hue)
override fun shade(factor: Double): ColorHPLUVa = copy(l = l * factor)
override fun saturate(factor: Double): ColorHPLUVa = copy(s = s * factor)
override val saturation: Double = s
override fun withSaturation(saturation: Double): ColorHPLUVa = copy(s = saturation)
override fun toRGBa(): ColorRGBa = toLCHUVa().toRGBa()

View File

@@ -114,11 +114,12 @@ data class ColorHSLUVa(val h: Double, val s: Double, val l: Double, override val
return ColorXSLUVa(hueToX(h), s, l, alpha)
}
override fun shiftHue(shiftInDegrees: Double) = copy(h = h + (shiftInDegrees))
override val hue: Double =h
override fun withHue(hue: Double): ColorHSLUVa = copy(h = hue)
override fun shade(factor: Double) = copy(l = l * factor)
override fun saturate(factor: Double) = copy(s = s * factor)
override val saturation: Double = s
override fun withSaturation(saturation: Double): ColorHSLUVa = copy(s = saturation)
override fun toRGBa(): ColorRGBa {
return toLCHUVa().toRGBa()

View File

@@ -95,11 +95,14 @@ data class ColorOKHSLa(val h: Double, val s: Double, val l: Double, override val
).toRGBa().toSRGB()
}
override fun shiftHue(shiftInDegrees: Double): ColorOKHSLa = copy(h = h + shiftInDegrees)
override val hue: Double = h
override fun withHue(hue: Double): ColorOKHSLa = copy(h = hue)
override fun opacify(factor: Double): ColorOKHSLa = copy(alpha = alpha * factor)
override val saturation: Double = s
override fun saturate(factor: Double): ColorOKHSLa = copy(s = s * factor)
override fun withSaturation(saturation: Double): ColorOKHSLa = copy(s = saturation)
override fun shade(factor: Double): ColorOKHSLa = copy(l = l * factor)

View File

@@ -102,9 +102,14 @@ data class ColorOKHSVa(val h: Double, val s: Double, val v: Double, override val
).toRGBa().toSRGB()
}
override fun shiftHue(shiftInDegrees: Double): ColorOKHSVa = copy(h = h + shiftInDegrees)
override val hue: Double = h
override fun withHue(hue: Double): ColorOKHSVa = copy(h = hue)
override fun opacify(factor: Double): ColorOKHSVa = copy(alpha = alpha * factor)
override fun saturate(factor: Double): ColorOKHSVa = copy(s = s * factor)
override val saturation: Double = s
override fun withSaturation(saturation: Double): ColorOKHSVa = copy(s = saturation)
override fun shade(factor: Double): ColorOKHSVa = copy(v = v * factor)
override fun minus(right: ColorOKHSVa) =
copy(h = h - right.h, s = s - right.s, v = v - right.v, alpha = alpha - right.alpha)

View File

@@ -12,8 +12,8 @@ import kotlin.math.*
data class ColorOKLCHa(val l: Double, val c: Double, val h: Double, override val alpha: Double = 1.0) :
ColorModel<ColorOKLCHa>,
ShadableColor<ColorOKLCHa>,
ChromaColor<ColorOKLCHa>,
HueShiftableColor<ColorOKLCHa>,
SaturatableColor<ColorOKLCHa>,
AlgebraicColor<ColorOKLCHa> {
companion object {
@@ -35,8 +35,6 @@ data class ColorOKLCHa(val l: Double, val c: Double, val h: Double, override val
override fun opacify(factor: Double) = copy(alpha = alpha * factor)
override fun shade(factor: Double) = copy(l = l * factor)
override fun shiftHue(shiftInDegrees: Double) = copy(h = h + shiftInDegrees)
override fun saturate(factor: Double) = copy(c = c * factor)
override fun plus(right: ColorOKLCHa) = copy(l = l + right.l, c = c + right.c, h = h + right.h, alpha = alpha + right.alpha)
override fun minus(right: ColorOKLCHa) = copy(l = l - right.l, c = c - right.c, h = h - right.h, alpha = alpha - right.alpha)
@@ -51,6 +49,11 @@ data class ColorOKLCHa(val l: Double, val c: Double, val h: Double, override val
override fun toRGBa(): ColorRGBa = toOKLABa().toRGBa()
override fun toVector4(): Vector4 = Vector4(l, c, h, alpha)
override val chroma: Double = c
override fun withChroma(chroma: Double): ColorOKLCHa = copy(c = chroma)
override val hue: Double = h
override fun withHue(hue: Double): ColorOKLCHa = copy(h = hue)
}
fun mix(left: ColorOKLCHa, right: ColorOKLCHa, x: Double): ColorOKLCHa {

View File

@@ -16,12 +16,13 @@ data class ColorXSLUVa(val x: Double, val s: Double, val l: Double, override val
@Deprecated("Legacy alpha parameter name", ReplaceWith("alpha"))
val a = alpha
override fun shiftHue(shiftInDegrees: Double) = copy(x = x + (shiftInDegrees))
override val hue: Double = x
override fun withHue(hue: Double): ColorXSLUVa = copy(x = hue)
override fun shade(factor: Double) = copy(l = l * factor)
override val saturation: Double = s
override fun saturate(factor: Double) = copy(s = s * factor)
override fun withSaturation(saturation: Double): ColorXSLUVa = copy(s = saturation)
override fun toRGBa(): ColorRGBa = toHSLUVa().toRGBa()

View File

@@ -3,9 +3,27 @@ package org.openrndr.extra.color.tools
import org.openrndr.color.*
import org.openrndr.extra.color.spaces.*
fun ColorRGBa.matchLinearity(other: ColorRGBa): ColorRGBa {
return if (other.linearity.isEquivalent(linearity)) {
this
} else {
if (other.linearity.isEquivalent(Linearity.LINEAR)) {
toLinear()
} else if (other.linearity.isEquivalent(Linearity.SRGB)) {
toSRGB()
} else {
this
}
}
}
inline fun <reified T> ColorRGBa.hue(): Double
where T : HueShiftableColor<T>,
T : ColorModel<T> = convertTo<T>().hue
inline fun <reified T> ColorRGBa.blendWith(other: ColorRGBa, steps: Int): Sequence<ColorRGBa>
where T : AlgebraicColor<T>,
T: ColorModel<T> {
T : ColorModel<T> {
return sequence {
for (step in 0 until steps) {
yield(mixedWith<T>(other, step / (steps - 1.0)))
@@ -13,6 +31,7 @@ inline fun <reified T> ColorRGBa.blendWith(other: ColorRGBa, steps: Int): Sequen
}
}
inline fun <reified T : ColorModel<T>> ColorRGBa.convertTo(): T {
val converted = when (T::class) {
ColorHSLa::class -> this.toHSLa()
@@ -38,61 +57,37 @@ inline fun <reified T : ColorModel<T>> ColorRGBa.convertTo(): T {
return converted as T
}
inline fun <reified T> ColorRGBa.mixHue(hue: Double, factor: Double): ColorRGBa
where T : HueShiftableColor<T>,
T : ColorModel<T>,
T : ConvertibleToColorRGBa = convertTo<T>().mixHue(hue, factor).toRGBa().matchLinearity(this)
inline fun <reified T> ColorRGBa.withHue(hue: Double): ColorRGBa
where T : HueShiftableColor<T>,
T : ColorModel<T>,
T : ConvertibleToColorRGBa = convertTo<T>().withHue(hue).toRGBa().matchLinearity(this)
inline fun <reified T> ColorRGBa.mixSaturation(saturation: Double, factor: Double): ColorRGBa
where T : SaturatableColor<T>,
T : ColorModel<T>,
T : ConvertibleToColorRGBa =
convertTo<T>().mixSaturation(saturation, factor).toRGBa().matchLinearity(this)
inline fun <reified T> ColorRGBa.mixedWith(other: ColorRGBa, factor: Double): ColorRGBa
where T : AlgebraicColor<T>, T : ColorModel<T> {
val source = convertTo<T>()
val target = other.convertTo<T>()
val mixed = source.mix(target, factor).toRGBa()
return if (mixed.linearity.isEquivalent(linearity)) {
mixed
} else {
if (linearity.isEquivalent(Linearity.LINEAR)) {
mixed.toLinear()
} else if (linearity.isEquivalent(Linearity.SRGB)) {
mixed.toSRGB()
} else {
mixed
}
}
return source.mix(target, factor).toRGBa().matchLinearity(this)
}
inline fun <reified T> ColorRGBa.saturate(factor: Double): ColorRGBa
where T : SaturatableColor<T>,
T : ColorModel<T>,
T : ConvertibleToColorRGBa {
val saturated = convertTo<T>().saturate(factor).toRGBa()
return if (saturated.linearity.isEquivalent(linearity)) {
saturated
} else {
if (linearity.isEquivalent(Linearity.LINEAR)) {
saturated.toLinear()
} else if (linearity.isEquivalent(Linearity.SRGB)) {
saturated.toSRGB()
} else {
saturated
}
}
}
T : ConvertibleToColorRGBa = convertTo<T>().saturate(factor).toRGBa().matchLinearity(this)
inline fun <reified T> ColorRGBa.shiftHue(degrees: Double): ColorRGBa where
T : HueShiftableColor<T>,
T : ColorModel<T>,
T : ConvertibleToColorRGBa {
val converted = convertTo<T>()
val shifted = (converted.shiftHue(degrees) as ConvertibleToColorRGBa).toRGBa()
return if (shifted.linearity.isEquivalent(linearity)) {
shifted
} else {
if (linearity.isEquivalent(Linearity.LINEAR)) {
shifted.toLinear()
} else if (linearity.isEquivalent(Linearity.SRGB)) {
shifted.toSRGB()
} else {
shifted
}
}
}
T : ConvertibleToColorRGBa = convertTo<T>().shiftHue(degrees).toRGBa().matchLinearity(this)

View File

@@ -18,7 +18,6 @@ fun main() {
configure {
width = 800
height = 800
}
program {
val mesh = sphereMesh(8, 8, radius = 0.1)

View File

@@ -0,0 +1,44 @@
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.isolated
import org.openrndr.extra.color.presets.NAVY
import org.openrndr.extra.color.spaces.OKHSV
import org.openrndr.extra.color.tools.hue
import org.openrndr.extra.color.tools.mixHue
import org.openrndr.extra.color.tools.withHue
import kotlin.math.cos
fun main() {
application {
configure {
width = 800
height = 800
}
program {
extend {
val seedColor = ColorRGBa.PINK
val targetHue = seconds*100.0
val rows = 10
val columns = 12
val cellWidth = width / columns.toDouble()
val cellHeight = height / rows.toDouble()
drawer.stroke = null
for (j in 0 until 10) {
drawer.isolated {
for (i in 0 until columns) {
drawer.fill = seedColor
.withHue<OKHSV>(i * 360.0 / columns)
.mixHue<OKHSV>(targetHue, j / (rows.toDouble()-1.0))
drawer.rectangle(0.0, 0.0, cellWidth, cellHeight)
drawer.translate(cellWidth, 0.0)
}
}
drawer.translate(0.0, cellHeight)
}
}
}
}
}