[orx-shapes] Add edge/contour replacement
This commit is contained in:
@@ -1,9 +1,27 @@
|
|||||||
package org.openrndr.extra.shapes.adjust
|
package org.openrndr.extra.shapes.adjust
|
||||||
|
|
||||||
import org.openrndr.math.Vector2
|
import org.openrndr.math.Vector2
|
||||||
|
import org.openrndr.shape.ShapeContour
|
||||||
|
|
||||||
data class ContourAdjusterEdge(val contourAdjuster: ContourAdjuster, val segmentIndex: () -> Int) {
|
data class ContourAdjusterEdge(val contourAdjuster: ContourAdjuster, val segmentIndex: () -> Int) {
|
||||||
|
|
||||||
|
val startPosition
|
||||||
|
get() = contourAdjuster.contour.segments[segmentIndex()].start
|
||||||
|
|
||||||
|
val endPosition
|
||||||
|
get() = contourAdjuster.contour.segments[segmentIndex()].end
|
||||||
|
|
||||||
|
fun position(t: Double) : Vector2 {
|
||||||
|
return contourAdjuster.contour.segments[segmentIndex()].position(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun normal(t: Double) : Vector2 {
|
||||||
|
return contourAdjuster.contour.segments[segmentIndex()].normal(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A [ContourAdjusterVertex] interface for the start-vertex of the edge
|
* A [ContourAdjusterVertex] interface for the start-vertex of the edge
|
||||||
*/
|
*/
|
||||||
@@ -62,9 +80,10 @@ data class ContourAdjusterEdge(val contourAdjuster: ContourAdjuster, val segment
|
|||||||
fun scale(scaleFactor: Double, anchorT: Double = 0.5, updateTangents: Boolean = true) =
|
fun scale(scaleFactor: Double, anchorT: Double = 0.5, updateTangents: Boolean = true) =
|
||||||
wrap { scaledBy(scaleFactor, anchorT, updateTangents = true) }
|
wrap { scaledBy(scaleFactor, anchorT, updateTangents = true) }
|
||||||
|
|
||||||
fun replaceWith(t:Double, updateTangents: Boolean = true) {
|
fun replaceWith(t:Double, updateTangents: Boolean = true) = wrap { replacedWith(t, updateTangents) }
|
||||||
wrap { replacedWith(t, updateTangents) }
|
|
||||||
}
|
fun replaceWith(openContour: ShapeContour) = wrap { replacedWith(openContour) }
|
||||||
|
|
||||||
|
|
||||||
fun sub(t0:Double, t1: Double, updateTangents: Boolean = true) {
|
fun sub(t0:Double, t1: Double, updateTangents: Boolean = true) {
|
||||||
contourAdjuster.contour =
|
contourAdjuster.contour =
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import org.openrndr.extra.shapes.utilities.insertPointAt
|
|||||||
import org.openrndr.math.Matrix44
|
import org.openrndr.math.Matrix44
|
||||||
import org.openrndr.math.Vector2
|
import org.openrndr.math.Vector2
|
||||||
import org.openrndr.math.transforms.buildTransform
|
import org.openrndr.math.transforms.buildTransform
|
||||||
|
import org.openrndr.shape.Segment
|
||||||
import org.openrndr.shape.SegmentType
|
import org.openrndr.shape.SegmentType
|
||||||
import org.openrndr.shape.ShapeContour
|
import org.openrndr.shape.ShapeContour
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
@@ -50,17 +51,17 @@ data class ContourEdge(
|
|||||||
* convert the edge to a linear edge, truncating control points if those exist
|
* convert the edge to a linear edge, truncating control points if those exist
|
||||||
*/
|
*/
|
||||||
fun toLinear(): ContourEdge {
|
fun toLinear(): ContourEdge {
|
||||||
if (contour.segments[segmentIndex].type != SegmentType.LINEAR) {
|
return if (contour.segments[segmentIndex].type != SegmentType.LINEAR) {
|
||||||
val newSegment = contour.segments[segmentIndex].copy(control = emptyArray())
|
val newSegment = contour.segments[segmentIndex].copy(control = emptyArray())
|
||||||
val newSegments = contour.segments
|
val newSegments = contour.segments
|
||||||
.update(segmentIndex to newSegment)
|
.update(segmentIndex to newSegment)
|
||||||
|
|
||||||
return ContourEdge(
|
ContourEdge(
|
||||||
ShapeContour.fromSegments(newSegments, contour.closed),
|
ShapeContour.fromSegments(newSegments, contour.closed),
|
||||||
segmentIndex
|
segmentIndex
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return this
|
this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,17 +69,17 @@ data class ContourEdge(
|
|||||||
* convert the edge to a cubic edge
|
* convert the edge to a cubic edge
|
||||||
*/
|
*/
|
||||||
fun toCubic(): ContourEdge {
|
fun toCubic(): ContourEdge {
|
||||||
if (contour.segments[segmentIndex].type != SegmentType.CUBIC) {
|
return if (contour.segments[segmentIndex].type != SegmentType.CUBIC) {
|
||||||
val newSegment = contour.segments[segmentIndex].cubic
|
val newSegment = contour.segments[segmentIndex].cubic
|
||||||
val newSegments = contour.segments
|
val newSegments = contour.segments
|
||||||
.update(segmentIndex to newSegment)
|
.update(segmentIndex to newSegment)
|
||||||
|
|
||||||
return ContourEdge(
|
ContourEdge(
|
||||||
ShapeContour.fromSegments(newSegments, contour.closed),
|
ShapeContour.fromSegments(newSegments, contour.closed),
|
||||||
segmentIndex
|
segmentIndex
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return this
|
this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,6 +111,34 @@ data class ContourEdge(
|
|||||||
return ContourEdge(ShapeContour.fromSegments(newSegments, contour.closed), segmentIndex, adjustments)
|
return ContourEdge(ShapeContour.fromSegments(newSegments, contour.closed), segmentIndex, adjustments)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun replacedWith(openContour: ShapeContour) : ContourEdge {
|
||||||
|
if (contour.empty) {
|
||||||
|
return withoutAdjustments()
|
||||||
|
}
|
||||||
|
require(!openContour.closed) { "openContour should be open"}
|
||||||
|
val segment = contour.segments[segmentIndex]
|
||||||
|
var newSegments = contour.segments.toMutableList()
|
||||||
|
|
||||||
|
var insertIndex = segmentIndex
|
||||||
|
val adjustments = newSegments.adjust {
|
||||||
|
removeAt(segmentIndex)
|
||||||
|
|
||||||
|
if (segment.start.distanceTo(openContour.position(0.0)) > 1E-3) {
|
||||||
|
add(insertIndex, Segment(segment.start, openContour.position(0.0)))
|
||||||
|
insertIndex++
|
||||||
|
}
|
||||||
|
for (s in openContour.segments) {
|
||||||
|
add(insertIndex, s)
|
||||||
|
insertIndex++
|
||||||
|
}
|
||||||
|
if (segment.end.distanceTo(openContour.position(1.0)) > 1E-3) {
|
||||||
|
add(insertIndex, Segment(segment.end, openContour.position(1.0)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ContourEdge(ShapeContour.fromSegments(newSegments, contour.closed), segmentIndex, adjustments)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* subs the edge from [t0] to [t1], preserves topology unless t0 = t1
|
* subs the edge from [t0] to [t1], preserves topology unless t0 = t1
|
||||||
* @param t0 the start edge t-value, between 0 and 1
|
* @param t0 the start edge t-value, between 0 and 1
|
||||||
@@ -226,5 +255,7 @@ data class ContourEdge(
|
|||||||
translate(-anchor)
|
translate(-anchor)
|
||||||
}, updateTangents)
|
}, updateTangents)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ class SegmentAdjuster(val list: MutableList<Segment>) {
|
|||||||
list.add(segment)
|
list.add(segment)
|
||||||
adjustments.add(SegmentOperation.Insert(list.lastIndex, 1))
|
adjustments.add(SegmentOperation.Insert(list.lastIndex, 1))
|
||||||
}
|
}
|
||||||
|
fun add(index: Int, segment: Segment) {
|
||||||
|
list.add(index, segment)
|
||||||
|
adjustments.add(SegmentOperation.Insert(index, 1))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MutableList<Segment>.adjust(block: SegmentAdjuster.() -> Unit) : List<SegmentOperation> {
|
fun MutableList<Segment>.adjust(block: SegmentAdjuster.() -> Unit) : List<SegmentOperation> {
|
||||||
|
|||||||
58
orx-shapes/src/jvmDemo/kotlin/DemoAdjustContour07.kt
Normal file
58
orx-shapes/src/jvmDemo/kotlin/DemoAdjustContour07.kt
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import org.openrndr.application
|
||||||
|
import org.openrndr.color.ColorRGBa
|
||||||
|
import org.openrndr.extra.shapes.adjust.adjustContour
|
||||||
|
import org.openrndr.math.Vector2
|
||||||
|
import org.openrndr.shape.Circle
|
||||||
|
import org.openrndr.shape.contour
|
||||||
|
import kotlin.math.cos
|
||||||
|
import kotlin.math.sin
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
application {
|
||||||
|
configure {
|
||||||
|
width = 800
|
||||||
|
height = 800
|
||||||
|
}
|
||||||
|
program {
|
||||||
|
extend {
|
||||||
|
var contour =
|
||||||
|
Circle(drawer.bounds.center, 300.0).contour
|
||||||
|
|
||||||
|
contour = adjustContour(contour) {
|
||||||
|
selectEdges(0, 2)
|
||||||
|
|
||||||
|
for (e in edges) {
|
||||||
|
e.replaceWith(contour {
|
||||||
|
moveTo(e.startPosition)
|
||||||
|
lineTo(e.position(0.5) + e.normal(0.5) * cos(seconds) * 150.0)
|
||||||
|
lineTo(e.endPosition)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
selectEdges(0, 1)
|
||||||
|
|
||||||
|
for (e in edges) {
|
||||||
|
e.replaceWith(contour {
|
||||||
|
moveTo(e.startPosition)
|
||||||
|
val t = 0.5
|
||||||
|
lineTo(e.position(t) + e.normal(t) * cos(seconds) * 50.0)
|
||||||
|
lineTo(e.endPosition)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
selectEdges(0, 1)
|
||||||
|
for (e in edges) {
|
||||||
|
e.replaceWith(contour {
|
||||||
|
moveTo(e.startPosition)
|
||||||
|
val t = 0.5
|
||||||
|
lineTo(e.position(t) + e.normal(t) * sin(seconds) * 50.0)
|
||||||
|
lineTo(e.endPosition)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drawer.stroke = ColorRGBa.RED
|
||||||
|
drawer.contour(contour)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user