package org.osm2world.core.map_elevation.data; import java.util.ArrayList; import java.util.Collection; import org.osm2world.core.map_data.data.MapArea; import org.osm2world.core.map_data.data.MapElement; import org.osm2world.core.map_elevation.creation.ElevationCalculator; import org.osm2world.core.math.TriangleXYZ; import org.osm2world.core.math.VectorXYZ; import org.osm2world.core.math.VectorXZ; import com.google.common.base.Function; /** * elevation profile for a {@link MapArea} */ public class AreaElevationProfile extends ElevationProfile { private final MapArea area; private Collection<VectorXYZ> pointsWithEle = null; private Function<VectorXZ, VectorXYZ> eleFunction; Collection<TriangleXYZ> triangulation = null; public AreaElevationProfile(MapArea area) { super(); this.area = area; } @Override protected MapElement getElement() { return area; } /** * returns all points on the area where elevation values exist. * This will at least include the outline points. * Points are not sorted in any way. Must not be used before calculation * results have been set using {@link #addPointWithEle(VectorXYZ)} */ @Override public Collection<VectorXYZ> getPointsWithEle() { if (pointsWithEle == null) { throw new IllegalStateException("elevations have not been calculated yet"); } else if (pointsWithEle.size() < 2) { throw new IllegalStateException("an area must have at least two points with elevation"); } return pointsWithEle; } @Override public double getEleAt(final VectorXZ pos) { // if (triangulation == null) { // calculateTriangulation(); // } //TODO: calculate correctly and with better performance. //Should be possible using a triangulation. //temporary solution: find closest point with ele // VectorXYZ closestPoint = Collections.min(pointsWithEle, new Comparator<VectorXYZ>(){ // public int compare(VectorXYZ p1, VectorXYZ p2) { // return Double.compare( // p1.xz().distanceTo(pos), // p2.xz().distanceTo(pos)); // }; // }); // // return closestPoint.y; return eleFunction.apply(pos).y; } @Override public VectorXYZ getWithEle(VectorXZ pos) { //TODO keep in sync with getEleAt return eleFunction.apply(pos); } /** * adds a result of {@link ElevationCalculator}. * Must be called at least once for every outline node */ public void addPointWithEle(VectorXYZ pointWithEle) { if (pointsWithEle == null) { pointsWithEle = new ArrayList<VectorXYZ>(); } this.pointsWithEle.add(pointWithEle); } public void setEleFunction(Function<VectorXZ, VectorXYZ> eleFunction) { this.eleFunction = eleFunction; } @Override public double getMaxEle() { if (pointsWithEle == null) { throw new IllegalStateException("elevations have not been calculated yet"); } double maxEle = Double.MIN_VALUE; for (VectorXYZ pointWithEle : pointsWithEle) { maxEle = Math.max(maxEle, pointWithEle.y); } return maxEle; } @Override public double getMinEle() { if (pointsWithEle == null) { throw new IllegalStateException("elevations have not been calculated yet"); } double minEle = Double.MAX_VALUE; for (VectorXYZ pointWithEle : pointsWithEle) { minEle = Math.min(minEle, pointWithEle.y); } return minEle; } // TODO: finish implementation // /** // * returns a triangulation of the associated area // * (the one returned by {@link #getElement()}), // * with elevation information // */ // public Collection<TriangleXYZ> getTriangulation() { // return triangulation; // } // // /** // * calculates a triangulation of this area // * and writes the result to {@link #triangulation} // */ // private void calculateTriangulation() { // // if (pointsWithEle == null) { // throw new IllegalStateException("elevations have not been calculated yet"); // } else if (pointsWithEle.size() < 2) { // throw new IllegalStateException("an area must have at least two points with elevation"); // } // // Collection<TriangleXZ> trianglesXZ = // TriangulationUtil.triangulate(area.getPolygon()); // // Collection<TriangleXYZ> trianglesXYZ = // new ArrayList<TriangleXYZ>(trianglesXZ.size()); // // for (TriangleXZ triangleXZ : trianglesXZ) { // VectorXYZ v1 = eleProfile.getWithEle(triangleXZ.v1); // VectorXYZ v2 = eleProfile.getWithEle(triangleXZ.v2); // VectorXYZ v3 = eleProfile.getWithEle(triangleXZ.v3); // if (triangleXZ.isClockwise()) { // trianglesXYZ.add(new TriangleXYZ(v3, v2, v1)); // } else { // trianglesXYZ.add(new TriangleXYZ(v1, v2, v3)); // } // } // // } }