001package sec.geo.kml; 002 003import armyc2.c2sd.graphics2d.PathIterator; 004import sec.sun.awt.geom.AreaIterator; 005import java.util.ArrayList; 006import sec.geo.utilities.StringBuilder; 007 008import sec.geo.shape.*; 009 010public class KmlRenderer { 011 012 private static final String EXCEPTION = "EXCEPTION:"; 013 014 private static final String colorDefault = "ff003fff"; 015 private static final String descriptionField = "#DESCRIPTION#"; 016 private static final String extendedData = "#EXTENDEDDATA#"; 017 private static final String colorField = "#COLOR#"; 018 private static final String nameField = "#NAME#"; 019 private static final String idField = "#ID#"; 020 private static final String placemarkidField = "#PLACEMARKID#"; 021 022 private static final String KML_START = "<Folder id=\"" + idField + "\">\n"; 023 private static final String KML_END = "</Folder>\n"; 024 025 private static final String PLACEMARK_START = "" 026 + " <Placemark id=\"" + placemarkidField + "\">\n" 027 + " <Style>\n" 028 + " <PolyStyle>\n" 029 + " <color>" + colorField + "</color>\n" 030 + " </PolyStyle>\n" 031 + " <LineStyle>\n" 032 + " <color>" + colorField + "</color>\n" 033 + " </LineStyle>\n" 034 + " </Style>\n" 035 + " <name>" + nameField + "</name>\n" 036 + " <description>" + descriptionField + "</description>\n" 037 + " <ExtendedData>" + extendedData + "</ExtendedData>\n" 038 + " <MultiGeometry>\n"; 039 040 private static final String PLACEMARK_END = "" 041 + " </MultiGeometry>\n" 042 + " </Placemark>\n"; 043 044 //private static final String DEFAULT_EXDAT = "<Data name='sid'><value>#ID#</value></Data><Data name='shapeType'><value>#SHAPETYPE#</value></Data><Data name='lat'><value>#LAT#</value></Data><Data name='lon'><value>#LON#</value></Data><Data name='alt'><value>#ALT#</value></Data>"; 045 //private static final String DEFAULT_BLSTY = "<!" + "[CDAT" + "A[" + "$[sid]" +"]]"+">"; 046 public ArrayList<KmlPolygon> renderPolygons(AExtObject ext) { 047 ArrayList<KmlPolygon> polys = new ArrayList<KmlPolygon>(); 048 049 ext.setMaxDistance(200000); 050 //ext.setFlatness(1); 051 //ext.setLimit(3); 052 ext.setFlatness(2); 053 ext.setLimit(8); 054 055 // Render perimeter polys 056 ArrayList<Point> perimeterPoints = new ArrayList<Point>(); 057 PathIterator it = null; 058 AreaIterator ait = null; 059 //PathIterator it = ext.getShape().getPathIterator(null); 060 Object oit = ext.getPathIterator(null); 061 if (oit instanceof PathIterator) { 062 it = (PathIterator) oit; 063 } else if (oit instanceof AreaIterator) { 064 ait = (AreaIterator) oit; 065 } 066 067 Point pre = null; 068 if (it != null) { 069 while (!it.isDone()) { 070 071 double[] strokePoints = new double[6]; 072 int type = it.currentSegment(strokePoints); 073 074 double longitudeDegrees = strokePoints[0]; 075 double latitudeDegrees = strokePoints[1]; 076 if (longitudeDegrees < -180) { 077 longitudeDegrees += 360; 078 } 079 switch (type) { 080 case PathIterator.SEG_MOVETO: 081 case PathIterator.SEG_LINETO: 082 if (pre != null) { 083 ArrayList<Point> ps = new ArrayList<Point>(); 084 ps.add(new Point(pre.getLongitude(), pre.getLatitude(), ext.getMinAltitude())); 085 ps.add(new Point(pre.getLongitude(), pre.getLatitude(), ext.getMaxAltitude())); 086 ps.add(new Point(longitudeDegrees, latitudeDegrees, ext.getMaxAltitude())); 087 ps.add(new Point(longitudeDegrees, latitudeDegrees, ext.getMinAltitude())); 088 ps.add(new Point(pre.getLongitude(), pre.getLatitude(), ext.getMinAltitude())); 089 polys.add(new KmlPolygon(ps, ext.getAltitudeMode())); 090 } 091 pre = new Point(longitudeDegrees, latitudeDegrees); 092 perimeterPoints.add(pre); 093 } 094 it.next(); 095 } 096 } else if (ait != null) { 097 while (!ait.isDone()) { 098 099 double[] strokePoints = new double[6]; 100 int type = ait.currentSegment(strokePoints); 101 102 double longitudeDegrees = strokePoints[0]; 103 double latitudeDegrees = strokePoints[1]; 104 if (longitudeDegrees < -180) { 105 longitudeDegrees += 360; 106 } 107 switch (type) { 108 case PathIterator.SEG_MOVETO: 109 case PathIterator.SEG_LINETO: 110 if (pre != null) { 111 ArrayList<Point> ps = new ArrayList<Point>(); 112 ps.add(new Point(pre.getLongitude(), pre.getLatitude(), ext.getMinAltitude())); 113 ps.add(new Point(pre.getLongitude(), pre.getLatitude(), ext.getMaxAltitude())); 114 ps.add(new Point(longitudeDegrees, latitudeDegrees, ext.getMaxAltitude())); 115 ps.add(new Point(longitudeDegrees, latitudeDegrees, ext.getMinAltitude())); 116 ps.add(new Point(pre.getLongitude(), pre.getLatitude(), ext.getMinAltitude())); 117 polys.add(new KmlPolygon(ps, ext.getAltitudeMode())); 118 } 119 pre = new Point(longitudeDegrees, latitudeDegrees); 120 perimeterPoints.add(pre); 121 } 122 ait.next(); 123 } 124 } 125 // Render top and bottom poly if the perimeter is complete 126 if (perimeterPoints.size() > 0) { 127 // In some weird cases, for routes, when it builds an area, it will drop the closing 128 // point in the shape. Route uses an area. This causes this condition to not execute. 129 // adding the first point to the perimeterPoints fixes the issue, not sure if it causes any 130 // side effects. 131 if (perimeterPoints.get(0).equals(perimeterPoints.get(perimeterPoints.size() - 1))) { 132 133 polys.add(new KmlPolygon(transformPoints(perimeterPoints, ext.getMinAltitude()), ext.getAltitudeMode())); 134 polys.add(new KmlPolygon(transformPoints(perimeterPoints, ext.getMaxAltitude()), ext.getAltitudeMode())); 135 } else { 136 perimeterPoints.add(perimeterPoints.get(0)); 137 138 polys.add(new KmlPolygon(transformPoints(perimeterPoints, ext.getMinAltitude()), ext.getAltitudeMode())); 139 polys.add(new KmlPolygon(transformPoints(perimeterPoints, ext.getMaxAltitude()), ext.getAltitudeMode())); 140 } 141 } 142 143 return polys; 144 } 145 146 //public String getPlacemarkKml(AExtrusion ext, String id, String name, String description, String lineColor, String fillColor) { 147 public String getPlacemarkKml(AExtObject ext, String id, String name, String description, String lineColor, String fillColor) { 148 149 try { 150 StringBuilder sb = new StringBuilder(); 151 ArrayList<KmlPolygon> polys = renderPolygons(ext); 152 sb.append(PLACEMARK_START); 153 int placemarkIdIndex = sb.indexOf(placemarkidField); 154 int placemarkIdLength = placemarkidField.length(); 155 if (id != null) { 156 sb.replace(placemarkIdIndex, placemarkIdIndex + placemarkIdLength, id + "_mg"); 157 } 158 159 int descriptionIndex = sb.indexOf(descriptionField); 160 int descriptionLength = descriptionField.length(); 161 if (description != null) { 162 sb.replace(descriptionIndex, descriptionIndex + descriptionLength, description); 163 } 164 int colorIndex = sb.indexOf(colorField); 165 int colorLength = colorField.length(); 166 if (fillColor != null) { 167 sb.replace(colorIndex, colorIndex + colorLength, fillColor); 168 } else { 169 sb.replace(colorIndex, colorIndex + colorLength, colorDefault); 170 } 171 172 int lineColorIndex = sb.indexOf2(colorField, colorIndex + colorLength); 173 if (lineColor != null) { 174 sb.replace(lineColorIndex, lineColorIndex + colorLength, lineColor); 175 } else { 176 sb.replace(lineColorIndex, lineColorIndex + colorLength, colorDefault); 177 } 178 179 int nameIndex = sb.indexOf(nameField); 180 int nameLength = nameField.length(); 181 if (name != null) { 182 sb.replace(nameIndex, nameIndex + nameLength, name); 183 } 184 185 for (KmlPolygon poly : polys) { 186 187 sb.append(poly.toString()); 188 } 189 190 sb.append(PLACEMARK_END); 191 return sb.toString(); 192 } catch (Exception e) { 193 e.printStackTrace(); 194 return EXCEPTION + e.getMessage(); 195 } 196 197 } 198 199 //public String getKml(AExtrusion ext, String id, String name, String description, String lineColor, String fillColor) { 200 201 public String getKml(Object ext, String id, String name, String description, String lineColor, String fillColor) { 202 try { 203 AExtObject aext = getAExtObject(ext); 204 if (aext.getElements() != null) { 205 return (getTrackKml(ext, id, name, description, lineColor, fillColor)); 206 } 207 StringBuilder sb = new StringBuilder(); 208 sb.append(KML_START); 209 int idIndex = sb.indexOf(idField); 210 int idLength = idField.length(); 211 sb.replace(idIndex, idIndex + idLength, id); 212 sb.append(getPlacemarkKml(aext, id, name, description, lineColor, fillColor)); 213 sb.append(KML_END); 214 return sb.toString(); 215 } catch (Exception e) { 216 e.printStackTrace(); 217 return EXCEPTION + e.getMessage(); 218 } 219 } 220 221 public String getTrackKml(Object ext, String id, String name, String description, String lineColor, String fillColor) { 222 try { 223 AExtObject aext = getAExtObject(ext); 224 StringBuilder sb = new StringBuilder(); 225 sb.append(this.KML_START); 226 int idIndex = sb.indexOf(this.idField); 227 int idLength = idField.length(); 228 sb.replace(idIndex, idIndex + idLength, id); 229 230 ArrayList elements = aext.getElements(); 231 int j = 0; 232 int n = elements.size(); 233 //for (j = 0; j < elements.size(); j++) 234 for (j = 0; j < n; j++) { 235 Route route = (Route) elements.get(j); 236 AExtObject aext2 = new sec.geo.shape.AExtObject(route); 237 sb.append(this.getPlacemarkKml(aext2, id, name, description, lineColor, fillColor)); 238 } 239 240 sb.append(this.KML_END); 241 return sb.toString(); 242 } catch (Exception e) { 243 e.printStackTrace(); 244 return EXCEPTION + e.getMessage(); 245 } 246 } 247 248 public String getCakeKml(Cake com, String id, String name, String description, String lineColor, String fillColor) { 249 StringBuilder sb = new StringBuilder(); 250 //Set<KmlPolygon> polys; 251 sb.append(KML_START); 252 int idIndex = sb.indexOf(idField); 253 int idLength = idField.length(); 254 sb.replace(idIndex, idIndex + idLength, id); 255 256 for (Object ext : com.getElements()) { 257 AExtObject aext = new AExtObject(ext); 258 String extStr = getPlacemarkKml(aext, id, name, description, lineColor, fillColor); 259 260 if (!extStr.startsWith(EXCEPTION)) { 261 sb.append(extStr); 262 } 263 } 264 265 sb.append(KML_END); 266 return sb.toString(); 267 } 268 269 private AExtObject getAExtObject(Object obj) { 270 Line line = null; 271 Route route = null; 272 Circle circle = null; 273 Polyarc polyarc = null; 274 Polygon polygon = null; 275 Orbit orbit = null; 276 Radarc radarc = null; 277 Track track = null; 278 Cake cake = null; 279 Point point = null; 280 AExtObject ext = null; 281 if (obj instanceof Line) { 282 line = (Line) obj; 283 ext = new AExtObject(line); 284 } else if (obj instanceof Route) { 285 route = (Route) obj; 286 ext = new AExtObject(route); 287 } else if (obj instanceof Polyarc) { 288 polyarc = (Polyarc) obj; 289 ext = new AExtObject(polyarc); 290 } else if (obj instanceof Orbit) { 291 orbit = (Orbit) obj; 292 ext = new AExtObject(orbit); 293 } else if (obj instanceof Polygon) { 294 polygon = (Polygon) obj; 295 ext = new AExtObject(polygon); 296 } else if (obj instanceof Circle) { 297 circle = (Circle) obj; 298 ext = new AExtObject(circle); 299 } else if (obj instanceof Radarc) { 300 radarc = (Radarc) obj; 301 ext = new AExtObject(radarc); 302 } else if (obj instanceof Track) { 303 track = (Track) obj; 304 ext = new AExtObject(track); 305 } else if (obj instanceof Cake) { 306 cake = (Cake) obj; 307 ext = new AExtObject(cake); 308 } else if (obj instanceof Point) { 309 point = (Point) obj; 310 ext = new AExtObject(point); 311 } 312 return ext; 313 } 314 315 public String[] getCoords(Object obj) { 316 AExtObject ext = getAExtObject(obj); 317 ArrayList<KmlPolygon> polys = renderPolygons(ext); 318 319 // Iterate through the polygons and produce an array of KML coordinates 320 String[] coords = new String[polys.size()]; 321 int i = 0; 322 for (KmlPolygon poly : polys) { 323 coords[i] = poly.toCoordString(); 324 i++; 325 } 326 return coords; 327 } 328 329 private ArrayList<Point> transformPoints(ArrayList<Point> points, double altitudeMeters) { 330 ArrayList<Point> returnPoints = new ArrayList<Point>(); 331 for (Point p : points) { 332 returnPoints.add(new Point(p.getLongitude(), p.getLatitude(), altitudeMeters)); 333 } 334 return returnPoints; 335 } 336}