Package org.terasology.utilities.procedural

Source Code of org.terasology.utilities.procedural.Voronoi$VoronoiResult

/*
* Copyright 2013 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.terasology.utilities.procedural;

import org.terasology.math.TeraMath;

import javax.vecmath.Vector2f;
import java.util.Random;

/**
* @author Immortius
*/
public class Voronoi {

    private static final float DENSITY_ADJUSTMENT = 0.39815f;
    private static final float INVERSE_DENSITY_ADJUSTMENT = 1.0f / DENSITY_ADJUSTMENT;

    private Vector2f offset;

    private int[] poissonCount = new int[]{
            4, 3, 1, 1, 1, 2, 4, 2, 2, 2, 5, 1, 0, 2, 1, 2, 2, 0, 4, 3, 2, 1, 2, 1, 3, 2, 2, 4, 2, 2, 5, 1, 2, 3,
            2, 2, 2, 2, 2, 3, 2, 4, 2, 5, 3, 2, 2, 2, 5, 3, 3, 5, 2, 1, 3, 3, 4, 4, 2, 3, 0, 4, 2, 2, 2, 1, 3, 2,
            2, 2, 3, 3, 3, 1, 2, 0, 2, 1, 1, 2, 2, 2, 2, 5, 3, 2, 3, 2, 3, 2, 2, 1, 0, 2, 1, 1, 2, 1, 2, 2, 1, 3,
            4, 2, 2, 2, 5, 4, 2, 4, 2, 2, 5, 4, 3, 2, 2, 5, 4, 3, 3, 3, 5, 2, 2, 2, 2, 2, 3, 1, 1, 4, 2, 1, 3, 3,
            4, 3, 2, 4, 3, 3, 3, 4, 5, 1, 4, 2, 4, 3, 1, 2, 3, 5, 3, 2, 1, 3, 1, 3, 3, 3, 2, 3, 1, 5, 5, 4, 2, 2,
            4, 1, 3, 4, 1, 5, 3, 3, 5, 3, 4, 3, 2, 2, 1, 1, 1, 1, 1, 2, 4, 5, 4, 5, 4, 2, 1, 5, 1, 1, 2, 3, 3, 3,
            2, 5, 2, 3, 3, 2, 0, 2, 1, 1, 4, 2, 1, 3, 2, 1, 2, 2, 3, 2, 5, 5, 3, 4, 5, 5, 2, 4, 4, 5, 3, 2, 2, 2,
            1, 4, 2, 3, 3, 4, 2, 5, 4, 2, 4, 2, 2, 2, 4, 5, 3, 2
    };


    public Voronoi(Random random) {
        offset = new Vector2f(99999 * random.nextFloat(), 99999 * random.nextFloat());
    }

    public static float standardDistanceFunction(Vector2f delta) {
        return delta.x * delta.x + delta.y * delta.y;
    }

    /**
     * @param at
     * @param numPoints Should be <= 5. The number of points to return
     * @return
     */
    public VoronoiResult[] getClosestPoints(Vector2f at, int numPoints) {
        VoronoiResult[] results = new VoronoiResult[numPoints];
        for (VoronoiResult result : results) {
            result.distance = Float.MAX_VALUE;
        }

        at.scale(DENSITY_ADJUSTMENT);
        at.add(offset);

        int cellX = TeraMath.floorToInt(at.x);
        int cellY = TeraMath.floorToInt(at.y);

        processCell(cellX, cellY, at, results);

        Vector2f cellPos = new Vector2f(at);
        cellPos.x -= cellX;
        cellPos.y -= cellY;
        Vector2f distMax = new Vector2f(standardDistanceFunction(new Vector2f(1 - cellPos.x, 0)), standardDistanceFunction(new Vector2f(0, 1 - cellPos.y)));
        Vector2f distMin = new Vector2f(standardDistanceFunction(new Vector2f(cellPos.x, 0)), standardDistanceFunction(new Vector2f(0, cellPos.y)));

        // Test near cells
        if (distMin.x < results[results.length - 1].distance) {
            processCell(cellX - 1, cellY, at, results);
        }
        if (distMin.y < results[results.length - 1].distance) {
            processCell(cellX, cellY - 1, at, results);
        }
        if (distMax.x < results[results.length - 1].distance) {
            processCell(cellX + 1, cellY, at, results);
        }
        if (distMax.y < results[results.length - 1].distance) {
            processCell(cellX, cellY + 1, at, results);
        }

        // Test further cells
        if (distMin.x + distMin.y < results[results.length - 1].distance) {
            processCell(cellX - 1, cellY - 1, at, results);
        }
        if (distMax.x + distMax.y < results[results.length - 1].distance) {
            processCell(cellX + 1, cellY + 1, at, results);
        }
        if (distMin.x + distMax.y < results[results.length - 1].distance) {
            processCell(cellX - 1, cellY + 1, at, results);
        }
        if (distMax.x + distMin.y < results[results.length - 1].distance) {
            processCell(cellX + 1, cellY - 1, at, results);
        }

        for (int i = 0; i < results.length; i++) {
            results[i].delta.scale(INVERSE_DENSITY_ADJUSTMENT);
            results[i].distance *= INVERSE_DENSITY_ADJUSTMENT * INVERSE_DENSITY_ADJUSTMENT;
        }

        return results;
    }

    private long incrementSeed(long last) {
        return (1402024253L * last + 586950981L) & 0xFFFFFFFFL;
    }

    private void processCell(int cellX, int cellY, Vector2f at, VoronoiResult[] results) {
        long seed = (702395077 * cellX + 915488749 * cellY);
        // Number of features
        int count = poissonCount[(int) (seed >> 24)];
        seed = incrementSeed(seed);

        for (int point = 0; point < count; point++) {
            long id = seed;
            seed = incrementSeed(seed);

            float x = (seed + 0.5f) / 4294967296.0f;
            seed = incrementSeed(seed);
            float y = (seed + 0.5f) / 4294967296.0f;
            seed = incrementSeed(seed);
            Vector2f innerPos = new Vector2f(x, y);
            Vector2f delta = new Vector2f(cellX + innerPos.x - at.x, cellY + innerPos.y - at.y);

            float dist = standardDistanceFunction(delta);

            if (dist < results[results.length - 1].distance) {
                int index = results.length - 1;
                while (index > 0 && dist < results[index - 1].distance) {
                    index--;
                }

                for (int i = results.length - 1; i > index; i--) {
                    results[i] = results[i - 1];
                }
                results[index].distance = dist;
                results[index].delta = new Vector2f(delta);
                results[index].id = (int) id;
            }
        }
    }

    public static class VoronoiResult {
        public float distance;
        public Vector2f delta;
        public int id;
    }
}
TOP

Related Classes of org.terasology.utilities.procedural.Voronoi$VoronoiResult

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.