Dragon Curve Fractal - Complex & Bits
A familiar image is re-discovered in a sequence of complex numbers, and the binary bits of natural numbers.
Keywords
fractals, dragon, curve, complex, imaginary, binary
Part 1: Complex Numbers
Clojure’s fastmath library provides complex numbers.
For example, if we let a=b=1
, then
\[a+bi=1+1i\]
1 1) (c/complex
1.0 1.0] [
Here’s a fun fact about powers of one more than the imaginary unit.
\[(1+i)^k=\sqrt{2}^ke^{ik\pi/4}\]
One does not need to be Euler to sense spinning,
and k
from (0 1 2 3 ...)
gives a sequence of points.
def pts
(for [k (range)]
(1 1)
(c/pow (c/complex 0)))) (c/complex k
The first few of which are…
take 10 pts) (
1.0 0.0]
([1.0000000000000002 1.0]
[1.2246467990769217E-16 1.9999999999999998]
[1.9999999999999996 2.0000000000000004]
[-4.0 4.898587196307688E-16]
[-4.000000000000002 -3.999999999999999]
[-1.4695761589957038E-15 -7.999999999999999]
[-7.999999999999997 -8.000000000000004]
[16.0 -3.91886975704615E-15]
[16.000000000000004 15.999999999999993]) [
I plot, therefore I am:
(kind/hiccupinto [:svg {:width "256" :height "256" :viewBox "-24 -24 48 48"}
(:rect {:x -24 :y -24 :width 48 :height 48 :fill :#f8f8f8}]]
[concat (for [[x y] (take 10 pts)]
(:line {:x1 0 :y1 0 :x2 x :y2 y :stroke :#222}])
[for [[x y] (take 10 pts)]
(:circle {:cx x :cy y :r 1.5 :fill :#88f}])))) [
Spinning indeed.
Part 2: Binary Bits
In computers, numbers are made of bits.
defn bit
(
[n pos]bit-and (int (/ n (Math/pow 2 pos))) 1)) (
for [pos (reverse (range 8))]
(42 pos)) (bit
0 0 1 0 1 0 1 0) (
Hidden in the bits is a draconiform structure, we use them to carefully sum the pts
.
defn dragon-by-bits
(count (Integer/toBinaryString n))))
([n] (dragon-by-bits n (
([n pos]letfn [(a [n pos]
(;; We move according to pts, occasionally turning
if (zero? (bit n pos))
(
c/ZEROlet [turn? (if (zero? (bit n (inc pos)))
(
c/ONE
c/I)nth pts pos)] ;; (1+i)^pos
pt (
(c/mult turn? pt))))
(m [n pos];; When the bits flip, we turn
if (= (bit n pos) (bit n (inc pos)))
(
c/ONE
c/I))]if (>= pos 0)
(
(c/add (a n pos)
(c/mult (m n pos)dec pos))))
(dragon-by-bits n ( c/ZERO))))
Part 3: A Glimpse
“It does not do to leave a live dragon out of your calculations, if you live near him.”
– J.R.R. Tolkien
let [dragon-pts (for [n (range 512)] (dragon-by-bits n))
(* 1.15 (apply max (map Math/abs (flatten dragon-pts))))
furthest (- furthest) (- furthest) (* 2 furthest) (* 2 furthest)]]
[l t w h] [(
(kind/hiccup:svg {:width "512" :height "512" :viewBox (s/join " " [l t w h])
[:shape-rendering :crispEdges}
:rect {:x l :y t :width w :height h :fill :#f8f8f8}]
[:path {:d (reduce (fn [eax [x y]]
[str eax " L" x " " y))
(let [[x y] (first dragon-pts)]
(str "M" x " " y))
(rest dragon-pts))
(:vector-effect "non-scaling-stroke"
:stroke :#222
:fill :none}]]))
Inspired by this lovely rosettacode gnuplot code.