[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
|
* 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 {
|
fun flatten(composition: Composition? = null): ShapeNode {
|
||||||
return ShapeNode(shape.transform(transform(this))).also {
|
|
||||||
|
val viewport = composition?.calculateViewportTransform() ?: Matrix44.IDENTITY
|
||||||
|
|
||||||
|
return ShapeNode(shape.transform(viewport * transform(this))).also {
|
||||||
it.id = id
|
it.id = id
|
||||||
it.parent = parent
|
it.parent = parent
|
||||||
it.style = effectiveStyle
|
it.style = effectiveStyle
|
||||||
@@ -293,10 +298,10 @@ data class CompositionDimensions(val x: Length, val y: Length, val width: Length
|
|||||||
// but otherwise equality checks will never succeed
|
// but otherwise equality checks will never succeed
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
return other is CompositionDimensions
|
return other is CompositionDimensions
|
||||||
&& x.value == other.x.value
|
&& x.value == other.x.value
|
||||||
&& y.value == other.y.value
|
&& y.value == other.y.value
|
||||||
&& width.value == other.width.value
|
&& width.value == other.width.value
|
||||||
&& height.value == other.height.value
|
&& height.value == other.height.value
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import org.openrndr.application
|
import org.openrndr.application
|
||||||
import org.openrndr.draw.loadFont
|
import org.openrndr.draw.loadFont
|
||||||
import org.openrndr.extra.envelopes.ADSRTracker
|
import org.openrndr.extra.envelopes.ADSRTracker
|
||||||
import org.openrndr.extra.noise.uniform
|
import org.openrndr.extra.noise.shapes.uniform
|
||||||
import org.openrndr.shape.Rectangle
|
import org.openrndr.shape.Rectangle
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
@@ -15,13 +15,13 @@ fun main() {
|
|||||||
|
|
||||||
keyboard.keyDown.listen {
|
keyboard.keyDown.listen {
|
||||||
if (it.name == "t") {
|
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 ->
|
tracker.triggerOn(0) { time, value, position ->
|
||||||
drawer.circle(center, value * 100.0)
|
drawer.circle(center, value * 100.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (it.name == "r") {
|
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 ->
|
tracker.triggerOn(1) { time, value, position ->
|
||||||
val r = Rectangle.fromCenter(center, width = value * 100.0, height = value * 100.0)
|
val r = Rectangle.fromCenter(center, width = value * 100.0, height = value * 100.0)
|
||||||
drawer.rectangle(r)
|
drawer.rectangle(r)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package typed
|
package typed
|
||||||
|
|
||||||
import org.openrndr.extra.expressions.typed.compileFunction1OrNull
|
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 org.openrndr.math.Vector2
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import org.openrndr.application
|
import org.openrndr.application
|
||||||
import org.openrndr.extra.hashgrid.filter
|
import org.openrndr.extra.hashgrid.filter
|
||||||
import org.openrndr.extra.noise.uniform
|
import org.openrndr.extra.noise.shapes.uniform
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import org.openrndr.application
|
import org.openrndr.application
|
||||||
import org.openrndr.color.ColorRGBa
|
import org.openrndr.color.ColorRGBa
|
||||||
import org.openrndr.extra.hashgrid.HashGrid
|
import org.openrndr.extra.hashgrid.HashGrid
|
||||||
import org.openrndr.extra.noise.uniform
|
import org.openrndr.extra.noise.shapes.uniform
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
fun main() {
|
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
|
* 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() {
|
fun main() {
|
||||||
application {
|
application {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import kotlin.math.PI
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Demonstrate decal generation and rendering
|
* Demonstrate decal generation and rendering
|
||||||
|
* @see <img src="https://raw.githubusercontent.com/openrndr/orx/media/orx-mesh-generators/images/decal-DemoDecal02Kt.png">
|
||||||
*/
|
*/
|
||||||
fun main() {
|
fun main() {
|
||||||
application {
|
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.math)
|
||||||
api(libs.openrndr.shape)
|
api(libs.openrndr.shape)
|
||||||
api(project(":orx-mesh"))
|
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.IIndexedPolygon
|
||||||
import org.openrndr.extra.mesh.IMeshData
|
import org.openrndr.extra.mesh.IMeshData
|
||||||
import org.openrndr.extra.mesh.IVertexData
|
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 org.openrndr.math.Vector3
|
||||||
import kotlin.math.sqrt
|
import kotlin.math.sqrt
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
@@ -20,6 +23,23 @@ fun uniformBarycentric(random: Random = Random.Default): Vector3 {
|
|||||||
return Vector3(b0, b1, 1.0 - b0 - b1)
|
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]
|
* Generate a uniformly distributed point that lies inside this [IIndexedPolygon]
|
||||||
* @param vertexData vertex data used to resolve positions
|
* @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
|
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 {
|
internal fun IIndexedPolygon.area(vertexData: IVertexData): Double {
|
||||||
require(positions.size == 3) { "polygon must be a triangle"}
|
require(positions.size == 3) { "polygon must be a triangle"}
|
||||||
val x = vertexData.positions.slice(positions)
|
val x = vertexData.positions.slice(positions)
|
||||||
@@ -62,4 +95,27 @@ fun IMeshData.uniform(count: Int, random: Random = Random.Default): List<Vector3
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
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
|
package org.openrndr.extra.noise
|
||||||
|
|
||||||
import org.openrndr.extra.hashgrid.HashGrid
|
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.math.Vector2
|
||||||
import org.openrndr.shape.*
|
import org.openrndr.shape.*
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a random [Vector2] point located inside a [ShapeProvider] while
|
* Generates specified amount of random points that lie inside the [Shape].
|
||||||
* maintaining a distance to the edge of the shape of [distanceToEdge] units.
|
*
|
||||||
|
* @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 {
|
fun ShapeProvider.uniform(pointCount: Int, random: Random = Random.Default): List<Vector2> {
|
||||||
val shape = shape
|
return shape.triangulation.uniform(pointCount, random)
|
||||||
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.hash(pointCount: Int, seed: Int, x: Int): List<Vector2> {
|
||||||
* Generate [sampleCount] uniformly distributed points inside the area of [ShapeProvider]
|
return shape.triangulation.hash(pointCount, seed, x)
|
||||||
*/
|
}
|
||||||
fun ShapeProvider.uniform(sampleCount: Int, random: Random = Random.Default) : List<Vector2> = shape.triangulation.uniform(sampleCount, random)
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of pairs in which the first component is a radius and the
|
* 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
|
(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(
|
fun Vector2.Companion.uniform(
|
||||||
min: Vector2 = -ONE, max: Vector2 = ONE,
|
min: Vector2 = -ONE, max: Vector2 = ONE,
|
||||||
random: Random = Random.Default
|
random: Random = Random.Default
|
||||||
@@ -32,12 +38,28 @@ fun Vector2.Companion.uniform(
|
|||||||
Double.uniform(min.y, max.y, random)
|
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(
|
fun Vector2.Companion.uniform(
|
||||||
min: Double = -1.0, max: Double = 1.0,
|
min: Double = -1.0, max: Double = 1.0,
|
||||||
random: Random = Random.Default
|
random: Random = Random.Default
|
||||||
) =
|
) =
|
||||||
Vector2.uniform(Vector2(min, min), Vector2(max, max), random)
|
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(
|
fun Vector2.Companion.uniform(
|
||||||
rect: Rectangle,
|
rect: Rectangle,
|
||||||
random: Random = Random.Default
|
random: Random = Random.Default
|
||||||
@@ -78,7 +100,7 @@ fun Vector2.Companion.uniformRing(
|
|||||||
|
|
||||||
val eps = 1E-6
|
val eps = 1E-6
|
||||||
|
|
||||||
if ( abs(innerRadius - outerRadius) < eps) {
|
if (abs(innerRadius - outerRadius) < eps) {
|
||||||
val angle = Double.uniform(-180.0, 180.0, random)
|
val angle = Double.uniform(-180.0, 180.0, random)
|
||||||
return Polar(angle, innerRadius).cartesian
|
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.application
|
||||||
import org.openrndr.color.ColorRGBa
|
import org.openrndr.color.ColorRGBa
|
||||||
import org.openrndr.extra.noise.uniform
|
import org.openrndr.extra.noise.shapes.hash
|
||||||
import org.openrndr.shape.Triangle
|
import org.openrndr.shape.Triangle
|
||||||
import kotlin.random.Random
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Demonstrate the generation of uniformly distributed points inside a list of triangles
|
* Demonstrate the generation of uniformly distributed points inside a list of triangles
|
||||||
@@ -17,8 +16,10 @@ fun main() {
|
|||||||
program {
|
program {
|
||||||
val r = drawer.bounds.offsetEdges(-100.0)
|
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 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 {
|
extend {
|
||||||
|
val pts = listOf(triangle).hash(1000, 0, (seconds*500.0).toInt())
|
||||||
drawer.clear(ColorRGBa.PINK)
|
drawer.clear(ColorRGBa.PINK)
|
||||||
drawer.stroke = null
|
drawer.stroke = null
|
||||||
drawer.contour(triangle.contour)
|
drawer.contour(triangle.contour)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import org.openrndr.extra.shapes.primitives.intersection
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Demonstrate rectangle-rectangle intersection
|
* Demonstrate rectangle-rectangle intersection
|
||||||
|
* @see <img src="https://raw.githubusercontent.com/openrndr/orx/media/orx-shapes/images/primitives-DemoRectangleIntersection01Kt.png">
|
||||||
*/
|
*/
|
||||||
fun main() {
|
fun main() {
|
||||||
application {
|
application {
|
||||||
|
|||||||
Reference in New Issue
Block a user