001package sec.geo.kml; 002 003import java.util.ArrayList; 004import org.gavaghan.geodesy.Ellipsoid; 005import sec.geo.kml.KmlOptions.AltitudeMode; 006import sec.geo.shape.Point; 007import sec.geo.utilities.StringBuilder; 008 009public class KmlPolygon { 010 011 private final ArrayList<Point> points; 012 013 private AltitudeMode altitudeMode = AltitudeMode.ABSOLUTE; 014 015 protected static final Ellipsoid REFERENCE_ELLIPSOID = Ellipsoid.WGS84; 016 private static final String altitudeModeField = "#ALTITUDEMODE#"; 017 018 private static final String PREFIX = "" 019 + " <Polygon>\n" 020 + " <tessellate>1</tessellate>\n" 021 + " <altitudeMode>" + altitudeModeField + "</altitudeMode>\n" 022 + " <outerBoundaryIs><LinearRing><coordinates>"; 023 private static final String SUFFIX = "" 024 + " </coordinates></LinearRing></outerBoundaryIs>\n" 025 + " </Polygon>\n"; 026 027 public KmlPolygon() { 028 points = new ArrayList<Point>(); 029 } 030 031 public KmlPolygon(ArrayList<Point> points, AltitudeMode altitudeMode) { 032 this(); 033 this.points.addAll(points); 034 this.altitudeMode = altitudeMode; 035 } 036 037 public void addPoint(Point point) { 038 points.add(point); 039 } 040 041 public void addPoints(ArrayList<Point> points) { 042 this.points.addAll(points); 043 } 044 045 @Override 046 public String toString() { 047 StringBuilder sb = new StringBuilder(); 048 049 sb.append(PREFIX); 050 sb.append(toCoordString()); 051 sb.append(SUFFIX); 052 053 int altitudeModeIndex = sb.indexOf(altitudeModeField); 054 int altitudeModeLength = altitudeModeField.length(); 055 if (altitudeMode != null) { 056 sb.replace(altitudeModeIndex, altitudeModeIndex + altitudeModeLength, altitudeMode.toString()); 057 } 058 059 return sb.toString(); 060 } 061 062 public String toCoordString() { 063 StringBuilder sb = new StringBuilder(); 064 065 ArrayList<Point> orderedPoints = getPointsCounterClockwise(); 066 if (orderedPoints == null) { 067 return ""; 068 } 069 070 for (Point point : orderedPoints) { 071 sb.append(point.getLongitude()); 072 sb.append(","); 073 sb.append(point.getLatitude()); 074 sb.append(","); 075 sb.append(point.getAltitude()); 076 sb.append(" "); 077 } 078 079 // Close off the list of coordinates if necessary 080 Point point = orderedPoints.get(0); 081 if (!point.equals(orderedPoints.get(orderedPoints.size() - 1))) { 082 sb.append(point.getLongitude()); 083 sb.append(","); 084 sb.append(point.getLatitude()); 085 sb.append(","); 086 sb.append(point.getAltitude()); 087 sb.append(" "); 088 } 089 090 return sb.toString(); 091 } 092 093 public AltitudeMode getAltitudeMode() { 094 return altitudeMode; 095 } 096 097 public void setAltitudeMode(AltitudeMode altitudeMode) { 098 this.altitudeMode = altitudeMode; 099 } 100 101 public ArrayList<Point> getPointsClockwise() { //did return List 102 if (points == null || points.size() < 3) { 103 return null; 104 } 105 106 //List<Point> result = points.subList(0, points.size()-1); 107 ArrayList<Point> result = subList(points, 0, points.size() - 1); 108 int order = getPointOrder(); 109 if (order < 0) { 110 //Collections.reverse(result); 111 result = reverse(result); 112 return result; 113 } else { 114 return result; 115 } 116 } 117 118 public ArrayList<Point> getPointsCounterClockwise() { //did return List 119 if (points == null || points.size() < 3) { 120 return null; 121 } 122 123 //List<Point> result = points.subList(0, points.size()-1); 124 ArrayList<Point> result = subList(points, 0, points.size() - 1); 125 int order = getPointOrder(); 126 if (order > 0) { 127 //Collections.reverse(result); 128 result = reverse(result); 129 return result; 130 } else { 131 return result; 132 } 133 } 134 135 public int getPointOrder() { 136 if (points == null || points.size() < 3) { 137 return 0; 138 } 139 140 int n = points.size(); 141 int j, k, count = 0; 142 double z; 143 for (int i = 0; i < n; i++) { 144 j = (i + 1) % n; 145 k = (i + 2) % n; 146 z = (points.get(j).getLongitude() - points.get(i).getLongitude()) * (points.get(k).getLatitude() - points.get(i).getLatitude()); 147 z -= (points.get(j).getLatitude() - points.get(i).getLatitude()) * (points.get(k).getLongitude() - points.get(i).getLongitude()); 148 if (z < 0) { 149 count--; 150 } else if (z > 0) { 151 count++; 152 } 153 } 154 if (count > 0) { 155 return -1; //counterclockwise 156 } else if (count < 0) { 157 return 1; //clockwise 158 } else { 159 return 0; //invalid 160 } 161 } 162 /* 163 * ArrayList from fromIndex, inclusive to toIndex, exclusive 164 * 165 */ 166 167 private ArrayList subList(ArrayList al, int fromIndex, int toIndex) { 168 ArrayList result = new ArrayList(); 169 int j = 0; 170 for (j = fromIndex; j < toIndex; j++) { 171 result.add(al.get(j)); 172 } 173 174 return result; 175 } 176 /* 177 * reverses the order of an arraylist 178 */ 179 180 private ArrayList reverse(ArrayList al) { 181 int j = 0; 182 ArrayList result = new ArrayList(); 183 int n = al.size(); 184 //for(j=al.size()-1;j>=0;j--) 185 for (j = n - 1; j >= 0; j--) { 186 result.add(al.get(j)); 187 } 188 return result; 189 } 190 191}