package NoiseGen.NoiseGenerator;
import util.ValueArray.NativeArray.NativeDoubleArray3D;
import util.Vectors.Vector.Vector3Double;
import java.util.ArrayList;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Created by IntelliJ IDEA.
* Author: Jesse Weiman
* Date: 6/1/12
* Time: 7:55 PM
*/
public class VoronoiGenerator extends SimpleNoiseGenerator {
//TODO: Add option to create random weights for each point
public enum DistanceType {
Quadratic, City
}
public enum ShadingType {
Distance, Solid
}
private int numPoints;
private double maxDistanceX;
private double maxDistanceY;
private double maxDistanceZ;
private ArrayList<Vector3Double> points;
private ArrayList<Double> solidShadingValues;
private DistanceType distanceType = DistanceType.Quadratic;
private ShadingType shadingType = ShadingType.Distance;
public VoronoiGenerator(int numPoints, double maxDistance) {
this(numPoints, maxDistance, maxDistance, maxDistance);
}
public VoronoiGenerator(int numPoints, double maxDistanceX, double maxDistanceY, double maxDistanceZ){
super();
setNumPoints(numPoints);
setMaxDistance(maxDistanceX, maxDistanceY, maxDistanceZ);
init();
}
public VoronoiGenerator(Random random, int numPoints, double maxDistance) {
this(random, numPoints, maxDistance, maxDistance, maxDistance);
}
public VoronoiGenerator(Random random, int numPoints, double maxDistanceX, double maxDistanceY, double maxDistanceZ){
super(random);
setNumPoints(numPoints);
setMaxDistance(maxDistanceX, maxDistanceY, maxDistanceZ);
init();
}
public void init() {
points = new ArrayList<>();
solidShadingValues = new ArrayList<>();
NativeDoubleArray3D xcoords = new NativeDoubleArray3D(getNumPoints(), 1, 1);
NativeDoubleArray3D ycoords = new NativeDoubleArray3D(getNumPoints(), 1, 1);
NativeDoubleArray3D zcoords = new NativeDoubleArray3D(getNumPoints(), 1, 1);
for(int i = 0; i < getNumPoints(); i++){
xcoords.setValue(i, 0, 0, getRandom().nextDouble());
ycoords.setValue(i, 0, 0, getRandom().nextDouble());
zcoords.setValue(i, 0, 0, getRandom().nextDouble());
}
// RangeWrapper xrange = new RangeWrapper(xcoords, 0, getMaxDistanceX());
// RangeWrapper yrange = new RangeWrapper(ycoords, 0, getMaxDistanceY());
// RangeWrapper zrange = new RangeWrapper(zcoords, 0, getMaxDistanceZ());
for(int i = 0; i < getNumPoints(); i++){
// double x = xrange.getValue(i, 0, 0);
// double y = yrange.getValue(i, 0, 0);
// double z = zrange.getValue(i, 0, 0);
double x = xcoords.getValue(i, 0, 0) * getMaxDistanceX();
double y = ycoords.getValue(i, 0, 0) * getMaxDistanceY();
double z = zcoords.getValue(i, 0, 0) * getMaxDistanceZ();
points.add(new Vector3Double(x, y, z));
solidShadingValues.add(getRandom().nextDouble());
}
Logger.getLogger("generator").log(Level.INFO, "Voronoi point list: " + points);
}
public DistanceType getDistanceType() {
return distanceType;
}
public void setDistanceType(DistanceType distanceType) {
this.distanceType = distanceType;
}
public ShadingType getShadingType() {
return shadingType;
}
public void setShadingType(ShadingType shadingType) {
this.shadingType = shadingType;
}
public int getNumPoints() {
return numPoints;
}
public void setNumPoints(int numPoints) {
this.numPoints = numPoints;
}
public void setMaxDistance(Double maxDistanceX, Double maxDistanceY, Double maxDistanceZ) {
this.maxDistanceX = maxDistanceX;
this.maxDistanceY = maxDistanceY;
this.maxDistanceZ = maxDistanceZ;
}
public double getMaxDistanceX() {
return maxDistanceX;
}
public double getMaxDistanceY() {
return maxDistanceY;
}
public double getMaxDistanceZ() {
return maxDistanceZ;
}
/**
* 1- 2- and 3-dimensional NoiseGen algorithms.
*
* @param x
*/
@Override
public Double getValue(Double x) {
Vector3Double px = new Vector3Double(x, (double) 0, (double) 0);
switch (shadingType) {
case Distance:
return getDistance1D(getClosestPoint1D(x), px);
case Solid:
return solidShadingValues.get(points.indexOf(getClosestPoint1D(x)));
default:
return getDistance1D(getClosestPoint1D(x), px);
}
}
@Override
public Double getValue(Double x, Double y) {
Vector3Double pxy = new Vector3Double(x, y, (double) 0);
switch (shadingType) {
case Distance:
return getDistance2D(getClosestPoint2D(x, y), pxy);
case Solid:
return solidShadingValues.get(points.indexOf(getClosestPoint2D(x, y)));
default:
return getDistance2D(getClosestPoint2D(x, y), pxy);
}
}
@Override
public Double getValue(Double x, Double y, Double z) {
Vector3Double pxyz = new Vector3Double(x, y, z);
switch (shadingType) {
case Distance:
return getDistance3D(getClosestPoint3D(x, y, z), pxyz);
case Solid:
return solidShadingValues.get(points.indexOf(getClosestPoint3D(x, y, z)));
default:
return getDistance3D(getClosestPoint3D(x, y, z), pxyz);
}
}
private Vector3Double getClosestPoint1D(double x) {
Vector3Double refPoint = new Vector3Double(x, (double) 0, (double) 0);
Vector3Double currentPoint = null;
double currentDistance = Double.MAX_VALUE;
for (Vector3Double p : points) {
if (getDistance1D(p, refPoint) < currentDistance) {
currentPoint = p;
currentDistance = getDistance1D(p, refPoint);
}
}
return currentPoint;
}
private Vector3Double getClosestPoint2D(double x, double y) {
Vector3Double refPoint = new Vector3Double(x, y, (double) 0);
Vector3Double currentPoint = null;
double currentDistance = Double.MAX_VALUE;
for (Vector3Double p : points) {
if (getDistance2D(p, refPoint) < currentDistance) {
currentPoint = p;
currentDistance = getDistance2D(p, refPoint);
}
}
return currentPoint;
}
private Vector3Double getClosestPoint3D(double x, double y, double z) {
Vector3Double refPoint = new Vector3Double(x, y, z);
Vector3Double currentPoint = null;
double currentDistance = Double.MAX_VALUE;
for (Vector3Double p : points) {
if (getDistance3D(p, refPoint) < currentDistance) {
currentPoint = p;
currentDistance = getDistance3D(p, refPoint);
}
}
return currentPoint;
}
private double getDistance1D(Vector3Double p1, Vector3Double p2) {
return Math.abs(p1.getX() - p2.getX());
}
private double getDistance2D(Vector3Double p1, Vector3Double p2) {
switch (distanceType) {
case Quadratic:
return Math.sqrt(Math.pow(p1.getX() - p2.getX(), 2) + Math.pow(p1.getY() - p2.getY(), 2));
case City:
return Math.abs(p1.getX() - p2.getX()) + Math.abs(p1.getY() - p2.getY());
default:
return Math.sqrt(Math.pow(p1.getX() - p2.getX(), 2) + Math.pow(p1.getY() - p2.getY(), 2));
}
}
private double getDistance3D(Vector3Double p1, Vector3Double p2) {
switch (distanceType) {
case Quadratic:
return Math.sqrt(Math.pow(p1.getX() - p2.getX(), 2) + Math.pow(p1.getY() - p2.getY(), 2) + Math.pow(p1.getZ() - p2.getZ(), 2));
case City:
return Math.abs(p1.getX() - p2.getX()) + Math.abs(p1.getY() - p2.getY()) + Math.abs(p1.getZ() - p2.getZ());
default:
return Math.sqrt(Math.pow(p1.getX() - p2.getX(), 2) + Math.pow(p1.getY() - p2.getY(), 2) + Math.pow(p1.getZ() - p2.getZ(), 2));
}
}
}