[orx-noise] Add hash functions
This commit is contained in:
@@ -1,35 +1,25 @@
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
import org.openrndr.extra.hashgrid.HashGrid
|
||||
import org.openrndr.extra.noise.shapes.hash
|
||||
import org.openrndr.extra.noise.shapes.uniform
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.shape.*
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* Returns a random [Vector2] point located inside a [ShapeProvider] while
|
||||
* maintaining a distance to the edge of the shape of [distanceToEdge] units.
|
||||
* Generates specified amount of random points that lie inside the [Shape].
|
||||
*
|
||||
* @param pointCount The number of points to generate.
|
||||
* @param random The [Random] number generator to use, defaults to [Random.Default].
|
||||
*/
|
||||
fun ShapeProvider.uniform(distanceToEdge: Double = 0.0, random: Random = Random.Default): Vector2 {
|
||||
val shape = shape
|
||||
require(!shape.empty)
|
||||
var attempts = 0
|
||||
val innerBounds = shape.bounds.offsetEdges(-distanceToEdge.coerceAtLeast(0.0))
|
||||
return Vector2.uniformSequence(innerBounds, random).first {
|
||||
attempts++
|
||||
require(attempts < 100)
|
||||
if (distanceToEdge == 0.0) {
|
||||
shape.contains(it)
|
||||
} else {
|
||||
shape.contains(it) && shape.contours.minOf { c -> c.nearest(it).position.distanceTo(it) } > distanceToEdge
|
||||
}
|
||||
}
|
||||
fun ShapeProvider.uniform(pointCount: Int, random: Random = Random.Default): List<Vector2> {
|
||||
return shape.triangulation.uniform(pointCount, random)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate [sampleCount] uniformly distributed points inside the area of [ShapeProvider]
|
||||
*/
|
||||
fun ShapeProvider.uniform(sampleCount: Int, random: Random = Random.Default) : List<Vector2> = shape.triangulation.uniform(sampleCount, random)
|
||||
|
||||
fun ShapeProvider.hash(pointCount: Int, seed: Int, x: Int): List<Vector2> {
|
||||
return shape.triangulation.hash(pointCount, seed, x)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of pairs in which the first component is a radius and the
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.shape.Triangle
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* Generate [count] uniform samples from a list of [Triangle]s
|
||||
*/
|
||||
fun List<Triangle>.uniform(count: Int, random: Random = Random.Default): List<Vector2> {
|
||||
val totalArea = this.sumOf { it.area }
|
||||
val randoms = (0 until count).map {
|
||||
Double.uniform(0.0, totalArea, random = random)
|
||||
}.sorted()
|
||||
val result = mutableListOf<Vector2>()
|
||||
var idx = 0
|
||||
var sum = 0.0
|
||||
for (t in this) {
|
||||
sum += t.area
|
||||
while (idx <= randoms.lastIndex && sum > randoms[idx]) {
|
||||
result.add(t.randomPoint(random))
|
||||
idx++
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -23,6 +23,12 @@ fun Double.Companion.uniform(
|
||||
) =
|
||||
(random.nextDouble() * (max - min)) + min
|
||||
|
||||
fun Double.Companion.hash(
|
||||
seed: Int, x: Int,
|
||||
min: Double = -1.0, max: Double = 1.0
|
||||
) = fhash1D(seed, x) * (max - min) + min
|
||||
|
||||
|
||||
fun Vector2.Companion.uniform(
|
||||
min: Vector2 = -ONE, max: Vector2 = ONE,
|
||||
random: Random = Random.Default
|
||||
@@ -32,12 +38,28 @@ fun Vector2.Companion.uniform(
|
||||
Double.uniform(min.y, max.y, random)
|
||||
)
|
||||
|
||||
fun Vector2.Companion.hash(
|
||||
seed: Int, x: Int,
|
||||
min: Vector2 = -ONE, max: Vector2 = ONE
|
||||
) =
|
||||
Vector2(
|
||||
Double.hash(seed, x, min.x, max.x),
|
||||
Double.hash(seed xor 0x7f7f7f7f, x, min.y, max.y)
|
||||
)
|
||||
|
||||
fun Vector2.Companion.uniform(
|
||||
min: Double = -1.0, max: Double = 1.0,
|
||||
random: Random = Random.Default
|
||||
) =
|
||||
Vector2.uniform(Vector2(min, min), Vector2(max, max), random)
|
||||
|
||||
fun Vector2.Companion.hash(
|
||||
seed: Int, x: Int,
|
||||
min: Double = -1.0, max: Double = 1.0,
|
||||
) =
|
||||
Vector2.hash(seed, x, Vector2(min, min), Vector2(max, max))
|
||||
|
||||
|
||||
fun Vector2.Companion.uniform(
|
||||
rect: Rectangle,
|
||||
random: Random = Random.Default
|
||||
@@ -78,7 +100,7 @@ fun Vector2.Companion.uniformRing(
|
||||
|
||||
val eps = 1E-6
|
||||
|
||||
if ( abs(innerRadius - outerRadius) < eps) {
|
||||
if (abs(innerRadius - outerRadius) < eps) {
|
||||
val angle = Double.uniform(-180.0, 180.0, random)
|
||||
return Polar(angle, innerRadius).cartesian
|
||||
|
||||
|
||||
28
orx-noise/src/commonMain/kotlin/shapes/Box.kt
Normal file
28
orx-noise/src/commonMain/kotlin/shapes/Box.kt
Normal file
@@ -0,0 +1,28 @@
|
||||
package org.openrndr.extra.noise.shapes
|
||||
|
||||
import org.openrndr.extra.noise.uhash11
|
||||
import org.openrndr.math.Vector3
|
||||
import org.openrndr.shape.Box
|
||||
import kotlin.random.Random
|
||||
|
||||
fun Box.uniform(random: Random = Random.Default): Vector3 {
|
||||
val x = random.nextDouble() * width + corner.x
|
||||
val y = random.nextDouble() * height + corner.y
|
||||
val z = random.nextDouble() * depth + corner.z
|
||||
return Vector3(x, y ,z)
|
||||
}
|
||||
|
||||
fun Box.hash(seed: Int, x: Int): Vector3 {
|
||||
val ux = uhash11(seed.toUInt() + uhash11(x.toUInt()))
|
||||
val uy = uhash11(ux + x.toUInt())
|
||||
val uz = uhash11(uy + x.toUInt())
|
||||
|
||||
val fx = ux.toDouble() / UInt.MAX_VALUE.toDouble()
|
||||
val fy = uy.toDouble() / UInt.MAX_VALUE.toDouble()
|
||||
val fz = uz.toDouble() / UInt.MAX_VALUE.toDouble()
|
||||
|
||||
val x = fx * width + corner.x
|
||||
val y = fy * height + corner.y
|
||||
val z = fz * depth + corner.z
|
||||
return Vector3(x, y, z)
|
||||
}
|
||||
27
orx-noise/src/commonMain/kotlin/shapes/Circle.kt
Normal file
27
orx-noise/src/commonMain/kotlin/shapes/Circle.kt
Normal file
@@ -0,0 +1,27 @@
|
||||
package org.openrndr.extra.noise.shapes
|
||||
|
||||
import org.openrndr.extra.noise.fhash1D
|
||||
import org.openrndr.extra.noise.hash
|
||||
import org.openrndr.math.Polar
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.shape.Circle
|
||||
import kotlin.math.sqrt
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* Generate a uniformly distributed random point inside [Circle]
|
||||
*/
|
||||
fun Circle.hash(seed: Int, x: Int): Vector2 {
|
||||
val r = radius * sqrt(fhash1D(seed, x))
|
||||
val phi = 360.0 * fhash1D(seed xor 0x7f7f_7f7f, x)
|
||||
return Polar(phi, r).cartesian + center
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a uniformly distributed random point inside [Circle]
|
||||
*/
|
||||
fun Circle.uniform(random: Random = Random.Default): Vector2 {
|
||||
val r = radius * sqrt(random.nextDouble())
|
||||
val phi = 360.0 * random.nextDouble()
|
||||
return Polar(phi, r).cartesian + center
|
||||
}
|
||||
24
orx-noise/src/commonMain/kotlin/shapes/Rectangle.kt
Normal file
24
orx-noise/src/commonMain/kotlin/shapes/Rectangle.kt
Normal file
@@ -0,0 +1,24 @@
|
||||
package org.openrndr.extra.noise.shapes
|
||||
|
||||
import org.openrndr.extra.noise.uhash11
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.shape.Rectangle
|
||||
import kotlin.random.Random
|
||||
|
||||
fun Rectangle.uniform(random: Random = Random.Default): Vector2 {
|
||||
val x = random.nextDouble() * width + corner.x
|
||||
val y = random.nextDouble() * height + corner.y
|
||||
return Vector2(x, y)
|
||||
}
|
||||
|
||||
fun Rectangle.hash(seed: Int, x: Int): Vector2 {
|
||||
val ux = uhash11(seed.toUInt() + uhash11(x.toUInt()))
|
||||
val uy = uhash11(ux + x.toUInt())
|
||||
|
||||
val fx = ux.toDouble() / UInt.MAX_VALUE.toDouble()
|
||||
val fy = uy.toDouble() / UInt.MAX_VALUE.toDouble()
|
||||
|
||||
val x = fx * width + corner.x
|
||||
val y = fy * height + corner.y
|
||||
return Vector2(x, y)
|
||||
}
|
||||
58
orx-noise/src/commonMain/kotlin/shapes/Triangle.kt
Normal file
58
orx-noise/src/commonMain/kotlin/shapes/Triangle.kt
Normal file
@@ -0,0 +1,58 @@
|
||||
package org.openrndr.extra.noise.shapes
|
||||
|
||||
import org.openrndr.extra.noise.fhash1D
|
||||
import org.openrndr.extra.noise.uniform
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.shape.Triangle
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* Generate [count] uniform samples from a list of [Triangle]s
|
||||
*/
|
||||
fun List<Triangle>.uniform(count: Int, random: Random = Random.Default): List<Vector2> {
|
||||
val totalArea = this.sumOf { it.area }
|
||||
val randoms = (0 until count).map {
|
||||
Double.uniform(0.0, totalArea, random = random)
|
||||
}.sorted()
|
||||
val result = mutableListOf<Vector2>()
|
||||
var idx = 0
|
||||
var sum = 0.0
|
||||
for (t in this) {
|
||||
sum += t.area
|
||||
while (idx <= randoms.lastIndex && sum > randoms[idx]) {
|
||||
result.add(t.uniform(random))
|
||||
idx++
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun List<Triangle>.hash(count: Int, seed: Int = 0, x: Int = 0): List<Vector2> {
|
||||
val totalArea = this.sumOf { it.area }
|
||||
val randoms = (0 until count).map {
|
||||
Pair(x + it, fhash1D(seed, x + it) * totalArea)
|
||||
}.sortedBy { it.second }
|
||||
val result = mutableListOf<Vector2>()
|
||||
var idx = 0
|
||||
var sum = 0.0
|
||||
for (t in this) {
|
||||
sum += t.area
|
||||
while (idx <= randoms.lastIndex && sum > randoms[idx].second) {
|
||||
result.add(t.hash(seed, randoms[idx].first))
|
||||
idx++
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/** Generates a random point that lies inside the [Triangle]. */
|
||||
fun Triangle.uniform(random: Random = Random.Default): Vector2 {
|
||||
return position(random.nextDouble(), random.nextDouble())
|
||||
}
|
||||
|
||||
|
||||
fun Triangle.hash(seed: Int, x: Int): Vector2 {
|
||||
val u = fhash1D(seed, x)
|
||||
val v = fhash1D(seed, u.toRawBits().toInt() + x)
|
||||
return position(u, v)
|
||||
}
|
||||
33
orx-noise/src/jvmDemo/kotlin/DemoCircleHash01.kt
Normal file
33
orx-noise/src/jvmDemo/kotlin/DemoCircleHash01.kt
Normal file
@@ -0,0 +1,33 @@
|
||||
import org.openrndr.application
|
||||
import org.openrndr.extra.noise.shapes.hash
|
||||
import org.openrndr.extra.noise.shapes.uniform
|
||||
import org.openrndr.shape.Circle
|
||||
import kotlin.random.Random
|
||||
|
||||
fun main() {
|
||||
application {
|
||||
configure {
|
||||
width = 720
|
||||
height = 720
|
||||
}
|
||||
program {
|
||||
extend {
|
||||
val b = drawer.bounds
|
||||
val b0 = b.sub(0.0, 0.0, 0.5, 1.0).offsetEdges(-10.0)
|
||||
val b1 = b.sub(0.5, 0.0, 1.0, 1.0).offsetEdges(-10.0)
|
||||
|
||||
val c0 = Circle(b0.center, b0.width/2.0)
|
||||
val c1 = Circle(b1.center, b1.width/2.0)
|
||||
|
||||
val r = Random(0)
|
||||
for (i in 0 until 2000) {
|
||||
drawer.circle(c0.uniform(r), 2.0)
|
||||
drawer.circle(c1.hash(909, i),2.0)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
29
orx-noise/src/jvmDemo/kotlin/DemoRectangleHash01.kt
Normal file
29
orx-noise/src/jvmDemo/kotlin/DemoRectangleHash01.kt
Normal file
@@ -0,0 +1,29 @@
|
||||
import org.openrndr.application
|
||||
import org.openrndr.extra.noise.shapes.hash
|
||||
import org.openrndr.extra.noise.shapes.uniform
|
||||
import kotlin.random.Random
|
||||
|
||||
fun main() {
|
||||
application {
|
||||
configure {
|
||||
width = 720
|
||||
height = 720
|
||||
}
|
||||
program {
|
||||
extend {
|
||||
val b = drawer.bounds
|
||||
val b0 = b.sub(0.0, 0.0, 0.5, 1.0).offsetEdges(-10.0)
|
||||
val b1 = b.sub(0.5, 0.0, 1.0, 1.0).offsetEdges(-10.0)
|
||||
|
||||
val r = Random(0)
|
||||
for (i in 0 until 20000) {
|
||||
drawer.circle(b0.uniform(r), 2.0)
|
||||
drawer.circle(b1.hash(909, i),2.0)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
import org.openrndr.application
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.extra.noise.uniform
|
||||
import org.openrndr.extra.noise.shapes.hash
|
||||
import org.openrndr.shape.Triangle
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* Demonstrate the generation of uniformly distributed points inside a list of triangles
|
||||
@@ -17,8 +16,10 @@ fun main() {
|
||||
program {
|
||||
val r = drawer.bounds.offsetEdges(-100.0)
|
||||
val triangle = Triangle(r.position(0.5, 0.0), r.position(0.0, 1.0), r.position(1.0, 1.0))
|
||||
val pts = listOf(triangle).uniform(1000, Random(0))
|
||||
//val pts = listOf(triangle).uniform(1000, Random(0))
|
||||
|
||||
extend {
|
||||
val pts = listOf(triangle).hash(1000, 0, (seconds*500.0).toInt())
|
||||
drawer.clear(ColorRGBa.PINK)
|
||||
drawer.stroke = null
|
||||
drawer.contour(triangle.contour)
|
||||
|
||||
Reference in New Issue
Block a user