001package squidpony.squidgrid.mapping;
002
003import squidpony.squidmath.FastNoise;
004import squidpony.squidmath.NumberTools;
005
006/**
007 * Tools to create maps. Not commonly used outside of code that needs height maps.
008 *
009 * @see WorldMapGenerator WorldMapGenerator is a much-more-detailed kind of map generator.
010 * @author Eben Howard - http://squidpony.com - howard@squidpony.com
011 */
012public class HeightMapFactory {
013    /**
014     * Returns a randomly generated map of doubles that smoothly change nearby. Commonly referred to as a
015     * Height Map. Uses {@link FastNoise} to generate coherent heights. The {@code offset} parameter is
016     * converted to an int seed via {@link NumberTools#doubleToMixedIntBits(double)}, so it can be any
017     * double, even an infinite one, and will still be treated as a valid seed.
018     *
019     * @param width  in cells
020     * @param height in cells
021     * @param offset a double that changes the sampling process; the range doesn't matter
022     * @return the created map as a 2D double array
023     */
024    public static double[][] heightMap(int width, int height, double offset) {
025        double[][] heightMap = new double[width][height];
026        int seed = NumberTools.doubleToMixedIntBits(offset);
027        for (int x = 0; x < width; x++) {
028            for (int y = 0; y < height; y++) {
029                //Get noise; layered2D uses 6 octaves of Simplex noise with a low frequency
030                double n = FastNoise.instance.layered2D(x, y, seed, 6, 0.0125f) * 0.8
031                        // and singleFoam gets a very different type of noise, contributing less though
032                        + FastNoise.instance.singleFoam(~seed, x * 0x1p-4f, y * 0x1p-4f) * 0.2;
033                double xdist = x - width * 0.5;
034                xdist *= xdist;
035                double ydist = y - height * 0.5;
036                ydist *= ydist;
037                double dist = Math.sqrt(xdist + ydist);
038                // drop off height toward the east and west edges so the map kinda tiles
039                heightMap[x][y] = n - Math.max(0, Math.pow(dist / (width * 0.5), 2) - 0.4);
040            }
041        }
042        return heightMap;
043    }
044    private static final FastNoise noise = new FastNoise(1, 0x1p-5f, FastNoise.SIMPLEX_FRACTAL, 6);
045    /**
046     * Returns a randomly generated map of floats. Commonly referred to as a
047     * Height Map. Uses {@link FastNoise} (producing FBM Simplex noise) to generate coherent heights.
048     * Unlike {@link #heightMap(int, int, double)}, this doesn't drop off heights at the east and west edges of the map.
049     * As such, it may be more suitable for local maps than world maps, since it is unlikely to tile east-west.
050     * @param width  in cells
051     * @param height in cells
052     * @param seed   an int that significantly changes the generation process
053     * @return the created map as a 2D float array
054     */
055    public static float[][] heightMapSeeded(int width, int height, int seed) {
056        noise.setSeed(seed);
057        float[][] heights = new float[width][height];
058        for (int x = 0; x < width; x++) {
059            for (int y = 0; y < height; y++) {
060                heights[x][y] = noise.getConfiguredNoise(x, y);
061            }
062        }
063        return heights;
064    }
065}