#!/usr/bin/perl
my $level = shift;
my $dist = shift || 2 ** ($level + 1);

my $filename = shift;

if ($filename)
{
    open SVG, '>', $filename;
}
else
{
    *SVG = *STDOUT;
}

print SVG qq|<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg viewBox="0 0 $dist $dist" xmlns="http://www.w3.org/2000/svg" version="1.1">
  <title>Hilbert curve of level $level</title>
  <path d="|;

$dist /= 2 ** $level;
goToXY($dist/2, $dist/2);
HilbertA($level);

print SVG qq|" fill="none" stroke="blue" stroke-width="1"/>
</svg>|;

sub HilbertA
{
    my $level = shift;
    return if ($level == 0);

    HilbertB($level - 1);    lineRel(0, $dist);
    HilbertA($level - 1);    lineRel($dist, 0);
    HilbertA($level - 1);    lineRel(0, -$dist);
    HilbertC($level - 1);
}

sub HilbertB
{
    my $level = shift;
    return if ($level == 0);

    HilbertA($level - 1);    lineRel($dist, 0);
    HilbertB($level - 1);    lineRel(0, $dist);
    HilbertB($level - 1);    lineRel(-$dist, 0);
    HilbertD($level - 1);
}

sub HilbertC
{
    my $level = shift;
    return if ($level == 0);

    HilbertD($level - 1);    lineRel(-$dist, 0);
    HilbertC($level - 1);    lineRel(0, -$dist);
    HilbertC($level - 1);    lineRel($dist, 0);
    HilbertA($level - 1);
}

sub HilbertD
{
    my $level = shift;
    return if ($level == 0);

    HilbertC($level - 1);    lineRel(0, -$dist);
    HilbertD($level - 1);    lineRel(-$dist, 0);
    HilbertD($level - 1);    lineRel(0, $dist);
    HilbertB($level - 1);

}

sub goToXY
{
    my ($x, $y) = @_;
    print SVG "M $x $y ";
}

sub lineRel
{
    my ($dX, $dY) = @_;

    if ($dY == 0)
    {
        print SVG "h $dX ";
    }
    elsif ($dX == 0)
    {
        print SVG "v $dY ";
    }
    else
    {
        print SVG "l $dX $dY ";
    }
}
