[orx-shapes] Add RectifiedContour
This commit is contained in:
81
orx-shapes/src/commonMain/kotlin/rectify/RectifiedContour.kt
Normal file
81
orx-shapes/src/commonMain/kotlin/rectify/RectifiedContour.kt
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
package org.openrndr.extra.shapes.rectify
|
||||||
|
|
||||||
|
import org.openrndr.math.Matrix44
|
||||||
|
import org.openrndr.math.Vector2
|
||||||
|
import org.openrndr.math.clamp
|
||||||
|
import org.openrndr.shape.Segment
|
||||||
|
import org.openrndr.shape.ShapeContour
|
||||||
|
import kotlin.math.floor
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RectifiedContour provides an approximately uniform parameterization for [ShapeContour]
|
||||||
|
*/
|
||||||
|
class RectifiedContour(val contour: ShapeContour, lengthScale: Double = 1.0, distanceTolerance: Double = 0.5) {
|
||||||
|
val points = contour.equidistantPositionsWithT((contour.length * lengthScale).toInt(), distanceTolerance)
|
||||||
|
|
||||||
|
private fun safe(t: Double): Double {
|
||||||
|
return if (contour.closed) {
|
||||||
|
t.mod(1.0)
|
||||||
|
} else {
|
||||||
|
t.clamp(0.0, 1.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* computes a rectified t-value for [contour]
|
||||||
|
*/
|
||||||
|
fun rectify(t: Double): Double {
|
||||||
|
if (t <= 0.0) {
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
|
val fi = t * (points.size - 1.0)
|
||||||
|
val fr = fi.mod(1.0)
|
||||||
|
val i0 = fi.toInt()
|
||||||
|
val i1 = i0 + 1
|
||||||
|
|
||||||
|
return if (i0 >= points.size - 1) {
|
||||||
|
1.0
|
||||||
|
} else {
|
||||||
|
(points[i0].second * (1.0 - fr) + points[i1].second * fr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun position(t: Double): Vector2 {
|
||||||
|
return contour.position(rectify(safe(t)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun velocity(t: Double): Vector2 {
|
||||||
|
val (segment, st) = contour.segment(rectify(safe(t)))
|
||||||
|
return contour.segments[segment].direction(st)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun normal(t: Double): Vector2 {
|
||||||
|
return contour.normal(rectify(safe(t)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pose(t: Double): Matrix44 {
|
||||||
|
return contour.pose(rectify(safe(t)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sub(t0: Double, t1: Double): ShapeContour {
|
||||||
|
return if (contour.closed) {
|
||||||
|
contour.sub(rectify(t0.mod(1.0)) + floor(t0), rectify(t1.mod(1.0)) + floor(t1))
|
||||||
|
} else {
|
||||||
|
contour.sub(rectify(t0), rectify(t1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** create a rectified contour
|
||||||
|
* @param distanceTolerance distance tolerance to use, 0.5 is the default distance tolerance
|
||||||
|
**/
|
||||||
|
fun ShapeContour.rectified(distanceTolerance: Double = 0.5): RectifiedContour {
|
||||||
|
return RectifiedContour(this, distanceTolerance = distanceTolerance)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** create a rectified contour
|
||||||
|
* @param distanceTolerance distance tolerance to use, 0.5 is the default distance tolerance
|
||||||
|
* */
|
||||||
|
fun Segment.rectified(distanceTolerance: Double = 0.5): RectifiedContour {
|
||||||
|
return RectifiedContour(this.contour, distanceTolerance = distanceTolerance)
|
||||||
|
}
|
||||||
30
orx-shapes/src/jvmDemo/kotlin/DemoRectifiedContour01.kt
Normal file
30
orx-shapes/src/jvmDemo/kotlin/DemoRectifiedContour01.kt
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import org.openrndr.application
|
||||||
|
import org.openrndr.color.ColorRGBa
|
||||||
|
import org.openrndr.extra.noise.scatter
|
||||||
|
import org.openrndr.extra.shapes.hobbyCurve
|
||||||
|
import org.openrndr.extra.shapes.rectify.rectified
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
application {
|
||||||
|
configure {
|
||||||
|
width = 720
|
||||||
|
height = 720
|
||||||
|
}
|
||||||
|
program {
|
||||||
|
val points = drawer.bounds.scatter(50.0, distanceToEdge = 100.0, random = Random(0))
|
||||||
|
val curve = hobbyCurve(points)
|
||||||
|
val rectified = curve.rectified()
|
||||||
|
extend {
|
||||||
|
drawer.clear(ColorRGBa.BLACK)
|
||||||
|
drawer.stroke = ColorRGBa.PINK
|
||||||
|
drawer.contour(curve)
|
||||||
|
drawer.fill = ColorRGBa.RED
|
||||||
|
drawer.circle(curve.position(seconds*0.05), 10.0)
|
||||||
|
drawer.fill = ColorRGBa.GREEN
|
||||||
|
drawer.circle(rectified.position(seconds*0.05), 10.0)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
orx-shapes/src/jvmDemo/kotlin/DemoRectifiedContour02.kt
Normal file
33
orx-shapes/src/jvmDemo/kotlin/DemoRectifiedContour02.kt
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import org.openrndr.application
|
||||||
|
import org.openrndr.color.ColorRGBa
|
||||||
|
import org.openrndr.extra.noise.scatter
|
||||||
|
import org.openrndr.extra.shapes.hobbyCurve
|
||||||
|
import org.openrndr.extra.shapes.rectify.rectified
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
application {
|
||||||
|
configure {
|
||||||
|
width = 720
|
||||||
|
height = 720
|
||||||
|
}
|
||||||
|
program {
|
||||||
|
val points = drawer.bounds.scatter(80.0, distanceToEdge = 100.0, random = Random(0))
|
||||||
|
val curve = hobbyCurve(points, closed = true)
|
||||||
|
val rectified = curve.rectified()
|
||||||
|
extend {
|
||||||
|
drawer.clear(ColorRGBa.BLACK)
|
||||||
|
drawer.fill = null
|
||||||
|
drawer.stroke = ColorRGBa.GRAY
|
||||||
|
drawer.contour(curve)
|
||||||
|
drawer.strokeWeight = 4.0
|
||||||
|
|
||||||
|
drawer.stroke = ColorRGBa.RED
|
||||||
|
drawer.contour(curve.sub(seconds*0.1, seconds*0.1+0.01))
|
||||||
|
|
||||||
|
drawer.stroke = ColorRGBa.GREEN
|
||||||
|
drawer.contour(rectified.sub(seconds*0.1, seconds*0.1+0.01))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user