/*
* Copyright 2015 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.core.world.generator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Encapsulates climate distance calculations for the climate simulator
*/
public class ClimateSimulatorData {
private static final Logger logger = LoggerFactory.getLogger(ClimateSimulator.class);
private float[][] heightmap;
private int size;
public ClimateSimulatorData(float[][] heightmap, int size) {
this.heightmap = heightmap;
this.size = size;
}
public float[][] getHeightmap() {
return heightmap;
}
public int getSize() {
return size;
}
public float[][] initDist(String fromWhat) {
float[][] distArr = new float[size][size];
switch(fromWhat) {
case "water":
distanceFromWater(distArr);
break;
case "poles":
distanceFromPoles(distArr);
break;
case "equator":
distanceFromEquator(distArr);
break;
}
return distArr;
}
private void distanceFromWater(float[][] distArr) {
for (int width = 0; width < size; width++) {
for (int height = 0; height < size; height++) {
float heightFactor = heightmap[height][width] - 1;
if (heightFactor < 0) { // sea
distArr[height][width] = 0;
} else { // land
distArr[height][width] = size;
}
}
}
}
private void distanceFromPoles(float[][] distArr) {
for (int width = 0; width < size; width++) {
for (int height = 0; height < size; height++) {
if (height == 0) { // topOfTheMap
distArr[height][width] = 0;
} else {
distArr[height][width] = size;
}
}
}
}
private void distanceFromEquator(float[][] distArr) {
for (int width = 0; width < size; width++) {
for (int height = 0; height < size; height++) {
if (height == size / 2) { // topOfTheMap
distArr[height][width] = 0;
} else {
distArr[height][width] = size;
}
}
}
}
public float[][] distanceFrom(String fromWhat, float heightInfluence) {
float[][] distArr = initDist(fromWhat);
float currentDistance = 0;
logger.info("Starting distance calculation: {}", fromWhat);
while (currentDistance < size) {
for (int width = 0; width < size; width++) {
for (int height = 0; height < size; height++) {
float currHeight = heightmap[width][height];
if (distArr[width][height] == size) { //Block could update
int posW = (width + 1) % size;
int posH = (height + 1) % size;
int negW = ((width - 1) + size) % size;
int negH = (height - 1 + size) % size;
if (distArr[posW][height] + (heightmap[posW][height] - currHeight) * heightInfluence <= currentDistance
|| distArr[width][posH] + (heightmap[width][posH] - currHeight) * heightInfluence <= currentDistance
|| distArr[negW][height] + (heightmap[negW][height] - currHeight) * heightInfluence <= currentDistance
|| distArr[width][negH] + (heightmap[width][negH] - currHeight) * heightInfluence <= currentDistance) {
//Updates over an edge
distArr[width][height] = currentDistance + 1;
} else if (
distArr[posW][posH] + (heightmap[posW][posH] - currHeight) * heightInfluence <= currentDistance + 0.41421
|| distArr[negW][posH] + (heightmap[negW][posH] - currHeight) * heightInfluence <= currentDistance + 0.41421
|| distArr[posW][negH] + (heightmap[posW][negH] - currHeight) * heightInfluence <= currentDistance + 0.41421
|| distArr[negW][negH] + (heightmap[negW][negH] - currHeight) * heightInfluence <= currentDistance + 0.41421) {
//Updates over the corner
distArr[width][height] = currentDistance + 1.41421f;
}
}
}
}
currentDistance++;
}
//normalize Array
float max = 0;
for (int width = 0; width < size; width++) {
for (int height = 0; height < size; height++) {
max = distArr[width][height] > max ? distArr[width][height] : max;
}
}
for (int width = 0; width < size; width++) {
for (int height = 0; height < size; height++) {
distArr[width][height] /= max;
}
}
//invert if necessary
if (fromWhat.equals("equator")) {
for (int width = 0; width < size; width++) {
for (int height = 0; height < size; height++) {
distArr[width][height] = 1 - distArr[width][height];
}
}
}
return distArr;
}
}