[orx-noise] Add hash functions
This commit is contained in:
@@ -186,11 +186,16 @@ class ShapeNode(var shape: Shape) : CompositionNode() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* apply transforms of all ancestor nodes and return a new detached shape node with identity transform and transformed Shape
|
||||
* @param composition use viewport transform
|
||||
*/
|
||||
fun flatten(): ShapeNode {
|
||||
return ShapeNode(shape.transform(transform(this))).also {
|
||||
fun flatten(composition: Composition? = null): ShapeNode {
|
||||
|
||||
val viewport = composition?.calculateViewportTransform() ?: Matrix44.IDENTITY
|
||||
|
||||
return ShapeNode(shape.transform(viewport * transform(this))).also {
|
||||
it.id = id
|
||||
it.parent = parent
|
||||
it.style = effectiveStyle
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import org.openrndr.application
|
||||
import org.openrndr.draw.loadFont
|
||||
import org.openrndr.extra.envelopes.ADSRTracker
|
||||
import org.openrndr.extra.noise.uniform
|
||||
import org.openrndr.extra.noise.shapes.uniform
|
||||
import org.openrndr.shape.Rectangle
|
||||
|
||||
fun main() {
|
||||
@@ -15,13 +15,13 @@ fun main() {
|
||||
|
||||
keyboard.keyDown.listen {
|
||||
if (it.name == "t") {
|
||||
val center = drawer.bounds.uniform(distanceToEdge = 30.0)
|
||||
val center = drawer.bounds.offsetEdges(-30.0).uniform()
|
||||
tracker.triggerOn(0) { time, value, position ->
|
||||
drawer.circle(center, value * 100.0)
|
||||
}
|
||||
}
|
||||
if (it.name == "r") {
|
||||
val center = drawer.bounds.uniform(distanceToEdge = 30.0)
|
||||
val center = drawer.bounds.offsetEdges(-30.0).uniform()
|
||||
tracker.triggerOn(1) { time, value, position ->
|
||||
val r = Rectangle.fromCenter(center, width = value * 100.0, height = value * 100.0)
|
||||
drawer.rectangle(r)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package typed
|
||||
|
||||
import org.openrndr.extra.expressions.typed.compileFunction1OrNull
|
||||
import org.openrndr.extra.noise.uniform
|
||||
import org.openrndr.extra.noise.shapes.uniform
|
||||
import org.openrndr.math.Vector2
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import org.openrndr.application
|
||||
import org.openrndr.extra.hashgrid.filter
|
||||
import org.openrndr.extra.noise.uniform
|
||||
import org.openrndr.extra.noise.shapes.uniform
|
||||
import kotlin.random.Random
|
||||
|
||||
fun main() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import org.openrndr.application
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.extra.hashgrid.HashGrid
|
||||
import org.openrndr.extra.noise.uniform
|
||||
import org.openrndr.extra.noise.shapes.uniform
|
||||
import kotlin.random.Random
|
||||
|
||||
fun main() {
|
||||
|
||||
72
orx-mesh-generators/src/commonMain/kotlin/mesh/Box.kt
Normal file
72
orx-mesh-generators/src/commonMain/kotlin/mesh/Box.kt
Normal file
@@ -0,0 +1,72 @@
|
||||
package org.openrndr.extra.mesh.generators
|
||||
|
||||
import org.openrndr.extra.mesh.*
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
|
||||
class MeshBuilder {
|
||||
val vertexData = MutableVertexData()
|
||||
val polygons = mutableListOf<IndexedPolygon>()
|
||||
val mesh = MutableMeshData(vertexData, polygons)
|
||||
}
|
||||
|
||||
fun box(): MeshData {
|
||||
|
||||
val positions = listOf(
|
||||
Vector3(-0.5, -0.5, -0.5),
|
||||
Vector3(0.5, -0.5, -0.5),
|
||||
Vector3(-0.5, 0.5, -0.5),
|
||||
Vector3(0.5, 0.5, -0.5),
|
||||
|
||||
Vector3(-0.5, -0.5, 0.5),
|
||||
Vector3(0.5, -0.5, 0.5),
|
||||
Vector3(-0.5, 0.5, 0.5),
|
||||
Vector3(0.5, 0.5, 0.5),
|
||||
)
|
||||
|
||||
val textureCoords = listOf(
|
||||
Vector2(0.0, 0.0),
|
||||
Vector2(1.0, 0.0),
|
||||
Vector2(0.0, 1.0),
|
||||
Vector2(1.0, 1.0),
|
||||
)
|
||||
|
||||
val normals = listOf(
|
||||
Vector3(-1.0, 0.0, 0.0),
|
||||
Vector3(1.0, 0.0, 0.0),
|
||||
Vector3(0.0, -1.0, 0.0),
|
||||
Vector3(0.0, 1.0, 0.0),
|
||||
Vector3(0.0, 0.0, -1.0),
|
||||
Vector3(0.0, 0.0, 1.0)
|
||||
)
|
||||
|
||||
val polygons = listOf(
|
||||
// -x
|
||||
IndexedPolygon(
|
||||
positions = listOf(0, 2, 4, 6),
|
||||
textureCoords = listOf(0, 1, 3, 2),
|
||||
colors = emptyList(),
|
||||
normals = listOf(0, 0, 0, 0),
|
||||
tangents = listOf(5, 5, 5, 5),
|
||||
bitangents = listOf(3, 3, 3, 3)
|
||||
),
|
||||
// +x
|
||||
IndexedPolygon(
|
||||
positions = listOf(1, 3, 5, 7),
|
||||
textureCoords = listOf(0, 1, 3, 2),
|
||||
colors = emptyList(),
|
||||
normals = listOf(1, 1, 1, 1),
|
||||
tangents = listOf(4, 4, 4, 4),
|
||||
bitangents = listOf(3, 3, 3, 3)
|
||||
)
|
||||
)
|
||||
return MeshData(
|
||||
VertexData(
|
||||
positions = positions,
|
||||
textureCoords = textureCoords,
|
||||
normals = normals,
|
||||
tangents = normals,
|
||||
bitangents = normals
|
||||
), polygons
|
||||
)
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import java.io.File
|
||||
|
||||
/**
|
||||
* Demonstrate decal generator as an object slicer
|
||||
* @see <img src="https://raw.githubusercontent.com/openrndr/orx/media/orx-mesh-generators/images/decal-DemoDecal01Kt.png">
|
||||
*/
|
||||
fun main() {
|
||||
application {
|
||||
|
||||
@@ -15,6 +15,7 @@ import kotlin.math.PI
|
||||
|
||||
/**
|
||||
* Demonstrate decal generation and rendering
|
||||
* @see <img src="https://raw.githubusercontent.com/openrndr/orx/media/orx-mesh-generators/images/decal-DemoDecal02Kt.png">
|
||||
*/
|
||||
fun main() {
|
||||
application {
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package tangents
|
||||
|
||||
import org.openrndr.application
|
||||
import org.openrndr.draw.DrawPrimitive
|
||||
import org.openrndr.draw.shadeStyle
|
||||
import org.openrndr.extra.camera.Orbital
|
||||
import org.openrndr.extra.mesh.toVertexBuffer
|
||||
import org.openrndr.extra.meshgenerators.tangents.estimateTangents
|
||||
import org.openrndr.extra.objloader.loadOBJMeshData
|
||||
import org.openrndr.math.Vector3
|
||||
import java.io.File
|
||||
|
||||
fun main() = application {
|
||||
program {
|
||||
val obj = loadOBJMeshData(File("demo-data/obj-models/suzanne/Suzanne.obj")).toMeshData().triangulate()
|
||||
val tangentObj = obj.estimateTangents()
|
||||
|
||||
val objVB = tangentObj.toVertexBuffer()
|
||||
|
||||
extend(Orbital()) {
|
||||
eye = Vector3(0.0, 0.0, 2.0)
|
||||
}
|
||||
extend {
|
||||
drawer.shadeStyle = shadeStyle {
|
||||
fragmentTransform = """
|
||||
vec3 viewTangent = (u_viewNormalMatrix * u_modelNormalMatrix * vec4(va_tangent, 0.0)).xyz;
|
||||
vec3 viewBitangent = (u_viewNormalMatrix * u_modelNormalMatrix * vec4(va_bitangent, 0.0)).xyz;
|
||||
float c = cos(100.0*dot(v_worldPosition, va_normal)) * 0.5 + 0.5;
|
||||
|
||||
//x_fill.rgb = normalize(viewTangent)*0.5+0.5;
|
||||
x_fill.rgb = vec3(c);
|
||||
""".trimIndent()
|
||||
|
||||
}
|
||||
|
||||
drawer.vertexBuffer(objVB, DrawPrimitive.TRIANGLES)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ kotlin {
|
||||
api(libs.openrndr.math)
|
||||
api(libs.openrndr.shape)
|
||||
api(project(":orx-mesh"))
|
||||
implementation(project(":orx-noise"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@ package org.openrndr.extra.mesh.noise
|
||||
import org.openrndr.extra.mesh.IIndexedPolygon
|
||||
import org.openrndr.extra.mesh.IMeshData
|
||||
import org.openrndr.extra.mesh.IVertexData
|
||||
import org.openrndr.extra.noise.fhash1D
|
||||
import org.openrndr.extra.noise.uhash11
|
||||
import org.openrndr.extra.noise.uhash1D
|
||||
import org.openrndr.math.Vector3
|
||||
import kotlin.math.sqrt
|
||||
import kotlin.random.Random
|
||||
@@ -20,6 +23,23 @@ fun uniformBarycentric(random: Random = Random.Default): Vector3 {
|
||||
return Vector3(b0, b1, 1.0 - b0 - b1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a uniformly distributed barycentric coordinate
|
||||
* @param random a random number generator
|
||||
*/
|
||||
fun hashBarycentric(seed: Int, x: Int): Vector3 {
|
||||
val u = fhash1D(seed, x)
|
||||
val v = fhash1D(seed, u.toRawBits().toInt() - x)
|
||||
|
||||
|
||||
|
||||
val su0 = sqrt(u)
|
||||
val b0 = 1.0 - su0
|
||||
val b1 = v * su0
|
||||
return Vector3(b0, b1, 1.0 - b0 - b1)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate a uniformly distributed point that lies inside this [IIndexedPolygon]
|
||||
* @param vertexData vertex data used to resolve positions
|
||||
@@ -33,6 +53,19 @@ fun IIndexedPolygon.uniform(vertexData: IVertexData, random: Random = Random.Def
|
||||
return x[0] * b.x + x[1] * b.y + x[2] * b.z
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a uniformly distributed point that lies inside this [IIndexedPolygon]
|
||||
* @param vertexData vertex data used to resolve positions
|
||||
* @param random a random number generator
|
||||
*/
|
||||
fun IIndexedPolygon.hash(vertexData: IVertexData, seed:Int, x: Int): Vector3 {
|
||||
require(positions.size == 3) { "polygon must be a triangle"}
|
||||
|
||||
val s = vertexData.positions.slice(positions)
|
||||
val b = hashBarycentric(seed, x)
|
||||
return s[0] * b.x + s[1] * b.y + s[2] * b.z
|
||||
}
|
||||
|
||||
internal fun IIndexedPolygon.area(vertexData: IVertexData): Double {
|
||||
require(positions.size == 3) { "polygon must be a triangle"}
|
||||
val x = vertexData.positions.slice(positions)
|
||||
@@ -63,3 +96,26 @@ fun IMeshData.uniform(count: Int, random: Random = Random.Default): List<Vector3
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate points on the surface described by the mesh data
|
||||
*/
|
||||
fun IMeshData.hash(count: Int, seed:Int, x: Int): List<Vector3> {
|
||||
val triangulated = triangulate()
|
||||
val result = mutableListOf<Vector3>()
|
||||
val totalArea = triangulated.polygons.sumOf { it.area(vertexData) }
|
||||
val randoms = (0 until count).map {
|
||||
Pair(x + it, fhash1D(seed, x + it) * totalArea)
|
||||
}.sortedBy { it.second }
|
||||
|
||||
var idx = 0
|
||||
var sum = 0.0
|
||||
for (t in triangulated.polygons) {
|
||||
sum += t.area(vertexData)
|
||||
while (idx <= randoms.lastIndex && sum > randoms[idx].second) {
|
||||
result.add(t.hash(vertexData, seed xor 0x7f7f7f, randoms[idx].first))
|
||||
idx++
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
48
orx-mesh-noise/src/jvmDemo/kotlin/DemoMeshNoise02.kt
Normal file
48
orx-mesh-noise/src/jvmDemo/kotlin/DemoMeshNoise02.kt
Normal file
@@ -0,0 +1,48 @@
|
||||
import org.openrndr.application
|
||||
import org.openrndr.draw.DrawPrimitive
|
||||
import org.openrndr.draw.isolated
|
||||
import org.openrndr.draw.shadeStyle
|
||||
import org.openrndr.extra.camera.Orbital
|
||||
import org.openrndr.extra.mesh.noise.hash
|
||||
import org.openrndr.extra.objloader.loadOBJMeshData
|
||||
import org.openrndr.extra.mesh.noise.uniform
|
||||
import org.openrndr.extra.meshgenerators.sphereMesh
|
||||
import org.openrndr.math.Vector3
|
||||
import java.io.File
|
||||
import kotlin.math.cos
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* Demonstrate uniform point on mesh generation using hash functions
|
||||
*/
|
||||
fun main() {
|
||||
application {
|
||||
configure {
|
||||
width = 720
|
||||
height = 720
|
||||
}
|
||||
program {
|
||||
val mesh = loadOBJMeshData(File("demo-data/obj-models/suzanne/Suzanne.obj")).toMeshData()
|
||||
|
||||
val sphere = sphereMesh(radius = 0.01)
|
||||
extend(Orbital()) {
|
||||
eye = Vector3(0.0, 0.0, 2.0)
|
||||
}
|
||||
extend {
|
||||
|
||||
val points = mesh.hash((1000 + (cos(seconds)*0.5+0.5)*9000).toInt(), 808, (seconds*10000).toInt())
|
||||
|
||||
|
||||
drawer.shadeStyle = shadeStyle {
|
||||
fragmentTransform = "x_fill = vec4(v_viewNormal*0.5+0.5, 1.0);"
|
||||
}
|
||||
for (point in points) {
|
||||
drawer.isolated {
|
||||
drawer.translate(point)
|
||||
drawer.vertexBuffer(sphere, DrawPrimitive.TRIANGLES)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.openrndr.extra.shapes.primitives.intersection
|
||||
|
||||
/**
|
||||
* Demonstrate rectangle-rectangle intersection
|
||||
* @see <img src="https://raw.githubusercontent.com/openrndr/orx/media/orx-shapes/images/primitives-DemoRectangleIntersection01Kt.png">
|
||||
*/
|
||||
fun main() {
|
||||
application {
|
||||
|
||||
Reference in New Issue
Block a user