[orx-noise] Add demos and extensions for uniform simplex sampling

This commit is contained in:
Edwin Jakobs
2025-02-26 22:08:11 +01:00
parent 6ad584a262
commit 90d9e4685e
5 changed files with 336 additions and 1 deletions

View File

@@ -0,0 +1,48 @@
package org.openrndr.extra.noise.simplexrange
import org.openrndr.extra.math.simplexrange.simplexUpscale
import org.openrndr.math.LinearType
import kotlin.random.Random
/**
* Generates a random value within the convex hull of the elements in the list using a uniform
* distribution over the simplex formed by the elements, optionally applying bias to the distribution.
*
* @param random The random number generator used to produce random values. Defaults to `Random.Default`.
* @param biasOrder The number of iterations to apply bias adjustments to the weights. Defaults to 0.
* @param biasAmount The magnitude of the bias adjustment applied during each iteration. Defaults to 0.0.
* @return A value of type `T` representing the weighted interpolation of the list elements,
* with weights sampled uniformly or with bias adjustments if specified.
*/
fun <T : LinearType<T>> List<T>.uniformSimplex(random: Random = Random.Default,
biasOrder: Int = 0,
biasAmount: Double = 0.0): T {
return when (size) {
0 -> error("")
1 -> this[0]
2 -> {
val x = random.nextDouble()
this[0] * (1.0 - x) + this[1] * x
}
else -> {
val r = DoubleArray(size - 1) { random.nextDouble() }
val b = simplexUpscale(r)
if (biasOrder > 0) {
for (i in 0 until biasOrder) {
b[random.nextInt(b.size)] += random.nextDouble(biasAmount)
}
val sum = b.sum()
for (i in 0 until b.size) {
b[i] = b[i] / sum
}
}
var result = this[0] * b[0]
for (i in 1 until size) {
result += this[i] * b[i]
}
result
}
}
}

View File

@@ -4,6 +4,8 @@ import org.openrndr.math.LinearType
import org.openrndr.extra.math.simplexrange.SimplexRange4D
import org.openrndr.extra.math.simplexrange.SimplexRange3D
import org.openrndr.extra.math.simplexrange.SimplexRange2D
import kotlin.math.pow
import kotlin.random.Random
/**
@@ -16,6 +18,41 @@ fun <T:LinearType<T>> SimplexRange2D<T>.uniform(random: Random): T {
return value(random.nextDouble(), random.nextDouble())
}
/**
* Generates a uniformly distributed value within the SimplexRange2D.
*
* @param random the random number generator used to produce random values.
* @return a value of type T sampled uniformly within the 2D simplex range.
*/
fun <T:LinearType<T>> SimplexRange2D<T>.uniformPower(exp: Double, random: Random = Random.Default): T {
val b = upscale(random.nextDouble(), random.nextDouble())
for (i in 0 until b.size) {
b[i] = b[i].pow(exp)
}
val sum = b.sum()
return x0 * b[0] / sum + x1 * b[1] / sum + x2 * b[2] / sum
}
/**
* Generates a random point within the simplex represented by the `SimplexRange2D`,
* forming an interpolation of the three control points `x0`, `x1`, `x2` using a weighted
* random combination normalized to sum to 1.
*
* @param random The random number generator used to produce the random weights.
* @return A randomly interpolated point of type `T` within the simplex.
*/
fun <T:LinearType<T>> SimplexRange2D<T>.uniformCube(random: Random): T {
val r = DoubleArray(3) { random.nextDouble() }
val sum = r.sum()
if (sum > 0.0) {
for (i in 0 until r.size) {
r[i] /= sum
}
}
return this.x0 * r[0] + x1 * r[1] + x2 * r[2]
}
/**
* Generates a uniformly distributed value within the 3D simplex range.
*
@@ -26,6 +63,24 @@ fun <T:LinearType<T>> SimplexRange3D<T>.uniform(random: Random): T {
return value(random.nextDouble(), random.nextDouble(), random.nextDouble())
}
/**
* Generates a random point within the simplex represented by the `SimplexRange3D`,
* forming an interpolation of the four control points using a weighted random combination normalized to sum to 1.
*
* @param random The random number generator used to produce the random weights.
* @return A randomly interpolated point of type `T` within the simplex.
*/
fun <T:LinearType<T>> SimplexRange3D<T>.uniformCube(random: Random): T {
val r = DoubleArray(4) { random.nextDouble() }
val sum = r.sum()
if (sum > 0.0) {
for (i in 0 until r.size) {
r[i] /= sum
}
}
return this.x0 * r[0] + x1 * r[1] + x2 * r[2] + x3 * r[3]
}
/**
* Generates a uniformly distributed value within the 4D simplex range using a random generator.
*
@@ -34,4 +89,22 @@ fun <T:LinearType<T>> SimplexRange3D<T>.uniform(random: Random): T {
*/
fun <T:LinearType<T>> SimplexRange4D<T>.uniform(random: Random): T {
return value(random.nextDouble(), random.nextDouble(), random.nextDouble(), random.nextDouble())
}
}
/**
* Generates a random point within the simplex represented by the `SimplexRange4D`,
* forming an interpolation of the five control points using a weighted random combination normalized to sum to 1.
*
* @param random The random number generator used to produce the random weights.
* @return A randomly interpolated point of type `T` within the simplex.
*/
fun <T:LinearType<T>> SimplexRange4D<T>.uniformCube(random: Random): T {
val r = DoubleArray(5) { random.nextDouble() }
val sum = r.sum()
if (sum > 0.0) {
for (i in 0 until r.size) {
r[i] /= sum
}
}
return this.x0 * r[0] + x1 * r[1] + x2 * r[2] + x3 * r[3] + x4 * r[4]
}