[orx-shapes, orx-mesh-generator] Move frames code from orx-mesh-generator to orx-shapes

This commit is contained in:
Edwin Jakobs
2024-03-19 17:54:03 +01:00
parent 76f96d2278
commit c48aa83ced
10 changed files with 167 additions and 23 deletions

View File

@@ -9,6 +9,7 @@ kotlin {
dependencies { dependencies {
api(libs.openrndr.application) api(libs.openrndr.application)
api(libs.openrndr.math) api(libs.openrndr.math)
implementation(project(":orx-shapes"))
} }
} }

View File

@@ -1,14 +1,12 @@
package org.openrndr.extra.meshgenerators package org.openrndr.extra.meshgenerators
import org.openrndr.extra.shapes.frames.frames
import org.openrndr.math.Matrix44 import org.openrndr.math.Matrix44
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import org.openrndr.math.transforms.normalMatrix
import org.openrndr.shape.Path3D import org.openrndr.shape.Path3D
import org.openrndr.shape.Shape import org.openrndr.shape.Shape
import org.openrndr.shape.ShapeContour import org.openrndr.shape.ShapeContour
import org.openrndr.shape.Triangle
/** /**
* Writes quads to [writer] creating a surface that connects two * Writes quads to [writer] creating a surface that connects two

View File

@@ -1,5 +1,6 @@
package org.openrndr.extra.meshgenerators package org.openrndr.extra.meshgenerators
import org.openrndr.extra.shapes.frames.frames
import org.openrndr.math.Matrix44 import org.openrndr.math.Matrix44
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
import org.openrndr.shape.Path3D import org.openrndr.shape.Path3D

View File

@@ -1,5 +1,6 @@
package org.openrndr.extra.meshgenerators package org.openrndr.extra.meshgenerators
import org.openrndr.extra.shapes.frames.frames
import org.openrndr.math.Matrix44 import org.openrndr.math.Matrix44
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
import org.openrndr.shape.Path3D import org.openrndr.shape.Path3D

View File

@@ -1,4 +1,4 @@
package org.openrndr.extra.meshgenerators package org.openrndr.extra.shapes.frames
import org.openrndr.math.Matrix44 import org.openrndr.math.Matrix44
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
@@ -9,45 +9,51 @@ import org.openrndr.math.transforms.buildTransform
* Calculate frames (pose matrices) using parallel transport * Calculate frames (pose matrices) using parallel transport
* @param up0 initial up vector, should not be collinear with `this[1] - this[0]` * @param up0 initial up vector, should not be collinear with `this[1] - this[0]`
*/ */
fun List<Vector3>.frames(up0: Vector3): List<Matrix44> { fun List<Vector3>.frames(up0: Vector3): List<Matrix44> {
return frames(this, up0 = up0)
}
fun frames(positions: List<Vector3>, directions: List<Vector3> = emptyList(), up0: Vector3): List<Matrix44> {
require(up0.squaredLength > 0.0) {
"up0 ($up0) has 0 or NaN length"
}
val result = mutableListOf<Matrix44>() val result = mutableListOf<Matrix44>()
if (this.isEmpty()) { if (positions.isEmpty()) {
return emptyList() return emptyList()
} }
if (this.size == 1) { if (positions.size == 1) {
return listOf(Matrix44.IDENTITY) return listOf(Matrix44.IDENTITY)
} }
var up = up0.normalized var up = up0.normalized
run { run {
val current = this[0] val current = positions[0]
val next = this[1] val next = positions[1]
val forward = (next - current).normalized val forward = (directions.getOrNull(0) ?: (next - current)).normalized
val right = (forward cross up).normalized val right = (forward cross up).normalized
up = ((right cross forward)).normalized up = ((right cross forward)).normalized
result.add(Matrix44.fromColumnVectors(right.xyz0, up.xyz0, forward.xyz0, current.xyz1)) result.add(Matrix44.fromColumnVectors(right.xyz0, up.xyz0, forward.xyz0, current.xyz1))
} }
require(up.length > 0.0) { "initial `up.length` is zero in .frames()" } for (i in 1 until positions.size - 1) {
val prev = positions[i - 1]
for (i in 1 until size - 1) { val current = positions[i]
val prev = this[i - 1] val next = positions[i + 1]
val current = this[i]
val next = this[i + 1]
val f1 = (next - current).normalized val f1 = (next - current).normalized
val f0 = (current - prev).normalized val f0 = (current - prev).normalized
val forward = (f0 + f1).normalized val forward = (directions.getOrNull(i) ?: (f0 + f1)).normalized
require(forward.length > 0.0) { "`forward.length` is zero in .frames()" } require(forward.length > 0.0) { "`forward.length` is zero or NaN in .frames()" }
val right = (forward cross up).normalized val right = (forward cross up).normalized
up = ((right cross forward)).normalized up = ((right cross forward)).normalized
require(up.length > 0.0) { "`up.length` is zero in .frames()" } require(up.length > 0.0) { "`up.length` is zero or NaN in .frames()" }
require(right.length > 0.0) { "`right.length` is zero in .frames()" } require(right.length > 0.0) { "`right.length` is zero or NaN in .frames()" }
//val m = Matrix44.fromColumnVectors(right.xyz0, up.xyz0, forward.xyz0, current.xyz1)
val m = buildTransform { val m = buildTransform {
translate(current) translate(current)

View File

@@ -0,0 +1,20 @@
package org.openrndr.extra.shapes.frames
import org.openrndr.extra.shapes.rectify.RectifiedPath3D
import org.openrndr.math.Matrix44
import org.openrndr.math.Vector3
import org.openrndr.shape.Path3D
fun Path3D.frames(ascendingTs: List<Double>, up0: Vector3, analyticalDirections: Boolean) : List<Matrix44> {
val positions = ascendingTs.map { this.position(it) }
val directions = if (analyticalDirections) ascendingTs.map { this.direction(it) } else emptyList()
return frames(positions, directions, up0)
}
fun RectifiedPath3D.frames(ascendingTs: List<Double>, up0: Vector3, analyticalDirections: Boolean = true) : List<Matrix44> {
val positions = ascendingTs.map { this.position(it) }
val directions = if (analyticalDirections) ascendingTs.map { this.direction(it) } else emptyList()
return frames(positions, directions, up0)
}

View File

@@ -92,6 +92,14 @@ abstract class RectifiedPath<T : EuclideanVector<T>>(
} }
} }
fun direction(t: Double): T {
return if (path.empty) {
path.infinity
} else {
path.direction(rectify(safe(t)))
}
}
abstract fun sub(t0: Double, t1: Double): Path<T> abstract fun sub(t0: Double, t1: Double): Path<T>
/** /**

View File

@@ -9,7 +9,7 @@ import org.openrndr.extra.shapes.tunni.tunniPoint
import org.openrndr.extra.shapes.tunni.withTunniLine import org.openrndr.extra.shapes.tunni.withTunniLine
import org.openrndr.launch import org.openrndr.launch
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.shape.Segment import org.openrndr.shape.Segment2D
import kotlin.math.cos import kotlin.math.cos
fun main() { fun main() {
@@ -21,7 +21,7 @@ fun main() {
program { program {
var res = drawer.bounds.offsetEdges(-200.0).contour var res = drawer.bounds.offsetEdges(-200.0).contour
var selectedSegments = emptyList<Segment>() var selectedSegments = emptyList<Segment2D>()
var selectedPoints = emptyList<Vector2>() var selectedPoints = emptyList<Vector2>()
val contourSeq = adjustContourSequence(res) { val contourSeq = adjustContourSequence(res) {

View File

@@ -0,0 +1,44 @@
package arrangement
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.color.rgb
import org.openrndr.extra.color.spaces.OKHSV
import org.openrndr.extra.color.tools.saturate
import org.openrndr.extra.noise.uniform
import org.openrndr.extra.shapes.arrangement.Arrangement
import org.openrndr.math.Vector2
import org.openrndr.shape.Circle
import kotlin.math.sqrt
import kotlin.random.Random
fun main() {
application {
program {
val circles = listOf(
Circle(drawer.bounds.center -Vector2(50.0, 0.0), 50.0),
Circle(drawer.bounds.center + Vector2(50.0, 0.0), 50.0),
Circle(drawer.bounds.center + Vector2(0.0, 50.0), 50.0),
Circle(drawer.bounds.center - Vector2(0.0, 50.0), 50.0),
Circle(drawer.bounds.center -Vector2(50.0, 0.0), sqrt(50.0*50.0+50.0*50.0)-49.9),
Circle(drawer.bounds.center +Vector2(50.0, 0.0), sqrt(50.0*50.0+50.0*50.0)-49.9),
Circle(drawer.bounds.center -Vector2(0.0, 50.0), sqrt(50.0*50.0+50.0*50.0)-49.9),
Circle(drawer.bounds.center +Vector2(0.0, 50.0), sqrt(50.0*50.0+50.0*50.0)-49.9),
).shuffled()
val arr = Arrangement(circles)
extend {
val r = Random(100)
drawer.stroke = ColorRGBa.WHITE
for (f in arr.boundedFaces) {
drawer.fill =
rgb(Double.uniform(0.0, 1.0, r), Double.uniform(0.0, 1.0, r), Double.uniform(0.0, 1.0, r)).saturate<OKHSV>(0.25)
drawer.contour(f.contour)
}
}
}
}
}

View File

@@ -0,0 +1,65 @@
package frames
import org.openrndr.application
import org.openrndr.color.ColorRGBa
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.meshgenerators.cylinderMesh
import org.openrndr.extra.noise.uniformRing
import org.openrndr.extra.shapes.frames.frames
import org.openrndr.extra.shapes.rectify.rectified
import org.openrndr.math.Vector3
import org.openrndr.shape.path3D
import kotlin.random.Random
fun main() {
application {
configure {
width = 720
height = 720
}
program {
val random = Random(0)
val cylinder = cylinderMesh(radius = 0.5, length = 0.1)
val p = path3D {
moveTo(0.0, 0.0, 0.0)
curveTo(
Vector3.uniformRing(0.1, 1.0, random = random)*10.0,
Vector3.uniformRing(0.1, 1.0, random = random)*10.0,
Vector3.uniformRing(0.1, 1.0, random = random)*10.0
)
for (i in 0 until 10) {
continueTo(
Vector3.uniformRing(0.1, 1.0, random = random)*10.0,
Vector3.uniformRing(0.1, 1.0, random = random)*10.0
)
}
}
val pr = p.rectified(0.01, 100.0)
val frames = pr.frames((0 until 100).map { it / 100.0}, Vector3.UNIT_Y)
extend(Orbital())
extend {
drawer.shadeStyle = shadeStyle {
fragmentTransform = """
x_fill.rgb = vec3(abs(v_viewNormal.z)*0.9+ 0.1);
""".trimIndent()
}
drawer.stroke = ColorRGBa.PINK
drawer.path(p)
for (frame in frames) {
drawer.isolated {
drawer.model = frame
drawer.vertexBuffer(cylinder, DrawPrimitive.TRIANGLES)
}
}
}
}
}
}