Skip to content

Commit

Permalink
[orx-shapes] Add Tunni point/line operations
Browse files Browse the repository at this point in the history
  • Loading branch information
edwinRNDR committed Jan 16, 2024
1 parent 83b8fae commit 1e06304
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ data class ContourAdjusterEdge(val contourAdjuster: ContourAdjuster, val segment
contourAdjuster.selectEdge(segmentIndex())
}

private fun wrap(block: ContourEdge.() -> ContourEdge) {
internal fun wrap(block: ContourEdge.() -> ContourEdge) {
val newEdge = ContourEdge(contourAdjuster.contour, segmentIndex()).block()
contourAdjuster.contour = newEdge.contour
contourAdjuster.updateSelection(newEdge.adjustments)
Expand Down
71 changes: 71 additions & 0 deletions orx-shapes/src/commonMain/kotlin/tunni/Tunni.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.openrndr.extra.shapes.tunni

import org.openrndr.math.Vector2
import org.openrndr.shape.LineSegment
import org.openrndr.shape.Segment
import org.openrndr.shape.intersection

/**
* Find the Tunni point for the [Segment]
* @since orx 0.4.5
*/
val Segment.tunniPoint: Vector2
get() {
val c = this.cubic
val ac = LineSegment(c.start, c.control[0])
val bc = LineSegment(c.end, c.control[1])
val s = intersection(ac, bc, eps = Double.POSITIVE_INFINITY)
val t = c.control[0] * 2.0 - start + c.control[1] * 2.0 - end - s
return t
}

/**
* Find the Tunni line for the [Segment]
* @since orx 0.4.5
*/
val Segment.tunniLine: LineSegment
get() {
val c = this.cubic
return LineSegment(c.control[0], c.control[1])
}

/**
* Find a new segment that has [tunniPoint] as its Tunni-point
* @since orx 0.4.5
*/
fun Segment.withTunniPoint(tunniPoint: Vector2): Segment {
val ha = (start + tunniPoint) / 2.0
val hb = (end + tunniPoint) / 2.0
val hpa = ha + this.cubic.control[1] - end
val hpb = hb + this.cubic.control[0] - start

val hahpa = LineSegment(ha, hpa)
val ac0 = LineSegment(start, this.cubic.control[0])

val hbhpb = LineSegment(hb, hpb)
val bc1 = LineSegment(end, this.cubic.control[1])

val cp0 = intersection(hahpa, ac0, Double.POSITIVE_INFINITY)
val cp1 = intersection(hbhpb, bc1, Double.POSITIVE_INFINITY)

return if (cp0 != Vector2.INFINITY && cp1 != Vector2.INFINITY) {
copy(start = start, control = listOf(cp0, cp1), end = end)
} else this
}

/**
* Find a segment for which [pointOnLine] lies on its Tunni-line
* @since orx 0.4.5
*/
fun Segment.withTunniLine(pointOnLine: Vector2): Segment {
val ls = LineSegment(pointOnLine, pointOnLine + this.cubic.control[0] - this.cubic.control[1])
val ac0 = LineSegment(start, this.cubic.control[0])
val bc1 = LineSegment(end, this.cubic.control[1])

val cp0 = intersection(ls, ac0, Double.POSITIVE_INFINITY)
val cp1 = intersection(ls, bc1, Double.POSITIVE_INFINITY)

return if (cp0 != Vector2.INFINITY && cp1 != Vector2.INFINITY) {
copy(start, listOf(cp0, cp1), end)
} else this
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package tunni

import org.openrndr.extra.shapes.adjust.ContourAdjusterEdge
import org.openrndr.extra.shapes.adjust.ContourEdge
import org.openrndr.extra.shapes.tunni.tunniLine
import org.openrndr.extra.shapes.tunni.tunniPoint
import org.openrndr.extra.shapes.tunni.withTunniPoint
import org.openrndr.math.Vector2
import org.openrndr.shape.LineSegment
import org.openrndr.shape.Segment
import org.openrndr.shape.ShapeContour


/**
* The Tunni-point for this [ContourEdge]
* @see Segment.tunniPoint
*/
val ContourEdge.tunniPoint: Vector2
get() = contour.segments[segmentIndex].tunniPoint


/**
* The Tunni-line for this [ContourEdge]
* @see Segment.tunniLine
*/
val ContourEdge.tunniLine: LineSegment
get() = contour.segments[segmentIndex].tunniLine


val ContourAdjusterEdge.tunniPoint get() = contourAdjuster.contour.segments[segmentIndex()].tunniPoint

val ContourAdjusterEdge.tunniLine get() = contourAdjuster.contour.segments[segmentIndex()].tunniLine



fun ContourEdge.withTunniPoint(tunniPoint: Vector2): ContourEdge {
if (contour.empty) {
return withoutAdjustments()
} else {
val segment = contour.segments[segmentIndex].withTunniPoint(tunniPoint)
val newSegments = contour.segments.map { it }.toMutableList()
newSegments[segmentIndex] = segment
return ContourEdge(ShapeContour.fromSegments(newSegments, contour.closed), segmentIndex)
}
}
fun ContourEdge.withTunniLine(pointOnLine: Vector2): ContourEdge {
if (contour.empty) {
return withoutAdjustments()
} else {
val segment = contour.segments[segmentIndex].withTunniPoint(pointOnLine)
val newSegments = contour.segments.map { it }.toMutableList()
newSegments[segmentIndex] = segment
return ContourEdge(ShapeContour.fromSegments(newSegments, contour.closed), segmentIndex)
}
}

/**
* @see Segment.withTunniPoint
*/
fun ContourAdjusterEdge.withTunniPoint(tunniPoint: Vector2) = wrap { withTunniPoint(tunniPoint) }

/**
* @see Segment.withTunniLine
*/
fun ContourAdjusterEdge.withTunniLine(pointOnLine: Vector2) = wrap { withTunniLine(pointOnLine) }

0 comments on commit 1e06304

Please sign in to comment.