[orx-shapes] Add Tunni point/line operations
This commit is contained in:
@@ -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)
|
||||
|
||||
71
orx-shapes/src/commonMain/kotlin/tunni/Tunni.kt
Normal file
71
orx-shapes/src/commonMain/kotlin/tunni/Tunni.kt
Normal file
@@ -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
|
||||
}
|
||||
@@ -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) }
|
||||
Reference in New Issue
Block a user