import io.data2viz.color.* import io.data2viz.geom.* import io.data2viz.math.* import io.data2viz.viz.* import kotlin.math.* // compute a boundingBox from a rotating rectangle private fun Rect.rotate(rotation:Angle): Rect { val rxcos = x * rotation.cos val rxsin = x * rotation.sin val rwcos = width * rotation.cos val rwsin = width * rotation.sin val rysin = y * rotation.sin val rycos = y * rotation.cos val rhcos = height * rotation.cos val rhsin = height * 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) 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))) return RectGeom(minX, minY, maxX - minX, maxY - minY) } private fun GroupNode.recursiveRectangle(previous: Rect, rotation: Angle) = drawRectAndBoundingBox(previous.rotate(rotation), rotation) private fun GroupNode.drawRectAndBoundingBox(rect: Rect, rotation: Angle): Rect { group { transform { rotate(rotation.rad) } rect { x = rect.x y = rect.y width = rect.width height = rect.height fill = Colors.hsl(rotation, 100.pct, 50.pct).withAlpha(2.pct) strokeColor = Colors.hsl(rotation*2, 100.pct, 20.pct).withAlpha(80.pct) } } val boundingBox = rect.rotate(rotation) rect { x = boundingBox.x y = boundingBox.y width = boundingBox.width height = boundingBox.height fill = Colors.hsl(rotation, 80.pct, 50.pct).withAlpha(2.pct) strokeColor = Colors.hsl(rotation*.2, 100.pct, 20.pct).withAlpha(80.pct) } return boundingBox } 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 base rectangle val rect = RectGeom(-1.0, -1.0, 2.0, 2.0) // The current rotation angle var rotation = 0.rad viz { size = appSize val boundsLayer = layer() animation { // Increment the rotation rotation += 0.01.rad // Draw the bounding box and the rotated corners of the rectangle boundsLayer.apply { clear() group { transform { translate(offset.x, offset.y) rotate(rotation.rad) } var r = rect as Rect (0 .. 30).forEach { index -> r = recursiveRectangle(r, rotation * (1 + (index / 100.0))) } } } } }.bindRendererOnNewCanvas() }