Skip to content

Commit b0026ad

Browse files
committed
[orx-shapes] Add radii to RoundedRectangle
1 parent 658edcb commit b0026ad

3 files changed

Lines changed: 82 additions & 33 deletions

File tree

orx-shapes/src/commonMain/kotlin/primitives/RoundedRectangle.kt

Lines changed: 55 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,37 @@ package org.openrndr.extra.shapes.primitives
33
import org.openrndr.draw.Drawer
44
import org.openrndr.math.Vector2
55
import org.openrndr.shape.Rectangle
6-
import org.openrndr.shape.contour
76
import org.openrndr.shape.ShapeContour
7+
import org.openrndr.shape.contour
88
import kotlin.jvm.JvmRecord
99
import kotlin.math.min
1010

11+
/**
12+
* Rounded rectangle. When `radii` are given (instead of `radius`), they are specified clockwise
13+
* starting at the top-left. Fewer than 4 values are accepted and repeated cyclically.
14+
* (e.g., providing 2 values alternates them, providing 1 value applies it to all corners).
15+
*/
1116
@JvmRecord
12-
data class RoundedRectangle(val corner: Vector2, val width: Double, val height: Double, val radius: Double) {
13-
constructor(x: Double, y: Double, width: Double, height: Double, radius: Double) : this(
14-
Vector2(x, y),
15-
width,
16-
height,
17-
radius
18-
)
19-
20-
constructor(rectangle: Rectangle, radius: Double) : this(
21-
rectangle.corner,
22-
rectangle.width,
23-
rectangle.height,
24-
radius
25-
)
17+
data class RoundedRectangle(val corner: Vector2, val width: Double, val height: Double, val radii: List<Double>) {
18+
19+
init {
20+
require(radii.isNotEmpty()) { "RoundedRectangle can't be constructed with zero radii" }
21+
}
22+
23+
constructor(x: Double, y: Double, width: Double, height: Double, radii: List<Double>) :
24+
this(Vector2(x, y), width, height, radii)
25+
26+
constructor(rectangle: Rectangle, radii: List<Double>) :
27+
this(rectangle.corner, rectangle.width, rectangle.height, radii)
28+
29+
constructor(corner: Vector2, width: Double, height: Double, radius: Double) :
30+
this(corner, width, height, listOf(radius))
31+
32+
constructor(x: Double, y: Double, width: Double, height: Double, radius: Double) :
33+
this(Vector2(x, y), width, height, listOf(radius))
34+
35+
constructor(rectangle: Rectangle, radius: Double) :
36+
this(rectangle.corner, rectangle.width, rectangle.height, listOf(radius))
2637

2738
/** the center of the rounded rectangle */
2839
val center: Vector2
@@ -35,35 +46,46 @@ data class RoundedRectangle(val corner: Vector2, val width: Double, val height:
3546
val contour
3647
get() = contour {
3748
// A higher radius than half the width/height makes it go weird
38-
val r = min(min(radius, width / 2), height / 2)
49+
val r = List(4) {
50+
min(min(radii[it % radii.size], width / 2), height / 2)
51+
}
3952

40-
moveTo(x + r, y)
41-
lineTo(x + width - r, y)
53+
moveTo(x + r[0], y)
54+
lineTo(x + width - r[1], y)
4255

43-
arcTo(r, r, 90.0, false, true, Vector2(x + width, y + r))
44-
lineTo(x + width, y + height - r)
56+
arcTo(r[1], r[1], 90.0, false, true, Vector2(x + width, y + r[1]))
57+
lineTo(x + width, y + height - r[2])
4558

46-
arcTo(r, r, 90.0, false, true, Vector2(x + width - r, y + height))
47-
lineTo(x + r, y + height)
59+
arcTo(r[2], r[2], 90.0, false, true, Vector2(x + width - r[2], y + height))
60+
lineTo(x + r[3], y + height)
4861

49-
arcTo(r, r, 90.0, false, true, Vector2(x, y + height - r))
50-
lineTo(x, y + r)
62+
arcTo(r[3], r[3], 90.0, false, true, Vector2(x, y + height - r[3]))
63+
lineTo(x, y + r[0])
5164

52-
arcTo(r, r, 90.0, false, true, Vector2(x + r, y))
53-
close()
54-
}
65+
arcTo(r[0], r[0], 90.0, false, true, Vector2(x + r[0], y))
66+
close() }
5567

5668
val shape
5769
get() = contour.shape
5870
}
5971

72+
fun Drawer.roundedRectangle(roundedRectangle: RoundedRectangle) =
73+
contour(roundedRectangle.contour)
74+
75+
// radii
76+
fun Drawer.roundedRectangle(x: Double, y: Double, width: Double, height: Double, radii: List<Double>) =
77+
contour(RoundedRectangle(x, y, width, height, radii).contour)
78+
79+
fun Drawer.roundedRectangle(position: Vector2, width: Double, height: Double, radii: List<Double>) =
80+
contour(RoundedRectangle(position, width, height, radii).contour)
81+
82+
fun Rectangle.toRounded(radii: List<Double>) = RoundedRectangle(this, radii)
83+
84+
// radius
6085
fun Drawer.roundedRectangle(x: Double, y: Double, width: Double, height: Double, radius: Double) =
61-
contour(RoundedRectangle(x, y, width, height, radius).contour)
86+
contour(RoundedRectangle(x, y, width, height, listOf(radius)).contour)
6287

6388
fun Drawer.roundedRectangle(position: Vector2, width: Double, height: Double, radius: Double) =
64-
contour(RoundedRectangle(position, width, height, radius).contour)
65-
66-
fun Drawer.roundedRectangle(roundedRectangle: RoundedRectangle) =
67-
contour(roundedRectangle.contour)
89+
contour(RoundedRectangle(position, width, height, listOf(radius)).contour)
6890

69-
fun Rectangle.toRounded(radius: Double) = RoundedRectangle(this, radius)
91+
fun Rectangle.toRounded(radius: Double) = RoundedRectangle(this, listOf(radius))

orx-shapes/src/jvmDemo/kotlin/primitives/DemoRoundedRectangle.kt renamed to orx-shapes/src/jvmDemo/kotlin/primitives/DemoRoundedRectangle01.kt

File renamed without changes.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package primitives
2+
3+
import org.openrndr.application
4+
import org.openrndr.color.ColorRGBa
5+
import org.openrndr.extra.shapes.primitives.RoundedRectangle
6+
import kotlin.math.cos
7+
8+
/**
9+
* Demonstrates the use of `RoundedRectangle()` to create a rectangle in which the corners
10+
* are rounded by four changing `radii`
11+
*
12+
* The radii are animated between 0.0 and 100.0 using the cosine of the current time in seconds
13+
* and the corner index, demonstrating that corners can have differing radii.
14+
*/
15+
fun main() = application {
16+
program {
17+
extend {
18+
drawer.fill = ColorRGBa.WHITE
19+
drawer.stroke = ColorRGBa.PINK
20+
val radii = List(4) {
21+
cos(seconds + it) * 100.0 + 100.0
22+
}
23+
val rectangle = RoundedRectangle(50.0, 50.0, width - 100.0, height - 100.0, radii)
24+
drawer.contour(rectangle.contour)
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)