// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.plugins.elevation.grid; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.plugins.elevation.ElevationHelper; public class EleVertex { private static final int NPOINTS = 3; private static final double MIN_DIST = 90; private double avrgEle = Double.NaN; private double area = Double.NaN; private final EleCoordinate[] points = new EleCoordinate[NPOINTS]; public EleVertex(EleCoordinate p1, EleCoordinate p2, EleCoordinate p3) { points[0] = p1; points[1] = p2; points[2] = p3; // compute elevation double z = 0D; boolean eleValid = true; for (EleCoordinate point : points) { if (ElevationHelper.isValidElevation(p1.getEle())) { z += point.getEle(); } else { eleValid = false; break; } } if (eleValid) { avrgEle = z / NPOINTS; } else { avrgEle = ElevationHelper.NO_ELEVATION; } // compute the (approx.!) area of the vertex using heron's formula double a = p1.greatCircleDistance(p2); double b = p2.greatCircleDistance(p3); double c = p1.greatCircleDistance(p3); double s = (a + b + c) / 2D; double sq = s * (s - a) * (s - b) * (s - c); area = Math.sqrt(sq); } public List<EleVertex> divide() { TriangleEdge[] edges = new TriangleEdge[NPOINTS]; int k = 0; for (int i = 0; i < points.length; i++) { EleCoordinate c1 = points[i]; for (int j = i + 1; j < points.length; j++) { EleCoordinate c2 = points[j]; edges[k++] = new TriangleEdge(i, j, c1.greatCircleDistance(c2)); } } /* for (int i = 0; i < edges.length; i++) { TriangleEdge triangleEdge = edges[i]; System.out.println("#" + i + ": " +triangleEdge); }*/ // sort by distance Arrays.sort(edges); // pick the longest edge TriangleEdge longest = edges[0]; //System.out.println("Longest " + longest); EleCoordinate pI = points[longest.getI()]; EleCoordinate pJ = points[longest.getJ()]; EleCoordinate pK = points[longest.getK()]; EleCoordinate newP = getMid(pI, pJ); /* System.out.println(pI); System.out.println(pJ); System.out.println(pK); System.out.println(newP); */ List<EleVertex> res = new ArrayList<>(); res.add(new EleVertex(pI, pK, newP)); res.add(new EleVertex(pJ, pK, newP)); return res; } /** * Checks if vertex requires further processing or is finished. Currently this * method returns <code>true</code>, if the average deviation is < 5m * * @return true, if is finished */ public boolean isFinished() { /*double z = 0D; double avrgEle = getEle(); for (EleCoordinate point : points) { z += (avrgEle - point.getEle()) * (avrgEle - point.getEle()); }*/ // TODO: Check for proper limit return /*z < 75 || */getArea() < (30 * 30); // = 3 * 25 } /** * Gets the approximate area of this vertex in square meters. * * @return the area */ public double getArea() { return area; } /** * Gets the (linear interpolated) mid point of c1 and c2. * * @param c1 the first coordinate * @param c2 the second coordinate * @return the mid point */ public EleCoordinate getMid(EleCoordinate c1, EleCoordinate c2) { double x = (c1.getX() + c2.getX()) / 2.0; double y = (c1.getY() + c2.getY()) / 2.0; double z = (c1.getEle() + c2.getEle()) / 2.0; if (c1.greatCircleDistance(c2) > MIN_DIST) { double hgtZ = ElevationHelper.getSrtmElevation(new LatLon(y, x)); if (ElevationHelper.isValidElevation(hgtZ)) { z = hgtZ; } } return new EleCoordinate(y, x, z); } /** * Gets the coordinate for the given index. * * @param index the index between 0 and NPOINTS: * @return the elevation coordinate instance * @throws IllegalArgumentException, if index is invalid */ public EleCoordinate get(int index) { if (index < 0 || index >= NPOINTS) throw new IllegalArgumentException("Invalid index: " + index); return points[index]; } /** * Gets the average elevation of this vertex. * * @return the ele */ public double getEle() { return avrgEle; } @Override public String toString() { return "EleVertex [avrgEle=" + avrgEle + ", area=" + area + ", points=" + Arrays.toString(points) + ']'; } static class TriangleEdge implements Comparable<TriangleEdge> { private final int i; private final int j; private final double dist; TriangleEdge(int i, int j, double dist) { super(); this.i = i; this.j = j; this.dist = dist; } public int getI() { return i; } public int getJ() { return j; } public int getK() { if (i == 0) { return j == 1 ? 2 : 1; } else if (i == 1) { return j == 0 ? 2 : 0; } else { return j == 0 ? 1 : 0; } } public double getDist() { return dist; } @Override public int compareTo(TriangleEdge o) { return (int) (o.getDist() - dist); } @Override public String toString() { return "TriangleEdge [i=" + i + ", j=" + j + ", dist=" + dist + "]"; } } }