# tl;dr

This is part 2 of The algorithmic metamorphant: Reducing a logo to first principles. We continue reducing the number of arbitrary inputs by introducing some constraints using logical rules. You can find the code example in the algorithmic-metamorphant-logo github repo tag `second-blog-article`

.

# Starting point: Giving names

In The algorithmic metamorphant: Reducing a logo to first principles we succeeded in creating a base version of our magnificent metamorphant logo in Clojure using the SVG library Dali.

We will start by naming the parts of our logo.

# Ruling by constraints, constraining by rules

Creating rules is creating constraints. The logo is the outcome of solving the resulting system of equations that satisfy all constraints.

Our constraints will restrict the position of individual elements in the logo. We will visualize this by colored guiding lines. You may be familiar with that approach from using interactive graphics software like Inkscape or GIMP, where you can pull in horizontal and vertical guiding lines. We generalize that. In our approach, guiding lines may in principle be of arbitrary form - depending on the constraint. For example, we can also have

- diagonal lines,
- circular lines,
- sets of disconnected line segments or
- non-line-shapes like areas or points.

All rules are derived by interpreting the logo visually:

- Which parts are related to which other parts?
- What are “natural” rules to describe this relation?
- Which ratios and symmetries apply?

So our repertoire of possible rules boils down to very few options. Of those, we will use only the simplest ones.

## Fundamental shapes

One variant to overcome ambiguous shapes is the choice of primitive (in the sense of axiomatic) fundamental shapes instead of arbitrary paths:

- conic sections (circle, ellipse, parabola, hyperbola, …)
- triangles (equilateral, isosceles, right-angled, …),
- quadrilaterals (square, rectangle, trapezium, parallelogram, …),
- regular polygon (pentagon, hexagon, …),
- star-shaped regular polygons (pentagram, hexagram, …),
- …

## Symmetries

Symmetries also describe constraints on the resulting shape. The most prominent types of symmetries for 2D shapes are

- mirror symmetries,
- rotational symmetries,
- translational symmetries and
- scale symmetries.

## Proportions and the golden ratio

Parts of an image can be related quantitatively to other parts

- by size or
- by position.

Allegedly, human psychology favors proportions that are either

- repetitive (same size resp. equal distance) or
- determined by the golden ratio (see 25 creative logos for an example study).

Many other rules exist, e.g. consecutive Fibonacci numbers. After reading about some of these, I get the impression that most just approximate the golden ratio again - sort of “golden enough”. We will stick to the precise ratio in order to simplify and restrict our choices.

# Discovering concrete rules

So let’s start our journey and discover some rules.

## Rule: Inner left dots relation

We demand, that both inner left dots have to be horizontally aligned. In this rule we fix the x-position of inner ear dot and inner outline dot to the same value. This can be visualised by a vertical guiding line. Without further rules, this x-position would be an arbitrary input parameter.

## Rule: Inner left dots x

Our proposition is: The inner left dots divide the canvas width by the golden ratio. Translated to a formula, this rule means, that the x-position of the inner left dots is fixed to `(/ (:width canvas) (+ 1 golden-ratio))`

.

## Rule: Inner left outline dot y

Our next rule fixes the y-position of the inner left outline dot: The inner left outline dot divides the eye-to-bottom-distance by the golden ratio. It can be written as `(- (:height canvas) (/ (- (:height canvas) (:y eye)) (+ 1 golden-ratio)))`

and visualised by 3 horizontal guiding lines:

- 1 through the eye
- 1 on the bottom (= frame top)
- 1 through the inner left outline dot

## Rule: Inner left ear dot y

In order to fix the y-position of the inner left ear dot, we constrain it by a similar principle as the inner left outline dot. It shall divide the eye-to-top-distance by the golden ratio. Written as a formula, the y-position is `(- (:y eye) (/ (:y eye) (+ 1 golden-ratio)))`

. Visually, this can again be shown using 3 horizontal guiding lines:

- 1 through the eye (same as before)
- 1 on the top (= frame top)
- 1 through the inner left ear dot

## Rule: Eye x vs. y

It would look weird for the eye to be closer to the top than to the right. This is equivalent to a mirror symmetry along the rising diagonal starting from the bottom left, which will also serve as our guiding line.

Note: The concrete position of the eye stays an arbitrary input parameter!

## Rule: All outline borders

All outline borders shall end with the (quadratic) canvas. Naturally, the bottom dots will extend beyond the canvas. Looking at the SVG implementation details, we see that lines are not described by their border, but their center. Hence, the line padding correction has to be half the line width, i.e. `(/ line-width 2)`

. This can be visualised by a frame around the canvas.

## Rule: Ear end y

The lower end of the ear shall divide the canvas in the middle. This can be visualized by a horizontal guiding line.

## Rule: Bottom middle dot x

The y-position of the bottom middle dot is already fixed. We continue by fixing the x-position, having the bottom middle dot divide the distance from inner left dot to bottom right dot by the golden ratio. This can be visualised by the corresponding vertical lines:

- 1 through the left inner dots
- 1 through the bottom right dot
- 1 through the bottom middle dot

# The result so far…

After fine-tuning the remaining input parameters by overlap analysis, we arrive at an impressive result, already.

In order to analyse the matching quality, we will overlay this with the original logo (colored in orange for better contrast):

While most parts match the original quite closely, we still observe some differences:

- All dots are shifted slightly upwards, which is expected since our original logo is not quadratic, but slightly elongated along the vertical axis.
- The lower vertical line of the ear path is slightly offset to the left.

# “Good enough” reduction result

After some steps, we reduced our input parameters to

- corner arc radius
- dot radius
- line width
- eye offset

I want to encourage you to submit more ideas to reduce it even further. Especially the eye offset is something that should be under control, shouldn’t it?

# Necessity or Cyclosophy?

The result is definitely helpful for my personal needs in everyday work with the logo. However, the creation process feels quite like arbitrary pseudo-science; or like laying the groundworks for a church of ‘phantology.

We just have too many degrees of freedom of how to combine our input values to derived values. Even worse: We do it all after the fact. It reminds me of Cyclosophy, the mystical theory of the dutch bicycle.

Others seem to have these thoughts as well. There is also an interesting analysis about the alleged golden ratio design of the Apple logo. For fans of 99 francs I also recommend reading about the origins(!) of the pepsi logo.

But let us not spoil our fun by these pessimistic skeptical thoughts.

# Going the empirical way

When theory is vague, providing an empirical method would be paramount. How do you do that? How do you pin down which variant of a logo is superior? What is superiority in the domains of logos after all? Emotional effect? Pleasing Aesthetics? Uniqueness? I am happy about input and hints here.

For lack of better knowledge, I will at least do my duty and call for poor man’s empiry: Let us scan the combinatorial space of permissible input values and render it. Compare and judge the result for yourself:

The code used to generate it is:

```
(ns genlogo
(:require [dali.io]))
(def golden-ratio
1.61803398875)
(defn logo [{:keys [dot-radius line-width corner-arc-radius eye-offset]}]
(let [canvas {:width 1000 :height 1000}
eye {:x (- (:width canvas) eye-offset)
:y eye-offset}
inner-outline-dot {:x (/ (:width canvas) (+ 1 golden-ratio))
:y (- (:height canvas) (/ (- (:height canvas) (:y eye)) (+ 1 golden-ratio)))}
inner-ear-dot {:x (:x inner-outline-dot)
:y (- (:y eye) (/ (:y eye) (+ 1 golden-ratio)))}
line-padding (float (/ line-width 2))
bottom-right-dot {:x (- (:width canvas) line-padding corner-arc-radius)
:y (- (:height canvas) line-padding)}
bottom-middle-dot {:x (+ (:x inner-outline-dot) (/ (- (:x bottom-right-dot) (:x inner-outline-dot)) (+ 1 golden-ratio)))
:y (- (:height canvas) line-padding)}
ear-end {:x (+ (:x bottom-middle-dot) corner-arc-radius)
:y (/ (:height canvas) 2)}
dot-diameter (* 2 dot-radius)
view-box-padding-x (- line-padding dot-radius)
view-box-padding-y view-box-padding-x
total-width (- (:width canvas) (* 2 view-box-padding-x))
total-height (- (:height canvas) (* 2 view-box-padding-y))
line-style {:stroke "#02324b" :path-length 1000 :stroke-width line-width :stroke-linejoin "round" :fill "none" :marker-start "url(#bm)" :marker-end "url(#bm)"}]
[:dali/page {:width "100%" :height "100%" :view-box (str view-box-padding-x " " view-box-padding-y " " total-width " "total-height)}
[:defs
[:circle {:id "bubbel" :cx 0 :cy 0 :r dot-radius :fill "#02324b"}]
[:marker {:id "bm" :view-box (str "0 0 " dot-diameter " " dot-diameter) :ref-x dot-radius :ref-y dot-radius :marker-units "userSpaceOnUse" :marker-width dot-diameter :marker-height dot-diameter}
[:use {:x dot-radius :y dot-radius :xlink:href "#bubbel"}]]]
[:path line-style
:M [(:x inner-outline-dot)
(:y inner-outline-dot)]
:L [(:x inner-outline-dot)
(- (:height canvas) line-padding)]
:L [(+ corner-arc-radius line-padding)
(- (:height canvas) line-padding)]
:A [corner-arc-radius
corner-arc-radius]
0 false true
[line-padding
(- (:height canvas) corner-arc-radius line-padding)]
:L [line-padding
(+ corner-arc-radius line-padding)]
:A [corner-arc-radius
corner-arc-radius]
0 false true
[(+ corner-arc-radius line-padding)
line-padding]
:L [(- (:width canvas) corner-arc-radius line-padding)
line-padding]
:A [corner-arc-radius
corner-arc-radius]
0 false true
[(- (:width canvas) line-padding)
(+ corner-arc-radius line-padding)]
:L [(- (:width canvas) line-padding)
(- (:height canvas) corner-arc-radius line-padding)]
:A [corner-arc-radius
corner-arc-radius]
0 false true
[(:x bottom-right-dot)
(:y bottom-right-dot)]]
[:path line-style
:M [(:x inner-ear-dot)
(:y inner-ear-dot)]
:L [(:x inner-ear-dot)
(- (/ (:height canvas) 2) corner-arc-radius)]
:A [corner-arc-radius
corner-arc-radius]
0 false false
[(+ (:x inner-ear-dot) corner-arc-radius)
(/ (:height canvas) 2)]
:L [(:x ear-end)
(:y ear-end)]
:L [(:x ear-end)
(- (:height canvas) corner-arc-radius line-padding)]
:A [corner-arc-radius
corner-arc-radius]
0 false true
[(- (:x ear-end) corner-arc-radius)
(- (:height canvas) line-padding)]]
[:use {:x (:x eye) :y (:y eye) :xlink:href "#bubbel"}]
]))
(defn -main []
(doseq [dot-radius [40 55 70]
line-width [50 64 80]
corner-arc-radius [100 160 220]
eye-offset [230 265 300]]
(dali.io/render-svg (logo {:dot-radius dot-radius
:line-width line-width
:corner-arc-radius corner-arc-radius
:eye-offset eye-offset})
(str "metamorphant" "-" dot-radius "-" line-width "-" corner-arc-radius "-" eye-offset ".svg"))))
```

Admittedly the chosen values are a bit extreme. I chose them to demonstrate the effect of the individual parameters more clearly.

# What about color?

While formalizing the geometry of the logo went pretty well (all doubts ignored), I am totally lost when it comes to the next natural question: How to formalize Color?

Instead of following this track, I will just stick to the color scheme we have.

The deficiencies of a logo with too many fixed geometrical details has real practical consequences: among others, quality loss during format conversion, bad ab-initio reproducability in different vector formats, unnecessarily file size. I do not see any similar deficiencies with a fixed set of colors.

# Where to go from here?

So, as a next step, let’s get ready for a precisely defined vector animation of the metamorphant logo…