Terrain height map generator I wrote a Perl script that implements the algorithm described in this
article to generate terrain height maps.  The idea is to raise a random hill \$i\$ of size \$r_i\$ centered at point \$(x_i, y_i)\$, such that the height at point \$(x, y)\$ is

$$ z = r_i^2 - ((x - x_1)^2 + (y - y_1)^2) $$

The resulting terrain is the sum of many such hills, with some normalization and flattening.

The output of this program is a bunch of inserts into the database and a png. The only problem with it is that it has really bad performance.

#!/usr/bin/perl
# mapgen.pl
# Henry J Schmale
# August 16, 2015
# Generates a height map

use strict;
use warnings;
use DBI;
use Image::Magick;
use constant {
    MAX_X   =&gt;  2000,
    MAX_Y   =&gt;  2000,
    MAX_R   =&gt;  1075,
    MIN_R   =&gt;  100,
    NUM_HILLS =&gt; 250
};

my @heightmap;

makemap();

sub makemap {
    #init heightmap to 0
    for(my $i = 0 ; $i &lt; MAX_Y; $i++){
        my @arr;
        for(my $j = 0; $j &lt; MAX_X; $j++){
            $arr[$j] = 0;
        }
        $heightmap[$i] = \@arr;
    }

    # Start adding hills
    for(my $i = 0; $i &lt; NUM_HILLS; $i++){
        makehill(int(rand(MAX_X)), int(rand(MAX_Y)), int(rand(MAX_R) + MIN_R));
    }
    # normallize
    my $maxvalue = 0;
    for(my $x = 0; $x &lt; MAX_X; $x++){
        for(my $y = 0; $y &lt; MAX_Y; $y++){
            if($heightmap[$x][$y] &gt; $maxvalue){
                $maxvalue = $heightmap[$x][$y];
            }
        }
    }
    for(my $x = 0; $x &lt; MAX_X; $x++){
        for(my $y = 0; $y &lt; MAX_Y; $y++){
            $heightmap[$x][$y] /= $maxvalue;
        }
    }
    # Flatten
    for(my $x = 0; $x &lt; MAX_X; $x++){
        for(my $y = 0; $y &lt; MAX_Y; $y++){
            $heightmap[$x][$y] *= $heightmap[$x][$y];
            $heightmap[$x][$y] *= $heightmap[$x][$y];
            $heightmap[$x][$y] *= $heightmap[$x][$y];
        }
    }
    # Dump to file
    dumpToImg();
    dumpToDb();
}

sub makehill {
    my ($x1, $y1, $r) = @_;
    my $z;
    for(my $x = $x1 - $r; $x &lt; ($x1 + $r); $x++){
        for(my $y = $y1 - $r; $y &lt; ($y1 + $r); $y++){
            my $dx = $x - $x1;
            my $dy = $y - $y1;
            $z = ($r * $r) - (($dx * $dx) + ($dy * $dy));
            if($z &gt; 0 and $x &gt; 0 and $y &gt; 0){
                $heightmap[$x][$y] += $z;
            }
        }
    }
}

sub dumpToDb {
    my $dbh = DBI-&gt;connect("dbi:SQLite:dbname=server.sqlite",'','')
            or die DBI::errstr;
    my $sth = $dbh-&gt;prepare("INSERT INTO map_heights(lat_pt, long_pt, z_pt)".
                            "VALUES(?, ?, ?)");
    for(my $x = 0; $x &lt; MAX_X; $x++){
        for(my $y = 0; $y &lt; MAX_Y; $y++){
            $sth-&gt;execute($x, $y, $heightmap[$x][$y]);
        }
    }
    $dbh-&gt;disconnect();
}

sub dumpToImg {
    my $im = Image::Magick-&gt;new;
    my $junk = MAX_X.'x'.MAX_Y;
    print $junk."\n";
    $im-&gt;Set(size =&gt; $junk);
    $im-&gt;ReadImage('canvas:white');
    warn "$im" if "$im";
    for(my $x = 0; $x &lt; MAX_X; $x++){
        for(my $y = 0; $y &lt; MAX_Y; $y++){
            my $z = $heightmap[$x][$y];
            my @pixel = ($z, $z, $z);
            $im-&gt;SetPixel(x=&gt;$x, y=&gt;$y, color=&gt;\@pixel);
        }
    }
    my $x = $im-&gt;Write('heightmap.png');
    warn "$x" if "$x";
}
I see two things right off the bat that may help:


Calculate $maxvalue inside makehill() so you don't have to calculate it after
Do the normalization and flattening in 1 pass. Also, you can do the flattening in a single function call. You're basically raising each value to the 8th power, so use the power function. I don't know perl real well, but it's usually called pow() and takes a value and an exponent.


The other thing that looks problematic is setting each individual pixel through a function call. Is there any way to pass a buffer of memory to ImageMagick? If so, it would probably faster to do that.