The Hilbert Dragon

By default, this adds PerlTk graphics to Hilbert Curve. But, as penance for irritating the math gods (Math >> XKCD, even in my book), this one allows you to input any L-system you want.

Update: Forgot to explain that the obfu's pattern is in the (negative) shape of the Penrose dragon, but it makes the Hilbert curve by default. (hence "the Hilbert Dragon").

#!/usr/bin/perl use strict; use warnings; ;$_=q~&6P+H;M`4K]N!L$5@QtDLBO1`4#]AKC(mdfFkDqXF$1dEc+D>$3uAA[>Fm9@P&QN +[CZ>BJ X:"*2Bf@Rj)h(@ZIXvH`P6DR0zHAJR#@admir{JKMP,NBZ8IC`*NB$xDHXPJ^DhAH;TVB( +.kbyTJ X>J"HbMBX&D!`al{ ]^m)NXnBhYd+ZCpC MVEA0`H"8(JbX$L"PjDv`H +'C,lOg Y:MC,2EB@FT]m*CC tFAD G@9.%]p@PlPbEPqX D"G1 E;eY=M@VdD$dx[q<bD|k`4 +OD8"rT OBL`$yMELDDHc!tO DHfD DadnZ@4+sRF1\\9$ `b3z Jq\\D2X#%Hd$PD@tieRZ@J +TE\\)` HD!hHA.H@4NaMZB@ iFL,"@&6HP D>sOdDPY{ELj$H@E +Tm`P)P T^`l!d<i`Q\\7P]aF;%NOw 0ne| B$Yd@IF`r7DJy$5B @PP% tF@HEf?Fx>.YKJ@H +]9bwem !,a!`p]71aEH^`'NcwPXyT K&0L \\PEl(D<hLLn9PSS SL%A OD`PECT`p*!.0A4j +yPV{;P |gev 67`A XPDm /PJ`)TC<OADOmP8a +pHA|HA (x:0 `dJX ALF! XE@P $T\\ H`3k AHF> fX^{ 8@ws%tI@XB`n,Z@@&KfGxN +h>J`G@ "AX8 `@Hp 'bdD @_+> aXJA zV!T E>"@ xB2N @\\C`GKZA>CXiBJJ`*b$I0 +BBldpa qLHH jBJA @uIP g1[`IC0BQ@@`\\#& +q@OCP) P'B(HpA@F@ hH@$KDdrWI(,C^FQVE\\J4L`HF08 BFX9 TA2? $]Ap?`lGmDtTQU@d +MP?DHx Q0KLi`HH[1 G.R<k`|<Y*Ch+P[@:?DkqKD|T"]L ;y13 M\\5 Q7Mp[@}O`!gnLT+0 +ZFs>TY B@)H `VrE4N.Y<AwCPO(`|tvchG mNKiSp,oMLUQ@zGX +YPqGKH bf{Q W/D<`M@"^1WlbFuH@ZYMZOJBS724 w]J@ @R([ @P>YU,^_Sj'@kK$+V[I;MF +K8PB*C ka&Q Z!|"gBHjKfHPNI<\\r@`HI{Sa>G+ >B[] JDFt BKdKUSXHMVK@IJ>D9$A6M@ +5CXMyn !&\\ @;`D aB@`P_hF@eS@)F0G %k'l JxdBRI$Y(B + D@8f DDxDbvRhd6 2D|< @HIHFi9"^JyF@pC@Bv(BAN48$!:V[`B&xR 9y_dXE,@r#+WzMXA + @D0h 2f:NJGce&) Vbi% .\\Y"V]J@QbB9"M@pn)LAD7Zg(hMeZU@[X yi=8Xxo%wGt.(8az + Unq{ NCr?[NkU4[ Olm7[S,u5[Y.EuB:@`*DHx[$B![X n6t> + lFb1 VRA[O]e4`L0@D`_SX8|YfPHHVx\\<X%"dY.G#`&@@[V_BF H+af vBbm BPP` J\\^ +Y_AVqj ;]$meQLd6@RNh>E`'mpTvnFzHP.8xJD!")X02b6HX$B%(S \\83 ">Lx pI0M bJK@ +5"{8DD `Q`xDJRHh(^Z|>U@DAPAFZ@P@D\\<8x@^AMJ^\\~;s{\s} {}g; s/(. +)/join "",map{ord$1&2**(5-$_)?1:0}0..5/ge;my(%d,%r);sub p{sprintf"%b",0+keys% +d};$d{ chr$_}=p for 32..126;sub r{$;=1+int log(1+keys%d)/log(2);$_="0"x($;-le +ngth). $_ for values%d;%r=reverse%d;s/(.{$;})//?$1:0}$a=$^=$r{r()};while($"=r +){$^=~ /(.)/;$.=exists$r{$"}?$r{$"}:$^.$1;$a.=$.;$.=~/(.)/;$d{$^.$1}=p;$^=$.} +eval$a

(See the readmore for TONS more.)


There are parameters galore. Parameters are split on '=' signs. So, 'a=90' is the same as 'a 90'.

L-system options:
  a DEG = angle increment in degrees       default 90
  m RAD = initial angle offset in radians  default  0
  i N   = number of iterations             default  5

Output options:
  t NNN = total pixels (= width = height)
          default if Tk: 511
          default if terminal: 33
  w N   = width in pixels                  default = t
  h N   = height in pixels                 default = t
  n 1   = no Tk (default is to use Tk if it's present)
  b 1   = bit output (only applicable if no Tk)
          bit output can be fed into ImageMagick

L-system operators:
  S STR = start string (called 'axiom' in Fractint)
  +     = rotate by 'a' degrees
  -     = rotate by 'a' degrees in the opposite direction
  [     = push (save position and angle)
  ]     = pop  (restore position and angle)
  F     = draw one unit forward
  M     = move one unit forward (without drawing)

  any other characters =
    no drawing/movement operation, but used for substitution

Default L-system:
  S L

See below for examples.


If you've ever used Fractint, or want to try some Fractint L-systems that you find, there are some differences in format. My code doesn't do:

empty substitutions
   Due to the way parameters are parsed, you should use something like:
   F N          (where N is unused elsewhere)
   instead of:
   F=           ('F' goes to '' empty)

No D and G
   Use F and M instead.

@ operator
   This is the biggest difference. It seems like it can't usually be avoided.
   So some Fractint systems are just off-limits to my program [currently...].

angles are specified differently
   Fractint angle 10 means 360/10 degrees = in mine: a=36
   Fractint angle 6  means 360/6  degrees = in mine: a=60

| operator (just do it manually, by inserting multiple +'s or -'s)

\NN, /NN (can sometimes work around by using a=small, and changing all other angles)

anything with color (sorry, all smooth hue gradients here)


'bush'. Looks like a bush.

perl S ++++F F FF-[-F+F+F]+[+F-F-F] a 22.5 i 4

For a PNG of the same (requires ImageMagick's convert):

perl S ++++F F FF-[-F+F+F]+[+F-F-F] a 22.5 i 4 t 515 n 1 b 1 | convert -depth 8 -size 515x515 rgb:- bush.png



Dekking church. (Only looks good with odd-numbered iterations)

perl S WZYX F N W FW+F-XFW-F+Z X ++F--Y-F+Z++F--Y-F+Z Y ++F--Y+F-X Z FW+F-X i 5

Hilbert II


'hiway' (Penrose Dragon)

perl S FX X FX+FY Y FX-FY F N i 9

Penrose tiles

perl S [7]++[7]++[7]++[7]++[7] 6 8F++9F----7F[-8F----6F]++ 7 +8F--9F[---6F--7F]+ 8 -6F++7F[+++8F++9F]- 9 --8F++++6F[+9F++++7F]--7F F N a=36


perl a 30 S W W +++X--F--ZFX+ X ---W++F++YFW- Y +ZFX--F--Z+++ Z -YFW++F++Y--- i 6

PNG/GIF/JPEG/whatever output

Using ImageMagick, it's pretty easy to get files of any of these. Add to the end of the command:

n 1 b 1 | convert -depth 8 -size ${t}x${t} rgb:- filename.type

where the ${t}'s are whatever you specified for t=NNN (or 511, by default)


This wouldn't have been possible without several incredible sources:

Shameless plug

I made a gallery of fractals that this program (plus ImageMagick) created. (Page also has some of the same background that this node has -- and I haven't yet given proper credit to the L-systems' "inventors"/"transcribers".)