From 6a4e3c3a4424d30924fd333dc95bc6b0f06b0ec3 Mon Sep 17 00:00:00 2001 From: Edwin Jakobs Date: Tue, 23 Aug 2022 18:46:41 +0200 Subject: [PATCH] [orx-noise] Improve uni-/bipolar functions, add clamp functions --- orx-noise/src/commonMain/kotlin/Functions.kt | 191 +++++++++++++++---- 1 file changed, 151 insertions(+), 40 deletions(-) diff --git a/orx-noise/src/commonMain/kotlin/Functions.kt b/orx-noise/src/commonMain/kotlin/Functions.kt index 6440338a..dd782332 100644 --- a/orx-noise/src/commonMain/kotlin/Functions.kt +++ b/orx-noise/src/commonMain/kotlin/Functions.kt @@ -2,6 +2,7 @@ package org.openrndr.extra.noise import org.openrndr.math.* import kotlin.jvm.JvmName +import kotlin.math.PI import kotlin.random.Random @@ -23,70 +24,189 @@ fun ((Int, Double, Double) -> Vector2).gradient(epsilon: Double = 1e-6): (Int, D dfdx + dfdy } -fun ((Int, Double) -> Double).unipolar(sampleCount: Int = 1000, random: Random = Random(0)): (Int, Double) -> Double { - val samples = (0 until sampleCount).map { - this(0, random.nextDouble(-1.0, 1.0)) +fun ((Int, Double) -> Double).minMax(sampleCount: Int = 1000, random: Random = Random(0)): Pair { + val nmin: Double + val nmax: Double + when { + this === simplex1D -> { + nmin = -0.7127777710564248 + nmax = 0.7127779539425915 + } + + this === valueLinear1D || this === valueHermite1D || this == valueQuintic1D -> { + nmin = -1.0 + nmax = 1.0 + } + + this === perlin1D -> { + nmin = -0.5 + nmax = 0.5 + } + + else -> { + nmin = Double.POSITIVE_INFINITY + nmax = Double.NEGATIVE_INFINITY + } } - val min = samples.minOrNull()!! - val max = samples.maxOrNull()!! + + val min: Double + val max: Double + if (nmin == Double.POSITIVE_INFINITY) { + val samples = (0 until sampleCount).map { + this(random.nextInt(0, 16384), random.nextDouble(PI * 2.0, PI * 8.0)) + } + min = samples.minOrNull()!! + max = samples.maxOrNull()!! + } else { + min = nmin + max = nmax + } + return Pair(min, max) +} + + +fun ((Int, Double) -> Double).unipolar(sampleCount: Int = 1000, random: Random = Random(0)): (Int, Double) -> Double { + val (min, max) = this.minMax(sampleCount, random) return { seed, t -> (this(seed, t) - min) / (max - min) } } +fun ((seed: Int, t: Double) -> Double).clamp(min: Double, max: Double): (Int, Double) -> Double = { seed, t -> + this(seed, t).coerceIn(min, max) +} fun ((Int, Double) -> Double).bipolar(sampleCount: Int = 1000, random: Random = Random(0)): (Int, Double) -> Double { - val samples = (0 until sampleCount).map { - this(0, random.nextDouble(-1.0, 1.0)) - } - val min = samples.minOrNull()!! - val max = samples.maxOrNull()!! + val (min, max) = this.minMax(sampleCount, random) return { seed, t -> ((this(seed, t) - min) / (max - min)) * 2.0 - 1.0 } } +fun ((Int, Double, Double) -> Double).minMax( + sampleCount: Int = 1000, + random: Random = Random(0) +): Pair { + val nmin: Double + val nmax: Double + when { + this === simplex2D -> { + nmin = -0.7127777710564248 + nmax = 0.7127779539425915 + } + + this === valueLinear2D || this === valueHermite2D || this == valueQuintic2D -> { + nmin = -1.0 + nmax = 1.0 + } + + this === perlin2D -> { + nmin = -1.0 + nmax = 1.0 + } + + else -> { + nmin = Double.POSITIVE_INFINITY + nmax = Double.NEGATIVE_INFINITY + } + } + val min: Double + val max: Double + + if (nmin == Double.POSITIVE_INFINITY) { + val samples = (0 until sampleCount).map { + this(random.nextInt(0, 16384), random.nextDouble(PI * 2.0, PI * 8.0), random.nextDouble(PI * 2.0, PI * 8.0)) + } + min = samples.minOrNull()!! + max = samples.maxOrNull()!! + } else { + min = nmin + max = nmax + } + return Pair(min, max) +} + fun ((Int, Double, Double) -> Double).unipolar( sampleCount: Int = 1000, random: Random = Random(0) ): (Int, Double, Double) -> Double { - val samples = (0 until sampleCount).map { - this(0, random.nextDouble(-1.0, 1.0), random.nextDouble(-1.0, 1.0)) - } - val min = samples.minOrNull()!! - val max = samples.maxOrNull()!! + val (min, max) = this.minMax(sampleCount, random) return { seed, x, t -> (this(seed, x, t) - min) / (max - min) } } + +fun ((seed: Int, x: Double, t: Double) -> Double).clamp(min: Double, max: Double): (Int, Double, Double) -> Double = { seed, x, t -> + this(seed, x, t).coerceIn(min, max) +} + +fun ((Int, Double, Double, Double) -> Double).minMax( + sampleCount: Int = 1000, + random: Random = Random(0) +): Pair { + val nmin: Double + val nmax: Double + when { + this === simplex3D -> { + nmin = -0.9777 + nmax = 0.9777 + } + + this === valueLinear3D || this === valueHermite3D || this == valueQuintic3D -> { + nmin = -1.0 + nmax = 1.0 + } + + this === perlin3D -> { + nmin = -1.0 + nmax = 1.0 + } + + else -> { + nmin = Double.POSITIVE_INFINITY + nmax = Double.NEGATIVE_INFINITY + } + } + val min: Double + val max: Double + + if (nmin == Double.POSITIVE_INFINITY) { + val samples = (0 until sampleCount).map { + this( + random.nextInt(0, 16384), + random.nextDouble(PI * 2.0, PI * 8.0), + random.nextDouble(PI * 2.0, PI * 8.0), + random.nextDouble(PI * 2.0, PI * 8.0) + ) + } + min = samples.minOrNull()!! + max = samples.maxOrNull()!! + } else { + min = nmin + max = nmax + } + return Pair(min, max) +} + fun ((Int, Double, Double) -> Double).bipolar( sampleCount: Int = 1000, random: Random = Random(0) ): (Int, Double, Double) -> Double { - val samples = (0 until sampleCount).map { - this(0, random.nextDouble(-1.0, 1.0), random.nextDouble(-1.0, 1.0)) - } - val min = samples.minOrNull()!! - val max = samples.maxOrNull()!! + val (min, max) = this.minMax(sampleCount, random) return { seed, x, t -> ((this(seed, x, t) - min) / (max - min)) * 2.0 - 1.0 } } +fun ((seed: Int, x: Double, y:Double, t: Double) -> Double).clamp(min: Double, max: Double): (Int, Double, Double, Double) -> Double = { seed, x, y, t -> + this(seed, x, y, t).coerceIn(min, max) +} + fun ((Int, Double, Double, Double) -> Double).unipolar( sampleCount: Int = 1000, random: Random = Random(0) ): (Int, Double, Double, Double) -> Double { - val samples = (0 until sampleCount).map { - this( - 0, - random.nextDouble(-1.0, 1.0), - random.nextDouble(-1.0, 1.0), - random.nextDouble(-1.0, 1.0) - ) - } - val min = samples.minOrNull()!! - val max = samples.maxOrNull()!! + val (min, max) = this.minMax(sampleCount, random) return { seed, x, y, t -> (this(seed, x, y, t) - min) / (max - min) } @@ -96,16 +216,7 @@ fun ((Int, Double, Double, Double) -> Double).bipolar( sampleCount: Int = 1000, random: Random = Random(0) ): (Int, Double, Double, Double) -> Double { - val samples = (0 until sampleCount).map { - this( - 0, - random.nextDouble(-1.0, 1.0), - random.nextDouble(-1.0, 1.0), - random.nextDouble(-1.0, 1.0), - ) - } - val min = samples.minOrNull()!! - val max = samples.maxOrNull()!! + val (min, max) = this.minMax(sampleCount, random) return { seed, x, y, t -> ((this(seed, x, y, t) - min) / (max - min)) * 2.0 - 1.0 }