package sec.geo.kml; import java.util.ArrayList; import org.gavaghan.geodesy.Ellipsoid; import sec.geo.kml.KmlOptions.AltitudeMode; import sec.geo.shape.Point; import sec.geo.utilities.StringBuilder; public class KmlPolygon { private final ArrayList<Point> points; private AltitudeMode altitudeMode = AltitudeMode.ABSOLUTE; protected static final Ellipsoid REFERENCE_ELLIPSOID = Ellipsoid.WGS84; private static final String altitudeModeField = "#ALTITUDEMODE#"; private static final String PREFIX = "" + " <Polygon>\n" + " <tessellate>1</tessellate>\n" + " <altitudeMode>" + altitudeModeField + "</altitudeMode>\n" + " <outerBoundaryIs><LinearRing><coordinates>"; private static final String SUFFIX = "" + " </coordinates></LinearRing></outerBoundaryIs>\n" + " </Polygon>\n"; public KmlPolygon() { points = new ArrayList<Point>(); } public KmlPolygon(ArrayList<Point> points, AltitudeMode altitudeMode) { this(); this.points.addAll(points); this.altitudeMode = altitudeMode; } public void addPoint(Point point) { points.add(point); } public void addPoints(ArrayList<Point> points) { this.points.addAll(points); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(PREFIX); sb.append(toCoordString()); sb.append(SUFFIX); int altitudeModeIndex = sb.indexOf(altitudeModeField); int altitudeModeLength = altitudeModeField.length(); if (altitudeMode != null) { sb.replace(altitudeModeIndex, altitudeModeIndex + altitudeModeLength, altitudeMode.toString()); } return sb.toString(); } public String toCoordString() { StringBuilder sb = new StringBuilder(); ArrayList<Point> orderedPoints = getPointsCounterClockwise(); if (orderedPoints == null) { return ""; } for (Point point : orderedPoints) { sb.append(point.getLongitude()); sb.append(","); sb.append(point.getLatitude()); sb.append(","); sb.append(point.getAltitude()); sb.append(" "); } // Close off the list of coordinates if necessary Point point = orderedPoints.get(0); if (!point.equals(orderedPoints.get(orderedPoints.size() - 1))) { sb.append(point.getLongitude()); sb.append(","); sb.append(point.getLatitude()); sb.append(","); sb.append(point.getAltitude()); sb.append(" "); } return sb.toString(); } public AltitudeMode getAltitudeMode() { return altitudeMode; } public void setAltitudeMode(AltitudeMode altitudeMode) { this.altitudeMode = altitudeMode; } public ArrayList<Point> getPointsClockwise() { //did return List if (points == null || points.size() < 3) { return null; } //List<Point> result = points.subList(0, points.size()-1); ArrayList<Point> result = subList(points, 0, points.size() - 1); int order = getPointOrder(); if (order < 0) { //Collections.reverse(result); result = reverse(result); return result; } else { return result; } } public ArrayList<Point> getPointsCounterClockwise() { //did return List if (points == null || points.size() < 3) { return null; } //List<Point> result = points.subList(0, points.size()-1); ArrayList<Point> result = subList(points, 0, points.size() - 1); int order = getPointOrder(); if (order > 0) { //Collections.reverse(result); result = reverse(result); return result; } else { return result; } } public int getPointOrder() { if (points == null || points.size() < 3) { return 0; } int n = points.size(); int j, k, count = 0; double z; for (int i = 0; i < n; i++) { j = (i + 1) % n; k = (i + 2) % n; z = (points.get(j).getLongitude() - points.get(i).getLongitude()) * (points.get(k).getLatitude() - points.get(i).getLatitude()); z -= (points.get(j).getLatitude() - points.get(i).getLatitude()) * (points.get(k).getLongitude() - points.get(i).getLongitude()); if (z < 0) { count--; } else if (z > 0) { count++; } } if (count > 0) { return -1; //counterclockwise } else if (count < 0) { return 1; //clockwise } else { return 0; //invalid } } /* * ArrayList from fromIndex, inclusive to toIndex, exclusive * */ private ArrayList subList(ArrayList al, int fromIndex, int toIndex) { ArrayList result = new ArrayList(); int j = 0; for (j = fromIndex; j < toIndex; j++) { result.add(al.get(j)); } return result; } /* * reverses the order of an arraylist */ private ArrayList reverse(ArrayList al) { int j = 0; ArrayList result = new ArrayList(); int n = al.size(); //for(j=al.size()-1;j>=0;j--) for (j = n - 1; j >= 0; j--) { result.add(al.get(j)); } return result; } }