HiveBrain v1.2.0
Get Started
← Back to all entries
patternsqlMinor

Terrain height map generator

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
mapgeneratorheightterrain

Problem

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   =>  2000,
    MAX_Y   =>  2000,
    MAX_R   =>  1075,
    MIN_R   =>  100,
    NUM_HILLS => 250
};

my @heightmap;

makemap();

sub makemap {
    #init heightmap to 0
    for(my $i = 0 ; $i  $maxvalue){
                $maxvalue = $heightmap[$x][$y];
            }
        }
    }
    for(my $x = 0; $x  0 and $x > 0 and $y > 0){
                $heightmap[$x][$y] += $z;
            }
        }
    }
}

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

sub dumpToImg {
    my $im = Image::Magick->new;
    my $junk = MAX_X.'x'.MAX_Y;
    print $junk."\n";
    $im->Set(size => $junk);
    $im->ReadImage('canvas:white');
    warn "$im" if "$im";
    for(my $x = 0; $x SetPixel(x=>$x, y=>$y, color=>\@pixel);
        }
    }
    my $x = $im->Write('heightmap.png');
    warn "$x" if "$x";
}

Solution

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.

Context

StackExchange Code Review Q#101145, answer score: 2

Revisions (0)

No revisions yet.