[orx-turtle] Add orx-turtle module
This commit is contained in:
51
orx-turtle/src/commonMain/kotlin/NinjaTurtle.kt
Normal file
51
orx-turtle/src/commonMain/kotlin/NinjaTurtle.kt
Normal file
@@ -0,0 +1,51 @@
|
||||
package org.openrndr.extra.turtle
|
||||
|
||||
import org.openrndr.math.Matrix44
|
||||
import org.openrndr.math.Vector4
|
||||
import org.openrndr.math.transforms.buildTransform
|
||||
import org.openrndr.shape.Segment
|
||||
import org.openrndr.shape.ShapeContour
|
||||
|
||||
fun Turtle.contour(contour: ShapeContour, alignTangent: Boolean = true) {
|
||||
if (!contour.empty) {
|
||||
val align = segment(contour.segments.first(), alignTangent)
|
||||
for (segment in contour.segments.drop(1)) {
|
||||
segment(segment, alignTangent = false, externalAlignTransform = align)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Turtle.segment(
|
||||
segment: Segment,
|
||||
alignTangent: Boolean = true,
|
||||
externalAlignTransform: Matrix44 = Matrix44.IDENTITY
|
||||
): Matrix44 {
|
||||
var segment0 = segment.transform(buildTransform {
|
||||
translate(-segment.start)
|
||||
})
|
||||
|
||||
var alignTransform = externalAlignTransform
|
||||
|
||||
if (alignTangent) {
|
||||
val n = -segment0.normal(0.0)
|
||||
val t = n.perpendicular()
|
||||
val m = Matrix44.fromColumnVectors(t.xy00, n.xy00, Vector4.UNIT_Z, Vector4.UNIT_W)
|
||||
alignTransform = orientation * m.inversed
|
||||
}
|
||||
|
||||
segment0 = segment0.transform(buildTransform {
|
||||
translate(position)
|
||||
multiply(alignTransform)
|
||||
})
|
||||
|
||||
require(position.distanceTo(segment0.start) < 1E-5) {
|
||||
"""${position}, ${segment0.start}"""
|
||||
}
|
||||
cb.segment(segment0)
|
||||
orientation = cb.segments.last().pose(1.0).matrix33.matrix44
|
||||
|
||||
if (!isPenDown) {
|
||||
cb.segments.removeLastOrNull()
|
||||
}
|
||||
return alignTransform
|
||||
}
|
||||
96
orx-turtle/src/commonMain/kotlin/Turtle.kt
Normal file
96
orx-turtle/src/commonMain/kotlin/Turtle.kt
Normal file
@@ -0,0 +1,96 @@
|
||||
package org.openrndr.extra.turtle
|
||||
|
||||
import org.openrndr.math.*
|
||||
import org.openrndr.math.transforms.rotateZ
|
||||
import org.openrndr.shape.*
|
||||
|
||||
class Turtle(initialPosition: Vector2) {
|
||||
val cb = ContourBuilder(multipleContours = true).apply {
|
||||
moveTo(initialPosition)
|
||||
}
|
||||
|
||||
var orientation = Matrix44.fromColumnVectors(Vector4.UNIT_X, -Vector4.UNIT_Y, Vector4.UNIT_Z, Vector4.UNIT_W)
|
||||
private val orientationStack = ArrayDeque<Matrix44>()
|
||||
fun pushOrientation() {
|
||||
orientationStack.addLast(orientation)
|
||||
}
|
||||
|
||||
fun popOrientation() {
|
||||
orientation = orientationStack.removeLastOrNull() ?: error("orientation stack underflow")
|
||||
}
|
||||
|
||||
var position: Vector2
|
||||
get() {
|
||||
return cb.cursor
|
||||
}
|
||||
set(value) {
|
||||
cb.moveTo(value)
|
||||
}
|
||||
|
||||
private val positionStack = ArrayDeque<Vector2>()
|
||||
fun pushPosition() {
|
||||
positionStack.addLast(position)
|
||||
}
|
||||
|
||||
fun popPosition() {
|
||||
position = positionStack.removeLastOrNull() ?: error("position stack underflow")
|
||||
}
|
||||
|
||||
fun close() {
|
||||
cb.close()
|
||||
}
|
||||
|
||||
fun resetOrientation() {
|
||||
orientation = Matrix44.fromColumnVectors(Vector4.UNIT_X, -Vector4.UNIT_Y, Vector4.UNIT_Z, Vector4.UNIT_W)
|
||||
}
|
||||
|
||||
var direction: Vector2
|
||||
get() = (orientation * Vector4.UNIT_X).xy
|
||||
set(value) {
|
||||
val directionNormalized = value.normalized
|
||||
orientation = Matrix44.fromColumnVectors(
|
||||
directionNormalized.xy00,
|
||||
directionNormalized.perpendicular().xy00,
|
||||
Vector4.UNIT_Z,
|
||||
Vector4.UNIT_W
|
||||
)
|
||||
}
|
||||
|
||||
var isPenDown = true
|
||||
|
||||
fun penUp() {
|
||||
isPenDown = false
|
||||
}
|
||||
|
||||
fun penDown() {
|
||||
isPenDown = true
|
||||
}
|
||||
|
||||
fun push() {
|
||||
pushOrientation()
|
||||
pushPosition()
|
||||
}
|
||||
|
||||
fun pop() {
|
||||
popPosition()
|
||||
popOrientation()
|
||||
}
|
||||
|
||||
fun rotate(degrees: Double) {
|
||||
orientation *= Matrix44.rotateZ(degrees)
|
||||
}
|
||||
|
||||
fun forward(distance: Double) {
|
||||
if (distance >= 1E-6) {
|
||||
if (isPenDown) {
|
||||
cb.lineTo(position + direction * distance)
|
||||
} else {
|
||||
cb.moveTo(position + direction * distance)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun turtle(initalPosition: Vector2, program: Turtle.() -> Unit): List<ShapeContour> {
|
||||
return Turtle(initalPosition).apply(program).cb.result
|
||||
}
|
||||
Reference in New Issue
Block a user