Skip to content

Commit 02afa41

Browse files
authored
New orx-axidraw (#356)
1 parent 15dad43 commit 02afa41

13 files changed

Lines changed: 1038 additions & 2 deletions

File tree

buildSrc/src/main/kotlin/org/openrndr/extra/convention/kotlin-jvm.gradle.kts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,16 @@ val main: SourceSet by sourceSets.getting
3535

3636
@Suppress("UNUSED_VARIABLE")
3737
val demo: SourceSet by sourceSets.creating {
38-
val skipDemos = setOf("openrndr-demos", "orx-minim", "orx-realsense2", "orx-runway", "orx-video-profiles", "orx-midi", "orx-syphon")
38+
val skipDemos = setOf(
39+
"openrndr-demos",
40+
"orx-axidraw",
41+
"orx-midi",
42+
"orx-minim",
43+
"orx-realsense2",
44+
"orx-runway",
45+
"orx-syphon",
46+
"orx-video-profiles",
47+
)
3948
if (project.name !in skipDemos) {
4049
collectScreenshots(project, this@creating) { }
4150
}
@@ -141,4 +150,4 @@ if (shouldPublish) {
141150
setRequired({ isReleaseVersion && gradle.taskGraph.hasTask("publish") })
142151
sign(publishing.publications)
143152
}
144-
}
153+
}

orx-composition/src/commonMain/kotlin/CompositionDrawer.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,7 @@ class CompositionDrawer(
765765
groupNode.children.forEach {
766766
it.parent = groupNode
767767
}
768+
groupNode.attributes.putAll(node.attributes)
768769
groupNode
769770
}
770771
}

orx-jvm/orx-axidraw/README.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# orx-axidraw
2+
3+
GUI for configuring and plotting with an Axidraw pen-plotter.
4+
5+
Uses the [AxiCLI](https://axidraw.com/doc/cli_api/#introduction) command line tool
6+
to communicate with the pen plotter.
7+
8+
Requires: Python 3.8 or higher.
9+
10+
This orx create a Python virtual environment and downloads AxiCLI automatically.
11+
12+
## Usage
13+
14+
```kotlin
15+
fun main() = application {
16+
program {
17+
val axi = Axidraw(this, PaperSize.A5)
18+
axi.resizeWindow()
19+
20+
val gui = WindowedGUI()
21+
gui.add(axi)
22+
23+
axi.draw {
24+
fill = null
25+
axi.bounds.grid(4, 6).flatten().forEach {
26+
circle(it.center, Double.uniform(20.0, 50.0))
27+
}
28+
}
29+
30+
extend(gui)
31+
extend {
32+
drawer.clear(ColorRGBa.WHITE)
33+
axi.display(drawer)
34+
}
35+
}
36+
}
37+
```
38+
39+
Study the inputs available in the GUI. Most are explained in the [AxiCLI](https://axidraw.com/doc/cli_api/#introduction) documentation page.
40+
41+
### Important
42+
43+
* Choose the correct pen-plotter model and servo type in the GUI before plotting.
44+
* Always make sure the pen is at the home position before starting to plot. If it's not, unpower the steppers,
45+
drag the carriage home (near the Axidraw's CPU), then power the steppers back on.
46+
47+
### Tips
48+
49+
* One can repeatedly click on `toggle up/down` and adjust `pen pos down` and `pen pos up`
50+
to find the ideal heights for the pen.
51+
* Enable `fills occlude strokes` and increase margin value to hide elements near
52+
the borders of the paper.
53+
* Click `save` to save your SVG file.
54+
* Click `plot` to plot the visible design using the current settings.
55+
* A [2D camera](https://guide.openrndr.org/extensions/camera2D.html) is enabled by default to place your design on the paper.
56+
* Click `resume plotting` after pressing the hardware pause button (or including a pause
57+
command on a layer) to continue.
58+
* To get a plotting time estimate, enable `preview` and click `plot`. Nothing will be plotted, but the estimate will be shown in the IDE console.
59+
60+
The `Load` and `Save` buttons *at the top of the GUI* can be used to load and save the plotting settings. In a future version we may embed the plotting settings into the SVG file.
61+
62+
### Multi color plots
63+
64+
orx-axidraw makes it easy to create multi-pen plots. To do that, use two or more stroke colors in your design. The order of the lines does not matter. Then, before plotting, call `axi.groupStrokeColors()`. This will group curves into layers based on their stroke colors and insert a pause between layers, allowing you to change the pen.
65+
66+
When the plotter pauses during plotting, change the pen and click `resume plotting` to continue.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
plugins {
2+
org.openrndr.extra.convention.`kotlin-jvm`
3+
}
4+
5+
dependencies {
6+
implementation(libs.openrndr.application)
7+
implementation(libs.openrndr.dialogs)
8+
implementation(project(":orx-jvm:orx-gui"))
9+
implementation(project(":orx-composition"))
10+
implementation(project(":orx-svg"))
11+
implementation(project(":orx-image-fit"))
12+
implementation(project(":orx-shapes"))
13+
implementation(project(":orx-camera"))
14+
demoImplementation(project(":orx-camera"))
15+
demoImplementation(project(":orx-noise"))
16+
demoImplementation(project(":orx-parameters"))
17+
demoImplementation(project(":orx-jvm:orx-axidraw"))
18+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import org.openrndr.application
2+
import org.openrndr.color.ColorRGBa
3+
import org.openrndr.extra.axidraw.Axidraw
4+
import org.openrndr.extra.axidraw.PaperSize
5+
import org.openrndr.extra.gui.GUI
6+
import org.openrndr.extra.noise.uniform
7+
import org.openrndr.extra.parameters.ActionParameter
8+
import org.openrndr.extra.parameters.Description
9+
import org.openrndr.extra.parameters.IntParameter
10+
import kotlin.math.min
11+
12+
/**
13+
* Demonstrates:
14+
* - how to create an AxiDraw GUI
15+
* - how to add a slider and a button to that GUI
16+
* - how to include code to generate new random designs that match
17+
* the paper size via `axi.bounds`.
18+
* - how to display the generated design using `axi.display`.
19+
*
20+
* Toggle the GUI by pressing F11.
21+
*/
22+
fun main() = application {
23+
configure {
24+
width = PaperSize.A5.size.x * 5
25+
height = PaperSize.A5.size.y * 5
26+
}
27+
program {
28+
val axi = Axidraw(this, PaperSize.A5)
29+
axi.resizeWindow()
30+
31+
val gui = GUI()
32+
gui.add(axi)
33+
34+
val settings = @Description("Main") object {
35+
@IntParameter("count", 1, 50)
36+
var count = 20
37+
38+
@ActionParameter("generate")
39+
fun generate() {
40+
axi.clear()
41+
axi.draw {
42+
val l = min(axi.bounds.width, axi.bounds.height) / 2.0
43+
repeat(count) {
44+
circle(axi.bounds.center, Double.uniform(l / 4.0, l))
45+
}
46+
}
47+
}
48+
}
49+
gui.add(settings)
50+
51+
settings.generate()
52+
53+
extend(gui)
54+
extend {
55+
drawer.clear(ColorRGBa.WHITE)
56+
axi.display(drawer)
57+
}
58+
}
59+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import org.openrndr.application
2+
import org.openrndr.color.ColorRGBa
3+
import org.openrndr.extra.axidraw.Axidraw
4+
import org.openrndr.extra.axidraw.PaperOrientation
5+
import org.openrndr.extra.axidraw.PaperSize
6+
import org.openrndr.extra.gui.WindowedGUI
7+
import org.openrndr.extra.noise.uniform
8+
import org.openrndr.extra.parameters.ActionParameter
9+
import org.openrndr.extra.parameters.Description
10+
11+
/**
12+
* Demonstrates:
13+
* - How to set the window size based on the chosen paper size.
14+
* - How to use a windowed GUI.
15+
*
16+
*/
17+
fun main() = application {
18+
program {
19+
val axi = Axidraw(this, PaperSize.A5, PaperOrientation.LANDSCAPE)
20+
axi.resizeWindow()
21+
22+
val gui = WindowedGUI()
23+
gui.add(axi)
24+
25+
val settings = @Description("Main") object {
26+
27+
@ActionParameter("generate")
28+
fun generate() {
29+
axi.clear()
30+
axi.draw {
31+
repeat(20) {
32+
circle(axi.bounds.center, Double.uniform(50.0, 200.0))
33+
}
34+
}
35+
}
36+
}
37+
gui.add(settings)
38+
39+
extend(gui)
40+
extend {
41+
drawer.clear(ColorRGBa.WHITE)
42+
axi.display(drawer)
43+
}
44+
}
45+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import org.openrndr.application
2+
import org.openrndr.color.ColorRGBa
3+
import org.openrndr.extra.axidraw.Axidraw
4+
import org.openrndr.extra.axidraw.PaperOrientation
5+
import org.openrndr.extra.axidraw.PaperSize
6+
import org.openrndr.extra.axidraw.configure
7+
import org.openrndr.extra.gui.WindowedGUI
8+
import org.openrndr.extra.noise.uniform
9+
import org.openrndr.extra.shapes.primitives.grid
10+
11+
/**
12+
* Demonstrates:
13+
* - How to create layers via `group` and give each layer
14+
* a unique pen height and pen speed.
15+
*
16+
*/
17+
fun main() = application {
18+
program {
19+
val axi = Axidraw(this, PaperSize.A5, PaperOrientation.PORTRAIT)
20+
axi.resizeWindow(100.0)
21+
22+
val gui = WindowedGUI()
23+
gui.add(axi)
24+
25+
axi.clear()
26+
axi.draw {
27+
fill = null
28+
axi.bounds.grid(4, 6).flatten().forEach {
29+
group {
30+
circle(it.center, 50.0)
31+
}.configure(
32+
penHeight = Int.uniform(30, 60),
33+
penSpeed = Int.uniform(20, 50)
34+
)
35+
}
36+
}
37+
38+
extend(gui)
39+
extend {
40+
drawer.clear(ColorRGBa.WHITE)
41+
axi.display(drawer)
42+
}
43+
}
44+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import org.openrndr.application
2+
import org.openrndr.color.ColorRGBa
3+
import org.openrndr.extra.axidraw.*
4+
import org.openrndr.extra.gui.WindowedGUI
5+
import org.openrndr.extra.shapes.primitives.grid
6+
7+
/**
8+
* Demonstrates:
9+
* - How to create a flattened grid of with 24 items
10+
* - How to randomize the order of those items
11+
* - How to take chunks of 10 items, then make
12+
* a pause to change the pen after plotting each chunk
13+
*
14+
* Operation: After plotting ten circles, plotting will stop to let you change the pen.
15+
* With the second pen installed, click `resume`. It will plot ten circles more.
16+
* Change the pen again and click `resume` to plot the remaining 4 circles.
17+
* Once done, click `resume` one more time to bring the pen home.
18+
*/
19+
fun main() = application {
20+
program {
21+
val axi = Axidraw(this, PaperSize.A5, PaperOrientation.PORTRAIT)
22+
axi.resizeWindow(100.0)
23+
24+
val gui = WindowedGUI()
25+
gui.add(axi)
26+
27+
axi.clear()
28+
axi.draw {
29+
fill = null
30+
axi.bounds.grid(4, 6).flatten()
31+
.shuffled().chunked(10).forEach { chunk ->
32+
group {
33+
chunk.forEach {
34+
circle(it.center, 50.0)
35+
}
36+
}
37+
group {
38+
}.configure(layerMode = AxiLayerMode.PAUSE)
39+
}
40+
}
41+
42+
extend(gui)
43+
extend {
44+
drawer.clear(ColorRGBa.WHITE)
45+
axi.display(drawer)
46+
}
47+
}
48+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import org.openrndr.application
2+
import org.openrndr.color.ColorRGBa
3+
import org.openrndr.extra.axidraw.Axidraw
4+
import org.openrndr.extra.axidraw.PaperOrientation
5+
import org.openrndr.extra.axidraw.PaperSize
6+
import org.openrndr.extra.gui.WindowedGUI
7+
import org.openrndr.extra.shapes.primitives.grid
8+
9+
/**
10+
* Demonstrates:
11+
* - How to create a flattened grid of with 24 items
12+
* - How to apply random colors from a palette to each item.
13+
* - How to use `groupStrokeColors()` to plot a multi-pen design.
14+
*
15+
*/
16+
fun main() = application {
17+
program {
18+
val axi = Axidraw(this, PaperSize.A5, PaperOrientation.PORTRAIT)
19+
axi.resizeWindow(100.0)
20+
21+
val gui = WindowedGUI()
22+
gui.add(axi)
23+
24+
val palette = listOf(
25+
ColorRGBa.RED,
26+
ColorRGBa.GREEN,
27+
ColorRGBa.BLUE
28+
)
29+
30+
axi.clear()
31+
axi.draw {
32+
fill = null
33+
axi.bounds.grid(4, 6).flatten().forEach {
34+
stroke = palette.random()
35+
circle(it.center, 50.0)
36+
}
37+
}
38+
axi.groupStrokeColors()
39+
40+
extend(gui)
41+
extend {
42+
drawer.clear(ColorRGBa.WHITE)
43+
axi.display(drawer)
44+
}
45+
}
46+
}

0 commit comments

Comments
 (0)