[orx-marching-squares] Add orx-marching-squares module
This commit is contained in:
@@ -19,6 +19,7 @@ def multiplatformModules = [
|
|||||||
"orx-gradient-descent",
|
"orx-gradient-descent",
|
||||||
"orx-image-fit",
|
"orx-image-fit",
|
||||||
"orx-jumpflood",
|
"orx-jumpflood",
|
||||||
|
"orx-marching-squares",
|
||||||
"orx-no-clear",
|
"orx-no-clear",
|
||||||
"orx-noise",
|
"orx-noise",
|
||||||
"orx-parameters",
|
"orx-parameters",
|
||||||
|
|||||||
21
orx-marching-squares/README.md
Normal file
21
orx-marching-squares/README.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# orx-marching-squares
|
||||||
|
|
||||||
|
Tools for extracting contours from functions
|
||||||
|
|
||||||
|
## How to use it?
|
||||||
|
|
||||||
|
`orx-marching-squares` provides the `findContours()` function
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
fun f(v: Vector2) = v.distanceTo(drawer.bounds.center) - 200.0
|
||||||
|
val segments = findContours(::f, drawer.bounds, 16.0)
|
||||||
|
drawer.lineSegments(segments)
|
||||||
|
```
|
||||||
|
|
||||||
|
With a small adjustment to the given function one can use `findContours` to find iso contours. The trick is to add a cosine over the distance function.
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
fun f(v: Vector2) = cos((v.distanceTo(drawer.bounds.center) / 100.0) * 2 * PI)
|
||||||
|
val segments = findContours(::f, drawer.bounds.offsetEdges(32.0), 16.0)
|
||||||
|
drawer.lineSegments(segments)
|
||||||
|
```
|
||||||
23
orx-marching-squares/build.gradle.kts
Normal file
23
orx-marching-squares/build.gradle.kts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
plugins {
|
||||||
|
org.openrndr.extra.convention.`kotlin-multiplatform`
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
sourceSets {
|
||||||
|
@Suppress("UNUSED_VARIABLE")
|
||||||
|
val commonMain by getting {
|
||||||
|
dependencies {
|
||||||
|
api(libs.openrndr.math)
|
||||||
|
api(libs.openrndr.shape)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNUSED_VARIABLE")
|
||||||
|
val jvmDemo by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":orx-shapes"))
|
||||||
|
implementation(project(":orx-noise"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
107
orx-marching-squares/src/commonMain/kotlin/MarchingSquares.kt
Normal file
107
orx-marching-squares/src/commonMain/kotlin/MarchingSquares.kt
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
package org.openrndr.extra.marchingsquares
|
||||||
|
|
||||||
|
import org.openrndr.math.IntVector2
|
||||||
|
import org.openrndr.math.Vector2
|
||||||
|
import org.openrndr.shape.LineSegment
|
||||||
|
import org.openrndr.shape.Rectangle
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
fun findContours(
|
||||||
|
f: (Vector2) -> Double,
|
||||||
|
area: Rectangle,
|
||||||
|
cellSize: Double,
|
||||||
|
useInterpolation: Boolean = true
|
||||||
|
): List<LineSegment> {
|
||||||
|
val segments = mutableListOf<LineSegment>()
|
||||||
|
val values = mutableMapOf<IntVector2, Double>()
|
||||||
|
|
||||||
|
for (y in 0 until (area.width / cellSize).toInt()) {
|
||||||
|
for (x in 0 until (area.width / cellSize).toInt()) {
|
||||||
|
values[IntVector2(x, y)] = f(Vector2(x * cellSize + area.x, y * cellSize + area.y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val zero = 0.0
|
||||||
|
for (y in 0 until (area.width / cellSize).toInt()) {
|
||||||
|
for (x in 0 until (area.width / cellSize).toInt()) {
|
||||||
|
val v00 = (values[IntVector2(x, y)] ?: zero)
|
||||||
|
val v10 = (values[IntVector2(x + 1, y)] ?: zero)
|
||||||
|
val v01 = (values[IntVector2(x, y + 1)] ?: zero)
|
||||||
|
val v11 = (values[IntVector2(x + 1, y + 1)] ?: zero)
|
||||||
|
|
||||||
|
val p00 = Vector2(x.toDouble(), y.toDouble()) * cellSize + area.corner
|
||||||
|
val p10 = Vector2((x + 1).toDouble(), y.toDouble()) * cellSize + area.corner
|
||||||
|
val p01 = Vector2(x.toDouble(), (y + 1).toDouble()) * cellSize + area.corner
|
||||||
|
val p11 = Vector2((x + 1).toDouble(), (y + 1).toDouble()) * cellSize + area.corner
|
||||||
|
|
||||||
|
val index = (if (v00 >= 0.0) 1 else 0) +
|
||||||
|
(if (v10 >= 0.0) 2 else 0) +
|
||||||
|
(if (v01 >= 0.0) 4 else 0) +
|
||||||
|
(if (v11 >= 0.0) 8 else 0)
|
||||||
|
|
||||||
|
fun blend(v1: Double, v2: Double): Double {
|
||||||
|
if (useInterpolation) {
|
||||||
|
require(v1 == v1 && v2 == v2)
|
||||||
|
val f1 = min(v1, v2)
|
||||||
|
val f2 = max(v1, v2)
|
||||||
|
val v = (-f1) / (f2 - f1)
|
||||||
|
|
||||||
|
require(v == v)
|
||||||
|
require(v in 0.0..1.0)
|
||||||
|
|
||||||
|
return if (f1 == v1) {
|
||||||
|
v
|
||||||
|
} else {
|
||||||
|
1.0 - v
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun emitLine(
|
||||||
|
p00: Vector2, p01: Vector2, v00: Double, v01: Double,
|
||||||
|
p10: Vector2, p11: Vector2, v10: Double, v11: Double
|
||||||
|
) {
|
||||||
|
val r0 = blend(v00, v01)
|
||||||
|
val r1 = blend(v10, v11)
|
||||||
|
val l0 = LineSegment(p00.mix(p01, r0), p10.mix(p11, r1))
|
||||||
|
segments.add(l0)
|
||||||
|
}
|
||||||
|
|
||||||
|
when (index) {
|
||||||
|
0, 15 -> {}
|
||||||
|
1, 15 xor 1 -> {
|
||||||
|
emitLine(p00, p01, v00, v01, p00, p10, v00, v10)
|
||||||
|
}
|
||||||
|
|
||||||
|
2, 15 xor 2 -> {
|
||||||
|
emitLine(p00, p10, v00, v10, p10, p11, v10, v11)
|
||||||
|
}
|
||||||
|
|
||||||
|
3, 15 xor 3 -> {
|
||||||
|
emitLine(p00, p01, v00, v01, p10, p11, v10, v11)
|
||||||
|
}
|
||||||
|
|
||||||
|
4, 15 xor 4 -> {
|
||||||
|
emitLine(p00, p01, v00, v01, p01, p11, v01, v11)
|
||||||
|
}
|
||||||
|
|
||||||
|
5, 15 xor 5 -> {
|
||||||
|
emitLine(p00, p10, v00, v10, p01, p11, v01, v11)
|
||||||
|
}
|
||||||
|
|
||||||
|
6, 15 xor 6 -> {
|
||||||
|
emitLine(p00, p01, v00, v01, p00, p10, v00, v10)
|
||||||
|
emitLine(p01, p11, v01, v11, p10, p11, v10, v11)
|
||||||
|
}
|
||||||
|
|
||||||
|
7, 15 xor 7 -> {
|
||||||
|
emitLine(p01, p11, v01, v11, p10, p11, v10, v11)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return segments
|
||||||
|
}
|
||||||
22
orx-marching-squares/src/jvmDemo/kotlin/FindContours01.kt
Normal file
22
orx-marching-squares/src/jvmDemo/kotlin/FindContours01.kt
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import org.openrndr.application
|
||||||
|
import org.openrndr.color.ColorRGBa
|
||||||
|
import org.openrndr.extra.marchingsquares.findContours
|
||||||
|
import org.openrndr.math.Vector2
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
application {
|
||||||
|
configure {
|
||||||
|
width = 720
|
||||||
|
height = 720
|
||||||
|
}
|
||||||
|
program {
|
||||||
|
extend {
|
||||||
|
drawer.clear(ColorRGBa.BLACK)
|
||||||
|
drawer.stroke = ColorRGBa.PINK
|
||||||
|
fun f(v: Vector2) = v.distanceTo(drawer.bounds.center) - 200.0
|
||||||
|
val segments = findContours(::f, drawer.bounds, 16.0)
|
||||||
|
drawer.lineSegments(segments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
orx-marching-squares/src/jvmDemo/kotlin/FindContours02.kt
Normal file
24
orx-marching-squares/src/jvmDemo/kotlin/FindContours02.kt
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import org.openrndr.application
|
||||||
|
import org.openrndr.color.ColorRGBa
|
||||||
|
import org.openrndr.extra.marchingsquares.findContours
|
||||||
|
import org.openrndr.math.Vector2
|
||||||
|
import kotlin.math.PI
|
||||||
|
import kotlin.math.cos
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
application {
|
||||||
|
configure {
|
||||||
|
width = 720
|
||||||
|
height = 720
|
||||||
|
}
|
||||||
|
program {
|
||||||
|
extend {
|
||||||
|
drawer.clear(ColorRGBa.BLACK)
|
||||||
|
drawer.stroke = ColorRGBa.PINK
|
||||||
|
fun f(v: Vector2) = cos((v.distanceTo(drawer.bounds.center) / 100.0) * 2 * PI)
|
||||||
|
val segments = findContours(::f, drawer.bounds.offsetEdges(32.0), 16.0)
|
||||||
|
drawer.lineSegments(segments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
30
orx-marching-squares/src/jvmDemo/kotlin/FindContours03.kt
Normal file
30
orx-marching-squares/src/jvmDemo/kotlin/FindContours03.kt
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import org.openrndr.application
|
||||||
|
import org.openrndr.color.ColorRGBa
|
||||||
|
import org.openrndr.extra.marchingsquares.findContours
|
||||||
|
import org.openrndr.math.Vector2
|
||||||
|
import kotlin.math.PI
|
||||||
|
import kotlin.math.cos
|
||||||
|
import kotlin.math.sin
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
application {
|
||||||
|
configure {
|
||||||
|
width = 720
|
||||||
|
height = 720
|
||||||
|
}
|
||||||
|
program {
|
||||||
|
extend {
|
||||||
|
drawer.clear(ColorRGBa.BLACK)
|
||||||
|
drawer.stroke = ColorRGBa.PINK
|
||||||
|
fun f(v: Vector2): Double {
|
||||||
|
|
||||||
|
val p = v + Vector2(cos(v.y * 0.1 + seconds) * 40.0, sin(v.x * 0.1 + seconds) * 40.0)
|
||||||
|
return cos((p.distanceTo(drawer.bounds.center) / 720.0) * 6 * PI)
|
||||||
|
}
|
||||||
|
|
||||||
|
val segments = findContours(::f, drawer.bounds.offsetEdges(32.0), 4.0)
|
||||||
|
drawer.lineSegments(segments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
36
orx-marching-squares/src/jvmDemo/kotlin/FindContours04.kt
Normal file
36
orx-marching-squares/src/jvmDemo/kotlin/FindContours04.kt
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import org.openrndr.application
|
||||||
|
import org.openrndr.color.ColorRGBa
|
||||||
|
import org.openrndr.draw.grayscale
|
||||||
|
import org.openrndr.draw.loadImage
|
||||||
|
import org.openrndr.extra.marchingsquares.findContours
|
||||||
|
import org.openrndr.math.Vector2
|
||||||
|
import kotlin.math.PI
|
||||||
|
import kotlin.math.cos
|
||||||
|
import kotlin.math.sin
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
application {
|
||||||
|
configure {
|
||||||
|
width = 640
|
||||||
|
height = 480
|
||||||
|
}
|
||||||
|
program {
|
||||||
|
val image = loadImage("demo-data/images/image-001.png")
|
||||||
|
image.shadow.download()
|
||||||
|
extend {
|
||||||
|
drawer.clear(ColorRGBa.BLACK)
|
||||||
|
drawer.stroke = ColorRGBa.BLACK
|
||||||
|
fun f(v: Vector2): Double {
|
||||||
|
val iv = v.toInt()
|
||||||
|
val d = if (iv.x >= 0 && iv.y >= 0 && iv.x < image.width && iv.y < image.height) image.shadow[iv.x, iv.y].luminance else 0.0
|
||||||
|
return cos(d * PI * 8.0 + seconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
val segments = findContours(::f, drawer.bounds.offsetEdges(32.0), 4.0)
|
||||||
|
drawer.drawStyle.colorMatrix = grayscale()
|
||||||
|
drawer.image(image)
|
||||||
|
drawer.lineSegments(segments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,6 +47,7 @@ include(
|
|||||||
"orx-no-clear",
|
"orx-no-clear",
|
||||||
"orx-noise",
|
"orx-noise",
|
||||||
"orx-obj-loader",
|
"orx-obj-loader",
|
||||||
|
"orx-marching-squares",
|
||||||
"orx-jvm:orx-olive",
|
"orx-jvm:orx-olive",
|
||||||
"orx-jvm:orx-osc",
|
"orx-jvm:orx-osc",
|
||||||
"orx-palette",
|
"orx-palette",
|
||||||
|
|||||||
Reference in New Issue
Block a user