Or red chalk is a mineral pigment made of clay and hematite (Fe2O3). It is deep red in color and has been used for artistic expression already by the neanderthals. Since the renaissance it has been shaped into a kind of pencil, used mainly for sketches similar to graphite pencils today.
The goal is to build a framework for generative art for pen plotters in Rust.
Hello, World!
- generate art as svg
- parse a limited number of shapes from svg files (WIP).
- add more organic ways to generate images, such as voronoi diagrams
- adapt composition things to work with voronoi diagrams
- experiment with L-systems.
- add noise generator
- add camera input, so the generated art can be a reaction to what already is on paper.
- project layout that allows for easy transitions between creating art work with lots of predefined functions, writing custom parts for the frame work and switching between different works of art.
- generate art without svg output, by addressing the pen plotter directly
- input from hardware rngs
I added a basic implementation of L-Systems, as described here [https://paulbourke.net/fractals/lsys/]. I omitted rules about filled polygons, and will add more rules about shapes that are already present in the lib. There is also a need for more randomness in the parameters.
A generated Tree.New shape dropped. The Circloid.
5 Circloids. Many Circloids.Inspired by mushroom lamellas. Bezier Arcs are now possible.
Inspired by mushroom lamellas.Epiphany!💡 I have been on this track, implementing traits for shared behavior of the types VoronoiDiagram
and Grid
. But the actual breakthrough in reducing tons of somewhat similar code is the idea, that the Grid
is only a special case of a voronoi diagram. One, where all cells have exactly four sides, and corresponding sides have the same length throughout the entire thing. The main difference besides the data type is that in the Grid
version, the cell sides are constructed first, and the center point follows, the VoronoiDiagram
type does it the other way around. In the Grid
type, single fields can be addressed by their row and column number, which is mostly convenient as a picture in my head, but in practice requires the same iteration over and over again.And maybe it's not needed? Maybe each Grid
cell has enough identifying properties to work without that, just like the VoronoiDiagram
.
I am not sure if I will implement this fully soon, as I feel I am also due to make more art. But realization definitely feels like a huge lesson towards more generic, reusable and thus cleaner code. The key to avoid writing so much duplicate code in the first place is to think bigger, with more use cases from the start.
Another step I took towards making the library part more generic is moving most of the composition implementation to the project part, and only keep the traits and type definitions in place. This seems way more logic, as the implementations were rather specific for my artistic work, and this is not the purpose of the crate.
Set up a Raspberry Pi with Saxi so my computer does not need to be tethered to the AxiDraw in order for the plotter to be active.
Refactored the way Grid and Voronoi Diagrams are constructed. Now all diagram types are constructed with the same constructor, only with different variants, which in the end decides, which diagram type is first built. I added a trait, so that the diagram types can share behavior regarding compositional aspects. This way I was able to remove a lot of somewhat similar, somewhat duplicate code, and suddenly I had way less types named Voronoi something. I slowly get the way, one needs to think code a lot bigger then what you're currently working on. The ability to see future variants of something, future expansions, and functions. Not being able to see that leads to rewriting code a lot.
Tesselated Voronoi Cells.Added a characteristic timestamp to the filename of the generated images. The timestamp can later be part of the stamp on the backside of the image.
Added the type that keeps data for the polygons, so that the center may be saved with each cell, to be able to address each cell by the center point. Following this I am also starting to think about how to order the center points in a meaningful way.
Off to new experiments! I implemented the ability to generate the cells of a voronoi diagram, and draw the lines.
Drawn cells of a voronoi diagram.I have started to work on parsing svg files. While the results for my art work are currently not very usable, the general principle works and it lead to implementing Shape
as a trait
and usage of it as a trait object with all the pitfalls of sized types that comes with it. I decided to drop the topic of including vectorization from a camera for now, to pic it up later again, as I figured I don't want to work on a grid based system with this.
link to a video on instagram showing the finished plots
You can buy one to support this work!
- put an order to the generated coordinates for the lines, so they are no completely random. The effort was well spent, the images look a lot cleaner, without looking too ordered, but the many "stray" looking lines are gone.
- added a compositional feature that sets the focus of generation into the bottom third of the image. This feature needs a lot of improvement.
- decided this is good enough for a first series, generated 100, and selected the 10 I liked and started plotting them.
- changed how coordinates are generated to be more versatile in use
- avoid doubles and coordinates that are too close together (this still needs improvement, but its also good enough for now)
- added more graphical elements that are derived from the original star_burst motif and different algorithms that place them. (This turned out to be a key part in the development of the first series)
- added compositional layer, that sets random centers of attention
- support for tesselation
- cleaner collision of lines with circles. Probably good enough for plotting.
- also, we now get into the territory of panics, calculations that go on indefinetly... so there was
Some()
introduction of Options.
- added support for some math operations to generate lines and points and not just plot random shapes. This lead to an understanding, that this framework has different layers: a more abtract one that generates the lines to be plottet, and the svg functions that visualize the generated works. Currently it makes sense to me, to have the an
fn draw()
method for every shape that does just that. - another oldie but good to remember: on paper algebraic solutions are simpler, in programming, iterative methods are more elegant and flexible.
-
split code into modules, reduced a lot of duplicate code.
-
wrote abstractions for the functions provided by the svg crate, since colors, line width, the absence of fill etc. can be hard coded, as those things don't matter to a pen plotter.
-
split code into modules, reduced a lot of duplicate code.
-
wrote abstractions for the functions provided by the svg crate, since colors, line width, the absence of fill etc. can be hard coded, as those things don't matter to a pen plotter.
-
added lines from border from the grid field to the circle center
- changed distored squares to circles in a 5x5 grid
-
I ran into an ownership problem with instances of the type
std::ops::Range<i32>
when generating that range early and using it in an iteration. The current solution is passing the values of the range and generating the range inside that function that is called in the iteration. -
Hello, World!