[orx-shapes, orx-mesh-generator] Move frames code from orx-mesh-generator to orx-shapes
This commit is contained in:
66
orx-shapes/src/commonMain/kotlin/frames/Frames.kt
Normal file
66
orx-shapes/src/commonMain/kotlin/frames/Frames.kt
Normal file
@@ -0,0 +1,66 @@
|
||||
package org.openrndr.extra.shapes.frames
|
||||
|
||||
import org.openrndr.math.Matrix44
|
||||
import org.openrndr.math.Vector3
|
||||
import org.openrndr.math.Vector4
|
||||
import org.openrndr.math.transforms.buildTransform
|
||||
|
||||
/**
|
||||
* Calculate frames (pose matrices) using parallel transport
|
||||
* @param up0 initial up vector, should not be collinear with `this[1] - this[0]`
|
||||
*/
|
||||
|
||||
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>()
|
||||
|
||||
if (positions.isEmpty()) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
if (positions.size == 1) {
|
||||
return listOf(Matrix44.IDENTITY)
|
||||
}
|
||||
|
||||
var up = up0.normalized
|
||||
run {
|
||||
val current = positions[0]
|
||||
val next = positions[1]
|
||||
val forward = (directions.getOrNull(0) ?: (next - current)).normalized
|
||||
val right = (forward cross up).normalized
|
||||
up = ((right cross forward)).normalized
|
||||
result.add(Matrix44.fromColumnVectors(right.xyz0, up.xyz0, forward.xyz0, current.xyz1))
|
||||
}
|
||||
|
||||
for (i in 1 until positions.size - 1) {
|
||||
val prev = positions[i - 1]
|
||||
val current = positions[i]
|
||||
val next = positions[i + 1]
|
||||
val f1 = (next - current).normalized
|
||||
val f0 = (current - prev).normalized
|
||||
|
||||
val forward = (directions.getOrNull(i) ?: (f0 + f1)).normalized
|
||||
require(forward.length > 0.0) { "`forward.length` is zero or NaN in .frames()" }
|
||||
val right = (forward cross up).normalized
|
||||
up = ((right cross forward)).normalized
|
||||
|
||||
require(up.length > 0.0) { "`up.length` is zero or NaN in .frames()" }
|
||||
require(right.length > 0.0) { "`right.length` is zero or NaN in .frames()" }
|
||||
|
||||
val m = buildTransform {
|
||||
translate(current)
|
||||
multiply(Matrix44.fromColumnVectors(right.xyz0, up.xyz0, forward.xyz0, Vector4.UNIT_W))
|
||||
}
|
||||
|
||||
result.add(m)
|
||||
}
|
||||
return result
|
||||
}
|
||||
20
orx-shapes/src/commonMain/kotlin/frames/Path3DExtensions.kt
Normal file
20
orx-shapes/src/commonMain/kotlin/frames/Path3DExtensions.kt
Normal 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)
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user