[orx-shapes] Add Arc, Net, Pulley, Tear and bounds tools

This commit is contained in:
Edwin Jakobs
2023-02-02 10:06:05 +01:00
parent aabdf9fc0e
commit aed6efb87a
8 changed files with 258 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
package org.openrndr.extra.shapes
import org.openrndr.math.*
import org.openrndr.shape.ShapeContour
import org.openrndr.shape.contour
/**
* A circular arc
*/
class Arc(val center: Vector2, val radius: Double, val angle0: Double, val angle1: Double) : LinearType<Arc> {
fun position(t: Double): Vector2 {
val angle = mix(angle0, angle1, t.clamp(0.0, 1.0))
return Polar(angle, radius).cartesian + center
}
val contour: ShapeContour
get() {
return contour {
moveTo(position(0.0))
circularArcTo(position(0.5), position(1.0))
}
}
override fun div(scale: Double) = Arc(center / scale, radius / scale, angle0 / scale, angle1 / scale)
override fun times(scale: Double) = Arc(center * scale, radius * scale, angle0 * scale, angle1 * scale)
override fun plus(right: Arc) =
Arc(center + right.center, radius + right.radius, angle0 + right.angle0, angle1 + right.angle1)
override fun minus(right: Arc) =
Arc(center - right.center, radius - right.radius, angle0 - right.angle0, angle1 - right.angle1)
}

View File

@@ -0,0 +1,33 @@
package org.openrndr.extra.shapes
import org.openrndr.math.LinearType
import org.openrndr.math.Polar
import org.openrndr.math.Vector2
import org.openrndr.shape.Circle
import org.openrndr.shape.LineSegment
import org.openrndr.shape.ShapeContour
class Net(val point0: Vector2, val point1: Vector2, val circle: Circle) : LinearType<Net> {
override fun div(scale: Double) = Net(point0 / scale, point1 / scale, circle / scale)
override fun times(scale: Double) = Net(point0 * scale, point1 * scale, circle * scale)
override fun plus(right: Net) = Net(point0 + right.point0, point1 + right.point1, circle + right.circle)
override fun minus(right: Net) = Net(point0 - right.point0, point1 - right.point1, circle - right.circle)
val contour: ShapeContour
get() {
val tangents0 = circle.tangents(point0)
val tangents1 = circle.tangents(point1)
var k = LineSegment(point0, tangents0.first).contour
run {
val th0 = Polar.fromVector(tangents0.first - circle.center).theta
var th1 = Polar.fromVector(tangents1.second - circle.center).theta
if (th1 < th0) th1 += 360.0
k += Arc(circle.center, circle.radius, th0, th1).contour
}
k += LineSegment(tangents1.second, point1).contour
return k
}
}

View File

@@ -0,0 +1,50 @@
package org.openrndr.extra.shapes
import org.openrndr.math.LinearType
import org.openrndr.math.Polar
import org.openrndr.shape.Circle
import org.openrndr.shape.LineSegment
import org.openrndr.shape.ShapeContour
class Pulley(val circle0: Circle, val circle1: Circle) : LinearType<Pulley> {
override fun div(scale: Double): Pulley {
return Pulley(circle0 / scale, circle1 / scale)
}
override fun times(scale: Double): Pulley {
return Pulley(circle0 * scale, circle1 * scale)
}
override fun plus(right: Pulley): Pulley {
return Pulley(circle0 + right.circle0, circle1 + right.circle1)
}
override fun minus(right: Pulley): Pulley {
return Pulley(circle0 - right.circle0, circle1 - right.circle1)
}
val contour: ShapeContour
get() {
val tangents = circle0.tangents(circle1)
if (tangents.isEmpty()) {
return ShapeContour.EMPTY
} else {
var k = LineSegment(tangents[0].first, tangents[0].second).contour
run {
var th0 = Polar.fromVector(tangents[0].second - circle1.center).theta
val th1 = Polar.fromVector(tangents[1].second - circle1.center).theta
if (th0 < th1) th0 += 360.0
k += Arc(circle1.center, circle1.radius, th0, th1).contour
}
k += LineSegment(tangents[1].first, tangents[1].second).contour.reversed
run {
val th0 = Polar.fromVector(tangents[0].first - circle0.center).theta
var th1 = Polar.fromVector(tangents[1].first - circle0.center).theta
if (th0 > th1) th1 += 360.0
k += Arc(circle0.center, circle0.radius, th0, th1).contour.reversed
}
return k.close()
}
}
}

View File

@@ -0,0 +1,32 @@
package org.openrndr.extra.shapes
import org.openrndr.math.LinearType
import org.openrndr.math.Polar
import org.openrndr.math.Vector2
import org.openrndr.shape.Circle
import org.openrndr.shape.LineSegment
import org.openrndr.shape.ShapeContour
class Tear(val point: Vector2, val circle: Circle) : LinearType<Tear> {
override fun div(scale: Double) = Tear(point / scale, circle / scale)
override fun times(scale: Double) = Tear(point * scale, circle * scale)
override fun plus(right: Tear) = Tear(point + right.point, circle + right.circle)
override fun minus(right: Tear) = Tear(point - right.point, circle - right.circle)
val contour: ShapeContour
get() {
val tangents = circle.tangents(point)
var k = LineSegment(point, tangents.first).contour
run {
val th0 = Polar.fromVector(tangents.first - circle.center).theta
var th1 = Polar.fromVector(tangents.second - circle.center).theta
if (th1 < th0) th1 += 360.0
k += Arc(circle.center, circle.radius, th0, th1).contour
}
k += LineSegment(tangents.second, point).contour
return k.close()
}
}

View File

@@ -0,0 +1,33 @@
package org.openrndr.extra.shapes.bounds
import org.openrndr.shape.*
import kotlin.jvm.JvmName
/**
* Evaluates the bounds around all [ShapeContour] instances in the [Iterable]
*/
val Iterable<ShapeContour>.bounds : Rectangle
@JvmName("shapeContourBounds")
get() = map {
it.bounds
}.bounds
/**
* Evaluates the bounds around all [Shape] instances in the [Iterable]
*/
val Iterable<Shape>.bounds : Rectangle
@JvmName("shapeBounds")
get() = map {
it.bounds
}.bounds
/**
* Evaluates the bounds around all [Segment] instances in the [Iterable]
*/
val Iterable<Segment>.bounds : Rectangle
@JvmName("segmentBounds")
get() = map {
it.bounds
}.bounds

View File

@@ -0,0 +1,22 @@
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.shapes.Arc
fun main() {
application {
configure {
width = 720
height = 720
}
program {
extend {
val a = Arc(drawer.bounds.center, 100.0, 0.0 + seconds * 36.0, -180.0 + seconds * 36.0)
drawer.clear(ColorRGBa.PINK)
drawer.contour(a.contour)
drawer.circle(a.position(0.0), 5.0)
drawer.circle(a.position(0.5), 5.0)
drawer.circle(a.position(1.0), 5.0)
}
}
}
}

View File

@@ -0,0 +1,26 @@
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.shapes.Pulley
import org.openrndr.math.Vector2
import org.openrndr.shape.Circle
fun main() {
application {
configure {
width = 720
height = 720
}
program {
extend {
drawer.clear(ColorRGBa.BLACK)
drawer.stroke = ColorRGBa.WHITE
drawer.fill = ColorRGBa.PINK
val pulley = Pulley(
Circle(drawer.bounds.center - Vector2(100.0, 100.0), 150.0),
Circle(drawer.bounds.center + Vector2(150.0, 150.0), 75.0)
)
drawer.contour(pulley.contour)
}
}
}
}

View File

@@ -0,0 +1,29 @@
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.noise.scatter
import org.openrndr.extra.shapes.Tear
import org.openrndr.math.Vector2
import org.openrndr.shape.Circle
import kotlin.random.Random
fun main() {
application {
configure {
width = 720
height = 720
}
program {
val points = drawer.bounds.scatter(40.0, distanceToEdge = 150.0, random = Random(0))
val tears = points.map {
Tear(it - Vector2(0.0, 20.0), Circle(it + Vector2(0.0, 20.0), 20.0))
}
extend {
drawer.clear(ColorRGBa.BLACK)
drawer.fill = ColorRGBa.PINK
drawer.stroke = ColorRGBa.WHITE
drawer.contours(tears.map { it.contour })
}
}
}
}