From fd5d6f70205b5344518121f67b81c3a9edc1a086 Mon Sep 17 00:00:00 2001 From: Edwin Jakobs Date: Fri, 27 Oct 2023 16:27:19 +0200 Subject: [PATCH] [orx-shapes] Add edge/contour replacement --- .../kotlin/adjust/ContourAdjusterEdge.kt | 25 +++++++- .../commonMain/kotlin/adjust/ContourEdge.kt | 43 ++++++++++++-- .../kotlin/adjust/SegmentAdjustments.kt | 4 ++ .../src/jvmDemo/kotlin/DemoAdjustContour07.kt | 58 +++++++++++++++++++ 4 files changed, 121 insertions(+), 9 deletions(-) create mode 100644 orx-shapes/src/jvmDemo/kotlin/DemoAdjustContour07.kt diff --git a/orx-shapes/src/commonMain/kotlin/adjust/ContourAdjusterEdge.kt b/orx-shapes/src/commonMain/kotlin/adjust/ContourAdjusterEdge.kt index c8dff546..a588653f 100644 --- a/orx-shapes/src/commonMain/kotlin/adjust/ContourAdjusterEdge.kt +++ b/orx-shapes/src/commonMain/kotlin/adjust/ContourAdjusterEdge.kt @@ -1,9 +1,27 @@ package org.openrndr.extra.shapes.adjust import org.openrndr.math.Vector2 +import org.openrndr.shape.ShapeContour 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 */ @@ -62,9 +80,10 @@ data class ContourAdjusterEdge(val contourAdjuster: ContourAdjuster, val segment fun scale(scaleFactor: Double, anchorT: Double = 0.5, updateTangents: Boolean = true) = wrap { scaledBy(scaleFactor, anchorT, updateTangents = true) } - fun replaceWith(t:Double, updateTangents: Boolean = true) { - wrap { replacedWith(t, updateTangents) } - } + fun replaceWith(t:Double, updateTangents: Boolean = true) = wrap { replacedWith(t, updateTangents) } + + fun replaceWith(openContour: ShapeContour) = wrap { replacedWith(openContour) } + fun sub(t0:Double, t1: Double, updateTangents: Boolean = true) { contourAdjuster.contour = diff --git a/orx-shapes/src/commonMain/kotlin/adjust/ContourEdge.kt b/orx-shapes/src/commonMain/kotlin/adjust/ContourEdge.kt index 750031b2..3d4ec46b 100644 --- a/orx-shapes/src/commonMain/kotlin/adjust/ContourEdge.kt +++ b/orx-shapes/src/commonMain/kotlin/adjust/ContourEdge.kt @@ -4,6 +4,7 @@ import org.openrndr.extra.shapes.utilities.insertPointAt import org.openrndr.math.Matrix44 import org.openrndr.math.Vector2 import org.openrndr.math.transforms.buildTransform +import org.openrndr.shape.Segment import org.openrndr.shape.SegmentType import org.openrndr.shape.ShapeContour import kotlin.math.abs @@ -50,17 +51,17 @@ data class ContourEdge( * convert the edge to a linear edge, truncating control points if those exist */ 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 newSegments = contour.segments .update(segmentIndex to newSegment) - return ContourEdge( + ContourEdge( ShapeContour.fromSegments(newSegments, contour.closed), segmentIndex ) } else { - return this + this } } @@ -68,17 +69,17 @@ data class ContourEdge( * convert the edge to a cubic edge */ 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 newSegments = contour.segments .update(segmentIndex to newSegment) - return ContourEdge( + ContourEdge( ShapeContour.fromSegments(newSegments, contour.closed), segmentIndex ) } else { - return this + this } } @@ -110,6 +111,34 @@ data class ContourEdge( 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 * @param t0 the start edge t-value, between 0 and 1 @@ -226,5 +255,7 @@ data class ContourEdge( translate(-anchor) }, updateTangents) } + + } diff --git a/orx-shapes/src/commonMain/kotlin/adjust/SegmentAdjustments.kt b/orx-shapes/src/commonMain/kotlin/adjust/SegmentAdjustments.kt index af3f74d4..760b152a 100644 --- a/orx-shapes/src/commonMain/kotlin/adjust/SegmentAdjustments.kt +++ b/orx-shapes/src/commonMain/kotlin/adjust/SegmentAdjustments.kt @@ -29,6 +29,10 @@ class SegmentAdjuster(val list: MutableList) { list.add(segment) 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.adjust(block: SegmentAdjuster.() -> Unit) : List { diff --git a/orx-shapes/src/jvmDemo/kotlin/DemoAdjustContour07.kt b/orx-shapes/src/jvmDemo/kotlin/DemoAdjustContour07.kt new file mode 100644 index 00000000..9a983456 --- /dev/null +++ b/orx-shapes/src/jvmDemo/kotlin/DemoAdjustContour07.kt @@ -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) + } + } + } +} \ No newline at end of file