The first examples dealt with the basic approach of replacing thinking in terms of shapes/objects/nouns with thinking in terms of processes/functions/verbs. This is not just required by the more or less functional nature of Clojure, but also a fundamental approach for the generally bottom-up nature of generative design. Therefore, I believe Clojure is actually a superb fit for this field.

A circle is a shape, but it becomes so much more useful and malleable if understood as the process of a point rotating around another. This immediately leads to questions like: What is rotation? What is space? How to define it, how to work with it and how to map from one space to another (e.g. polar vs. cartesian). When is it better to solve a problem in one or the other, how do the same ideas exist in other domains (e.g. color spaces). It also leads us to question how this all can be controlled and manipulated, through the introduction of parameters and other processes to control their values over time. What happens if we rotate a set of points instead of a single point around the center, what happens if we connect these points? How can existing process metrics be used to form new relationships and drive other parts of the design? E.g. What happens if we make the radius itself a function of the rotation angle?

Whereas Clojure already offers an interactive workflow out of the box, working on visual generative systems, we also want to naturally visualize the results, straight from the REPL and as a way of unit testing, using our eye to judge the correctness and aesthetic potential of the system. All examples in this workshop are largely using vanilla Clojure, though we also extensively used the thi.ng/geom, thi.ng/math & thi.ng/color libraries to help us with vector algebra, SVG generation, geometry data types & export and to simplify working with color (in multiple color spaces & formats).

Polygons, polymorphism & graphs

We talked about various fundamental geometry data types, abstractions and polymorphic operations provided by thi.ng/geom. These types could be considered classes (in the OOP sense), but they too can act as configurable point, line and shape generators and provide dozens of other useful operations: analysis of dimensions, bounds, area, volume, intersections with other types, conversions to other types, point classifications, spatial transforms, interior & boundary sampling, extrusions, subdivisions, tessellations etc. Many types also provide a kind of graph access, e.g. to extract the vertices, edges, cycles (i.e. mesh faces), find vertex valence, split/join edges etc. Much like many of the functions in clojure.core, all of the 50+ operations defined in the thi.ng.geom.core namespace are protocols and implemented to varying extents by the currently 20+ shape types, thus keeping the main API surface area small and easy to learn.

As a variation of these first examples, we put some of the above operations to use and learned how to create polygons from a circle, first by sampling the circle with a given resolution (e.g. resolution = 6 produces a hexagon) and then continued re-sampling the edges of the resulting polygon perimeter at a fixed distance to produce a sequence of uniformly spaced points.

A simple transformation like that can yield a quite major change in the resulting output of an otherwise unchanged process (this one inspired by my childhood hobby of taking hundreds of long exposure photos of a torch hanging in a dark room, though here we’re not using Lissajous curves).