From 168d1ed2d05b9b328ca35ed1727bdf5c44003063 Mon Sep 17 00:00:00 2001 From: Abe Pazos Date: Wed, 27 Aug 2025 11:26:35 +0200 Subject: [PATCH] [orx-composition] reverse argument order in draw() Add demos with comments --- .../commonMain/kotlin/CompositionDrawer.kt | 8 +-- .../jvmDemo/kotlin/DemoCompositionDrawer01.kt | 25 ++++---- .../jvmDemo/kotlin/DemoCompositionDrawer02.kt | 14 ++++- .../jvmDemo/kotlin/DemoCompositionDrawer03.kt | 21 ++++++- .../jvmDemo/kotlin/DemoCompositionDrawer04.kt | 61 +++++++++++++++++++ .../jvmDemo/kotlin/DemoCompositionDrawer05.kt | 43 +++++++++++++ 6 files changed, 151 insertions(+), 21 deletions(-) create mode 100644 orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer04.kt create mode 100644 orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer05.kt diff --git a/orx-composition/src/commonMain/kotlin/CompositionDrawer.kt b/orx-composition/src/commonMain/kotlin/CompositionDrawer.kt index a8c24d37..264e4633 100644 --- a/orx-composition/src/commonMain/kotlin/CompositionDrawer.kt +++ b/orx-composition/src/commonMain/kotlin/CompositionDrawer.kt @@ -804,15 +804,15 @@ fun drawComposition( } /** - * Draws the content of an existing composition using the provided drawing function. + * Draws content into an existing composition using the provided drawing function. * - * @param drawFunction the drawing logic to be executed using a [CompositionDrawer]. - * This function allows defining how the composition should be rendered visually. * @param cursor an optional [GroupNode] that serves as the starting point for drawing. * Defaults to the root of the composition if not provided. + * @param drawFunction the drawing logic to be executed using a [CompositionDrawer]. + * This function should contain instructions to draw content into the composition. */ @OptIn(ExperimentalContracts::class) -fun Composition.draw(drawFunction: CompositionDrawer.() -> Unit, cursor: GroupNode? = this.root as? GroupNode) { +fun Composition.draw(cursor: GroupNode? = this.root as? GroupNode, drawFunction: CompositionDrawer.() -> Unit) { contract { callsInPlace(drawFunction, InvocationKind.EXACTLY_ONCE) } diff --git a/orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer01.kt b/orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer01.kt index b1440657..154e9892 100644 --- a/orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer01.kt +++ b/orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer01.kt @@ -5,21 +5,22 @@ import org.openrndr.extra.composition.drawComposition import org.openrndr.extra.svg.toSVG import org.openrndr.math.Vector2 +/** + * Demonstrates how to + * + * - Create a Composition + * - Draw it on the program window + * - Save it to an SVG file + * - Print the SVG content as text + */ fun main() = application { program { val composition = drawComposition { - val layer = group { - fill = ColorRGBa.PINK - stroke = ColorRGBa.BLACK - strokeWeight = 10.0 - circle(Vector2(width / 2.0, height / 2.0), 100.0) - circle(Vector2(200.0, 200.0), 50.0) - } - // demonstrating how to set custom attributes on the CompositionNode - // these are stored in SVG - //layer.id = "Layer_2" - //layer.attributes["inkscape:label"] = "Layer 1" - //layer.attributes["inkscape:groupmode"] = "layer" + fill = ColorRGBa.PINK + stroke = ColorRGBa.BLACK + strokeWeight = 10.0 + circle(Vector2(width / 2.0, height / 2.0), 100.0) + circle(Vector2(200.0, 200.0), 50.0) } // print the svg to the console diff --git a/orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer02.kt b/orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer02.kt index 11acbfec..f8b32370 100644 --- a/orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer02.kt +++ b/orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer02.kt @@ -4,9 +4,18 @@ import org.openrndr.extra.composition.ClipMode import org.openrndr.extra.composition.composition import org.openrndr.extra.composition.drawComposition +/** + * Demonstrates how to draw a Composition and how to use + * `ClipMode.REVERSE_DIFFERENCE` to clip shapes. + * + * The first shape clips part of the second one away, + * producing a shape that seems to be behind the first one. + * + * Without clipping, the second circle would cover part of the first one. + */ fun main() = application { program { - val cd = drawComposition { + val composition = drawComposition { fill = null circle(width / 2.0, height / 2.0, 100.0) @@ -15,10 +24,9 @@ fun main() = application { circle(width / 2.0 + 50.0, height / 2.0, 100.0) } - extend { drawer.clear(ColorRGBa.PINK) - drawer.composition(cd) + drawer.composition(composition) } } } diff --git a/orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer03.kt b/orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer03.kt index 7889f9fe..d9266f17 100644 --- a/orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer03.kt +++ b/orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer03.kt @@ -3,10 +3,22 @@ import org.openrndr.color.ColorRGBa import org.openrndr.extra.composition.ClipMode import org.openrndr.extra.composition.composition import org.openrndr.extra.composition.drawComposition +import org.openrndr.extra.svg.saveToFile +import java.io.File +/** + * Draws a composition using 3 circles and `ClipMode.REVERSE_DIFFERENCE`. + * + * A println() demonstrates that the result contains 3 shapes: + * a complete circle, a moon-like shape, and a shape with two small black areas. + * + * One way to verify this is by saving the design as an SVG file and opening + * it in vector editing software. + * + */ fun main() = application { program { - val cd = drawComposition { + val composition = drawComposition { fill = null clipMode = ClipMode.REVERSE_DIFFERENCE @@ -17,9 +29,14 @@ fun main() = application { circle(width / 2.0, height / 2.0, 100.0) } + println(composition.findShapes().size) + + // save svg to a File + //composition.saveToFile(File("/path/to/design.svg")) + extend { drawer.clear(ColorRGBa.PINK) - drawer.composition(cd) + drawer.composition(composition) } } } diff --git a/orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer04.kt b/orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer04.kt new file mode 100644 index 00000000..01d04c1d --- /dev/null +++ b/orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer04.kt @@ -0,0 +1,61 @@ +import org.openrndr.MouseButton +import org.openrndr.application +import org.openrndr.color.ColorRGBa +import org.openrndr.extra.composition.composition +import org.openrndr.extra.composition.draw +import org.openrndr.extra.composition.drawComposition +import org.openrndr.math.Polar +import org.openrndr.math.Vector2 +import kotlin.math.sin + +/** + * Demonstrates how to add content to and how to clear an existing Composition. + * + * A number of circles are added when the program starts. + * Dragging the mouse button adds more circles. + * Right-clicking the mouse clears the Composition. + */ +fun main() = application { + program { + val composition = drawComposition { } + + // initial Composition content + repeat(360) { + composition.draw { + fill = ColorRGBa.WHITE + val r = sin(it / 90.0) * 30 + 40 + circle( + drawer.bounds.center + Polar(it * 5.0, r * 2).cartesian, + r + ) + } + } + + extend { + drawer.clear(ColorRGBa.PINK) + drawer.composition(composition) + } + + // To avoid drawing too many circles when dragging the mouse, + // we require a minimum separation between them + var lastPosition = Vector2.INFINITY + val minSeparation = 10.0 + + mouse.dragged.listen { + if(it.position.distanceTo(lastPosition) > minSeparation) { + composition.draw { + fill = ColorRGBa.WHITE + // the drag speed affects the radius + circle(it.position, 5.0 + it.dragDisplacement.length * 5.0) + } + lastPosition = it.position + } + } + + mouse.buttonDown.listen { + if (it.button == MouseButton.RIGHT) { + composition.clear() + } + } + } +} diff --git a/orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer05.kt b/orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer05.kt new file mode 100644 index 00000000..5bea2f58 --- /dev/null +++ b/orx-composition/src/jvmDemo/kotlin/DemoCompositionDrawer05.kt @@ -0,0 +1,43 @@ +import org.openrndr.application +import org.openrndr.color.ColorRGBa +import org.openrndr.extra.composition.composition +import org.openrndr.extra.composition.drawComposition +import org.openrndr.math.Vector2 +import org.openrndr.extra.svg.saveToFile +import java.io.File + +/** + * Demonstrates how to + * + * - Create a Composition with a group + * - Add XML attributes so the group appears as a layer in Inkscape + */ +fun main() = application { + program { + val composition = drawComposition { + val layer = group { + fill = ColorRGBa.PINK + stroke = ColorRGBa.BLACK + strokeWeight = 10.0 + circle(Vector2(width / 2.0, height / 2.0), 100.0) + circle(Vector2(200.0, 200.0), 50.0) + } + // Demonstrate how to set custom attributes on the `GroupNode` + // These are stored in the SVG file. + + layer.id = "Layer_2" + layer.attributes["inkscape:label"] = "Layer 1" + layer.attributes["inkscape:groupmode"] = "layer" + } + + // save svg to a File + //composition.saveToFile(File("/path/to/design.svg")) + + extend { + drawer.clear(ColorRGBa.WHITE) + + // draw the composition to the screen + drawer.composition(composition) + } + } +}