package sec.web.render; // This import is if we need to call a javascript function // It requires that you import the plugins.jar from the jdk folder into the project libraries //import netscape.javascript.JSObject; import android.util.SparseArray; import armyc2.c2sd.renderer.MilStdIconRenderer; import armyc2.c2sd.renderer.utilities.ErrorLogger; import armyc2.c2sd.renderer.utilities.MilStdAttributes; import armyc2.c2sd.renderer.utilities.MilStdSymbol; import armyc2.c2sd.renderer.utilities.ModifiersTG; import armyc2.c2sd.renderer.utilities.RendererSettings; import armyc2.c2sd.renderer.utilities.SymbolUtilities; import armyc2.c2sd.renderer.utilities.Color; import armyc2.c2sd.graphics2d.*; import sec.web.render.utilities.JavaRendererUtilities; import java.util.logging.Level; import sec.geo.kml.KmlOptions; import sec.web.json.utilities.JSONArray; import sec.web.json.utilities.JSONException; import sec.web.json.utilities.JSONObject; import sec.geo.utilities.StringBuilder; import java.util.Map; import java.util.ArrayList; /** * * @author Administrator */ //@SuppressWarnings("unused") public final class SECWebRenderer /* extends Applet */ { private static final long serialVersionUID = -2691218568602318366L; // constants for the available shape types that can be generated into KML public static final String CYLINDER = "CYLINDER-------"; public static final String ORBIT = "ORBIT----------"; public static final String ROUTE = "ROUTE----------"; public static final String POLYGON = "POLYGON--------"; public static final String RADARC = "RADARC---------"; public static final String POLYARC = "POLYARC--------"; public static final String CAKE = "CAKE-----------"; public static final String TRACK = "TRACK----------"; // Attribute names of the 3D shapes public static final String ATTRIBUTES = "attributes"; public static final String MIN_ALT = "minalt"; public static final String MAX_ALT = "maxalt"; public static final String RADIUS1 = "radius1"; public static final String RADIUS2 = "radius2"; public static final String LEFT_AZIMUTH = "leftAzimuth"; public static final String RIGHT_AZIMUTH = "rightAzimuth"; // Arbitrary default values of attributes public static final double MIN_ALT_DEFAULT = 0.0D; public static final double MAX_ALT_DEFAULT = 100.0D; public static final double RADIUS1_DEFAULT = 50.0D; public static final double RADIUS2_DEFAULT = 100.0D; public static final double LEFT_AZIMUTH_DEFAULT = 0.0D; public static final double RIGHT_AZIMUTH_DEFAULT = 90.0D; public static final String ERR_ATTRIBUTES_NOT_FORMATTED = "{\"type\":\"error\"," + "\"error\":\"The attribute paramaters are not formatted " + "correctly"; public static final String DEFAULT_ATTRIBUTES = "[{radius1:" + RADIUS1_DEFAULT + ",radius2:" + RADIUS2_DEFAULT + ",minalt:" + MIN_ALT_DEFAULT + ",maxalt:" + MAX_ALT_DEFAULT + ",rightAzimuth:" + RIGHT_AZIMUTH_DEFAULT + ",leftAzimuth:" + LEFT_AZIMUTH_DEFAULT + "}]"; private static boolean _initSuccess = false; public static synchronized void init(String cacheDir) { try { if(_initSuccess == false) { MilStdIconRenderer.getInstance().init(cacheDir); //use SECWebRenderer.setLoggingLevel() //sets default value for single point symbology to have an outline. //outline color will be automatically determined based on line color //unless a color value is manually set. //Set Renderer Settings///////////////////////////////////////////// RendererSettings.getInstance().setSinglePointSymbolOutlineWidth(1); RendererSettings.getInstance().setTextRenderMethod(RendererSettings.RenderMethod_NATIVE); RendererSettings.getInstance().setTextBackgroundMethod( RendererSettings.TextBackgroundMethod_OUTLINE_QUICK); RendererSettings.getInstance().setTextOutlineWidth(2); RendererSettings.getInstance().setLabelForegroundColor(Color.BLACK.toARGB()); RendererSettings.getInstance().setLabelBackgroundColor(new Color(255, 255, 255, 200).toARGB()); RendererSettings.getInstance().setModifierFont("arial", Font.PLAIN, 12); ErrorLogger.setLevel(Level.FINE); } } catch(Exception exc) { ErrorLogger.LogException("SECWebRenderer", "init", exc, Level.WARNING); } } /**\ * Set minimum level at which an item can be logged. * In descending order: * OFF = Integer.MAX_VALUE * Severe = 1000 * Warning = 900 * Info = 800 * Config = 700 * Fine = 500 * Finer = 400 * Finest = 300 * All = Integer.MIN_VALUE * Use like SECWebRenderer.setLoggingLevel(Level.INFO); * or * Use like SECWebRenderer.setLoggingLevel(800); * @param level java.util.logging.level */ public static void setLoggingLevel(Level level) { try { ErrorLogger.setLevel(level,true); ErrorLogger.LogMessage("SECWebRenderer", "setLoggingLevel(Level)", "Logging level set to: " + ErrorLogger.getLevel().getName(), Level.CONFIG); } catch(Exception exc) { ErrorLogger.LogException("SECWebRenderer", "setLoggingLevel(Level)", exc, Level.INFO); } } /**\ * Set minimum level at which an item can be logged. * In descending order: * OFF = Integer.MAX_VALUE * Severe = 1000 * Warning = 900 * Info = 800 * Config = 700 * Fine = 500 * Finer = 400 * Finest = 300 * All = Integer.MIN_VALUE * Use like SECWebRenderer.setLoggingLevel(Level.INFO); * or * Use like SECWebRenderer.setLoggingLevel(800); * @param level int */ public static void setLoggingLevel(int level) { try { if(level > 1000) ErrorLogger.setLevel(Level.OFF,true); else if(level > 900) ErrorLogger.setLevel(Level.SEVERE,true); else if(level > 800) ErrorLogger.setLevel(Level.WARNING,true); else if(level > 700) ErrorLogger.setLevel(Level.INFO,true); else if(level > 500) ErrorLogger.setLevel(Level.CONFIG,true); else if(level > 400) ErrorLogger.setLevel(Level.FINE,true); else if(level > 300) ErrorLogger.setLevel(Level.FINER,true); else if(level > Integer.MIN_VALUE) ErrorLogger.setLevel(Level.FINEST,true); else ErrorLogger.setLevel(Level.ALL,true); ErrorLogger.LogMessage("SECWebRenderer", "setLoggingLevel(int)", "Logging level set to: " + ErrorLogger.getLevel().getName(), Level.CONFIG); } catch(Exception exc) { ErrorLogger.LogException("SECWebRenderer", "setLoggingLevel(int)", exc, Level.INFO); } } /** * Let's user choose between 2525Bch2 and 2525C. * Ideally, set only once at startup. * 2525Bch2 = 0, 2525C = 1. * @param symStd */ public static void setDefaultSymbologyStandard(int symStd) { RendererSettings.getInstance().setSymbologyStandard(symStd); } /** * Single Point Tactical Graphics are rendered from font files. * The font size you specify here determines how big the symbols will * be rendered. This should be set once at startup. * @param size */ public static void setTacticalGraphicPointSize(int size) { // sps.setTacticalGraphicPointSize(size); } /** * Units are rendered from font files. * The font size you specify here determines how big the symbols will * be rendered. This should be set once at startup. * @param size */ public static void setUnitPointSize(int size) { // sps.setUnitPointSize(size); } /** * Modifier Text Color will by default match the line color. * This will override all modifier text color. * @param hexColor */ public static void setModifierTextColor(String hexColor) { Color textColor = SymbolUtilities.getColorFromHexString(hexColor); if(textColor==null) { textColor = Color.black; } RendererSettings.getInstance().setLabelForegroundColor(textColor.toARGB()); } /** * Renders all multi-point symbols, creating KML that can be used to draw * it on a Google map. Multipoint symbols cannot be draw the same * at different scales. For instance, graphics with arrow heads will need to * redraw arrowheads when you zoom in on it. Similarly, graphics like a * Forward Line of Troops drawn with half circles can improve performance if * clipped when the parts of the graphic that aren't on the screen. To help * readjust graphics and increase performance, this function requires the * scale and bounding box to help calculate the new locations. * @param id A unique identifier used to identify the symbol by Google map. * The id will be the folder name that contains the graphic. * @param name a string used to display to the user as the name of the * graphic being created. * @param description a brief description about the graphic being made and * what it represents. * @param symbolCode A 15 character symbolID corresponding to one of the * graphics in the MIL-STD-2525C * @param controlPoints The vertices of the graphics that make up the * graphic. Passed in the format of a string, using decimal degrees * separating lat and lon by a comma, separating coordinates by a space. * The following format shall be used "x1,y1[,z1] [xn,yn[,zn]]..." * @param altitudeMode Indicates whether the symbol should interpret * altitudes as above sea level or above ground level. Options are * "clampToGround", "relativeToGround" (from surface of earth), "absolute" * (sea level), "relativeToSeaFloor" (from the bottom of major bodies of * water). * @param scale A number corresponding to how many meters one meter of our * map represents. A value "50000" would mean 1:50K which means for every * meter of our map it represents 50000 meters of real world distance. * @param bbox The viewable area of the map. Passed in the format of a * string "lowerLeftX,lowerLeftY,upperRightX,upperRightY." Not required * but can speed up rendering in some cases. * example: "-50.4,23.6,-42.2,24.2" * @param modifiers SparseArray<String>, keyed using constants from ModifiersTG. * Pass in comma delimited String for modifiers with multiple values like AM, AN & X * @param attributes SparseArray<String>, keyed using constants from MilStdAttributes. * @param format An enumeration: 0 for KML, 1 for JSON. * @param symStd An enumeration: 0 for 2525Bch2, 1 for 2525C. * @return A JSON string representation of the graphic. */ public static String RenderSymbol(String id, String name, String description, String symbolCode, String controlPoints, String altitudeMode, double scale, String bbox, SparseArray<String> modifiers, SparseArray<String> attributes, int format, int symStd) { String output = ""; try { JavaRendererUtilities.addAltModeToModifiersString(attributes,altitudeMode); //if (JavaRendererUtilities.is3dSymbol(symbolCode, modifiers)) if (altitudeMode.equals("clampToGround") == false && format == 0 && JavaRendererUtilities.is3dSymbol(symbolCode, modifiers)) { if (altitudeMode.isEmpty()) altitudeMode = "absolute"; output = RenderMilStd3dSymbol(name, id, symbolCode, description, altitudeMode, controlPoints, modifiers, attributes); //get modifiers///////////////////////////////////////////////// String modifierKML = MultiPointHandler.getModififerKML(id, name, description, symbolCode, controlPoints, scale, bbox, modifiers, attributes, format,symStd); modifierKML += "</Folder>"; output = output.replaceFirst("</Folder>", modifierKML); //////////////////////////////////////////////////////////////// // Check the output of the 3D Symbol Drawing. If this returned an error // it should either be "" or it should be a JSON string starting with "{". // This really is not a good solution, but was up to 13.0.6 and had to make // this bug fix in quick turnaround. More consistent error handling should // be done through code. if (output.equals("") || output.startsWith("{")) { output = MultiPointHandler.RenderSymbol(id, name, description, symbolCode, controlPoints, scale, bbox, modifiers, attributes, format,symStd); } } else { output = MultiPointHandler.RenderSymbol(id, name, description, symbolCode, controlPoints, scale, bbox, modifiers, attributes, format,symStd); //DEBUGGING if(ErrorLogger.getLevel().intValue() <= Level.FINER.intValue()) { System.out.println(""); StringBuilder sb = new StringBuilder(); sb.append("\nID: " + id + "\n"); sb.append("Name: " + name + "\n"); sb.append("Description: " + description + "\n"); sb.append("SymbolID: " + symbolCode + "\n"); sb.append("SymStd: " + String.valueOf(symStd) + "\n"); sb.append("Scale: " + String.valueOf(scale) + "\n"); sb.append("BBox: " + bbox + "\n"); sb.append("Coords: " + controlPoints + "\n"); sb.append("Modifiers: " + modifiers + "\n"); ErrorLogger.LogMessage("SECWebRenderer", "RenderSymbol", sb.toString(),Level.FINER); } if(ErrorLogger.getLevel().intValue() <= Level.FINEST.intValue()) { String briefOutput = output.replaceAll("</Placemark>", "</Placemark>\n"); briefOutput = output.replaceAll("(?s)<description[^>]*>.*?</description>", "<description></description>"); ErrorLogger.LogMessage("SECWebRenderer", "RenderSymbol", "Output:\n" + briefOutput,Level.FINEST); } } } catch (Exception ea) { output = "{\"type\":'error',error:'There was an error creating the MilStdSymbol - " + ea.toString() + "'}"; ErrorLogger.LogException("SECWebRenderer", "RenderSymbol", ea, Level.WARNING); } return output; } /** * Renders all multi-point symbols, creating KML or JSON for the user to * parse and render as they like. * This function requires the bounding box to help calculate the new * locations. * @param id A unique identifier used to identify the symbol by Google map. * The id will be the folder name that contains the graphic. * @param name a string used to display to the user as the name of the * graphic being created. * @param description a brief description about the graphic being made and * what it represents. * @param symbolCode A 15 character symbolID corresponding to one of the * graphics in the MIL-STD-2525C * @param controlPoints The vertices of the graphics that make up the * graphic. Passed in the format of a string, using decimal degrees * separating lat and lon by a comma, separating coordinates by a space. * The following format shall be used "x1,y1 [xn,yn]..." * @param pixelWidth pixel dimensions of the viewable map area * @param pixelHeight pixel dimensions of the viewable map area * @param bbox The viewable area of the map. Passed in the format of a * string "lowerLeftX,lowerLeftY,upperRightX,upperRightY." * example: "-50.4,23.6,-42.2,24.2" * @param modifiers SparseArray<String>, keyed using constants from ModifiersTG. * Pass in comma delimited String for modifiers with multiple values like AM, AN & X * @param attributes SparseArray<String>, keyed using constants from MilStdAttributes. * @param format An enumeration: 0 for KML, 1 for JSON. * @param symStd An enumeration: 0 for 2525Bch2, 1 for 2525C. * @return A JSON (1) or KML (0) string representation of the graphic. */ public static String RenderSymbol2D(String id, String name, String description, String symbolCode, String controlPoints, int pixelWidth, int pixelHeight, String bbox, SparseArray<String> modifiers, SparseArray<String> attributes, int format, int symStd) { String output = ""; try { output = MultiPointHandler.RenderSymbol2D(id, name, description, symbolCode, controlPoints, pixelWidth, pixelHeight, bbox, modifiers, attributes, format, symStd); } catch(Exception exc) { output = "{\"type\":'error',error:'There was an error creating the MilStdSymbol: " + symbolCode + " - " + exc.toString() + "'}"; } return output; } /** * Creates a 3D symbol to be displayed on some 3D globe surface. Generates * Keyhole Markup Language (KML) to return that specifies the points and format of * the rendering. * <br/> * Control points should be of the format of: * <tr><code>"x,y,z [x,y,z]..."</code></tr> * Attributes should be passed in as a JSON array. If more than one set of * parameters are passed in as an array or more than one item, they will map * to the vertex specified in the control points. The attributes are * of the format: * <tr><code>{"attributes":[{"<i>attribute1</i>":<i>value</i>,...},{<i>[optional]</i>]}</code></tr> * * @param name The user displayed name for the symbol. Users will use this * to identify with the symbol. * @param id An internally used unique id that developers can use to * uniquely distinguish this symbol from others. * @param shapeType A 15 character ID of the type of symbol to draw. * @param description A brief description of what the symbol represents. * Generic text that does not require any format. * @param color The fill color of the graphic * @param altitudeMode Indicates whether the symbol should interpret * altitudes as above sea level or above ground level. Options are * "relativeToGround" (from surface of earth), "absolute" (sea level), * "relativeToSeaFloor" (from the bottom of major bodies of water). * @param controlPoints The vertices of the shape. The number of required * vertices varies based on the shapeType of the symbol. The simplest shape * requires at least one point. Shapes that require more points than * required will ignore extra points. Format for numbers is as follows: * <br/><br/> * "x,y,z [x,y,z ]..." * @param attributes A JSON array holding the parameters for the * shape. Attributes should be of the following format: <br/><br/> * <tr><code>{"attributes":[{"<i>attribute1</i>":<i>value</i>,...},{<i>[optional]</i>]}</code></tr> * @return A KML string that represents a placemark for the 3D shape */ public static String Render3dSymbol(String name, String id, String shapeType, String description, String lineColor, String fillColor, String altitudeMode, String controlPoints, String attributes) { String returnValue = ""; try { StringBuilder output = new StringBuilder(); SymbolModifiers modifiers = new SymbolModifiers(); JSONObject attributesJSON; // Retrieve the attributes from the attributes object // Attributes should be a JSON array string of this format // { "attributes":[{"radius1":50, "minalt":0, "maxalt:100"}]} // There should only be one item in the JSON array, but if // there is more items this will ignore them. //attributes="{attributes:[{radius1:5000, minalt:0, maxalt:100}]}"; attributesJSON = new JSONObject(attributes); // If no attributes passed in or attributes set to null // default to an empty string. if (attributesJSON == null || attributes.equals("")) { attributesJSON = new JSONObject(DEFAULT_ATTRIBUTES); } JSONArray attributesArray = attributesJSON.getJSONArray(ATTRIBUTES); int attributesArrayLength = attributesArray.length(); if (attributesArrayLength> 0) { for(int i = 0; i < attributesArrayLength; i++) { // get the first item in the array and use those parameters. // if any of the parameters don't exist, it will use defaults. // Defaults are arbitrary, no reason not to change them. JSONObject currentAttributeSet = attributesArray.getJSONObject(i); if (currentAttributeSet.has(RADIUS1)) { modifiers.AM_DISTANCE.add(currentAttributeSet.getDouble(RADIUS1)); } if (currentAttributeSet.has(RADIUS2)) { modifiers.AM_DISTANCE.add(currentAttributeSet.getDouble(RADIUS2)); } if (currentAttributeSet.has(MIN_ALT)) { modifiers.X_ALTITUDE_DEPTH.add(currentAttributeSet.getDouble(MIN_ALT)); } if (currentAttributeSet.has(MAX_ALT)) { modifiers.X_ALTITUDE_DEPTH.add(currentAttributeSet.getDouble(MAX_ALT)); } if (currentAttributeSet.has(LEFT_AZIMUTH)) { modifiers.AN_AZIMUTH.add(currentAttributeSet.getDouble(LEFT_AZIMUTH)); } if (currentAttributeSet.has(RIGHT_AZIMUTH)) { modifiers.AN_AZIMUTH.add(currentAttributeSet.getDouble(RIGHT_AZIMUTH)); } } } // Send to the 3D renderer for generating the 3D point and creating // the KML to return. returnValue = Shape3DHandler.render3dSymbol(name, id, shapeType, description, lineColor, fillColor, altitudeMode, controlPoints, modifiers); } catch (JSONException je) { return ERR_ATTRIBUTES_NOT_FORMATTED; } catch (Exception ea) { ErrorLogger.LogException("SECWebRenderer", "Render3dSymbol()", ea); return ""; } return returnValue; } /** * Creates a 3D symbol from the MilStd2525B USAS or MIL-STD-2525C to be * displayed on a 3D globe surface. Only certain symbols from the MIL-STD * can be displayed in 3D. Most of these are graphics that fall under Fire * Support. Any graphic that has an X modifier (altitude/depth) should * have a 3D representation. Generates * Keyhole Markup Language (KML) to return that * specifies the points and format of * the rendering. * <br/> * Control points should be of the format of: * <tr><code>"x,y,z [x,y,z]..."</code></tr> * * * @param name The user displayed name for the symbol. Users will use this * to identify with the symbol. * @param id An internally used unique id that developers can use to * uniquely distinguish this symbol from others. * @param symbolCode A 15 character ID of the type of symbol to draw. Only * symbols with an X modifier from the standard will draw. * @param description A brief description of what the symbol represents. * Generic text that does not require any format. * @param altitudeMode Indicates whether the symbol should interpret * altitudes as above sea level or above ground level. Options are * "relativeToGround" (from surface of earth), "absolute" (sea level), * "relativeToSeaFloor" (from the bottom of major bodies of water). * @param controlPoints The vertices of the shape. The number of required * vertices varies based on the shapeType of the symbol. The simplest shape * requires at least one point. Shapes that require more points than * required will ignore extra points. Format for numbers is as follows: * <br/><br/> * "x,y,z [x,y,z ]..." * @saModifiers SparseArray<String> keyed on ModifiersTG. Only using values AM, AN and X. * Strings should be comma delimited for multiple values. * @saAttributes SparseArray<String> keyed on MilStdAttributes. Only using value FillColor. * @return A KML string that represents a placemark for the 3D shape */ private static String RenderMilStd3dSymbol(String name, String id, String symbolCode, String description, String altitudeMode, String controlPoints, SparseArray<String> saModifiers, SparseArray<String> saAttributes) { String symbolId = symbolCode.substring(4,10); SymbolModifiers attributes = new SymbolModifiers(); String output = ""; KmlOptions.AltitudeMode convertedAltitudeMode = KmlOptions.AltitudeMode.RELATIVE_TO_GROUND; // Convert altitude mode to an enum that we understand. If it does not // understand or is "", then convert to ALTITUDE_RELATIVE_TO_GROUND. if (!altitudeMode.equals("")) { convertedAltitudeMode = KmlOptions.AltitudeMode.fromString(altitudeMode); } try { String[] altitudeDepth = null; String[] distance = null; String[] azimuth = null; int altitudeDepthLength = 0; int distanceLength = 0; int azimuthLength = 0; String lineColor = ""; String fillColor = ""; if (saModifiers.indexOfKey(ModifiersTG.X_ALTITUDE_DEPTH)>=0) { altitudeDepth = saModifiers.get(ModifiersTG.X_ALTITUDE_DEPTH).split(","); altitudeDepthLength = altitudeDepth.length; } if (saModifiers.indexOfKey(ModifiersTG.AN_AZIMUTH)>=0) { azimuth = saModifiers.get(ModifiersTG.AN_AZIMUTH).split(","); azimuthLength = azimuth.length; } if (saModifiers.indexOfKey(ModifiersTG.AM_DISTANCE)>=0) { distance = saModifiers.get(ModifiersTG.AM_DISTANCE).split(","); distanceLength = distance.length; } if (saAttributes.indexOfKey(MilStdAttributes.LineColor)>=0) { lineColor = saAttributes.get(MilStdAttributes.LineColor); } else { Color c = SymbolUtilities.getFillColorOfAffiliation(symbolCode); lineColor = c.toHexString(); // ensure that some color is selected. If no color can be // found, use black. if (lineColor == null) { lineColor = "FF000000"; } } if (saAttributes.indexOfKey(MilStdAttributes.FillColor)>=0) { fillColor = saAttributes.get(MilStdAttributes.FillColor); } else { Color c = SymbolUtilities.getFillColorOfAffiliation(symbolCode); fillColor = c.toHexString(); // ensure that some color is selected. If no color can be // found, use black. if (fillColor == null) { fillColor = "AA000000"; } } lineColor = JavaRendererUtilities.ARGBtoABGR(lineColor); fillColor = JavaRendererUtilities.ARGBtoABGR(fillColor); for (int i=0; i < altitudeDepthLength; i++) { // if it's a killbox, need to set minimum alt to 0. if (symbolId.startsWith("AJP")) { attributes.X_ALTITUDE_DEPTH.add(0D); i++; } attributes.X_ALTITUDE_DEPTH.add(Double.parseDouble(altitudeDepth[i])); } for (int i=0; i < distanceLength; i++) { // If this is a 'track' type graphic, then we need to take the distance // and divide it by half, than add it twice. This is due // to the TAIS requirement that Tracks must have a left width // and a right width. if (symbolId.equals("ACAR--") || // ACA - rectangular symbolId.equals("AKPR--") || // Killbox - rectangular symbolId.equals("ALC---") || // air corricor symbolId.equals("ALM---") || // MRR symbolId.equals("ALS---") || // SAAFR symbolId.equals("ALU---") || // unmanned aircraft symbolId.equals("ALL---")) { // LLTR) { double width = Double.parseDouble(distance[i]) / 2; attributes.AM_DISTANCE.add(width); attributes.AM_DISTANCE.add(width); } else { attributes.AM_DISTANCE.add(Double.parseDouble(distance[i])); } } if (symbolId.equals("ACAI--") || // ACA - irregular symbolId.equals("AKPI--") || // Killbox - irregular symbolId.equals("AAR---") || // ROZ symbolId.equals("AAF---") || // SHORADEZ symbolId.equals("AAH---") || // HIDACZ symbolId.equals("AAM---") || // MEZ symbolId.equals("AAML--") || // LOMEZ symbolId.equals("AAMH--")) // HIMEZ { output = Shape3DHandler.buildPolygon(controlPoints, id, name, description, lineColor, fillColor, convertedAltitudeMode, attributes); } else if (symbolId.equals("ACAR--") || // ACA - rectangular symbolId.equals("AKPR--") || // Killbox - rectangular symbolId.equals("ALC---") || // air corricor symbolId.equals("ALM---") || // MRR symbolId.equals("ALS---") || // SAAFR symbolId.equals("ALU---") || // unmanned aircraft symbolId.equals("ALL---")) // LLTR { output = Shape3DHandler.buildTrack(controlPoints, id, name, description, lineColor, fillColor, convertedAltitudeMode, attributes); } else if (symbolId.equals("ACAC--") || // ACA - circular symbolId.equals("AKPC--")) // Killbox - circular { output = Shape3DHandler.buildCylinder(controlPoints, id, name, description, lineColor, fillColor, convertedAltitudeMode, attributes); } } catch (Exception exc) { output = ""; } return output; } /** * Renders all MilStd 2525 multi-point symbols, creating MilStdSymbol that contains the * information needed to draw the symbol on the map. * DOES NOT support RADARC, CAKE, TRACK etc... * ArrayList<Point2D> milStdSymbol.getSymbolShapes.get(index).getPolylines() * and * ShapeInfo = milStdSymbol.getModifierShapes.get(index). * * * @param id * A unique identifier used to identify the symbol by Google map. * The id will be the folder name that contains the graphic. * @param name * a string used to display to the user as the name of the * graphic being created. * @param description * a brief description about the graphic being made and what it * represents. * @param symbolCode * A 15 character symbolID corresponding to one of the graphics * in the MIL-STD-2525C * @param controlPoints * The vertices of the graphics that make up the graphic. Passed * in the format of a string, using decimal degrees separating * lat and lon by a comma, separating coordinates by a space. The * following format shall be used "x1,y1[,z1] [xn,yn[,zn]]..." * @param altitudeMode * Indicates whether the symbol should interpret altitudes as * above sea level or above ground level. Options are * "clampToGround", "relativeToGround" (from surface of earth), * "absolute" (sea level), "relativeToSeaFloor" (from the bottom * of major bodies of water). * @param scale * A number corresponding to how many meters one meter of our map * represents. A value "50000" would mean 1:50K which means for * every meter of our map it represents 50000 meters of real * world distance. * @param bbox * The viewable area of the map. Passed in the format of a string * "lowerLeftX,lowerLeftY,upperRightX,upperRightY." Not required * but can speed up rendering in some cases. example: * "-50.4,23.6,-42.2,24.2" * @param modifiers * Used like: * modifiers.put(ModifiersTG.T_UNIQUE_DESIGNATION_1, "T"); * Or * modifiers.put(ModifiersTG.AM_DISTANCE, "1000,2000,3000"); * @param attributes * Used like: * attributes.put(MilStdAttributes.LineWidth, "3"); * Or * attributes.put(MilStdAttributes.LineColor, "#00FF00"); * @param symStd * An enumeration: 0 for 2525Bch2, 1 for 2525C. * @return MilStdSymbol */ public static MilStdSymbol RenderMultiPointAsMilStdSymbol(String id, String name, String description, String symbolCode, String controlPoints, String altitudeMode, double scale, String bbox, SparseArray<String> modifiers, SparseArray<String> attributes, int symStd) { MilStdSymbol mSymbol = null; try { mSymbol = MultiPointHandler.RenderSymbolAsMilStdSymbol(id, name, description, symbolCode, controlPoints, scale, bbox, modifiers, attributes, symStd); } catch (Exception ea) { mSymbol=null; ErrorLogger.LogException("SECRenderer", "RenderMultiPointAsMilStdSymbol" + " - " + symbolCode, ea, Level.WARNING); } //System.out.println("RenderMultiPointAsMilStdSymbol exit"); return mSymbol; } /** * Given a symbol code meant for a single point symbol, returns the * anchor point at which to display that image based off the image returned * from the URL of the SinglePointServer. * * @param symbolID - the 15 character symbolID of a single point MilStd2525 * symbol. * @return A pixel coordinate of the format "x,y". * Returns an empty string if an error occurs. * @deprecated */ public String getSinglePointAnchor(String symbolID) { String anchorPoint = ""; Point2D anchor = new Point2D.Double(); anchorPoint = anchor.getX() + "," + anchor.getY(); return anchorPoint; } /** * Given a symbol code meant for a single point symbol, returns the * anchor point at which to display that image based off the image returned * from the URL of the SinglePointServer. * * @param symbolID - the 15 character symbolID of a single point MilStd2525 * symbol. * @return A pixel coordinate of the format "anchorX,anchorY,SymbolBoundsX, * SymbolBoundsY,SymbolBoundsWidth,SymbolBoundsHeight,IconWidth,IconHeight". * Anchor, represents the center point of the core symbol within the image. * The image should be centered on this point. * Symbol bounds represents the bounding rectangle of the core symbol within * the image. * IconWidth/Height represents the height and width of the image in its * entirety. * Returns an empty string if an error occurs. */ public static String getSinglePointInfo(String symbolID) { String info = ""; Point2D anchor = new Point2D.Double(); Rectangle2D symbolBounds = new Rectangle2D.Double(); return info; } /** * Returns true if we recommend clipping a particular symbol. * Would return false for and Ambush but would return true for a Line of * Contact due to the decoration on the line. * @param symbolID * @return */ public static String ShouldClipMultipointSymbol(String symbolID) { if(MultiPointHandler.ShouldClipSymbol(symbolID)) return "true"; else return "false"; } /** * Given a symbol code meant for a single point symbol, returns the * symbol as a byte array. * * @param symbolID - the 15 character symbolID of a single point MilStd2525 * symbol. * @return byte array. */ public static byte[] getSinglePointByteArray(String symbolID) { //return sps.getSinglePointByteArray(symbolID); return null; } /** * Put this here rather than in multipointhandler so that I could get the * port info from the single point server. * @param modifiers * @param clip * @return */ public static String GenerateSymbolLineFillUrl(SparseArray<String> modifiers, ArrayList<Point2D> pixels, Rectangle clip) { int shapeType = 0; String url = ""; String symbolFillIDs=null; String symbolLineIDs=null; String strClip=null; //int symbolSize = AreaSymbolFill.DEFAULT_SYMBOL_SIZE; int symbolSize = 25; int imageoffset = 0; ArrayList<ArrayList<Point2D>> lines = null; ArrayList<Point2D> points = null; Point2D point = null; Shape shape = null; //PathIterator itr = null; double height = 0; double width = 0; int offsetX = 0; int offsetY = 0; int x = 0; int y = 0; //Rectangle2D bounds = null; Rectangle bounds = null; try { //Path2D path = new GeneralPath(); GeneralPath path = new GeneralPath(); Point2D temp = null; //Get bounds of the polygon/polyline path for(int i=0; i<pixels.size();i++) { temp = pixels.get(i); if(i>0) { path.lineTo(temp.getX(), temp.getY()); } else if(i==0) { path.moveTo(temp.getX(), temp.getY()); } } bounds = path.getBounds(); height = bounds.getHeight(); width = bounds.getWidth(); // System.out.println("bounds: "+ bounds.toString()); // System.out.println("height: "+ String.valueOf(height)); // System.out.println("width: "+ String.valueOf(width)); //pixels may be in negative space so get offsets to put everything //in the positive if(bounds.getX()<0) { offsetX = (int)(bounds.getX()*-1); } else if((bounds.getX()+bounds.getWidth()) > width) { offsetX = (int)((bounds.getX()+bounds.getWidth())-width)*-1; } if(bounds.getY()<0) { offsetY = (int)(bounds.getY()*-1); } else if((bounds.getY()+bounds.getHeight()) > height) { offsetY = (int)((bounds.getY()+bounds.getHeight())-height)*-1; } //build clip string if(clip!=null) { StringBuilder sbClip = new StringBuilder(); sbClip.append("&clip="); sbClip.append(Integer.toString((int)clip.getX())); sbClip.append(","); sbClip.append(Integer.toString((int)clip.getY())); sbClip.append(","); sbClip.append(Integer.toString((int)clip.getWidth())); sbClip.append(","); sbClip.append(Integer.toString((int)clip.getHeight())); strClip=sbClip.toString(); } StringBuilder sbCoords = new StringBuilder(); StringBuilder sbUrl = new StringBuilder(); sbCoords.append("coords="); if (modifiers.indexOfKey(ModifiersTG.SYMBOL_FILL_IDS) >= 0) { symbolFillIDs = (String) modifiers.get(ModifiersTG.SYMBOL_FILL_IDS); } //build coordinate string for(int i = 0; i< pixels.size(); i++) { if(i>0) { sbCoords.append(","); } point = pixels.get(i); x = (int)(point.getX() + offsetX); y = (int)(point.getY() + offsetY); sbCoords.append(Integer.toString(x)); sbCoords.append(","); sbCoords.append(Integer.toString(y)); } //build image url sbUrl.append("http://127.0.0.1:"); //sbUrl.append(String.valueOf(spsPortNumber)); sbUrl.append("6789"); sbUrl.append("/AREASYMBOLFILL?"); sbUrl.append("renderer=AreaSymbolFillRenderer&"); sbUrl.append(sbCoords.toString()); if(symbolFillIDs != null) { sbUrl.append("&symbolFillIds="); sbUrl.append(symbolFillIDs); } if(symbolLineIDs != null) { sbUrl.append("&symbolLineIds="); sbUrl.append(symbolLineIDs); } if(symbolSize>0) { sbUrl.append("&symbolFillIconSize="); sbUrl.append(Integer.toString(symbolSize)); } if(strClip!=null) { sbUrl.append(strClip); } sbUrl.append("&height="); //sbUrl.append(Integer.valueOf((int)height)); sbUrl.append(Integer.toString((int)height)); sbUrl.append("&width="); //sbUrl.append(Integer.valueOf((int)width)); sbUrl.append(Integer.toString((int)width)); url = sbUrl.toString(); } catch(Exception exc) { System.out.println(exc.getMessage()); exc.printStackTrace(); } return url; } }