package org.osm2world.core.map_elevation.creation; import static java.lang.Math.*; import java.util.Collection; import org.osm2world.core.math.AxisAlignedBoundingBoxXZ; import org.osm2world.core.math.VectorXYZ; import org.osm2world.core.math.VectorXZ; import org.osm2world.core.math.datastructures.IntersectionGrid; public class InverseDistanceWeightingInterpolator implements TerrainInterpolator { private static final double CUTOFF = 300; private final double negExp; private Collection<VectorXYZ> sites; private IntersectionGrid<VectorXYZ> siteGrid; //TODO: rename IntersectionGrid to something more generic public InverseDistanceWeightingInterpolator() { this(2); } public InverseDistanceWeightingInterpolator(double exponent) { this.negExp = -exponent; } @Override public void setKnownSites(Collection<VectorXYZ> sites) { this.sites = sites; siteGrid = new IntersectionGrid<VectorXYZ>( new AxisAlignedBoundingBoxXZ(sites).pad(CUTOFF/2), CUTOFF, CUTOFF); for (VectorXYZ site : sites) { siteGrid.insert(site); } } @Override public VectorXYZ interpolateEle(VectorXZ pos) { double weightSum = 0; double eleSum = 0; Collection<VectorXYZ>[][] cellArray = siteGrid.getCellArray(); int cellX = siteGrid.cellXForCoord(pos.x, pos.z); int cellZ = siteGrid.cellZForCoord(pos.x, pos.z); for (int i = max(cellX-1, 0); i < min(cellX+2, cellArray.length); i++) { for (int j = max(cellZ-1, 0); j < min(cellZ+2, cellArray[i].length); j++) { Collection<VectorXYZ> sitesInCell = cellArray[i][j]; if (sitesInCell == null) continue; for (VectorXYZ site : sitesInCell) { double distance = site.distanceToXZ(pos); if (distance < CUTOFF) { double weight = pow(distance, negExp); weightSum += weight; eleSum += site.y * weight; } } } } //System.out.println(pos + ": " + eleSum + ", " + weightSum + ", " + eleSum / weightSum); return pos.xyz(eleSum / weightSum); } }