Rotating rectangle bounding box

import io.data2viz.color.* import io.data2viz.geom.* import io.data2viz.math.* import io.data2viz.viz.* import kotlin.math.* private fun GroupNode.drawText(text:String, pos:Point, color:Color) { text { textContent = text textColor = Colors.Web.white x = pos.x y = pos.y vAlign = TextVAlign.MIDDLE hAlign = TextHAlign.MIDDLE fontWeight = FontWeight.BOLD fontSize = 20.0 } text { textContent = text textColor = color x = pos.x y = pos.y vAlign = TextVAlign.MIDDLE hAlign = TextHAlign.MIDDLE fontSize = 20.0 } } fun main() { val appSize = size(600, 600) // Offset is used to translate things at the center of the screen val offset = Point(appSize.width / 2.0, appSize.height / 2.0) // The rectangle top-left corner var rectX = -60.0 var rectY = 40.0 // The rectangle size var rectWidth = 220.0 var rectHeight = 160.0 // The current rotation angle var rotation = 0.rad viz { size = appSize val centerLayer = layer() val rectLayer = layer() val boundsLayer = layer() // mark the center of rotation centerLayer.apply { circle { fill = Colors.Web.black x = offset.x y = offset.y radius = 3.0 } drawText("O", offset + Point(10.0, 10.0), Colors.Web.black) } animation { // Increment the rotation rotation += 0.02.rad // Draw the rotated rectangle (using a transformation) rectLayer.apply { clear() group { transform { translate(offset.x, offset.y) rotate(rotation.rad) } rect { stroke = Colors.Web.blue fill = Colors.Web.blue.withAlpha(20.pct) x = rectX y = rectY width = rectWidth height = rectHeight } } } // Draw the bounding box and the rotated corners of the rectangle boundsLayer.apply { clear() group { transform { translate(offset.x, offset.y) } val rxcos = rectX * rotation.cos val rxsin = rectX * rotation.sin val rwcos = rectWidth * rotation.cos val rwsin = rectWidth * rotation.sin val rysin = rectY * rotation.sin val rycos = rectY * rotation.cos val rhcos = rectHeight * rotation.cos val rhsin = rectHeight * rotation.sin // compute point ABCD of the rotated rectangle val a = Point(rxcos - rysin, rxsin + rycos) val b = Point(a.x + rwcos, a.y + rwsin) val c = Point(b.x - rhsin, b.y + rhcos) val d = Point(a.x - rhsin, a.y + rhcos) // get min/max coordinates to draw the bounding box val minX = min(a.x, min(b.x, min(c.x, d.x))) val minY = min(a.y, min(b.y, min(c.y, d.y))) val maxX = max(a.x, max(b.x, max(c.x, d.x))) val maxY = max(a.y, max(b.y, max(c.y, d.y))) rect { x = minX y = minY width = maxX - minX height = maxY - minY stroke = Colors.Web.red } drawText("A", a, Colors.Web.blue) drawText("B", b, Colors.Web.blue) drawText("C", c, Colors.Web.blue) drawText("D", d, Colors.Web.blue) drawText("E", Point(minX, minY), Colors.Web.red) drawText("F", Point(maxX, minY), Colors.Web.red) drawText("G", Point(maxX, maxY), Colors.Web.red) drawText("H", Point(minX, maxY), Colors.Web.red) } } } }.bindRendererOnNewCanvas() }
pierre avatar

Sketch created by

pierre

Animated bounding box around a rotating rectangle. O is the center of rotation. ABCD is the rotating rectangle. EFGH is the bounding box Change rectangle values (position and size) to see different bounding boxes.

comments