[orx-hash-grid] Add HashGrid space partitioning
This commit is contained in:
@@ -31,6 +31,8 @@ def multiplatformModules = [
|
|||||||
"orx-shader-phrases",
|
"orx-shader-phrases",
|
||||||
"orx-shapes",
|
"orx-shapes",
|
||||||
"orx-quadtree",
|
"orx-quadtree",
|
||||||
|
"orx-hash-grid"
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
def doNotPublish = ["openrndr-demos"]
|
def doNotPublish = ["openrndr-demos"]
|
||||||
|
|||||||
3
orx-hash-grid/README.md
Normal file
3
orx-hash-grid/README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# orx-hash-grid
|
||||||
|
|
||||||
|
A 2D space partitioning for points.
|
||||||
93
orx-hash-grid/build.gradle.kts
Normal file
93
orx-hash-grid/build.gradle.kts
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("multiplatform")
|
||||||
|
kotlin("plugin.serialization")
|
||||||
|
}
|
||||||
|
|
||||||
|
val kotlinxSerializationVersion: String by rootProject.extra
|
||||||
|
val kotestVersion: String by rootProject.extra
|
||||||
|
val junitJupiterVersion: String by rootProject.extra
|
||||||
|
val jvmTarget: String by rootProject.extra
|
||||||
|
val kotlinApiVersion: String by rootProject.extra
|
||||||
|
val kotlinVersion: String by rootProject.extra
|
||||||
|
val kotlinLoggingVersion: String by rootProject.extra
|
||||||
|
val kluentVersion: String by rootProject.extra
|
||||||
|
val openrndrVersion: String by rootProject.extra
|
||||||
|
val openrndrOS: String by rootProject.extra
|
||||||
|
val spekVersion: String by rootProject.extra
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvm {
|
||||||
|
compilations {
|
||||||
|
val demo by creating {
|
||||||
|
defaultSourceSet {
|
||||||
|
kotlin.srcDir("src/demo")
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":orx-camera"))
|
||||||
|
implementation("org.openrndr:openrndr-application:$openrndrVersion")
|
||||||
|
implementation("org.openrndr:openrndr-extensions:$openrndrVersion")
|
||||||
|
runtimeOnly("org.openrndr:openrndr-gl3:$openrndrVersion")
|
||||||
|
runtimeOnly("org.openrndr:openrndr-gl3-natives-$openrndrOS:$openrndrVersion")
|
||||||
|
implementation(compilations["main"]!!.output.allOutputs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compilations.all {
|
||||||
|
kotlinOptions.jvmTarget = jvmTarget
|
||||||
|
kotlinOptions.apiVersion = kotlinApiVersion
|
||||||
|
}
|
||||||
|
testRuns["test"].executionTask.configure {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
js(IR) {
|
||||||
|
browser()
|
||||||
|
nodejs()
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
@Suppress("UNUSED_VARIABLE")
|
||||||
|
val commonMain by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":orx-parameters"))
|
||||||
|
implementation(project(":orx-shader-phrases"))
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$kotlinxSerializationVersion")
|
||||||
|
implementation("org.openrndr:openrndr-application:$openrndrVersion")
|
||||||
|
implementation("org.openrndr:openrndr-draw:$openrndrVersion")
|
||||||
|
implementation("org.openrndr:openrndr-filter:$openrndrVersion")
|
||||||
|
implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
|
||||||
|
implementation("io.github.microutils:kotlin-logging:$kotlinLoggingVersion")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Suppress("UNUSED_VARIABLE")
|
||||||
|
val commonTest by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-common"))
|
||||||
|
implementation(kotlin("test-annotations-common"))
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinxSerializationVersion")
|
||||||
|
implementation("io.kotest:kotest-assertions-core:$kotestVersion")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNUSED_VARIABLE")
|
||||||
|
val jvmTest by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-common"))
|
||||||
|
implementation(kotlin("test-annotations-common"))
|
||||||
|
implementation(kotlin("test-junit5"))
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinxSerializationVersion")
|
||||||
|
runtimeOnly("org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion")
|
||||||
|
runtimeOnly("org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion")
|
||||||
|
implementation("org.spekframework.spek2:spek-dsl-jvm:$spekVersion")
|
||||||
|
implementation("org.amshove.kluent:kluent:$kluentVersion")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNUSED_VARIABLE")
|
||||||
|
val jsTest by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-js"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
95
orx-hash-grid/src/commonMain/kotlin/HashGrid.kt
Normal file
95
orx-hash-grid/src/commonMain/kotlin/HashGrid.kt
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
package org.openrndr.extra.hashgrid
|
||||||
|
|
||||||
|
import org.openrndr.math.Vector2
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
import kotlin.math.sqrt
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
private fun Double.fastFloor(): Int {
|
||||||
|
return if (this >= 0) this.toInt() else this.toInt() - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class GridCoords(val x: Int, val y: Int) {
|
||||||
|
fun offset(i: Int, j: Int): GridCoords = copy(x = x + i, y = y + j)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Cell(
|
||||||
|
var xMin: Double = Double.POSITIVE_INFINITY,
|
||||||
|
var xMax: Double = Double.NEGATIVE_INFINITY,
|
||||||
|
var yMin: Double = Double.POSITIVE_INFINITY,
|
||||||
|
var yMax: Double = Double.NEGATIVE_INFINITY,
|
||||||
|
) {
|
||||||
|
val points = mutableListOf<Vector2>()
|
||||||
|
fun insert(point: Vector2) {
|
||||||
|
points.add(point)
|
||||||
|
xMin = min(xMin, point.x)
|
||||||
|
xMax = max(xMax, point.x)
|
||||||
|
yMin = min(yMin, point.y)
|
||||||
|
yMax = max(yMax, point.y)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun squaredDistanceTo(query: Vector2): Double {
|
||||||
|
val width = xMax - xMin
|
||||||
|
val height = yMax - yMin
|
||||||
|
val x = (xMin + xMax) / 2.0
|
||||||
|
val y = (yMin + yMax) / 2.0
|
||||||
|
val dx = max(abs(query.x - x) - width / 2, 0.0)
|
||||||
|
val dy = max(abs(query.y - y) - height / 2, 0.0)
|
||||||
|
return dx * dx + dy * dy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HashGrid(val radius: Double) {
|
||||||
|
private val cells = mutableMapOf<GridCoords, Cell>()
|
||||||
|
val cellSize = radius / sqrt(2.0)
|
||||||
|
private inline fun coords(v: Vector2): GridCoords {
|
||||||
|
val x = (v.x / cellSize).fastFloor()
|
||||||
|
val y = (v.y / cellSize).fastFloor()
|
||||||
|
return GridCoords(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun points() = sequence {
|
||||||
|
for (cell in cells.values) {
|
||||||
|
for (point in cell.points) {
|
||||||
|
yield(point)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun random(random: Random = Random.Default) : Vector2 {
|
||||||
|
return cells.values.random(random).points.random()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun insert(point: Vector2) {
|
||||||
|
val gc = coords(point)
|
||||||
|
val cell = cells.getOrPut(gc) { Cell() }
|
||||||
|
cell.insert(point)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isFree(query: Vector2): Boolean {
|
||||||
|
val c = coords(query)
|
||||||
|
if (cells[c] == null) {
|
||||||
|
for (j in -2..2) {
|
||||||
|
for (i in -2..2) {
|
||||||
|
if (i == 0 && j == 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
val n = c.offset(i, j)
|
||||||
|
val nc = cells[n]
|
||||||
|
if (nc != null && nc.squaredDistanceTo(query) <= radius * radius) {
|
||||||
|
for (p in nc.points) {
|
||||||
|
if (p.squaredDistanceTo(query) <= radius * radius) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ include 'openrndr-demos',
|
|||||||
'orx-jvm:orx-git-archiver-gradle',
|
'orx-jvm:orx-git-archiver-gradle',
|
||||||
'orx-glslify',
|
'orx-glslify',
|
||||||
'orx-gradient-descent',
|
'orx-gradient-descent',
|
||||||
|
'orx-hash-grid',
|
||||||
'orx-integral-image',
|
'orx-integral-image',
|
||||||
'orx-interval-tree',
|
'orx-interval-tree',
|
||||||
'orx-jumpflood',
|
'orx-jumpflood',
|
||||||
|
|||||||
Reference in New Issue
Block a user