Package org.codemap.internal

Source Code of org.codemap.internal.DEMAlgorithm

package org.codemap.internal;

import org.codemap.Location;
import org.codemap.MapAlgorithm;
import org.codemap.util.StopWatch;


/** Creates the digital elevation model of a map. A digital elevation model (DEM) is a raster of z-ordinates for each pixel.
*<p>
* For each location on the map, a hill is added to the digital elevation model. The elevation of a hill at position
* (x0,y0) with height (z) is defined as follows, f(x,y) = z * exp ^ (-0.5 * (dist * factor) ^ 2) where
* dist = sqrt((x - x0) ^ 2 + (y - y0) ^ 2) and factor = k / z. The constant (k) is chosen such that a hill of height
* 100.0 has a diameter of 41% of the map.
*<p>
* The algorithm has been optimized to run fast.
*<p>
* Not thread-safe.
* @author Adrian Kuhn
*
*/
public class DEMAlgorithm extends MapAlgorithm<float[][]> {

    public static final int MAGIC_VALUE = 8*320; // TODO magic number!
    private static final double THRESHOLD = 1.0;
    private float[][] DEM;
    private int radius;

    @Override
    public float[][] call() {
        setup();
        compute();
        return DEM;
    }

    private void compute() {
        StopWatch stopWatch = new StopWatch("DEM").start();
        // TODO a map configuration on map should return locations on map
        for (Location each: map.getDEMLocations()) {
            elevateHill(each, computePie(each));
        }
        stopWatch.printStop();
    }

    private void elevateHill(Location each, float[][] pie) {
        final int y0, x0, top, bottom, left, right;
        y0 = each.py;
        x0 = each.px;
        top = y0 > radius ? 1 - radius : 0 - y0;
        left = x0 > radius ? 1 - radius : 0 - x0;
        bottom = y0 + radius < DEM.length ? radius : DEM.length - y0;
        right = x0 + radius < DEM.length ? radius : DEM.length - x0;
        for (int y = top; y < bottom; y++) {
            int absy = Math.abs(y);
            for (int x = left; x < right; x++) {
                DEM[x+x0][y+y0] += pie
                [Math.max(absy,Math.abs(x))]
                 [Math.min(absy,Math.abs(x))];
            }
        }
    }

    private float[][] computePie(Location each) {
        float[][] pie = new float[DEM.length][];
        double elevationFactor = each.getElevation();
        double distFactor2 = -1.0
        / (elevationFactor * elevationFactor)
        * (MAGIC_VALUE * MAGIC_VALUE)
        / (DEM.length * DEM.length) // bigger hill when there are more pixels
        / 2;
        radius = computePieLoop(pie, elevationFactor, distFactor2);
        return pie;
    }

    private int computePieLoop(float[][] pie, double elevationFactor, double distFactor2) {
        // generate square numbers by summing up all the odd numbers
        for (int n = 0, n2 = 0; n < pie.length; n2 += (++n)+n-1) {
            pie[n] = new float[n+1];
            for (int m = 0, dist2 = n2; m <= n; dist2 += (++m)+m-1) {
                double elevation = elevationFactor * Math.exp(distFactor2 * (double) dist2);
                if (elevation < THRESHOLD) {
                    if (m == 0) return n;
                    break;
                }
                pie[n][m] += elevation - THRESHOLD;
            }
        }
        throw new Error("Should not happen, nach Adam Riese.");
    }

    private void setup() {
        DEM = new float[map.getWidth()][map.getWidth()];
    }


}
TOP

Related Classes of org.codemap.internal.DEMAlgorithm

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.