001package armyc2.c5isr.web.render; 002 003import android.graphics.Bitmap; 004import android.graphics.Typeface; 005 006import java.util.ArrayList; 007import java.util.Collections; 008import java.util.Map; 009import java.util.logging.Level; 010 011import armyc2.c5isr.JavaLineArray.POINT2; 012import armyc2.c5isr.JavaTacticalRenderer.TGLight; 013import armyc2.c5isr.RenderMultipoints.clsRenderer; 014import armyc2.c5isr.graphics2d.BasicStroke; 015import armyc2.c5isr.graphics2d.Point2D; 016import armyc2.c5isr.graphics2d.Rectangle; 017import armyc2.c5isr.renderer.utilities.Color; 018import armyc2.c5isr.renderer.utilities.DrawRules; 019import armyc2.c5isr.renderer.utilities.ErrorLogger; 020import armyc2.c5isr.renderer.utilities.IPointConversion; 021import armyc2.c5isr.renderer.utilities.MSLookup; 022import armyc2.c5isr.renderer.utilities.MilStdAttributes; 023import armyc2.c5isr.renderer.utilities.MilStdSymbol; 024import armyc2.c5isr.renderer.utilities.Modifiers; 025import armyc2.c5isr.renderer.utilities.RendererSettings; 026import armyc2.c5isr.renderer.utilities.RendererUtilities; 027import armyc2.c5isr.renderer.utilities.ShapeInfo; 028import armyc2.c5isr.renderer.utilities.SymbolUtilities; 029import armyc2.c5isr.web.render.utilities.Basic3DShapes; 030import armyc2.c5isr.web.render.utilities.JavaRendererUtilities; 031import armyc2.c5isr.web.render.utilities.Point3D; 032import armyc2.c5isr.web.render.utilities.ShapeInfo3D; 033 034public class Shape3DHandler { 035 public static String RenderMilStd3dSymbol(String id, 036 String name, 037 String description, 038 String symbolCode, 039 String controlPoints, 040 String altitudeMode, 041 Double scale, 042 String bbox, 043 Map<String, String> symbolModifiers, 044 Map<String, String> symbolAttributes, 045 int format) { 046 //System.out.println("MultiPointHandler.RenderSymbol()"); 047 boolean normalize = true; 048 //Double controlLat = 0.0; 049 //Double controlLong = 0.0; 050 //Double metPerPix = GeoPixelConversion.metersPerPixel(scale); 051 //String bbox2=getBoundingRectangle(controlPoints,bbox); 052 StringBuilder jsonOutput = new StringBuilder(); 053 String jsonContent = ""; 054 055 Rectangle rect = null; 056 String[] coordinates = controlPoints.split(" "); 057 TGLight tgl = new TGLight(); 058 ArrayList<ShapeInfo3D> shapes = new ArrayList<ShapeInfo3D>(); 059 ArrayList<ShapeInfo3D> modifiers = new ArrayList<ShapeInfo3D>(); 060 //ArrayList<Point2D> pixels = new ArrayList<Point2D>(); 061 ArrayList<Point2D> geoCoords = new ArrayList<Point2D>(); 062 int len = coordinates.length; 063 //diagnostic create geoCoords here 064 Point2D coordsUL = null; 065 066 // 3D default colors 067 if (symbolAttributes.get(MilStdAttributes.LineColor) == null) { 068 Color defaultColor = SymbolUtilities.getLineColorOfAffiliation(symbolCode); 069 if (defaultColor == null) { 070 defaultColor = new Color(Color.BLACK); 071 } 072 symbolAttributes.put(MilStdAttributes.LineColor, defaultColor.toHexString()); 073 } 074 if (symbolAttributes.get(MilStdAttributes.FillColor) == null) { 075 Color defaultColor = SymbolUtilities.getFillColorOfAffiliation(symbolCode); 076 if (defaultColor == null) { 077 defaultColor = new Color(Color.WHITE); 078 } 079 defaultColor.setAlpha(170); 080 symbolAttributes.put(MilStdAttributes.FillColor, defaultColor.toHexString()); 081 } 082 083 if (altitudeMode == null || altitudeMode.equals("clampToGround")) 084 altitudeMode = "absolute"; 085 086 if (!JavaRendererUtilities.is3dSymbol(symbolCode)) { 087 String basicID = SymbolUtilities.getBasicSymbolID(symbolCode); 088 final String errorMsg = "Basic ID: " + basicID + " is not a 3D Symbol"; 089 String ErrorOutput = ""; 090 ErrorOutput += ("{\"type\":\"error\",\"error\":\"There was an error creating the 3D MilStdSymbol " + symbolCode + " - ID: " + id + " - "); 091 ErrorOutput += errorMsg; //reason for error 092 ErrorOutput += ("\"}"); 093 ErrorLogger.LogMessage("Shape3DHandler", "RenderMilStd3dSymbol", errorMsg, Level.FINE); 094 return ErrorOutput; 095 } 096 097 String symbolIsValid = MultiPointHandler.canRenderMultiPoint(symbolCode, symbolModifiers, len); 098 if (!symbolIsValid.equals("true")) { 099 String ErrorOutput = ""; 100 ErrorOutput += ("{\"type\":\"error\",\"error\":\"There was an error creating the 3D MilStdSymbol " + symbolCode + " - ID: " + id + " - "); 101 ErrorOutput += symbolIsValid; //reason for error 102 ErrorOutput += ("\"}"); 103 ErrorLogger.LogMessage("Shape3DHandler", "RenderMilStd3dSymbol", symbolIsValid, Level.WARNING); 104 return ErrorOutput; 105 } 106 107 if (MSLookup.getInstance().getMSLInfo(symbolCode).getDrawRule() != DrawRules.AREA10) // AREA10 can support infinite points 108 len = Math.min(len, MSLookup.getInstance().getMSLInfo(symbolCode).getMaxPointCount()); 109 for (int i = 0; i < len; i++) { 110 String[] coordPair = coordinates[i].split(","); 111 Double latitude = Double.valueOf(coordPair[1].trim()).doubleValue(); 112 Double longitude = Double.valueOf(coordPair[0].trim()).doubleValue(); 113 geoCoords.add(new Point2D.Double(longitude, latitude)); 114 } 115 ArrayList<POINT2> tgPoints = null; 116 IPointConversion ipc = null; 117 118 //Deutch moved section 6-29-11 119 Double left = 0.0; 120 Double right = 0.0; 121 Double top = 0.0; 122 Double bottom = 0.0; 123 Point2D temp = null; 124 Point2D ptGeoUL = null; 125 int width = 0; 126 int height = 0; 127 int leftX = 0; 128 int topY = 0; 129 int bottomY = 0; 130 int rightX = 0; 131 int j = 0; 132 ArrayList<Point2D> bboxCoords = null; 133 if (bbox != null && bbox.equals("") == false) { 134 String[] bounds = null; 135 if (bbox.contains(" "))//trapezoid 136 { 137 bboxCoords = new ArrayList<Point2D>(); 138 double x = 0; 139 double y = 0; 140 String[] coords = bbox.split(" "); 141 String[] arrCoord; 142 for (String coord : coords) { 143 arrCoord = coord.split(","); 144 x = Double.valueOf(arrCoord[0]); 145 y = Double.valueOf(arrCoord[1]); 146 bboxCoords.add(new Point2D.Double(x, y)); 147 } 148 //use the upper left corner of the MBR containing geoCoords 149 //to set the converter 150 ptGeoUL = MultiPointHandler.getGeoUL(bboxCoords); 151 left = ptGeoUL.getX(); 152 top = ptGeoUL.getY(); 153 String bbox2 = MultiPointHandler.getBboxFromCoords(bboxCoords); 154 scale = MultiPointHandler.getReasonableScale(bbox2, scale); 155 ipc = new PointConverter(left, top, scale); 156 Point2D ptPixels = null; 157 Point2D ptGeo = null; 158 int n = bboxCoords.size(); 159 //for (j = 0; j < bboxCoords.size(); j++) 160 for (j = 0; j < n; j++) { 161 ptGeo = bboxCoords.get(j); 162 ptPixels = ipc.GeoToPixels(ptGeo); 163 x = ptPixels.getX(); 164 y = ptPixels.getY(); 165 if (x < 20) { 166 x = 20; 167 } 168 if (y < 20) { 169 y = 20; 170 } 171 ptPixels.setLocation(x, y); 172 //end section 173 bboxCoords.set(j, (Point2D) ptPixels); 174 } 175 } else//rectangle 176 { 177 bounds = bbox.split(","); 178 left = Double.valueOf(bounds[0]); 179 right = Double.valueOf(bounds[2]); 180 top = Double.valueOf(bounds[3]); 181 bottom = Double.valueOf(bounds[1]); 182 scale = MultiPointHandler.getReasonableScale(bbox, scale); 183 ipc = new PointConverter(left, top, scale); 184 } 185 186 Point2D pt2d = null; 187 if (bboxCoords == null) { 188 pt2d = new Point2D.Double(left, top); 189 temp = ipc.GeoToPixels(pt2d); 190 191 leftX = (int) temp.getX(); 192 topY = (int) temp.getY(); 193 194 pt2d = new Point2D.Double(right, bottom); 195 temp = ipc.GeoToPixels(pt2d); 196 197 bottomY = (int) temp.getY(); 198 rightX = (int) temp.getX(); 199 //diagnostic clipping does not work at large scales 200// if(scale>10e6) 201// { 202// //diagnostic replace above by using a new ipc based on the coordinates MBR 203// coordsUL=getGeoUL(geoCoords); 204// temp = ipc.GeoToPixels(coordsUL); 205// left=coordsUL.getX(); 206// top=coordsUL.getY(); 207// //shift the ipc to coordsUL origin so that conversions will be more accurate for large scales. 208// ipc = new PointConverter(left, top, scale); 209// //shift the rect to compenstate for the shifted ipc so that we can maintain the original clipping area. 210// leftX -= (int)temp.getX(); 211// rightX -= (int)temp.getX(); 212// topY -= (int)temp.getY(); 213// bottomY -= (int)temp.getY(); 214// //end diagnostic 215// } 216 //end section 217 218 width = (int) Math.abs(rightX - leftX); 219 height = (int) Math.abs(bottomY - topY); 220 221 rect = new Rectangle(leftX, topY, width, height); 222 } 223 } else { 224 rect = null; 225 } 226 //end section 227 228// for (int i = 0; i < len; i++) { 229// String[] coordPair = coordinates[i].split(","); 230// Double latitude = Double.valueOf(coordPair[1].trim()); 231// Double longitude = Double.valueOf(coordPair[0].trim()); 232// geoCoords.add(new Point2D.Double(longitude, latitude)); 233// } 234 if (ipc == null) { 235 Point2D ptCoordsUL = MultiPointHandler.getGeoUL(geoCoords); 236 ipc = new PointConverter(ptCoordsUL.getX(), ptCoordsUL.getY(), scale); 237 } 238 //if (crossesIDL(geoCoords) == true) 239// if(Math.abs(right-left)>180) 240// { 241// normalize = true; 242// ((PointConverter)ipc).set_normalize(true); 243// } 244// else { 245// normalize = false; 246// ((PointConverter)ipc).set_normalize(false); 247// } 248 249 //seems to work ok at world view 250// if (normalize) { 251// NormalizeGECoordsToGEExtents(0, 360, geoCoords); 252// } 253 254 //M. Deutch 10-3-11 255 //must shift the rect pixels to synch with the new ipc 256 //the old ipc was in synch with the bbox, so rect x,y was always 0,0 257 //the new ipc synchs with the upper left of the geocoords so the boox is shifted 258 //and therefore the clipping rectangle must shift by the delta x,y between 259 //the upper left corner of the original bbox and the upper left corner of the geocoords 260 ArrayList<Point2D> geoCoords2 = new ArrayList<Point2D>(); 261 geoCoords2.add(new Point2D.Double(left, top)); 262 geoCoords2.add(new Point2D.Double(right, bottom)); 263 264// if (normalize) { 265// NormalizeGECoordsToGEExtents(0, 360, geoCoords2); 266// } 267 268 //disable clipping 269 if (MultiPointHandler.ShouldClipSymbol(symbolCode) == false) 270 if (MultiPointHandler.crossesIDL(geoCoords) == false) { 271 rect = null; 272 bboxCoords = null; 273 } 274 275 tgl.set_SymbolId(symbolCode);// "GFGPSLA---****X" AMBUSH symbol code 276 tgl.set_Pixels(null); 277 278 try { 279 280 //String fillColor = null; 281 MilStdSymbol mSymbol = new MilStdSymbol(symbolCode, null, geoCoords, null); 282 283 if (format == WebRenderer.OUTPUT_FORMAT_GEOSVG) { 284 // Use dash array and hatch pattern fill for SVG output 285 symbolAttributes.put(MilStdAttributes.UseDashArray, "true"); 286 symbolAttributes.put(MilStdAttributes.UsePatternFill, "true"); 287 } 288 289 if (symbolModifiers != null || symbolAttributes != null) { 290 MultiPointHandler.populateModifiers(symbolModifiers, symbolAttributes, mSymbol); 291 } else { 292 mSymbol.setFillColor(null); 293 } 294 295 if (bboxCoords == null) { 296 Rectangle clipBounds = MultiPointHandler.getOverscanClipBounds(rect, ipc); 297 clsRenderer.renderWithPolylines(mSymbol, ipc, clipBounds); 298 } else { 299 clsRenderer.renderWithPolylines(mSymbol, ipc, bboxCoords); 300 } 301 302 // Convert 2D shape to 3D 303 if (MSLookup.getInstance().getMSLInfo(symbolCode).getDrawRule() == DrawRules.CORRIDOR1) { 304 // Remove circles from air corridor for 3d 305 // Set line color for other shapes 306 for (int i = 0; i < mSymbol.getSymbolShapes().size() - 1; i++) { 307 mSymbol.getSymbolShapes().get(i).setLineColor(mSymbol.getSymbolShapes().get(mSymbol.getSymbolShapes().size() - 1).getLineColor()); 308 } 309 mSymbol.getSymbolShapes().remove(mSymbol.getSymbolShapes().size() - 1); 310 Collections.reverse(mSymbol.getSymbolShapes()); 311 } 312 // Confirm there are at least two altitudes per shape 313 ArrayList<Double> altitudes = mSymbol.getModifiers_AM_AN_X(Modifiers.X_ALTITUDE_DEPTH); 314 if (altitudes.size() == 1) { 315 altitudes.add(0, 0.0); 316 } 317 final Double lastAlt = altitudes.get(altitudes.size() - 1); 318 final Double nextToLastAlt = altitudes.get(altitudes.size() - 2); 319 while (altitudes.size() < mSymbol.getSymbolShapes().size() * 2) { 320 altitudes.add(nextToLastAlt); 321 altitudes.add(lastAlt); 322 } 323 for (int shapeIndex = 0; shapeIndex < mSymbol.getSymbolShapes().size(); shapeIndex++) { 324 final Double minAlt = altitudes.get(shapeIndex * 2); 325 final Double maxAlt = altitudes.get((shapeIndex * 2) + 1); 326 final ShapeInfo oldShape = mSymbol.getSymbolShapes().get(shapeIndex); 327 328 ShapeInfo3D bottomShape = new ShapeInfo3D(); 329 bottomShape.setShapeType(oldShape.getShapeType()); 330 bottomShape.setStroke(oldShape.getStroke()); 331 bottomShape.setLineColor(oldShape.getLineColor()); 332 bottomShape.setFillColor(oldShape.getFillColor()); 333 bottomShape.setPatternFillImage(oldShape.getPatternFillImage()); 334 bottomShape.setPolylines3D(new ArrayList<>()); 335 ShapeInfo3D topShape = new ShapeInfo3D(); 336 topShape.setShapeType(oldShape.getShapeType()); 337 topShape.setStroke(oldShape.getStroke()); 338 topShape.setLineColor(oldShape.getLineColor()); 339 topShape.setFillColor(oldShape.getFillColor()); 340 topShape.setPatternFillImage(oldShape.getPatternFillImage()); 341 topShape.setPolylines3D(new ArrayList<>()); 342 343 for (int polyLineIndex = 0; polyLineIndex < oldShape.getPolylines().size(); polyLineIndex++) { 344 final ArrayList<Point2D> polyline = oldShape.getPolylines().get(polyLineIndex); 345 bottomShape.getPolylines3D().add(new ArrayList<Point3D>()); 346 topShape.getPolylines3D().add(new ArrayList<Point3D>()); 347 for (int ptIndex = 0; ptIndex < polyline.size(); ptIndex++) { 348 final Point2D pt = polyline.get(ptIndex); 349 final Point2D pt2 = polyline.get((ptIndex + 1) % polyline.size()); 350 bottomShape.getPolylines3D().get(polyLineIndex).add(new Point3D(pt, minAlt)); 351 topShape.getPolylines3D().get(polyLineIndex).add(new Point3D(pt, maxAlt)); 352 353 ShapeInfo3D sideShape = new ShapeInfo3D(); 354 sideShape.setShapeType(oldShape.getShapeType()); 355 sideShape.setStroke(oldShape.getStroke()); 356 sideShape.setLineColor(oldShape.getLineColor()); 357 sideShape.setFillColor(oldShape.getFillColor()); 358 sideShape.setPatternFillImage(oldShape.getPatternFillImage()); 359 sideShape.setPolylines3D(new ArrayList<ArrayList<Point3D>>()); 360 sideShape.getPolylines3D().add(new ArrayList<>()); 361 sideShape.getPolylines3D().get(0).add(new Point3D(pt, minAlt)); 362 sideShape.getPolylines3D().get(0).add(new Point3D(pt2, minAlt)); 363 sideShape.getPolylines3D().get(0).add(new Point3D(pt2, maxAlt)); 364 sideShape.getPolylines3D().get(0).add(new Point3D(pt, maxAlt)); 365 sideShape.getPolylines3D().get(0).add(new Point3D(pt, minAlt)); 366 shapes.add(sideShape); 367 } 368 } 369 shapes.add(bottomShape); 370 shapes.add(topShape); 371 } 372 373 if (!mSymbol.getSymbolShapes().isEmpty() && !mSymbol.getModifierShapes().isEmpty()) { 374 final double modifierAlt = Collections.max(altitudes.subList(0, mSymbol.getSymbolShapes().size() * 2)); 375 for (ShapeInfo oldShape : mSymbol.getModifierShapes()) { 376 ShapeInfo3D modShape = new ShapeInfo3D(); 377 modShape.setModifierString(oldShape.getModifierString()); 378 modShape.setModifierPosition(new Point3D(oldShape.getModifierPosition(), modifierAlt)); 379 modShape.setModifierAngle(oldShape.getModifierAngle()); 380 modShape.setTextJustify(oldShape.getTextJustify()); 381 modShape.setModifierImage(oldShape.getModifierImage()); 382 modifiers.add(modShape); 383 } 384 } 385 386 if (format == WebRenderer.OUTPUT_FORMAT_KML) { 387 Color textColor = mSymbol.getTextColor(); 388 if (textColor == null) textColor = mSymbol.getLineColor(); 389 390 jsonContent = KMLize(id, name, description, symbolCode, shapes, modifiers, ipc, normalize, textColor, altitudeMode, mSymbol.get_WasClipped()); 391 jsonOutput.append(jsonContent); 392 } else if (format == WebRenderer.OUTPUT_FORMAT_GEOJSON) { 393 jsonOutput.append("{\"type\":\"FeatureCollection\",\"features\":"); 394 jsonContent = GeoJSONize(shapes, modifiers, ipc, normalize, mSymbol.getTextColor(), mSymbol.getTextBackgroundColor()); 395 jsonOutput.append(jsonContent); 396 397 //moving meta data properties to the last feature with no coords as feature collection doesn't allow properties 398 jsonOutput.replace(jsonOutput.toString().length() - 1, jsonOutput.toString().length(), ""); 399 if (jsonContent.length() > 2) jsonOutput.append(","); 400 jsonOutput.append("{\"type\": \"Feature\",\"geometry\": { \"type\": \"Polygon\",\"coordinates\": [ ]}"); 401 402 jsonOutput.append(",\"properties\":{\"id\":\""); 403 jsonOutput.append(id); 404 jsonOutput.append("\",\"name\":\""); 405 jsonOutput.append(name); 406 jsonOutput.append("\",\"description\":\""); 407 jsonOutput.append(description); 408 jsonOutput.append("\",\"symbolID\":\""); 409 jsonOutput.append(symbolCode); 410 jsonOutput.append("\",\"wasClipped\":\""); 411 jsonOutput.append(String.valueOf(mSymbol.get_WasClipped())); 412 jsonOutput.append("\"}}]}"); 413 } 414 } catch (Exception exc) { 415 String st = JavaRendererUtilities.getStackTrace(exc); 416 jsonOutput = new StringBuilder(); 417 jsonOutput.append("{\"type\":\"error\",\"error\":\"There was an error creating the 3D MilStdSymbol ").append(symbolCode).append(": ").append("- "); 418 jsonOutput.append(exc.getMessage()).append(" - "); 419 jsonOutput.append(st); 420 jsonOutput.append("\"}"); 421 422 ErrorLogger.LogException("Shape3DHandler", "RenderMilStd3dSymbol", exc); 423 } 424 425 boolean debug = false; 426 if (debug == true) { 427 System.out.println("Symbol Code: " + symbolCode); 428 System.out.println("Scale: " + scale); 429 System.out.println("BBOX: " + bbox); 430 if (controlPoints != null) { 431 System.out.println("Geo Points: " + controlPoints); 432 } 433 if (tgl != null && tgl.get_Pixels() != null)//pixels != null 434 { 435 System.out.println("Pixel: " + tgl.get_Pixels().toString()); 436 } 437 if (bbox != null) { 438 System.out.println("geo bounds: " + bbox); 439 } 440 if (rect != null) { 441 System.out.println("pixel bounds: " + rect.toString()); 442 } 443 if (jsonOutput != null) { 444 System.out.println(jsonOutput.toString()); 445 } 446 } 447 448 ErrorLogger.LogMessage("Shape3DHandler", "RenderMilStd3dSymbol()", "exit RenderMilStd3dSymbol", Level.FINER); 449 return jsonOutput.toString(); 450 } 451 452 public static String RenderBasic3DShape(String id, 453 String name, 454 String description, 455 int basicShapeType, 456 String controlPoints, 457 String altitudeMode, 458 Double scale, 459 String bbox, 460 Map<String, String> symbolModifiers, 461 Map<String, String> symbolAttributes, 462 int format) { 463 boolean normalize = true; 464 //Double controlLat = 0.0; 465 //Double controlLong = 0.0; 466 //Double metPerPix = GeoPixelConversion.metersPerPixel(scale); 467 //String bbox2=getBoundingRectangle(controlPoints,bbox); 468 StringBuilder jsonOutput = new StringBuilder(); 469 String jsonContent = ""; 470 471 Rectangle rect = null; 472 String[] coordinates = controlPoints.split(" "); 473 ArrayList<ShapeInfo3D> shapes = new ArrayList<ShapeInfo3D>(); 474 ArrayList<ShapeInfo3D> modifiers = new ArrayList<ShapeInfo3D>(); 475 //ArrayList<Point2D> pixels = new ArrayList<Point2D>(); 476 ArrayList<Point2D> geoCoords = new ArrayList<Point2D>(); 477 int len = coordinates.length; 478 //diagnostic create geoCoords here 479 Point2D coordsUL = null; 480 final String symbolCode = ""; 481 482 // 3D default colors 483 if (symbolAttributes.get(MilStdAttributes.LineColor) == null) { 484 symbolAttributes.put(MilStdAttributes.LineColor, Color.BLACK.toHexString()); 485 } 486 if (symbolAttributes.get(MilStdAttributes.FillColor) == null) { 487 Color defaultColor = new Color(255, 255, 255, 170); 488 symbolAttributes.put(MilStdAttributes.FillColor, defaultColor.toHexString()); 489 } 490 491 if (altitudeMode == null || altitudeMode.equals("clampToGround")) 492 altitudeMode = "absolute"; 493 494 for (int i = 0; i < len; i++) { 495 String[] coordPair = coordinates[i].split(","); 496 Double latitude = Double.valueOf(coordPair[1].trim()).doubleValue(); 497 Double longitude = Double.valueOf(coordPair[0].trim()).doubleValue(); 498 geoCoords.add(new Point2D.Double(longitude, latitude)); 499 } 500 ArrayList<POINT2> tgPoints = null; 501 IPointConversion ipc = null; 502 503 //Deutch moved section 6-29-11 504 Double left = 0.0; 505 Double right = 0.0; 506 Double top = 0.0; 507 Double bottom = 0.0; 508 Point2D temp = null; 509 Point2D ptGeoUL = null; 510 int width = 0; 511 int height = 0; 512 int leftX = 0; 513 int topY = 0; 514 int bottomY = 0; 515 int rightX = 0; 516 int j = 0; 517 ArrayList<Point2D> bboxCoords = null; 518 if (bbox != null && bbox.equals("") == false) { 519 String[] bounds = null; 520 if (bbox.contains(" "))//trapezoid 521 { 522 bboxCoords = new ArrayList<Point2D>(); 523 double x = 0; 524 double y = 0; 525 String[] coords = bbox.split(" "); 526 String[] arrCoord; 527 for (String coord : coords) { 528 arrCoord = coord.split(","); 529 x = Double.valueOf(arrCoord[0]); 530 y = Double.valueOf(arrCoord[1]); 531 bboxCoords.add(new Point2D.Double(x, y)); 532 } 533 //use the upper left corner of the MBR containing geoCoords 534 //to set the converter 535 ptGeoUL = MultiPointHandler.getGeoUL(bboxCoords); 536 left = ptGeoUL.getX(); 537 top = ptGeoUL.getY(); 538 String bbox2 = MultiPointHandler.getBboxFromCoords(bboxCoords); 539 scale = MultiPointHandler.getReasonableScale(bbox2, scale); 540 ipc = new PointConverter(left, top, scale); 541 Point2D ptPixels = null; 542 Point2D ptGeo = null; 543 int n = bboxCoords.size(); 544 //for (j = 0; j < bboxCoords.size(); j++) 545 for (j = 0; j < n; j++) { 546 ptGeo = bboxCoords.get(j); 547 ptPixels = ipc.GeoToPixels(ptGeo); 548 x = ptPixels.getX(); 549 y = ptPixels.getY(); 550 if (x < 20) { 551 x = 20; 552 } 553 if (y < 20) { 554 y = 20; 555 } 556 ptPixels.setLocation(x, y); 557 //end section 558 bboxCoords.set(j, (Point2D) ptPixels); 559 } 560 } else//rectangle 561 { 562 bounds = bbox.split(","); 563 left = Double.valueOf(bounds[0]); 564 right = Double.valueOf(bounds[2]); 565 top = Double.valueOf(bounds[3]); 566 bottom = Double.valueOf(bounds[1]); 567 scale = MultiPointHandler.getReasonableScale(bbox, scale); 568 ipc = new PointConverter(left, top, scale); 569 } 570 571 Point2D pt2d = null; 572 if (bboxCoords == null) { 573 pt2d = new Point2D.Double(left, top); 574 temp = ipc.GeoToPixels(pt2d); 575 576 leftX = (int) temp.getX(); 577 topY = (int) temp.getY(); 578 579 pt2d = new Point2D.Double(right, bottom); 580 temp = ipc.GeoToPixels(pt2d); 581 582 bottomY = (int) temp.getY(); 583 rightX = (int) temp.getX(); 584 585 width = (int) Math.abs(rightX - leftX); 586 height = (int) Math.abs(bottomY - topY); 587 588 rect = new Rectangle(leftX, topY, width, height); 589 } 590 } else { 591 rect = null; 592 } 593 594 if (ipc == null) { 595 Point2D ptCoordsUL = MultiPointHandler.getGeoUL(geoCoords); 596 ipc = new PointConverter(ptCoordsUL.getX(), ptCoordsUL.getY(), scale); 597 } 598 599 ArrayList<Point2D> geoCoords2 = new ArrayList<Point2D>(); 600 geoCoords2.add(new Point2D.Double(left, top)); 601 geoCoords2.add(new Point2D.Double(right, bottom)); 602 603// if (normalize) { 604// NormalizeGECoordsToGEExtents(0, 360, geoCoords2); 605// } 606 607 try { 608 609 //String fillColor = null; 610 MilStdSymbol mSymbol = new MilStdSymbol(symbolCode, null, geoCoords, null); 611 612 if (format == WebRenderer.OUTPUT_FORMAT_GEOSVG) { 613 // Use dash array and hatch pattern fill for SVG output 614 symbolAttributes.put(MilStdAttributes.UseDashArray, "true"); 615 symbolAttributes.put(MilStdAttributes.UsePatternFill, "true"); 616 } 617 618 if (symbolModifiers != null || symbolAttributes != null) { 619 MultiPointHandler.populateModifiers(symbolModifiers, symbolAttributes, mSymbol); 620 } else { 621 mSymbol.setFillColor(null); 622 } 623 624 TGLight tg = clsRenderer.createTGLightFromMilStdSymbolBasicShape(mSymbol, ipc, basicShapeType); 625 ArrayList<ShapeInfo> shapeInfos = new ArrayList(); 626 ArrayList<ShapeInfo> modifierShapeInfos = new ArrayList(); 627 Object clipArea; 628 if (bboxCoords == null) { 629 clipArea = rect; 630 } else { 631 clipArea = bboxCoords; 632 } 633 if (clsRenderer.intersectsClipArea(tg, ipc, clipArea)) { 634 clsRenderer.render_GE(tg, shapeInfos, modifierShapeInfos, ipc, clipArea); 635 } 636 mSymbol.setSymbolShapes(shapeInfos); 637 mSymbol.setModifierShapes(modifierShapeInfos); 638 mSymbol.set_WasClipped(tg.get_WasClipped()); 639 640 // Convert 2D shape to 3D 641 // Confirm there are at least two altitudes per shape 642 ArrayList<Double> altitudes = mSymbol.getModifiers_AM_AN_X(Modifiers.X_ALTITUDE_DEPTH); 643 if (altitudes.size() == 1) { 644 altitudes.add(0, 0.0); 645 } 646 if (basicShapeType == Basic3DShapes.ROUTE){ 647 altitudes = new ArrayList<>(altitudes.subList(0, 2)); 648 } 649 final Double lastAlt = altitudes.get(altitudes.size() - 1); 650 final Double nextToLastAlt = altitudes.get(altitudes.size() - 2); 651 while (altitudes.size() < mSymbol.getSymbolShapes().size() * 2) { 652 altitudes.add(nextToLastAlt); 653 altitudes.add(lastAlt); 654 } 655 for (int shapeIndex = 0; shapeIndex < mSymbol.getSymbolShapes().size(); shapeIndex++) { 656 final Double minAlt = altitudes.get(shapeIndex * 2); 657 final Double maxAlt = altitudes.get((shapeIndex * 2) + 1); 658 final ShapeInfo oldShape = mSymbol.getSymbolShapes().get(shapeIndex); 659 660 ShapeInfo3D bottomShape = new ShapeInfo3D(); 661 bottomShape.setShapeType(oldShape.getShapeType()); 662 bottomShape.setStroke(oldShape.getStroke()); 663 bottomShape.setLineColor(oldShape.getLineColor()); 664 bottomShape.setFillColor(oldShape.getFillColor()); 665 bottomShape.setPatternFillImage(oldShape.getPatternFillImage()); 666 bottomShape.setPolylines3D(new ArrayList<>()); 667 ShapeInfo3D topShape = new ShapeInfo3D(); 668 topShape.setShapeType(oldShape.getShapeType()); 669 topShape.setStroke(oldShape.getStroke()); 670 topShape.setLineColor(oldShape.getLineColor()); 671 topShape.setFillColor(oldShape.getFillColor()); 672 topShape.setPatternFillImage(oldShape.getPatternFillImage()); 673 topShape.setPolylines3D(new ArrayList<>()); 674 675 for (int polyLineIndex = 0; polyLineIndex < oldShape.getPolylines().size(); polyLineIndex++) { 676 final ArrayList<Point2D> polyline = oldShape.getPolylines().get(polyLineIndex); 677 bottomShape.getPolylines3D().add(new ArrayList<Point3D>()); 678 topShape.getPolylines3D().add(new ArrayList<Point3D>()); 679 for (int ptIndex = 0; ptIndex < polyline.size(); ptIndex++) { 680 final Point2D pt = polyline.get(ptIndex); 681 final Point2D pt2 = polyline.get((ptIndex + 1) % polyline.size()); 682 bottomShape.getPolylines3D().get(polyLineIndex).add(new Point3D(pt, minAlt)); 683 topShape.getPolylines3D().get(polyLineIndex).add(new Point3D(pt, maxAlt)); 684 685 ShapeInfo3D sideShape = new ShapeInfo3D(); 686 sideShape.setShapeType(oldShape.getShapeType()); 687 sideShape.setStroke(oldShape.getStroke()); 688 sideShape.setLineColor(oldShape.getLineColor()); 689 sideShape.setFillColor(oldShape.getFillColor()); 690 sideShape.setPatternFillImage(oldShape.getPatternFillImage()); 691 sideShape.setPolylines3D(new ArrayList<ArrayList<Point3D>>()); 692 sideShape.getPolylines3D().add(new ArrayList<>()); 693 sideShape.getPolylines3D().get(0).add(new Point3D(pt, minAlt)); 694 sideShape.getPolylines3D().get(0).add(new Point3D(pt2, minAlt)); 695 sideShape.getPolylines3D().get(0).add(new Point3D(pt2, maxAlt)); 696 sideShape.getPolylines3D().get(0).add(new Point3D(pt, maxAlt)); 697 sideShape.getPolylines3D().get(0).add(new Point3D(pt, minAlt)); 698 shapes.add(sideShape); 699 } 700 } 701 shapes.add(bottomShape); 702 shapes.add(topShape); 703 } 704 705 if (!mSymbol.getSymbolShapes().isEmpty() && !mSymbol.getModifierShapes().isEmpty()) { 706 final double modifierAlt = Collections.max(altitudes.subList(0, mSymbol.getSymbolShapes().size() * 2)); 707 for (ShapeInfo oldShape : mSymbol.getModifierShapes()) { 708 ShapeInfo3D modShape = new ShapeInfo3D(); 709 modShape.setModifierString(oldShape.getModifierString()); 710 modShape.setModifierPosition(new Point3D(oldShape.getModifierPosition(), modifierAlt)); 711 modShape.setModifierAngle(oldShape.getModifierAngle()); 712 modShape.setTextJustify(oldShape.getTextJustify()); 713 modShape.setModifierImage(oldShape.getModifierImage()); 714 modifiers.add(modShape); 715 } 716 } 717 718 if (format == WebRenderer.OUTPUT_FORMAT_KML) { 719 Color textColor = mSymbol.getTextColor(); 720 if (textColor == null) 721 textColor = mSymbol.getLineColor(); 722 723 jsonContent = KMLize(id, name, description, symbolCode, shapes, modifiers, ipc, normalize, textColor, altitudeMode, mSymbol.get_WasClipped()); 724 jsonOutput.append(jsonContent); 725 } else if (format == WebRenderer.OUTPUT_FORMAT_GEOJSON) { 726 jsonOutput.append("{\"type\":\"FeatureCollection\",\"features\":"); 727 jsonContent = GeoJSONize(shapes, modifiers, ipc, normalize, mSymbol.getTextColor(), mSymbol.getTextBackgroundColor()); 728 jsonOutput.append(jsonContent); 729 730 //moving meta data properties to the last feature with no coords as feature collection doesn't allow properties 731 jsonOutput.replace(jsonOutput.toString().length() - 1, jsonOutput.toString().length(), ""); 732 if (jsonContent.length() > 2) 733 jsonOutput.append(","); 734 jsonOutput.append("{\"type\": \"Feature\",\"geometry\": { \"type\": \"Polygon\",\"coordinates\": [ ]}"); 735 736 jsonOutput.append(",\"properties\":{\"id\":\""); 737 jsonOutput.append(id); 738 jsonOutput.append("\",\"name\":\""); 739 jsonOutput.append(name); 740 jsonOutput.append("\",\"description\":\""); 741 jsonOutput.append(description); 742 jsonOutput.append("\",\"symbolID\":\""); 743 jsonOutput.append(symbolCode); 744 jsonOutput.append("\",\"wasClipped\":\""); 745 jsonOutput.append(String.valueOf(mSymbol.get_WasClipped())); 746 //jsonOutput.append("\"}}"); 747 748 jsonOutput.append("\"}}]}"); 749 } 750 } catch (Exception exc) { 751 String st = JavaRendererUtilities.getStackTrace(exc); 752 jsonOutput = new StringBuilder(); 753 jsonOutput.append("{\"type\":\"error\",\"error\":\"There was an error creating the 3D MilStdSymbol " + symbolCode + ": " + "- "); 754 jsonOutput.append(exc.getMessage()).append(" - "); 755 jsonOutput.append(st); 756 jsonOutput.append("\"}"); 757 758 ErrorLogger.LogException("Shape3DHandler", "RenderBasic3DShape", exc); 759 } 760 761 boolean debug = false; 762 if (debug == true) { 763 System.out.println("Symbol Code: " + symbolCode); 764 System.out.println("Scale: " + scale); 765 System.out.println("BBOX: " + bbox); 766 if (controlPoints != null) { 767 System.out.println("Geo Points: " + controlPoints); 768 } 769 if (bbox != null) { 770 System.out.println("geo bounds: " + bbox); 771 } 772 if (rect != null) { 773 System.out.println("pixel bounds: " + rect.toString()); 774 } 775 if (jsonOutput != null) { 776 System.out.println(jsonOutput.toString()); 777 } 778 } 779 780 ErrorLogger.LogMessage("Shape3DHandler", "RenderBasic3DShape()", "exit RenderBasic3DShape", Level.FINER); 781 return jsonOutput.toString(); 782 783 } 784 785 private static String KMLize(String id, 786 String name, 787 String description, 788 String symbolCode, 789 ArrayList<ShapeInfo3D> shapes, 790 ArrayList<ShapeInfo3D> modifiers, 791 IPointConversion ipc, 792 boolean normalize, 793 Color textColor, 794 String altitudeMode, 795 boolean wasClipped) { 796 java.lang.StringBuilder kml = new java.lang.StringBuilder(); 797 ShapeInfo3D tempModifier = null; 798 String cdataStart = "<![CDATA["; 799 String cdataEnd = "]]>"; 800 int len = shapes.size(); 801 kml.append("<Folder id=\"").append(id).append("\">"); 802 kml.append("<name>").append(cdataStart).append(name).append(cdataEnd).append("</name>"); 803 kml.append("<visibility>1</visibility>"); 804 kml.append("<description>").append(cdataStart).append(description).append(cdataEnd).append("</description>"); 805 kml.append("<ExtendedData>"); 806 kml.append("<Data name=\"symbolID\"><value>").append(cdataStart).append(symbolCode).append(cdataEnd).append("</value></Data>"); 807 kml.append("<Data name=\"wasClipped\"><value>").append(cdataStart).append(wasClipped).append(cdataEnd).append("</value></Data>"); 808 kml.append("</ExtendedData>"); 809 for (int i = 0; i < len; i++) { 810 String shapesToAdd = ShapeToKMLString(shapes.get(i), ipc, normalize, altitudeMode); 811 kml.append(shapesToAdd); 812 } 813 814 int len2 = modifiers.size(); 815 816 for (int j = 0; j < len2; j++) { 817 818 tempModifier = modifiers.get(j); 819 820 //if(geMap)//if using google earth 821 //assume kml text is going to be centered 822 //AdjustModifierPointToCenter(tempModifier); 823 824 String labelsToAdd = LabelToKMLString(tempModifier, ipc, normalize, textColor, altitudeMode); 825 kml.append(labelsToAdd); 826 } 827 828 kml.append("</Folder>"); 829 return kml.toString(); 830 } 831 832 private static String ShapeToKMLString(ShapeInfo3D shapeInfo, 833 IPointConversion ipc, 834 boolean normalize, 835 String altitudeMode) { 836 java.lang.StringBuilder kml = new java.lang.StringBuilder(); 837 Color lineColor = null; 838 Color fillColor = null; 839 String googleLineColor = null; 840 String googleFillColor = null; 841 BasicStroke stroke = null; 842 int lineWidth = 4; 843 844 kml.append("<Placemark>"); 845 kml.append("<Style>"); 846 847 lineColor = shapeInfo.getLineColor(); 848 if (lineColor != null) { 849 googleLineColor = Integer.toHexString(shapeInfo.getLineColor().toARGB()); 850 851 stroke = shapeInfo.getStroke(); 852 853 if (stroke != null) { 854 lineWidth = (int) stroke.getLineWidth(); 855 } 856 857 googleLineColor = JavaRendererUtilities.ARGBtoABGR(googleLineColor); 858 859 kml.append("<LineStyle>"); 860 kml.append("<color>").append(googleLineColor).append("</color>"); 861 kml.append("<colorMode>normal</colorMode>"); 862 kml.append("<width>").append(String.valueOf(lineWidth)).append("</width>"); 863 kml.append("</LineStyle>"); 864 } 865 866 fillColor = shapeInfo.getFillColor(); 867 Bitmap fillPattern = shapeInfo.getPatternFillImage(); 868 if (fillColor != null || fillPattern != null) { 869 kml.append("<PolyStyle>"); 870 871 if (fillColor != null) { 872 googleFillColor = Integer.toHexString(shapeInfo.getFillColor().toARGB()); 873 googleFillColor = JavaRendererUtilities.ARGBtoABGR(googleFillColor); 874 kml.append("<color>").append(googleFillColor).append("</color>"); 875 kml.append("<colorMode>normal</colorMode>"); 876 } 877 if (fillPattern != null) { 878 kml.append("<shader>").append(MultiPointHandler.bitmapToString(fillPattern)).append("</shader>"); 879 } 880 881 kml.append("<fill>1</fill>"); 882 if (lineColor != null) { 883 kml.append("<outline>1</outline>"); 884 } else { 885 kml.append("<outline>0</outline>"); 886 } 887 kml.append("</PolyStyle>"); 888 } 889 890 kml.append("</Style>"); 891 892 ArrayList<ArrayList<Point3D>> shapesArray = shapeInfo.getPolylines3D(); 893 int len = shapesArray.size(); 894 kml.append("<MultiGeometry>"); 895 896 for (int i = 0; i < len; i++) { 897 ArrayList<Point3D> shape = shapesArray.get(i); 898 normalize = normalizePoints(shape, ipc); 899 if (lineColor != null && fillColor == null) { 900 kml.append("<Polygon>"); 901 kml.append("<tessellate>1</tessellate>"); 902 kml.append("<altitudeMode>").append(altitudeMode).append("</altitudeMode>"); 903 kml.append("<outerBoundaryIs><LinearRing><coordinates>"); 904 int n = shape.size(); 905 //for (int j = 0; j < shape.size(); j++) 906 for (int j = 0; j < n; j++) { 907 Point3D coord = shape.get(j); 908 Point2D geoCoord = ipc.PixelsToGeo(coord); 909 if (normalize) { 910 geoCoord = MultiPointHandler.NormalizeCoordToGECoord(geoCoord); 911 } 912 913 double latitude = Math.round(geoCoord.getY() * 100000000.0) / 100000000.0; 914 double longitude = Math.round(geoCoord.getX() * 100000000.0) / 100000000.0; 915 double altitude = coord.getZ(); 916 917 kml.append(longitude); 918 kml.append(","); 919 kml.append(latitude); 920 kml.append(","); 921 kml.append(altitude); 922 if (j < shape.size() - 1) kml.append(" "); 923 } 924 925 kml.append("</coordinates></LinearRing></outerBoundaryIs>"); 926 kml.append("</Polygon>"); 927 } 928 929 if (fillColor != null) { 930 931 if (i == 0) { 932 kml.append("<Polygon>"); 933 kml.append("<tessellate>1</tessellate>"); 934 kml.append("<altitudeMode>").append(altitudeMode).append("</altitudeMode>"); 935 } 936 //kml.append("<outerBoundaryIs>"); 937 if (i == 1 && len > 1) { 938 kml.append("<innerBoundaryIs>"); 939 } else { 940 kml.append("<outerBoundaryIs>"); 941 } 942 kml.append("<LinearRing>"); 943 kml.append("<coordinates>"); 944 945 int n = shape.size(); 946 //for (int j = 0; j < shape.size(); j++) 947 for (int j = 0; j < n; j++) { 948 Point3D coord = shape.get(j); 949 Point2D geoCoord = ipc.PixelsToGeo(coord); 950 951 double latitude = Math.round(geoCoord.getY() * 100000000.0) / 100000000.0; 952 double longitude = Math.round(geoCoord.getX() * 100000000.0) / 100000000.0; 953 double altitude = coord.getZ(); 954 955 //fix for fill crossing DTL 956 if (normalize) { 957 if (longitude > 0) { 958 longitude -= 360; 959 } 960 } 961 962 kml.append(longitude); 963 kml.append(","); 964 kml.append(latitude); 965 kml.append(","); 966 kml.append(altitude); 967 if (j < shape.size() - 1) kml.append(" "); 968 } 969 970 kml.append("</coordinates>"); 971 kml.append("</LinearRing>"); 972 if (i == 1 && len > 1) { 973 kml.append("</innerBoundaryIs>"); 974 } else { 975 kml.append("</outerBoundaryIs>"); 976 } 977 if (i == len - 1) { 978 kml.append("</Polygon>"); 979 } 980 } 981 } 982 983 kml.append("</MultiGeometry>"); 984 kml.append("</Placemark>"); 985 986 return kml.toString(); 987 } 988 989 private static String LabelToKMLString(ShapeInfo3D shapeInfo, 990 IPointConversion ipc, 991 boolean normalize, 992 Color textColor, 993 String altitudeMode) { 994 java.lang.StringBuilder kml = new java.lang.StringBuilder(); 995 996 //Point2D coord = (Point2D) new Point2D.Double(shapeInfo.getGlyphPosition().getX(), shapeInfo.getGlyphPosition().getY()); 997 Point3D coord = new Point3D(shapeInfo.getModifierPosition().getX(), shapeInfo.getModifierPosition().getY(), shapeInfo.getModifierPosition().getZ()); 998 Point2D geoCoord = ipc.PixelsToGeo(coord); 999 //M. Deutch 9-26-11 1000 if (normalize) { 1001 geoCoord = MultiPointHandler.NormalizeCoordToGECoord(geoCoord); 1002 } 1003 double latitude = Math.round(geoCoord.getY() * 100000000.0) / 100000000.0; 1004 double longitude = Math.round(geoCoord.getX() * 100000000.0) / 100000000.0; 1005 double altitude = coord.getZ(); 1006 long angle = Math.round(shapeInfo.getModifierAngle()); 1007 1008 String text = shapeInfo.getModifierString(); 1009 1010 String cdataStart = "<![CDATA["; 1011 String cdataEnd = "]]>"; 1012 1013 String color = Integer.toHexString(textColor.toARGB()); 1014 color = JavaRendererUtilities.ARGBtoABGR(color); 1015 float kmlScale = RendererSettings.getInstance().getKMLLabelScale(); 1016 1017 if (kmlScale > 0 && text != null && text.equals("") == false) { 1018 kml.append("<Placemark>");//("<Placemark id=\"" + id + "_lp" + i + "\">"); 1019 kml.append("<name>").append(cdataStart).append(text).append(cdataEnd).append("</name>"); 1020 kml.append("<Style>"); 1021 kml.append("<IconStyle>"); 1022 kml.append("<scale>").append(kmlScale).append("</scale>"); 1023 kml.append("<heading>").append(angle).append("</heading>"); 1024 kml.append("<Icon>"); 1025 kml.append("<href></href>"); 1026 kml.append("</Icon>"); 1027 kml.append("</IconStyle>"); 1028 kml.append("<LabelStyle>"); 1029 kml.append("<color>").append(color).append("</color>"); 1030 kml.append("<scale>").append(String.valueOf(kmlScale)).append("</scale>"); 1031 kml.append("</LabelStyle>"); 1032 kml.append("</Style>"); 1033 kml.append("<Point>"); 1034 kml.append("<extrude>0</extrude>"); 1035 kml.append("<altitudeMode>").append(altitudeMode).append("</altitudeMode>"); 1036 kml.append("<coordinates>"); 1037 kml.append(longitude); 1038 kml.append(","); 1039 kml.append(latitude); 1040 kml.append(","); 1041 kml.append(altitude); 1042 kml.append("</coordinates>"); 1043 kml.append("</Point>"); 1044 kml.append("</Placemark>"); 1045 } else { 1046 return ""; 1047 } 1048 1049 return kml.toString(); 1050 } 1051 1052 1053 private static String GeoJSONize(ArrayList<ShapeInfo3D> shapes, 1054 ArrayList<ShapeInfo3D> modifiers, 1055 IPointConversion ipc, 1056 boolean normalize, 1057 Color textColor, 1058 Color textBackgroundColor) { 1059 1060 ShapeInfo3D tempModifier = null; 1061 StringBuilder fc = new StringBuilder();//JSON feature collection 1062 1063 fc.append("["); 1064 1065 int len = shapes.size(); 1066 for (int i = 0; i < len; i++) { 1067 1068 String shapesToAdd = ShapeToGeoJSONString(shapes.get(i), ipc, normalize); 1069 if (shapesToAdd.length() > 0) { 1070 fc.append(shapesToAdd); 1071 if (i < len - 1) { 1072 fc.append(","); 1073 } 1074 } 1075 } 1076 1077 int len2 = modifiers.size(); 1078 1079 for (int j = 0; j < len2; j++) { 1080 tempModifier = modifiers.get(j); 1081 1082 String modifiersToAdd = null; 1083 if (modifiers.get(j).getModifierImage() != null) { 1084 modifiersToAdd = ImageToGeoJSONString(tempModifier, ipc, normalize); 1085 } else { 1086 modifiersToAdd = LabelToGeoJSONString(tempModifier, ipc, normalize, textColor, textBackgroundColor); 1087 } 1088 if (modifiersToAdd.length() > 0) { 1089 if (fc.length() > 1) fc.append(","); 1090 fc.append(modifiersToAdd); 1091 } 1092 } 1093 fc.append("]"); 1094 String GeoJSON = fc.toString(); 1095 return GeoJSON; 1096 } 1097 1098 private static String ShapeToGeoJSONString(ShapeInfo3D shapeInfo, IPointConversion ipc, boolean normalize) { 1099 StringBuilder JSONed = new StringBuilder(); 1100 StringBuilder properties = new StringBuilder(); 1101 StringBuilder geometry = new StringBuilder(); 1102 String geometryType = null; 1103 String sda = null; 1104 /* 1105 NOTE: Google Earth / KML colors are backwards. 1106 They are ordered Alpha,Blue,Green,Red, not Red,Green,Blue,Aplha like the rest of the world 1107 * */ 1108 Color lineColor = shapeInfo.getLineColor(); 1109 Color fillColor = shapeInfo.getFillColor(); 1110 1111 if (shapeInfo.getShapeType() == ShapeInfo.SHAPE_TYPE_FILL || fillColor != null || shapeInfo.getPatternFillImage() != null) { 1112 geometryType = "\"Polygon\""; 1113 } else //if(shapeInfo.getShapeType() == ShapeInfo.SHAPE_TYPE_POLYLINE) 1114 { 1115 geometryType = "\"MultiLineString\""; 1116 } 1117 1118 BasicStroke stroke = null; 1119 stroke = shapeInfo.getStroke(); 1120 int lineWidth = 4; 1121 1122 if (stroke != null) { 1123 lineWidth = (int) stroke.getLineWidth(); 1124 } 1125 1126 //generate JSON properties for feature 1127 properties.append("\"properties\":{"); 1128 properties.append("\"label\":\"\","); 1129 if (lineColor != null) { 1130 properties.append("\"strokeColor\":\"").append(RendererUtilities.colorToHexString(lineColor, false)).append("\","); 1131 properties.append("\"lineOpacity\":").append(String.valueOf(lineColor.getAlpha() / 255f)).append(","); 1132 } 1133 if (fillColor != null) { 1134 properties.append("\"fillColor\":\"").append(RendererUtilities.colorToHexString(fillColor, false)).append("\","); 1135 properties.append("\"fillOpacity\":").append(String.valueOf(fillColor.getAlpha() / 255f)).append(","); 1136 } 1137 if (shapeInfo.getPatternFillImage() != null) { 1138 properties.append("\"fillPattern\":\"").append(MultiPointHandler.bitmapToString(shapeInfo.getPatternFillImage())).append("\","); 1139 } 1140 if (stroke.getDashArray() != null) { 1141 float[] arrSDA = stroke.getDashArray(); 1142 sda = "["; 1143 sda += String.valueOf(arrSDA[0]); 1144 if (arrSDA.length > 1) { 1145 for (int i = 1; i < arrSDA.length; i++) { 1146 sda = sda + ", " + String.valueOf(arrSDA[i]); 1147 } 1148 } 1149 sda += "]"; 1150 sda = "\"strokeDasharray\":" + sda + ","; 1151 properties.append(sda); 1152 } 1153 1154 int lineCap = stroke.getEndCap(); 1155 properties.append("\"lineCap\":").append(lineCap).append(","); 1156 1157 String strokeWidth = String.valueOf(lineWidth); 1158 properties.append("\"strokeWidth\":").append(strokeWidth).append(","); 1159 properties.append("\"strokeWeight\":").append(strokeWidth); 1160 properties.append("},"); 1161 1162 1163 properties.append("\"style\":{"); 1164 if (lineColor != null) { 1165 properties.append("\"stroke\":\"").append(RendererUtilities.colorToHexString(lineColor, false)).append("\","); 1166 properties.append("\"line-opacity\":").append(String.valueOf(lineColor.getAlpha() / 255f)).append(","); 1167 } 1168 if (fillColor != null) { 1169 properties.append("\"fill\":\"").append(RendererUtilities.colorToHexString(fillColor, false)).append("\","); 1170 properties.append("\"fill-opacity\":").append(String.valueOf(fillColor.getAlpha() / 255f)).append(","); 1171 } 1172 if (stroke.getDashArray() != null) { 1173 float[] da = stroke.getDashArray(); 1174 sda = String.valueOf(da[0]); 1175 if (da.length > 1) { 1176 for (int i = 1; i < da.length; i++) { 1177 sda = sda + " " + String.valueOf(da[i]); 1178 } 1179 } 1180 sda = "\"stroke-dasharray\":\"" + sda + "\","; 1181 properties.append(sda); 1182 sda = null; 1183 } 1184 1185 if (lineCap == BasicStroke.CAP_SQUARE) properties.append("\"stroke-linecap\":\"square\","); 1186 else if (lineCap == BasicStroke.CAP_ROUND) 1187 properties.append("\"stroke-linecap\":\"round\","); 1188 else if (lineCap == BasicStroke.CAP_BUTT) properties.append("\"stroke-linecap\":\"butt\","); 1189 1190 strokeWidth = String.valueOf(lineWidth); 1191 properties.append("\"stroke-width\":").append(strokeWidth); 1192 properties.append("}"); 1193 1194 1195 //generate JSON geometry for feature 1196 geometry.append("\"geometry\":{\"type\":"); 1197 geometry.append(geometryType); 1198 geometry.append(",\"coordinates\":["); 1199 1200 ArrayList<ArrayList<Point3D>> shapesArray = shapeInfo.getPolylines3D(); 1201 1202 for (int i = 0; i < shapesArray.size(); i++) { 1203 ArrayList<Point3D> pointList = shapesArray.get(i); 1204 1205 normalize = normalizePoints(pointList, ipc); 1206 1207 geometry.append("["); 1208 1209 //System.out.println("Pixel Coords:"); 1210 for (int j = 0; j < pointList.size(); j++) { 1211 Point3D coord = pointList.get(j); 1212 Point2D geoCoord = ipc.PixelsToGeo(coord); 1213 //M. Deutch 9-27-11 1214 if (normalize) { 1215 geoCoord = MultiPointHandler.NormalizeCoordToGECoord(geoCoord); 1216 } 1217 double latitude = Math.round(geoCoord.getY() * 100000000.0) / 100000000.0; 1218 double longitude = Math.round(geoCoord.getX() * 100000000.0) / 100000000.0; 1219 double altitude = coord.getZ(); 1220 1221 //fix for fill crossing DTL 1222 if (normalize && fillColor != null) { 1223 if (longitude > 0) { 1224 longitude -= 360; 1225 } 1226 } 1227 1228 //diagnostic M. Deutch 10-18-11 1229 //set the point as geo so that the 1230 //coord.setLocation(longitude, latitude); 1231 coord = new Point3D(longitude, latitude, altitude); 1232 pointList.set(j, coord); 1233 //end section 1234 1235 geometry.append("["); 1236 geometry.append(longitude); 1237 geometry.append(","); 1238 geometry.append(latitude); 1239 geometry.append(","); 1240 geometry.append(altitude); 1241 geometry.append("]"); 1242 1243 if (j < (pointList.size() - 1)) { 1244 geometry.append(","); 1245 } 1246 } 1247 1248 geometry.append("]"); 1249 1250 if (i < (shapesArray.size() - 1)) { 1251 geometry.append(","); 1252 } 1253 } 1254 geometry.append("]}"); 1255 1256 JSONed.append("{\"type\":\"Feature\","); 1257 JSONed.append(properties.toString()); 1258 JSONed.append(","); 1259 JSONed.append(geometry.toString()); 1260 JSONed.append("}"); 1261 1262 return JSONed.toString(); 1263 } 1264 1265 private static String ImageToGeoJSONString(ShapeInfo3D shapeInfo, IPointConversion ipc, boolean normalize) { 1266 StringBuilder JSONed = new StringBuilder(); 1267 1268 //AffineTransform at = shapeInfo.getAffineTransform(); 1269 //Point2D coord = (Point2D)new Point2D.Double(at.getTranslateX(), at.getTranslateY()); 1270 //Point2D coord = (Point2D) new Point2D.Double(shapeInfo.getGlyphPosition().getX(), shapeInfo.getGlyphPosition().getY()); 1271 Point3D coord = new Point3D(shapeInfo.getModifierPosition().getX(), shapeInfo.getModifierPosition().getY(), shapeInfo.getModifierPosition().getZ()); 1272 Point2D geoCoord = ipc.PixelsToGeo(coord); 1273 //M. Deutch 9-27-11 1274 if (normalize) { 1275 geoCoord = MultiPointHandler.NormalizeCoordToGECoord(geoCoord); 1276 } 1277 double latitude = Math.round(geoCoord.getY() * 100000000.0) / 100000000.0; 1278 double longitude = Math.round(geoCoord.getX() * 100000000.0) / 100000000.0; 1279 double altitude = coord.getZ(); 1280 double angle = shapeInfo.getModifierAngle(); 1281 coord.setLocation(longitude, latitude); 1282 1283 //diagnostic M. Deutch 10-18-11 1284 shapeInfo.setGlyphPosition(coord); 1285 1286 Bitmap image = shapeInfo.getModifierImage(); 1287 1288 RendererSettings RS = RendererSettings.getInstance(); 1289 1290 if (image != null) { 1291 1292 JSONed.append("{\"type\":\"Feature\",\"properties\":{\"image\":\""); 1293 JSONed.append(MultiPointHandler.bitmapToString(image)); 1294 JSONed.append("\",\"rotation\":"); 1295 JSONed.append(angle); 1296 JSONed.append(",\"angle\":"); 1297 JSONed.append(angle); 1298 JSONed.append("},"); 1299 JSONed.append("\"geometry\":{\"type\":\"Point\",\"coordinates\":["); 1300 JSONed.append(longitude); 1301 JSONed.append(","); 1302 JSONed.append(latitude); 1303 JSONed.append(","); 1304 JSONed.append(altitude); 1305 JSONed.append("]"); 1306 JSONed.append("}}"); 1307 1308 } else { 1309 return ""; 1310 } 1311 1312 return JSONed.toString(); 1313 } 1314 1315 private static String LabelToGeoJSONString(ShapeInfo3D shapeInfo, IPointConversion ipc, boolean normalize, Color textColor, Color textBackgroundColor) { 1316 StringBuilder JSONed = new StringBuilder(); 1317 1318 Color outlineColor = MultiPointHandler.getIdealTextBackgroundColor(textColor); 1319 if (textBackgroundColor != null) outlineColor = textBackgroundColor; 1320 1321 //AffineTransform at = shapeInfo.getAffineTransform(); 1322 //Point2D coord = (Point2D)new Point2D.Double(at.getTranslateX(), at.getTranslateY()); 1323 //Point2D coord = (Point2D) new Point2D.Double(shapeInfo.getGlyphPosition().getX(), shapeInfo.getGlyphPosition().getY()); 1324 Point3D coord = new Point3D(shapeInfo.getModifierPosition().getX(), shapeInfo.getModifierPosition().getY(), shapeInfo.getModifierPosition().getZ()); 1325 Point2D geoCoord = ipc.PixelsToGeo(coord); 1326 //M. Deutch 9-27-11 1327 if (normalize) { 1328 geoCoord = MultiPointHandler.NormalizeCoordToGECoord(geoCoord); 1329 } 1330 double latitude = Math.round(geoCoord.getY() * 100000000.0) / 100000000.0; 1331 double longitude = Math.round(geoCoord.getX() * 100000000.0) / 100000000.0; 1332 double altitude = coord.getZ(); 1333 double angle = shapeInfo.getModifierAngle(); 1334 coord.setLocation(longitude, latitude); 1335 1336 //diagnostic M. Deutch 10-18-11 1337 shapeInfo.setGlyphPosition(coord); 1338 1339 String text = shapeInfo.getModifierString(); 1340 1341 int justify = shapeInfo.getTextJustify(); 1342 String strJustify = "left"; 1343 if (justify == 0) strJustify = "left"; 1344 else if (justify == 1) strJustify = "center"; 1345 else if (justify == 2) strJustify = "right"; 1346 1347 1348 RendererSettings RS = RendererSettings.getInstance(); 1349 1350 if (text != null && text.equals("") == false) { 1351 1352 JSONed.append("{\"type\":\"Feature\",\"properties\":{\"label\":\""); 1353 JSONed.append(text); 1354 JSONed.append("\",\"pointRadius\":0,\"fontColor\":\""); 1355 JSONed.append(RendererUtilities.colorToHexString(textColor, false)); 1356 JSONed.append("\",\"fontSize\":\""); 1357 JSONed.append(String.valueOf(RS.getMPLabelFontSize())).append("pt\""); 1358 JSONed.append(",\"fontFamily\":\""); 1359 JSONed.append(RS.getMPLabelFontName()); 1360 JSONed.append(", sans-serif"); 1361 1362 if (RS.getMPLabelFontType() == Typeface.BOLD) { 1363 JSONed.append("\",\"fontWeight\":\"bold\""); 1364 } else { 1365 JSONed.append("\",\"fontWeight\":\"normal\""); 1366 } 1367 1368 //JSONed.append(",\"labelAlign\":\"lm\""); 1369 JSONed.append(",\"labelAlign\":\""); 1370 JSONed.append(strJustify); 1371 JSONed.append("\",\"labelBaseline\":\"alphabetic\""); 1372 JSONed.append(",\"labelXOffset\":0"); 1373 JSONed.append(",\"labelYOffset\":0"); 1374 JSONed.append(",\"labelOutlineColor\":\""); 1375 JSONed.append(RendererUtilities.colorToHexString(outlineColor, false)); 1376 JSONed.append("\",\"labelOutlineWidth\":"); 1377 JSONed.append("4"); 1378 JSONed.append(",\"rotation\":"); 1379 JSONed.append(angle); 1380 JSONed.append(",\"angle\":"); 1381 JSONed.append(angle); 1382 JSONed.append("},"); 1383 1384 JSONed.append("\"geometry\":{\"type\":\"Point\",\"coordinates\":["); 1385 JSONed.append(longitude); 1386 JSONed.append(","); 1387 JSONed.append(latitude); 1388 JSONed.append(","); 1389 JSONed.append(altitude); 1390 JSONed.append("]"); 1391 JSONed.append("}}"); 1392 1393 } else { 1394 return ""; 1395 } 1396 1397 return JSONed.toString(); 1398 } 1399 1400 /** 1401 * copy of {@link MultiPointHandler#normalizePoints(ArrayList, IPointConversion)} with Point3D 1402 */ 1403 static Boolean normalizePoints(ArrayList<Point3D> shape, IPointConversion ipc) { 1404 ArrayList geoCoords = new ArrayList(); 1405 int n = shape.size(); 1406 //for (int j = 0; j < shape.size(); j++) 1407 for (int j = 0; j < n; j++) { 1408 Point2D coord = shape.get(j); 1409 Point2D geoCoord = ipc.PixelsToGeo(coord); 1410 geoCoord = MultiPointHandler.NormalizeCoordToGECoord(geoCoord); 1411 double latitude = geoCoord.getY(); 1412 double longitude = geoCoord.getX(); 1413 Point2D pt2d = new Point2D.Double(longitude, latitude); 1414 geoCoords.add(pt2d); 1415 } 1416 Boolean normalize = MultiPointHandler.crossesIDL(geoCoords); 1417 return normalize; 1418 } 1419}