Bump to OPENRNDR 0.3.44-rc.11, add colorSequence

This commit is contained in:
Edwin Jakobs
2020-08-21 15:06:59 +02:00
parent 48730123ba
commit 158ae715e4
9 changed files with 292 additions and 23 deletions

View File

@@ -0,0 +1,77 @@
// Create a simple rectangle composition based on colors sampled from image
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.isolated
import org.openrndr.extensions.SingleScreenshot
import org.openrndr.extras.color.palettes.rangeTo
import org.openrndr.extras.color.presets.CORAL
import org.openrndr.extras.color.spaces.toHSLUVa
fun main() = application {
program {
// -- this block is for automation purposes only
if (System.getProperty("takeScreenshot") == "true") {
extend(SingleScreenshot()) {
this.outputFile = System.getProperty("screenshotPath")
}
}
extend {
drawer.isolated {
for (c in ColorRGBa.PINK..ColorRGBa.BLUE.toHSVa() blend 10) {
drawer.fill = c
drawer.rectangle(0.0, 0.0, 40.0, 40.0)
drawer.translate(0.0, 40.0)
}
}
drawer.translate(50.0, 0.0)
drawer.isolated {
for (c in ColorRGBa.PINK..ColorRGBa.BLUE blend 10) {
drawer.fill = c
drawer.rectangle(0.0, 0.0, 40.0, 40.0)
drawer.translate(0.0, 40.0)
}
}
drawer.translate(50.0, 0.0)
drawer.isolated {
for (c in ColorRGBa.PINK..ColorRGBa.BLUE.toHSLUVa() blend 10) {
drawer.fill = c.toSRGB()
drawer.rectangle(0.0, 0.0, 40.0, 40.0)
drawer.translate(0.0, 40.0)
}
}
drawer.translate(50.0, 0.0)
drawer.isolated {
for (c in ColorRGBa.PINK..ColorRGBa.BLUE.toXSVa() blend 10) {
drawer.fill = c.toSRGB()
drawer.rectangle(0.0, 0.0, 40.0, 40.0)
drawer.translate(0.0, 40.0)
}
}
drawer.translate(50.0, 0.0)
drawer.isolated {
for (c in ColorRGBa.PINK..ColorRGBa.BLUE.toLUVa() blend 10) {
drawer.fill = c.toSRGB()
drawer.rectangle(0.0, 0.0, 40.0, 40.0)
drawer.translate(0.0, 40.0)
}
}
drawer.translate(50.0, 0.0)
drawer.isolated {
for (c in ColorRGBa.PINK..ColorRGBa.BLUE.toLCHUVa() blend 10) {
drawer.fill = c.toSRGB()
drawer.rectangle(0.0, 0.0, 40.0, 40.0)
drawer.translate(0.0, 40.0)
}
}
}
}
}

View File

@@ -0,0 +1,33 @@
// Create a colorSequence with multiple color models
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.isolated
import org.openrndr.extensions.SingleScreenshot
import org.openrndr.extras.color.palettes.colorSequence
import org.openrndr.extras.color.palettes.rangeTo
import org.openrndr.extras.color.presets.CORAL
import org.openrndr.extras.color.spaces.toHSLUVa
fun main() = application {
program {
// -- this block is for automation purposes only
if (System.getProperty("takeScreenshot") == "true") {
extend(SingleScreenshot()) {
this.outputFile = System.getProperty("screenshotPath")
}
}
extend {
val cs = colorSequence(0.0 to ColorRGBa.PINK,
0.5 to ColorRGBa.BLUE,
1.0 to ColorRGBa.PINK.toHSLUVa()) // <-- note this one is in hsluv
for (c in cs blend (width / 40)) {
drawer.fill = c
drawer.stroke = null
drawer.rectangle(0.0, 0.0, 40.0, height.toDouble())
drawer.translate(40.0, 0.0)
}
}
}
}

View File

@@ -0,0 +1,77 @@
package org.openrndr.extras.color.palettes
import org.openrndr.color.*
import org.openrndr.extras.color.spaces.ColorHPLUVa
import org.openrndr.extras.color.spaces.ColorHSLUVa
import org.openrndr.extras.color.spaces.toHPLUVa
import org.openrndr.extras.color.spaces.toHSLUVa
fun main() {
for (c in ColorRGBa.PINK..ColorRGBa.GRAY blend 10) {
}
for (c in ColorRGBa.PINK..ColorHSVa(20.0, 0.5, 0.5) blend 10) {
println(c)
}
colorSequence(
0.0 to ColorRGBa.PINK,
0.5 to ColorRGBa.RED,
1.0 to hsv(360.0, 1.0, 1.0)
).index(0.8)
}
fun <T> colorSequence(vararg offsets: Pair<Double, T>): ColorSequence
where T : ConvertibleToColorRGBa {
return ColorSequence(offsets.sortedBy { it.first })
}
class ColorSequence(val colors: List<Pair<Double, ConvertibleToColorRGBa>>) {
infix fun blend(steps: Int): List<ColorRGBa> = index(0.0, 1.0, steps)
fun index(t0: Double, t1: Double, steps: Int) = (0 until steps).map {
val f = (it / (steps+0.0))
val t = t0 * (1.0 - f) + t1 * f
index(t)
}
fun index(t: Double): ColorRGBa {
if (colors.size == 1) {
return colors.first().second.toRGBa()
}
if (t < colors[0].first) {
return colors[0].second.toRGBa()
}
if (t >= colors.last().first) {
return colors.last().second.toRGBa()
}
val rightIndex = colors.indexOfLast { it.first <= t }
val leftIndex = (rightIndex + 1).coerceIn(0, colors.size - 1)
val right = colors[rightIndex]
val left = colors[leftIndex]
val rt = t - right.first
val dt = left.first - right.first
val nt = rt / dt
return when (val l = left.second) {
is ColorRGBa -> right.second.toRGBa().mix(l, nt)
is ColorHSVa -> right.second.toRGBa().toHSVa().mix(l, nt).toRGBa()
is ColorHSLa -> right.second.toRGBa().toHSLa().mix(l, nt).toRGBa()
is ColorXSVa -> right.second.toRGBa().toXSVa().mix(l, nt).toRGBa()
is ColorXSLa -> right.second.toRGBa().toXSLa().mix(l, nt).toRGBa()
is ColorLABa -> right.second.toRGBa().toLABa().mix(l, nt).toRGBa()
is ColorLUVa -> right.second.toRGBa().toLUVa().mix(l, nt).toRGBa()
is ColorHSLUVa -> right.second.toRGBa().toHSLUVa().mix(l, nt).toRGBa()
is ColorHPLUVa -> right.second.toRGBa().toHPLUVa().mix(l, nt).toRGBa()
is ColorLCHUVa -> right.second.toRGBa().toLCHUVa().mix(l, nt).toRGBa()
is ColorLCHABa -> right.second.toRGBa().toLCHABa().mix(l, nt).toRGBa()
else -> error("unsupported color space: ${l::class}")
}.toSRGB()
}
}
operator fun ConvertibleToColorRGBa.rangeTo(end: ConvertibleToColorRGBa) = colorSequence(0.0 to this, 1.0 to end)

View File

@@ -1,7 +1,7 @@
package org.openrndr.extras.color.spaces
import org.openrndr.color.ColorLCHUVa
import org.openrndr.color.ColorRGBa
import org.openrndr.color.*
import org.openrndr.math.mixAngle
import java.util.*
import kotlin.math.min
import kotlin.math.pow
@@ -17,7 +17,7 @@ private val epsilon = 0.0088564516
private fun getBounds(L: Double): List<DoubleArray>? {
val result = ArrayList<DoubleArray>()
val sub1 = Math.pow(L + 16, 3.0) / 1560896
val sub1 = (L + 16).pow(3.0) / 1560896
val sub2 = if (sub1 > epsilon) sub1 else L / kappa
for (c in 0..2) {
val m1 = m[c][0]
@@ -77,35 +77,66 @@ fun maxChromaForLH(L: Double, H: Double): Double {
return min
}
data class ColorHSLUVa(val h: Double, val s: Double, val l: Double) {
data class ColorHSLUVa(val h: Double, val s: Double, val l: Double, val a: Double = 1.0) :
ConvertibleToColorRGBa,
HueShiftableColor<ColorHSLUVa>,
SaturatableColor<ColorHSLUVa>,
ShadableColor<ColorHSLUVa>,
OpacifiableColor<ColorHSLUVa>,
AlgebraicColor<ColorHSLUVa> {
fun toLCHUVa(): ColorLCHUVa {
if (l > 99.9999999) {
ColorLCHUVa(100.0, 0.0, h)
ColorLCHUVa(100.0, 0.0, h, a)
}
if (l < 0.00000001) {
ColorLCHUVa(0.0, 0.0, h)
ColorLCHUVa(0.0, 0.0, h, a)
}
val max = maxChromaForLH(l, h)
val c: Double = max / 100 * s
return ColorLCHUVa(l, c, h)
return ColorLCHUVa(l, c, h, a)
}
fun shiftHue(shiftInDegrees: Double): ColorHSLUVa {
return copy(h = h + (shiftInDegrees))
}
override fun shiftHue(shiftInDegrees: Double) = copy(h = h + (shiftInDegrees))
fun shade(factor: Double): ColorHSLUVa = copy(l = l * factor)
override fun shade(factor: Double) = copy(l = l * factor)
fun saturate(factor: Double): ColorHSLUVa = copy(s = s * factor)
override fun saturate(factor: Double) = copy(s = s * factor)
fun toRGBa(): ColorRGBa {
override fun toRGBa(): ColorRGBa {
return toLCHUVa().toRGBa()
}
override fun opacify(factor: Double) = copy(a = a * factor)
override fun minus(other: ColorHSLUVa) = copy(h = h - other.h, s = s - other.s, l = l - other.l, a = a - other.a)
override fun plus(other: ColorHSLUVa) = copy(h = h + other.h, s = s + other.s, l = l + other.l, a = a + other.a)
override fun times(factor: Double) = copy(h = h * factor, s = s * factor, l = l * factor, a = a * factor)
override fun mix(other: ColorHSLUVa, factor: Double) = mix(this, other, factor)
}
data class ColorHPLUVa(val h: Double, val s: Double, val l: Double) {
fun mix(left: ColorHSLUVa, right: ColorHSLUVa, x: Double): ColorHSLUVa {
val sx = x.coerceIn(0.0, 1.0)
return ColorHSLUVa(
mixAngle(left.h, right.h, sx),
(1.0 - sx) * left.s + sx * right.s,
(1.0 - sx) * left.l + sx * right.l,
(1.0 - sx) * left.a + sx * right.a)
}
data class ColorHPLUVa(val h: Double, val s: Double, val l: Double, val a: Double = 1.0) :
ConvertibleToColorRGBa,
HueShiftableColor<ColorHPLUVa>,
SaturatableColor<ColorHPLUVa>,
ShadableColor<ColorHPLUVa>,
OpacifiableColor<ColorHPLUVa>,
AlgebraicColor<ColorHPLUVa> {
fun toLCHUVa(): ColorLCHUVa {
if (l > 99.9999999) {
return ColorLCHUVa(100.0, 0.0, h)
@@ -117,17 +148,39 @@ data class ColorHPLUVa(val h: Double, val s: Double, val l: Double) {
val c = max / 100 * s
return ColorLCHUVa(l, c, h)
}
fun shiftHue(shiftInDegrees: Double): ColorHPLUVa {
override fun shiftHue(shiftInDegrees: Double): ColorHPLUVa {
return copy(h = h + (shiftInDegrees))
}
fun shade(factor: Double): ColorHPLUVa = copy(l = l * factor)
override fun shade(factor: Double): ColorHPLUVa = copy(l = l * factor)
fun saturate(factor: Double): ColorHPLUVa = copy(s = s * factor)
override fun saturate(factor: Double): ColorHPLUVa = copy(s = s * factor)
override fun toRGBa(): ColorRGBa = toLCHUVa().toRGBa()
override fun opacify(factor: Double) = copy(a = a * factor)
override fun minus(other: ColorHPLUVa) = copy(h = h - other.h, s = s - other.s, l = l - other.l, a = a - other.a)
override fun plus(other: ColorHPLUVa) = copy(h = h + other.h, s = s + other.s, l = l + other.l, a = a + other.a)
override fun times(factor: Double) = copy(h = h * factor, s = s * factor, l = l * factor, a = a * factor)
override fun mix(other: ColorHPLUVa, factor: Double) = mix(this, other, factor)
fun toRGBa(): ColorRGBa = toLCHUVa().toRGBa()
}
fun mix(left: ColorHPLUVa, right: ColorHPLUVa, x: Double): ColorHPLUVa {
val sx = x.coerceIn(0.0, 1.0)
return ColorHPLUVa(
mixAngle(left.h, right.h, sx),
(1.0 - sx) * left.s + sx * right.s,
(1.0 - sx) * left.l + sx * right.l,
(1.0 - sx) * left.a + sx * right.a)
}
fun ColorLCHUVa.toHPLUVa(): ColorHPLUVa {
if (l > 99.9999999) {
return ColorHPLUVa(h, 0.0, 100.0)
@@ -150,7 +203,7 @@ fun ColorLCHUVa.toHSLUVa(): ColorHSLUVa {
}
val max = maxChromaForLH(l, h)
val s = c / max * 100.0
return ColorHSLUVa(h, s, l)
return ColorHSLUVa(h, s, l, alpha)
}
fun ColorRGBa.toHSLUVa(): ColorHSLUVa = toLCHUVa().toHSLUVa()