commit #21
This commit is contained in:
parent
74f113e670
commit
926a52e34e
14 changed files with 105 additions and 99 deletions
|
@ -9,7 +9,6 @@ import de.moritzruth.theaterdsl.dmx.EnttecOpenDmxUsb
|
||||||
import de.moritzruth.theaterdsl.show.createShow
|
import de.moritzruth.theaterdsl.show.createShow
|
||||||
import de.moritzruth.theaterdsl.show.runShow
|
import de.moritzruth.theaterdsl.show.runShow
|
||||||
|
|
||||||
@Suppress("DuplicatedCode")
|
|
||||||
val show = createShow {
|
val show = createShow {
|
||||||
firstAct()
|
firstAct()
|
||||||
secondAct()
|
secondAct()
|
||||||
|
|
|
@ -4,6 +4,7 @@ import de.moritzruth.lampenfieber.device.devices
|
||||||
import de.moritzruth.theaterdsl.dmx.EnttecOpenDmxUsb
|
import de.moritzruth.theaterdsl.dmx.EnttecOpenDmxUsb
|
||||||
import de.moritzruth.theaterdsl.dmx.PerDeviceDmxDataWriter
|
import de.moritzruth.theaterdsl.dmx.PerDeviceDmxDataWriter
|
||||||
import kotlinx.coroutines.awaitCancellation
|
import kotlinx.coroutines.awaitCancellation
|
||||||
|
import kotlinx.coroutines.coroutineScope
|
||||||
|
|
||||||
suspend fun main() {
|
suspend fun main() {
|
||||||
EnttecOpenDmxUsb.start()
|
EnttecOpenDmxUsb.start()
|
||||||
|
@ -23,6 +24,6 @@ suspend fun main() {
|
||||||
awaitCancellation()
|
awaitCancellation()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun test() {
|
suspend fun test() = coroutineScope {
|
||||||
|
|
||||||
}
|
}
|
|
@ -353,6 +353,7 @@ fun ShowBuilderContext.fourthAct() = act("Vierter Akt") {
|
||||||
step(StepCue.MusicEnd) {
|
step(StepCue.MusicEnd) {
|
||||||
actors {
|
actors {
|
||||||
-"Paula"
|
-"Paula"
|
||||||
|
-"David"
|
||||||
-"Theaterlehrer"
|
-"Theaterlehrer"
|
||||||
-"Sven"
|
-"Sven"
|
||||||
-"Heike"
|
-"Heike"
|
||||||
|
@ -403,10 +404,6 @@ fun ShowBuilderContext.fourthAct() = act("Vierter Akt") {
|
||||||
|
|
||||||
scene("10") {
|
scene("10") {
|
||||||
step(StepCue.Text("Kai", "Hilfe, los, runter!")) {
|
step(StepCue.Text("Kai", "Hilfe, los, runter!")) {
|
||||||
actors {
|
|
||||||
+"Paula / steht bei Markierung"
|
|
||||||
}
|
|
||||||
|
|
||||||
curtainState = CurtainState.OPEN
|
curtainState = CurtainState.OPEN
|
||||||
|
|
||||||
onRun {
|
onRun {
|
||||||
|
@ -415,6 +412,10 @@ fun ShowBuilderContext.fourthAct() = act("Vierter Akt") {
|
||||||
}
|
}
|
||||||
|
|
||||||
step(StepCue.Curtain(CurtainState.OPEN, false)) {
|
step(StepCue.Curtain(CurtainState.OPEN, false)) {
|
||||||
|
actors {
|
||||||
|
+"Paula / steht bei Markierung"
|
||||||
|
}
|
||||||
|
|
||||||
onRun {
|
onRun {
|
||||||
Tops.both.forEach { it.brightness.fade(50.percent, 1.5.seconds) }
|
Tops.both.forEach { it.brightness.fade(50.percent, 1.5.seconds) }
|
||||||
bar.color.static(Color.WHITE)
|
bar.color.static(Color.WHITE)
|
||||||
|
|
|
@ -19,33 +19,32 @@ interface DynamicValue<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalTime::class)
|
@OptIn(ExperimentalTime::class)
|
||||||
abstract class FloatDV<T>(private val initialStaticValue: Float) : DynamicValue<T> {
|
abstract class DoubleDV<T>(private val initialStaticValue: Double) : DynamicValue<T> {
|
||||||
private sealed interface State {
|
private sealed interface State {
|
||||||
data class Static(val value: Float) : State
|
data class Static(val value: Double) : State
|
||||||
|
|
||||||
data class Fade(val start: Float, val end: Float, val duration: Duration) : State {
|
data class Fade(val start: Double, val end: Double, val duration: Duration) : State {
|
||||||
val delta = end - start
|
val delta = end - start
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Sine(
|
data class Sine(
|
||||||
val offset: Double,
|
val minimum: Double,
|
||||||
val minimum: Float,
|
val maximum: Double,
|
||||||
val maximum: Float,
|
val b: Double,
|
||||||
val period: Duration
|
val c: Double
|
||||||
) : State {
|
) : State {
|
||||||
companion object {
|
companion object {
|
||||||
fun calculateA(minimum: Float, maximum: Float) = (maximum - minimum) * 0.5
|
fun calculateB(period: Duration) = period.inWholeMilliseconds / (2 * PI)
|
||||||
fun calculateX(progress: Double, offset: Double) = 2 * PI * progress - offset
|
fun calculateX(elapsedTime: Duration, b: Double, c: Double) = b * elapsedTime.inWholeMilliseconds + c
|
||||||
fun calculateD(minimum: Float) = 0.5 + minimum
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Step(val steps: ImmutableList<Float>, val interval: Duration, val startIndex: Int) : State
|
data class Step(val steps: ImmutableList<Double>, val interval: Duration, val startIndex: Int) : State
|
||||||
data class PulseOnce(val rampUpDuration: Duration, val rampDownDuration: Duration, val peakValue: Float, val start: Float, val end: Float) : State
|
data class PulseOnce(val rampUpDuration: Duration, val rampDownDuration: Duration, val peakValue: Double, val start: Double, val end: Double) : State
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract fun toDomain(value: Float): T
|
protected abstract fun toDomain(value: Double): T
|
||||||
protected abstract fun fromDomain(value: T): Float
|
protected abstract fun fromDomain(value: T): Double
|
||||||
protected abstract val minimumValue: T
|
protected abstract val minimumValue: T
|
||||||
protected abstract val maximumValue: T
|
protected abstract val maximumValue: T
|
||||||
|
|
||||||
|
@ -63,15 +62,12 @@ abstract class FloatDV<T>(private val initialStaticValue: Float) : DynamicValue<
|
||||||
override fun getCurrentValue(): T {
|
override fun getCurrentValue(): T {
|
||||||
val elapsedTime = stateChangeMark.elapsedNow()
|
val elapsedTime = stateChangeMark.elapsedNow()
|
||||||
|
|
||||||
val float = when (val s = state) {
|
val double = when (val s = state) {
|
||||||
is State.Static -> s.value
|
is State.Static -> s.value
|
||||||
is State.Fade -> (min(elapsedTime / s.duration, 1.0) * s.delta + s.start).toFloat()
|
is State.Fade -> (min(elapsedTime / s.duration, 1.0) * s.delta + s.start)
|
||||||
is State.Sine -> {
|
is State.Sine -> {
|
||||||
val a = State.Sine.calculateA(s.minimum, s.maximum)
|
val fromZeroToOne = (sin(State.Sine.calculateX(elapsedTime, s.b, s.c)) + 1) / 2
|
||||||
val x = State.Sine.calculateX(elapsedTime / s.period, s.offset)
|
(fromZeroToOne * (s.maximum - s.minimum) + s.minimum)
|
||||||
val d = State.Sine.calculateD(s.minimum)
|
|
||||||
|
|
||||||
(a * sin(x) + d).toFloat()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is State.Step -> {
|
is State.Step -> {
|
||||||
|
@ -83,16 +79,16 @@ abstract class FloatDV<T>(private val initialStaticValue: Float) : DynamicValue<
|
||||||
if (elapsedTime <= s.rampUpDuration) {
|
if (elapsedTime <= s.rampUpDuration) {
|
||||||
val progress = elapsedTime / s.rampUpDuration
|
val progress = elapsedTime / s.rampUpDuration
|
||||||
val delta = s.peakValue - s.start
|
val delta = s.peakValue - s.start
|
||||||
(progress * delta + s.start).toFloat()
|
(progress * delta + s.start)
|
||||||
} else {
|
} else {
|
||||||
val progress = min(elapsedTime / s.rampDownDuration, 1.0)
|
val progress = min(elapsedTime / s.rampDownDuration, 1.0)
|
||||||
val delta = s.peakValue - s.end
|
val delta = s.peakValue - s.end
|
||||||
(s.peakValue - progress * delta).toFloat()
|
(s.peakValue - progress * delta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return toDomain(float)
|
return toDomain(double)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun static(value: T) {
|
fun static(value: T) {
|
||||||
|
@ -108,9 +104,14 @@ abstract class FloatDV<T>(private val initialStaticValue: Float) : DynamicValue<
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sine(period: Duration, minimum: T = minimumValue, maximum: T = maximumValue, start: T = getCurrentValue()) {
|
fun sine(period: Duration, minimum: T = minimumValue, maximum: T = maximumValue, start: T = getCurrentValue()) {
|
||||||
val coercedStart = fromDomain(start).coerceIn(fromDomain(minimum), fromDomain(maximum))
|
val b = State.Sine.calculateB(period)
|
||||||
val offset = asin((coercedStart - State.Sine.calculateD(fromDomain(minimum))) / State.Sine.calculateA(fromDomain(minimum), fromDomain(maximum)))
|
val doubleMinimum = fromDomain(minimum)
|
||||||
state = State.Sine(offset, fromDomain(minimum), fromDomain(maximum), period)
|
val doubleMaximum = fromDomain(maximum)
|
||||||
|
val delta = doubleMaximum - doubleMinimum
|
||||||
|
|
||||||
|
val coercedStart = fromDomain(start).coerceIn(doubleMinimum, fromDomain(maximum))
|
||||||
|
val c = asin(2 * ((coercedStart - doubleMinimum) / delta) - 1)
|
||||||
|
state = State.Sine(fromDomain(minimum), fromDomain(maximum), b, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun steps(steps: List<T>, interval: Duration, startIndex: Int = 0) {
|
fun steps(steps: List<T>, interval: Duration, startIndex: Int = 0) {
|
||||||
|
@ -132,16 +133,16 @@ abstract class FloatDV<T>(private val initialStaticValue: Float) : DynamicValue<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PercentageDV(initialStaticValue: Percentage = 0.percent) : FloatDV<Percentage>(initialStaticValue.value) {
|
class PercentageDV(initialStaticValue: Percentage = 0.percent) : DoubleDV<Percentage>(initialStaticValue.value) {
|
||||||
override fun fromDomain(value: Percentage): Float = value.value
|
override fun fromDomain(value: Percentage): Double = value.value
|
||||||
override fun toDomain(value: Float): Percentage = Percentage(value)
|
override fun toDomain(value: Double): Percentage = Percentage(value)
|
||||||
override val minimumValue: Percentage = 0.percent
|
override val minimumValue: Percentage = 0.percent
|
||||||
override val maximumValue: Percentage = 100.percent
|
override val maximumValue: Percentage = 100.percent
|
||||||
}
|
}
|
||||||
|
|
||||||
class AngleDV(initialStaticValue: Angle = 0.degrees) : FloatDV<Angle>(initialStaticValue.degrees) {
|
class AngleDV(initialStaticValue: Angle = 0.degrees) : DoubleDV<Angle>(initialStaticValue.degrees) {
|
||||||
override fun fromDomain(value: Angle): Float = value.degrees
|
override fun fromDomain(value: Angle): Double = value.degrees
|
||||||
override fun toDomain(value: Float): Angle = Angle(value)
|
override fun toDomain(value: Double): Angle = Angle(value)
|
||||||
override val minimumValue: Angle = 0.degrees
|
override val minimumValue: Angle = 0.degrees
|
||||||
override val maximumValue: Angle = 360.degrees
|
override val maximumValue: Angle = 360.degrees
|
||||||
}
|
}
|
||||||
|
@ -199,9 +200,9 @@ class ColorDV(private val initialStaticValue: Color = Color.WHITE) : DynamicValu
|
||||||
val progress = min(elapsedTime / s.duration, 1.0)
|
val progress = min(elapsedTime / s.duration, 1.0)
|
||||||
|
|
||||||
Color(
|
Color(
|
||||||
hue = Angle((s.start.hue.degrees + s.deltaHue * progress).toFloat()),
|
hue = Angle((s.start.hue.degrees + s.deltaHue * progress)),
|
||||||
saturation = Percentage((s.start.saturation.value + s.deltaSaturation * progress).toFloat()),
|
saturation = Percentage((s.start.saturation.value + s.deltaSaturation * progress)),
|
||||||
brightness = Percentage((s.start.brightness.value + s.deltaBrightness * progress).toFloat())
|
brightness = Percentage((s.start.brightness.value + s.deltaBrightness * progress))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,11 +210,11 @@ class ColorDV(private val initialStaticValue: Color = Color.WHITE) : DynamicValu
|
||||||
val startRandom = Random((elapsedTime / s.interval).toInt() - 1)
|
val startRandom = Random((elapsedTime / s.interval).toInt() - 1)
|
||||||
val endRandom = Random((elapsedTime / s.interval).toInt())
|
val endRandom = Random((elapsedTime / s.interval).toInt())
|
||||||
val progress = (elapsedTime / s.interval).mod(1.0)
|
val progress = (elapsedTime / s.interval).mod(1.0)
|
||||||
val startHue = s.hue.degrees - s.deviation.degrees + startRandom.nextFloat() * s.deviation.degrees * 2
|
val startHue = s.hue.degrees - s.deviation.degrees + startRandom.nextDouble() * s.deviation.degrees * 2
|
||||||
val endHue = s.hue.degrees - s.deviation.degrees + endRandom.nextFloat() * s.deviation.degrees * 2
|
val endHue = s.hue.degrees - s.deviation.degrees + endRandom.nextDouble() * s.deviation.degrees * 2
|
||||||
val delta = endHue - startHue
|
val delta = endHue - startHue
|
||||||
|
|
||||||
Color(hue = Angle((progress * delta).toFloat()))
|
Color(hue = Angle((progress * delta)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ interface DmxDataWriter {
|
||||||
/**
|
/**
|
||||||
* @param startAtOne Whether the written value is in `1..255` or in `0..255`.
|
* @param startAtOne Whether the written value is in `1..255` or in `0..255`.
|
||||||
*/
|
*/
|
||||||
fun writeInRange(range: ClosedFloatingPointRange<Float>, value: Float, startAtOne: Boolean = false) =
|
fun writeInRange(range: ClosedFloatingPointRange<Double>, value: Double, startAtOne: Boolean = false) =
|
||||||
writeRaw(Percentage((value - range.start) / (range.endInclusive - range.start)).roundToDmxValue(startAtOne))
|
writeRaw(Percentage((value - range.start) / (range.endInclusive - range.start)).roundToDmxValue(startAtOne))
|
||||||
|
|
||||||
fun writeHighByte(value: UShort) = writeRaw(DmxValue(value.toUInt().shr(8).toUByte()))
|
fun writeHighByte(value: UShort) = writeRaw(DmxValue(value.toUInt().shr(8).toUByte()))
|
||||||
|
|
|
@ -16,5 +16,5 @@ value class DmxValue(val value: UByte) : Comparable<UByte> {
|
||||||
* @param startAtOne Whether the output range is `1..255` or `0..255`.
|
* @param startAtOne Whether the output range is `1..255` or `0..255`.
|
||||||
*/
|
*/
|
||||||
fun Percentage.roundToDmxValue(startAtOne: Boolean = false): DmxValue =
|
fun Percentage.roundToDmxValue(startAtOne: Boolean = false): DmxValue =
|
||||||
if (startAtOne) DmxValue(((value * (DmxValue.VALUE_RANGE.last.toFloat() - 1f)).roundToInt() + 1).toUByte())
|
if (startAtOne) DmxValue(((value * (DmxValue.VALUE_RANGE.last.toDouble() - 1f)).roundToInt() + 1).toUByte())
|
||||||
else DmxValue((value * DmxValue.VALUE_RANGE.last.toFloat()).roundToInt().toUByte())
|
else DmxValue((value * DmxValue.VALUE_RANGE.last.toDouble()).roundToInt().toUByte())
|
|
@ -88,7 +88,7 @@ private fun buildAct(actIndex: Int, actName: String, build: ActBuilderContext.()
|
||||||
|
|
||||||
var leftSpotTarget: String?
|
var leftSpotTarget: String?
|
||||||
var rightSpotTarget: String?
|
var rightSpotTarget: String?
|
||||||
var curtainState = CurtainState.CLOSED
|
var curtainState_ = CurtainState.CLOSED
|
||||||
|
|
||||||
object : ActBuilderContext {
|
object : ActBuilderContext {
|
||||||
override fun scene(@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") sceneName: String, build: SceneBuilderContext.() -> Unit) {
|
override fun scene(@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") sceneName: String, build: SceneBuilderContext.() -> Unit) {
|
||||||
|
@ -111,7 +111,11 @@ private fun buildAct(actIndex: Int, actName: String, build: ActBuilderContext.()
|
||||||
override val props = PropsBuilderMap(changedProps)
|
override val props = PropsBuilderMap(changedProps)
|
||||||
override var rightSpotTarget: String? = null
|
override var rightSpotTarget: String? = null
|
||||||
override var leftSpotTarget: String? = null
|
override var leftSpotTarget: String? = null
|
||||||
override var curtainState: CurtainState by ::curtainState
|
override var curtainState: CurtainState
|
||||||
|
get() = curtainState_
|
||||||
|
set(value) {
|
||||||
|
curtainState_ = value
|
||||||
|
}
|
||||||
|
|
||||||
override fun actors(build: ActorsBuildContext.() -> Unit) {
|
override fun actors(build: ActorsBuildContext.() -> Unit) {
|
||||||
ActorsBuildContext(actorEntrances, actorExits).build()
|
ActorsBuildContext(actorEntrances, actorExits).build()
|
||||||
|
@ -155,7 +159,7 @@ private fun buildAct(actIndex: Int, actName: String, build: ActBuilderContext.()
|
||||||
logger.warn("These actors cannot enter because they are already on the stage: ${addedActorsAlreadyOnStage.joinToString()}")
|
logger.warn("These actors cannot enter because they are already on the stage: ${addedActorsAlreadyOnStage.joinToString()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
actorsOnStage.removeAll(actorExitsNames)
|
actorsOnStage.removeAll(actorExitsNames.toSet())
|
||||||
actorsOnStage.addAll(actorEntrancesNames)
|
actorsOnStage.addAll(actorEntrancesNames)
|
||||||
|
|
||||||
changedProps.forEach { (k, v) -> props[k] = v }
|
changedProps.forEach { (k, v) -> props[k] = v }
|
||||||
|
@ -171,7 +175,7 @@ private fun buildAct(actIndex: Int, actName: String, build: ActBuilderContext.()
|
||||||
changedProps.isNotEmpty(),
|
changedProps.isNotEmpty(),
|
||||||
leftSpotTarget,
|
leftSpotTarget,
|
||||||
rightSpotTarget,
|
rightSpotTarget,
|
||||||
curtainState,
|
curtainState_,
|
||||||
runner
|
runner
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package de.moritzruth.theaterdsl.value
|
package de.moritzruth.theaterdsl.value
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class Angle(val degrees: Float) : Comparable<Angle> {
|
value class Angle(val degrees: Double) : Comparable<Angle> {
|
||||||
override fun toString(): String = "${degrees}°"
|
override fun toString(): String = "${degrees}°"
|
||||||
|
|
||||||
override fun compareTo(other: Angle): Int = degrees.compareTo(other.degrees)
|
override fun compareTo(other: Angle): Int = degrees.compareTo(other.degrees)
|
||||||
|
|
||||||
fun inSingleRotation(): Angle = Angle(
|
fun inSingleRotation(): Angle = Angle(
|
||||||
if (degrees == 360f || degrees == -360f) degrees
|
if (degrees == 360.0 || degrees == -360.0) degrees
|
||||||
else degrees.mod(360f)
|
else degrees.mod(360f)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,18 +17,18 @@ value class Angle(val degrees: Float) : Comparable<Angle> {
|
||||||
): ClosedFloatingPointRange<Angle> {
|
): ClosedFloatingPointRange<Angle> {
|
||||||
override fun lessThanOrEquals(a: Angle, b: Angle): Boolean = a.degrees <= b.degrees
|
override fun lessThanOrEquals(a: Angle, b: Angle): Boolean = a.degrees <= b.degrees
|
||||||
|
|
||||||
fun asFloatRange(): ClosedFloatingPointRange<Float> = start.degrees..endInclusive.degrees
|
fun asDoubleRange(): ClosedFloatingPointRange<Double> = start.degrees..endInclusive.degrees
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val FULL_ROTATION: Range = Range(Angle(0f), Angle(360f))
|
val FULL_ROTATION: Range = Range(Angle(0.0), Angle(360.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline val Int.degrees: Angle
|
inline val Int.degrees: Angle
|
||||||
get() = Angle(this.toFloat())
|
get() = Angle(this.toDouble())
|
||||||
|
|
||||||
inline val Double.degrees: Angle
|
inline val Double.degrees: Angle
|
||||||
get() = Angle(this.toFloat())
|
get() = Angle(this)
|
||||||
|
|
||||||
fun Float.asAngle(): Angle = Angle(this)
|
fun Double.asAngle(): Angle = Angle(this)
|
||||||
|
|
|
@ -13,44 +13,44 @@ data class Color(
|
||||||
val x = c * (1 - abs(h.mod(2f) - 1))
|
val x = c * (1 - abs(h.mod(2f) - 1))
|
||||||
val m = brightness.value - c
|
val m = brightness.value - c
|
||||||
|
|
||||||
val r: Float
|
val r: Double
|
||||||
val g: Float
|
val g: Double
|
||||||
val b: Float
|
val b: Double
|
||||||
|
|
||||||
when {
|
when {
|
||||||
h < 1 -> {
|
h < 1 -> {
|
||||||
r = c
|
r = c
|
||||||
g = x
|
g = x
|
||||||
b = 0f
|
b = 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
h < 2 -> {
|
h < 2 -> {
|
||||||
r = x
|
r = x
|
||||||
g = c
|
g = c
|
||||||
b = 0f
|
b = 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
h < 3 -> {
|
h < 3 -> {
|
||||||
r = 0f
|
r = 0.0
|
||||||
g = c
|
g = c
|
||||||
b = x
|
b = x
|
||||||
}
|
}
|
||||||
|
|
||||||
h < 4 -> {
|
h < 4 -> {
|
||||||
r = 0f
|
r = 0.0
|
||||||
g = x
|
g = x
|
||||||
b = c
|
b = c
|
||||||
}
|
}
|
||||||
|
|
||||||
h < 5 -> {
|
h < 5 -> {
|
||||||
r = x
|
r = x
|
||||||
g = 0f
|
g = 0.0
|
||||||
b = c
|
b = c
|
||||||
}
|
}
|
||||||
|
|
||||||
else /* h < 6 */ -> {
|
else /* h < 6 */ -> {
|
||||||
r = c
|
r = c
|
||||||
g = 0f
|
g = 0.0
|
||||||
b = x
|
b = x
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package de.moritzruth.theaterdsl.value
|
package de.moritzruth.theaterdsl.value
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class Frequency(val hertz: Float) : Comparable<Frequency> {
|
value class Frequency(val hertz: Double) : Comparable<Frequency> {
|
||||||
companion object {
|
companion object {
|
||||||
val ZERO: Frequency = Frequency(0f)
|
val ZERO: Frequency = Frequency(0.0)
|
||||||
val INFINITY: Frequency = Frequency(Float.POSITIVE_INFINITY)
|
val INFINITY: Frequency = Frequency(Double.POSITIVE_INFINITY)
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -21,7 +21,7 @@ value class Frequency(val hertz: Float) : Comparable<Frequency> {
|
||||||
) : ClosedFloatingPointRange<Frequency> {
|
) : ClosedFloatingPointRange<Frequency> {
|
||||||
override fun lessThanOrEquals(a: Frequency, b: Frequency): Boolean = a.hertz <= b.hertz
|
override fun lessThanOrEquals(a: Frequency, b: Frequency): Boolean = a.hertz <= b.hertz
|
||||||
|
|
||||||
fun asFloatRange(): ClosedFloatingPointRange<Float> = start.hertz..endInclusive.hertz
|
fun asDoubleRange(): ClosedFloatingPointRange<Double> = start.hertz..endInclusive.hertz
|
||||||
|
|
||||||
override fun toString(): String = "$start..$endInclusive"
|
override fun toString(): String = "$start..$endInclusive"
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,15 +4,15 @@ import kotlin.math.pow
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
val IntProgression.delta: Int get() = last - first
|
val IntProgression.delta: Int get() = last - first
|
||||||
val ClosedFloatingPointRange<Float>.delta: Float get() = endInclusive - start
|
val ClosedFloatingPointRange<Double>.delta: Double get() = endInclusive - start
|
||||||
|
|
||||||
fun Int.transfer(from: IntRange, to: IntRange): Int =
|
fun Int.transfer(from: IntRange, to: IntRange): Int =
|
||||||
((this - from.first) / from.delta) * to.delta + to.first
|
((this - from.first) / from.delta) * to.delta + to.first
|
||||||
|
|
||||||
fun Float.transfer(from: ClosedFloatingPointRange<Float>, to: ClosedFloatingPointRange<Float>): Float =
|
fun Double.transfer(from: ClosedFloatingPointRange<Double>, to: ClosedFloatingPointRange<Double>): Double =
|
||||||
((this - from.start) / from.delta) * to.delta + to.start
|
((this - from.start) / from.delta) * to.delta + to.start
|
||||||
|
|
||||||
fun Float.toString(decimalPlaces: Int): String {
|
fun Double.toString(decimalPlaces: Int): String {
|
||||||
val s = (this * (10f.pow(decimalPlaces))).roundToInt().toString().padStart(decimalPlaces + 1, '0')
|
val s = (this * (10f.pow(decimalPlaces))).roundToInt().toString().padStart(decimalPlaces + 1, '0')
|
||||||
return s.dropLast(decimalPlaces) + "." + s.takeLast(decimalPlaces)
|
return s.dropLast(decimalPlaces) + "." + s.takeLast(decimalPlaces)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
package de.moritzruth.theaterdsl.value
|
package de.moritzruth.theaterdsl.value
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class Percentage(val value: Float) : Comparable<Percentage> {
|
value class Percentage(val value: Double) : Comparable<Percentage> {
|
||||||
companion object {
|
companion object {
|
||||||
val VALUE_RANGE: ClosedFloatingPointRange<Float> = 0f..1f
|
val VALUE_RANGE: ClosedFloatingPointRange<Double> = 0.0..1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
require(value in VALUE_RANGE) { "value ($value) must be in 0..1" }
|
require(value in VALUE_RANGE) { "value ($value) must be in 0..1" }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ofRange(range: ClosedFloatingPointRange<Float>): Float = value.transfer(VALUE_RANGE, range)
|
fun ofRange(range: ClosedFloatingPointRange<Double>): Double = value.transfer(VALUE_RANGE, range)
|
||||||
|
|
||||||
override fun compareTo(other: Percentage): Int = value.compareTo(other.value)
|
override fun compareTo(other: Percentage): Int = value.compareTo(other.value)
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ value class Percentage(val value: Float) : Comparable<Percentage> {
|
||||||
) : ClosedFloatingPointRange<Percentage> {
|
) : ClosedFloatingPointRange<Percentage> {
|
||||||
override fun lessThanOrEquals(a: Percentage, b: Percentage): Boolean = a.value <= b.value
|
override fun lessThanOrEquals(a: Percentage, b: Percentage): Boolean = a.value <= b.value
|
||||||
|
|
||||||
fun asFloatRange(): ClosedFloatingPointRange<Float> = start.value..endInclusive.value
|
fun asDoubleRange(): ClosedFloatingPointRange<Double> = start.value..endInclusive.value
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val FULL: Range = Range(VALUE_RANGE.start.asPercentage(), VALUE_RANGE.endInclusive.asPercentage())
|
val FULL: Range = Range(VALUE_RANGE.start.asPercentage(), VALUE_RANGE.endInclusive.asPercentage())
|
||||||
|
@ -32,16 +32,16 @@ value class Percentage(val value: Float) : Comparable<Percentage> {
|
||||||
|
|
||||||
inline val Int.percent: Percentage
|
inline val Int.percent: Percentage
|
||||||
get() = try {
|
get() = try {
|
||||||
Percentage(this / 100f)
|
Percentage(this / 100.0)
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (e: IllegalArgumentException) {
|
||||||
throw IllegalArgumentException("must be in 0..100")
|
throw IllegalArgumentException("must be in 0..100")
|
||||||
}
|
}
|
||||||
|
|
||||||
inline val Double.percent: Percentage
|
inline val Double.percent: Percentage
|
||||||
get() = try {
|
get() = try {
|
||||||
Percentage(this.toFloat() / 100f)
|
Percentage(this / 100f)
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (e: IllegalArgumentException) {
|
||||||
throw IllegalArgumentException("must be in 0..100")
|
throw IllegalArgumentException("must be in 0..100")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Float.asPercentage(): Percentage = Percentage(this)
|
fun Double.asPercentage(): Percentage = Percentage(this)
|
||||||
|
|
|
@ -3,31 +3,31 @@ package de.moritzruth.theaterdsl.value
|
||||||
import kotlinx.collections.immutable.ImmutableSet
|
import kotlinx.collections.immutable.ImmutableSet
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
data class FloatRangesAndValues(val ranges: ImmutableSet<ClosedFloatingPointRange<Float>>, val values: ImmutableSet<Float>) {
|
data class DoubleRangesAndValues(val ranges: ImmutableSet<ClosedFloatingPointRange<Double>>, val values: ImmutableSet<Double>) {
|
||||||
init {
|
init {
|
||||||
require(ranges.isNotEmpty() || values.isNotEmpty()) { "at least one range or value is required" }
|
require(ranges.isNotEmpty() || values.isNotEmpty()) { "at least one range or value is required" }
|
||||||
}
|
}
|
||||||
|
|
||||||
val highest: Float
|
val highest: Double
|
||||||
val highestBeforeInfinity: Float
|
val highestBeforeInfinity: Double
|
||||||
val lowest: Float
|
val lowest: Double
|
||||||
val lowestAfterInfinity: Float
|
val lowestAfterInfinity: Double
|
||||||
|
|
||||||
init {
|
init {
|
||||||
var l = Float.POSITIVE_INFINITY
|
var l = Double.POSITIVE_INFINITY
|
||||||
var lai = Float.POSITIVE_INFINITY
|
var lai = Double.POSITIVE_INFINITY
|
||||||
var h = Float.NEGATIVE_INFINITY
|
var h = Double.NEGATIVE_INFINITY
|
||||||
var hbi = Float.NEGATIVE_INFINITY
|
var hbi = Double.NEGATIVE_INFINITY
|
||||||
|
|
||||||
for (v in values + ranges.flatMap { listOf(it.start, it.endInclusive) }) {
|
for (v in values + ranges.flatMap { listOf(it.start, it.endInclusive) }) {
|
||||||
if (v < lai) {
|
if (v < lai) {
|
||||||
l = v
|
l = v
|
||||||
if (v != Float.NEGATIVE_INFINITY) lai = v
|
if (v != Double.NEGATIVE_INFINITY) lai = v
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v > hbi) {
|
if (v > hbi) {
|
||||||
h = v
|
h = v
|
||||||
if (v != Float.POSITIVE_INFINITY) hbi = v
|
if (v != Double.POSITIVE_INFINITY) hbi = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,12 +37,12 @@ data class FloatRangesAndValues(val ranges: ImmutableSet<ClosedFloatingPointRang
|
||||||
lowestAfterInfinity = lai
|
lowestAfterInfinity = lai
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNearestTo(value: Float): Float {
|
fun getNearestTo(value: Double): Double {
|
||||||
var nearestValue = 0f
|
var nearestValue = 0.0
|
||||||
var nearestDistance = 0f
|
var nearestDistance = 0.0
|
||||||
var isFirst = true
|
var isFirst = true
|
||||||
|
|
||||||
fun update(v: Float) {
|
fun update(v: Double) {
|
||||||
if (isFirst) {
|
if (isFirst) {
|
||||||
nearestValue = v
|
nearestValue = v
|
||||||
nearestDistance = v - value
|
nearestDistance = v - value
|
||||||
|
@ -71,5 +71,5 @@ data class FloatRangesAndValues(val ranges: ImmutableSet<ClosedFloatingPointRang
|
||||||
return nearestValue
|
return nearestValue
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun contains(value: Float): Boolean = getNearestTo(value) == value
|
operator fun contains(value: Double): Boolean = getNearestTo(value) == value
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package de.moritzruth.theaterdsl.value
|
package de.moritzruth.theaterdsl.value
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class Temperature(val kelvin: Float) : Comparable<Temperature> {
|
value class Temperature(val kelvin: Double) : Comparable<Temperature> {
|
||||||
override fun toString(): String = "${kelvin}K"
|
override fun toString(): String = "${kelvin}K"
|
||||||
|
|
||||||
override fun compareTo(other: Temperature): Int = kelvin.compareTo(other.kelvin)
|
override fun compareTo(other: Temperature): Int = kelvin.compareTo(other.kelvin)
|
||||||
|
|
Loading…
Add table
Reference in a new issue