001package armyc2.c5isr.web.render;
002// This import is if we need to call a javascript function
003// It requires that you import the plugins.jar from the jdk folder into the project libraries
004//import netscape.javascript.JSObject;
005
006import android.content.Context;
007import armyc2.c5isr.renderer.MilStdIconRenderer;
008import armyc2.c5isr.renderer.utilities.ErrorLogger;
009import armyc2.c5isr.renderer.utilities.MilStdAttributes;
010import armyc2.c5isr.renderer.utilities.MilStdSymbol;
011import armyc2.c5isr.renderer.utilities.Modifiers;
012import armyc2.c5isr.renderer.utilities.RendererSettings;
013import armyc2.c5isr.renderer.utilities.Color;
014import armyc2.c5isr.graphics2d.Font;
015import armyc2.c5isr.graphics2d.Point2D;
016import armyc2.c5isr.graphics2d.Rectangle2D;
017import armyc2.c5isr.renderer.utilities.SymbolID;
018import armyc2.c5isr.renderer.utilities.SymbolUtilities;
019import armyc2.c5isr.web.render.utilities.Basic3DShapes;
020import armyc2.c5isr.web.render.utilities.JavaRendererUtilities;
021
022import java.util.Map;
023import java.util.logging.Level;
024import armyc2.c5isr.web.json.utilities.JSONArray;
025import armyc2.c5isr.web.json.utilities.JSONException;
026import armyc2.c5isr.web.json.utilities.JSONObject;
027
028/**
029 * Main class for rendering multi-point graphics such as Control Measures, Atmospheric, and Oceanographic.
030 */
031//@SuppressWarnings("unused")
032public final class WebRenderer /* extends Applet */ {
033
034    public static final int OUTPUT_FORMAT_KML = 0;
035    @Deprecated
036    public static final int OUTPUT_FORMAT_JSON = 1;
037    public static final int OUTPUT_FORMAT_GEOJSON = 2;
038    public static final int OUTPUT_FORMAT_GEOSVG = 3;
039
040
041    // Arbitrary default values of attributes
042    public static final double MIN_ALT_DEFAULT = 0.0D;
043    public static final double MAX_ALT_DEFAULT = 100.0D;
044    public static final double RADIUS1_DEFAULT = 50.0D;
045    public static final double RADIUS2_DEFAULT = 100.0D;
046    public static final double LEFT_AZIMUTH_DEFAULT = 0.0D;
047    public static final double RIGHT_AZIMUTH_DEFAULT = 90.0D;
048    
049    public static final String ERR_ATTRIBUTES_NOT_FORMATTED = "{\"type\":\"error\","
050            + "\"error\":\"The attribute paramaters are not formatted "
051            + "correctly";
052    
053    public static final String DEFAULT_ATTRIBUTES = "[{radius1:"
054            + RADIUS1_DEFAULT + ",radius2:"
055            + RADIUS2_DEFAULT + ",minalt:"
056            + MIN_ALT_DEFAULT + ",maxalt:"
057            + MAX_ALT_DEFAULT + ",rightAzimuth:"
058            + RIGHT_AZIMUTH_DEFAULT + ",leftAzimuth:"
059            + LEFT_AZIMUTH_DEFAULT + "}]";
060
061    
062    private static boolean _initSuccess = false;
063    
064
065    public static synchronized void init(Context context, String cacheDir) {
066
067        try
068        {
069                if(_initSuccess == false)
070                {
071                    MilStdIconRenderer.getInstance().init(context);
072                    //use WebRenderer.setLoggingLevel()
073                    
074                    //sets default value for single point symbology to have an outline.
075                    //outline color will be automatically determined based on line color
076                    //unless a color value is manually set.
077                    
078                    //Set Renderer Settings/////////////////////////////////////////////
079                    //RendererSettings.getInstance().setSinglePointSymbolOutlineWidth(1);
080                RendererSettings.getInstance().setTextBackgroundMethod(RendererSettings.TextBackgroundMethod_OUTLINE);
081                    //RendererSettings.getInstance().setTextBackgroundMethod(RendererSettings.TextBackgroundMethod_OUTLINE_QUICK);
082                    //RendererSettings.getInstance().setTextOutlineWidth(2);
083                    //RendererSettings.getInstance().setLabelForegroundColor(Color.BLACK.toARGB());
084                    //RendererSettings.getInstance().setLabelBackgroundColor(new Color(255, 255, 255, 200).toARGB());
085                    RendererSettings.getInstance().setModifierFont("arial", Font.PLAIN, 12);
086                    ErrorLogger.setLevel(Level.FINE);
087                    _initSuccess = true;
088                }
089            
090        }
091        catch(Exception exc)
092        {
093            ErrorLogger.LogException("WebRenderer", "init", exc, Level.WARNING);
094        }
095
096
097    }
098
099    
100    /**\
101     * Set minimum level at which an item can be logged.
102     * In descending order:
103     * OFF = Integer.MAX_VALUE
104     * Severe = 1000
105     * Warning = 900
106     * Info = 800
107     * Config = 700
108     * Fine = 500
109     * Finer = 400 
110     * Finest = 300
111     * All = Integer.MIN_VALUE
112     * Use like WebRenderer.setLoggingLevel(Level.INFO);
113     * or
114     * Use like WebRenderer.setLoggingLevel(800);
115     * @param level java.util.logging.level
116     */
117    public static void setLoggingLevel(Level level)
118    {
119        try
120        {
121            ErrorLogger.setLevel(level,true);
122            ErrorLogger.LogMessage("WebRenderer", "setLoggingLevel(Level)",
123                    "Logging level set to: " + ErrorLogger.getLevel().getName(), 
124                    Level.CONFIG);
125        }
126        catch(Exception exc)
127        {
128            ErrorLogger.LogException("WebRenderer", "setLoggingLevel(Level)", exc, Level.INFO);
129        }
130    }
131    
132    /**\
133     * Set minimum level at which an item can be logged.
134     * In descending order:
135     * OFF = Integer.MAX_VALUE
136     * Severe = 1000
137     * Warning = 900
138     * Info = 800
139     * Config = 700
140     * Fine = 500
141     * Finer = 400 
142     * Finest = 300
143     * All = Integer.MIN_VALUE
144     * Use like WebRenderer.setLoggingLevel(Level.INFO);
145     * or
146     * Use like WebRenderer.setLoggingLevel(800);
147     * @param level int
148     */
149    public static void setLoggingLevel(int level)
150    {
151        try
152        {
153            if(level > 1000)
154                  ErrorLogger.setLevel(Level.OFF,true);
155            else if(level > 900)
156                  ErrorLogger.setLevel(Level.SEVERE,true);
157            else if(level > 800)
158                  ErrorLogger.setLevel(Level.WARNING,true);
159            else if(level > 700)
160                  ErrorLogger.setLevel(Level.INFO,true);
161            else if(level > 500)
162                  ErrorLogger.setLevel(Level.CONFIG,true);
163            else if(level > 400)
164                  ErrorLogger.setLevel(Level.FINE,true);
165            else if(level > 300)
166                  ErrorLogger.setLevel(Level.FINER,true);
167            else if(level > Integer.MIN_VALUE)
168                  ErrorLogger.setLevel(Level.FINEST,true);
169            else
170                ErrorLogger.setLevel(Level.ALL,true);
171            
172            ErrorLogger.LogMessage("WebRenderer", "setLoggingLevel(int)",
173                    "Logging level set to: " + ErrorLogger.getLevel().getName(), 
174                    Level.CONFIG);
175        }
176        catch(Exception exc)
177        {
178            ErrorLogger.LogException("WebRenderer", "setLoggingLevel(int)", exc, Level.INFO);
179        }
180    }
181
182    /**
183     * Single Point Tactical Graphics are rendered from font files.
184     * The font size you specify here determines how big the symbols will 
185     * be rendered.  This should be set once at startup.
186     * @param size
187     */
188    public static void setTacticalGraphicPointSize(int size)
189    {
190//        sps.setTacticalGraphicPointSize(size);
191    }
192    
193    /**
194     * Units are rendered from font files.
195     * The font size you specify here determines how big the symbols will 
196     * be rendered.  This should be set once at startup. 
197     * @param size
198     */
199    public static void setUnitPointSize(int size)
200    {
201//        sps.setUnitPointSize(size);
202    }
203    
204    /**
205     * Modifier Text Color will by default match the line color.
206     * This will override all modifier text color.
207     * @param hexColor 
208     */
209/*    public static void setModifierTextColor(String hexColor)
210    {
211        Color textColor = RendererUtilities.getColorFromHexString(hexColor);
212        if(textColor==null)
213        {
214            textColor = Color.black;
215        }
216        RendererSettings.getInstance().setLabelForegroundColor(textColor.toARGB());
217    }*/
218
219
220    
221
222
223    /**
224     * Renders all multi-point symbols, creating KML, GeoJSON or SVG that can be used to draw
225     * it on a Google map.  Multipoint symbols cannot be draw the same 
226     * at different scales. For instance, graphics with arrow heads will need to 
227     * redraw arrowheads when you zoom in on it.  Similarly, graphics like a 
228     * Forward Line of Troops drawn with half circles can improve performance if 
229     * clipped when the parts of the graphic that aren't on the screen.  To help 
230     * readjust graphics and increase performance, this function requires the 
231     * scale and bounding box to help calculate the new locations.
232     * @param id A unique identifier used to identify the symbol by Google map. 
233     * The id will be the folder name that contains the graphic.
234     * @param name a string used to display to the user as the name of the 
235     * graphic being created.
236     * @param description a brief description about the graphic being made and 
237     * what it represents.
238     * @param symbolCode A 20-30 digit symbolID corresponding to one of the
239     * graphics in the MIL-STD-2525D
240     * @param controlPoints The vertices of the graphics that make up the
241     * graphic.  Passed in the format of a string, using decimal degrees 
242     * separating lat and lon by a comma, separating coordinates by a space.  
243     * The following format shall be used "x1,y1[,z1] [xn,yn[,zn]]..."
244     * @param altitudeMode Indicates whether the symbol should interpret 
245     * altitudes as above sea level or above ground level. Options are 
246     * "clampToGround", "relativeToGround" (from surface of earth), "absolute" 
247     * (sea level), "relativeToSeaFloor" (from the bottom of major bodies of 
248     * water).
249     * @param scale A number corresponding to how many meters one meter of our 
250     * map represents. A value "50000" would mean 1:50K which means for every 
251     * meter of our map it represents 50000 meters of real world distance.
252     * <a href="https://github.com/missioncommand/mil-sym-java/wiki/2525D--Renderer-Overview#3316-scale-for-3d">Scale Calculation Example</a>
253     * @param bbox The viewable area of the map.  Passed in the format of a
254     * string "lowerLeftX,lowerLeftY,upperRightX,upperRightY." Not required
255     * but can speed up rendering in some cases.
256     * example: "-50.4,23.6,-42.2,24.2"
257     * @param modifiers keyed using constants from Modifiers.
258     * Pass in comma delimited String for modifiers with multiple values like AM, AN &amp; X
259     * @param attributes keyed using constants from MilStdAttributes.
260     * @param format {@link WebRenderer#OUTPUT_FORMAT_KML}, {@link WebRenderer#OUTPUT_FORMAT_GEOJSON} or {@link WebRenderer#OUTPUT_FORMAT_GEOSVG}
261     * @return A KML, GeoJSON or SVG string representation of the graphic.
262     */
263    public static String RenderSymbol(String id, String name, String description,
264                                      String symbolCode, String controlPoints, String altitudeMode,
265                                      double scale, String bbox, Map<String,String> modifiers, Map<String,String> attributes, int format) {
266        String output = "";
267        try {
268
269            //catch duplicate symbols and redirect to original symbol.
270            symbolCode = interceptAndAdjustCode(symbolCode,modifiers,attributes);
271
272                JavaRendererUtilities.addAltModeToModifiersString(attributes,altitudeMode);
273        
274            if (!altitudeMode.equals("clampToGround")
275                    && (format == WebRenderer.OUTPUT_FORMAT_KML || format == WebRenderer.OUTPUT_FORMAT_GEOJSON)
276                    && JavaRendererUtilities.is3dSymbol(symbolCode)
277                    && modifiers.get(Modifiers.X_ALTITUDE_DEPTH) != null
278                    && !modifiers.get(Modifiers.X_ALTITUDE_DEPTH).isEmpty()) {
279                output = RenderMilStd3dSymbol(id, name, description, symbolCode, controlPoints, altitudeMode, scale, bbox, modifiers, attributes, format);
280            }
281
282            if (output.isEmpty()) {
283                output = MultiPointHandler.RenderSymbol(id, name, description, symbolCode, controlPoints,
284                        scale, bbox, modifiers, attributes, format);
285
286                //DEBUGGING
287                if (ErrorLogger.getLevel().intValue() <= Level.FINER.intValue()) {
288                    System.out.println("");
289                    StringBuilder sb = new StringBuilder();
290                    sb.append("\nID: ").append(id).append("\n");
291                    sb.append("Name: ").append(name).append("\n");
292                    sb.append("Description: ").append(description).append("\n");
293                    sb.append("SymbolID: ").append(symbolCode).append("\n");
294                    sb.append("Scale: ").append(String.valueOf(scale)).append("\n");
295                    sb.append("BBox: ").append(bbox).append("\n");
296                    sb.append("Coords: ").append(controlPoints).append("\n");
297                    sb.append("Modifiers: ").append(modifiers).append("\n");
298                    ErrorLogger.LogMessage("WebRenderer", "RenderSymbol", sb.toString(), Level.FINER);
299                }
300                if (ErrorLogger.getLevel().intValue() <= Level.FINEST.intValue()) {
301                    String briefOutput = output.replaceAll("</Placemark>", "</Placemark>\n");
302                    briefOutput = output.replaceAll("(?s)<description[^>]*>.*?</description>", "<description></description>");
303                    ErrorLogger.LogMessage("WebRenderer", "RenderSymbol", "Output:\n" + briefOutput, Level.FINEST);
304                }
305
306            }
307
308        } catch (Exception ea) {
309            
310            output = "{\"type\":'error',error:'There was an error creating the MilStdSymbol - " + ea.toString() + "'}";
311            ErrorLogger.LogException("WebRenderer", "RenderSymbol", ea, Level.WARNING);
312        }
313        
314        return output;
315    }
316    
317
318         
319
320
321    /**
322     * Renders all multi-point symbols, creating KML, GeoJSON or SVG for the user to
323     * parse and render as they like.
324     * This function requires the bounding box to help calculate the new
325     * locations.
326     * @param id A unique identifier used to identify the symbol by Google map.
327     * The id will be the folder name that contains the graphic.
328     * @param name a string used to display to the user as the name of the 
329     * graphic being created.
330     * @param description a brief description about the graphic being made and 
331     * what it represents.
332     * @param symbolCode A 20-30 digit symbolID corresponding to one of the
333     * graphics in the MIL-STD-2525D
334     * @param controlPoints The vertices of the graphics that make up the
335     * graphic.  Passed in the format of a string, using decimal degrees
336     * separating lat and lon by a comma, separating coordinates by a space.
337     * The following format shall be used "x1,y1 [xn,yn]..."
338     * @param pixelWidth pixel dimensions of the viewable map area
339     * @param pixelHeight pixel dimensions of the viewable map area
340     * @param bbox The viewable area of the map.  Passed in the format of a
341     * string "lowerLeftX,lowerLeftY,upperRightX,upperRightY."
342     * example: "-50.4,23.6,-42.2,24.2"
343     * @param modifiers keyed using constants from Modifiers.
344     * Pass in comma delimited String for modifiers with multiple values like AM, AN &amp; X
345     * @param attributes keyed using constants from MilStdAttributes.
346     * @param format {@link WebRenderer#OUTPUT_FORMAT_KML}, {@link WebRenderer#OUTPUT_FORMAT_GEOJSON} or {@link WebRenderer#OUTPUT_FORMAT_GEOSVG}
347     * @return A KML, GeoJSON or SVG string representation of the graphic.
348     */
349    public static String RenderSymbol2D(String id, String name, String description, String symbolCode, String controlPoints,
350            int pixelWidth, int pixelHeight, String bbox, Map<String,String> modifiers, Map<String,String> attributes, int format)
351    {
352        String output = "";
353        try
354        {
355            //catch duplicate symbols and redirect to original symbol.
356            symbolCode = interceptAndAdjustCode(symbolCode,modifiers,attributes);
357
358            output = MultiPointHandler.RenderSymbol2D(id, name, description, 
359                    symbolCode, controlPoints, pixelWidth, pixelHeight, bbox, 
360                    modifiers, attributes, format);
361        }
362        catch(Exception exc)
363        {
364            output = "{\"type\":'error',error:'There was an error creating the MilStdSymbol: " + symbolCode + " - " + exc.toString() + "'}";
365        }
366        return output;
367    }
368
369    /**
370     * Renders all 3d multi-point symbols, creating KML or GeoJSON that can be
371     * used to draw it on a Google map.
372     * 3D version of RenderSymbol()
373     *
374     * @param id            A unique identifier used to identify the symbol by Google map.
375     *                      The id will be the folder name that contains the graphic.
376     * @param name          a string used to display to the user as the name of the
377     *                      graphic being created.
378     * @param description   a brief description about the graphic being made and
379     *                      what it represents.
380     * @param symbolCode    A 20-30 digit symbolID corresponding to one of the
381     *                      graphics in the MIL-STD-2525D
382     * @param controlPoints The vertices of the graphics that make up the
383     *                      graphic.  Passed in the format of a string, using decimal degrees
384     *                      separating lat and lon by a comma, separating coordinates by a space.
385     *                      The following format shall be used "x1,y1[,z1] [xn,yn[,zn]]..."
386     * @param altitudeMode  Indicates whether the symbol should interpret
387     *                      altitudes as above sea level or above ground level. Options are
388     *                      "clampToGround", "relativeToGround" (from surface of earth), "absolute"
389     *                      (sea level), "relativeToSeaFloor" (from the bottom of major bodies of
390     *                      water).
391     * @param scale         A number corresponding to how many meters one meter of our
392     *                      map represents. A value "50000" would mean 1:50K which means for every
393     *                      meter of our map it represents 50000 meters of real world distance.
394     *                      <a href="https://github.com/missioncommand/mil-sym-java/wiki/2525D--Renderer-Overview#3316-scale-for-3d">Scale Calculation Example</a>
395     * @param bbox          The viewable area of the map.  Passed in the format of a
396     *                      string "lowerLeftX,lowerLeftY,upperRightX,upperRightY." Not required
397     *                      but can speed up rendering in some cases.
398     *                      example: "-50.4,23.6,-42.2,24.2"
399     * @param modifiers     keyed using constants from Modifiers.
400     *                      Pass in comma delimited String for modifiers with multiple values like AM, AN &amp; X
401     * @param attributes    keyed using constants from MilStdAttributes.
402     * @param format        {@link WebRenderer#OUTPUT_FORMAT_KML}, {@link WebRenderer#OUTPUT_FORMAT_GEOJSON} or {@link WebRenderer#OUTPUT_FORMAT_GEOSVG}
403     * @return A KML, GeoJSON or SVG string representation of the graphic.
404     */
405    public static String RenderMilStd3dSymbol(String id, String name, String description,
406                                              String symbolCode, String controlPoints, String altitudeMode,
407                                              double scale, String bbox, Map<String, String> modifiers, Map<String, String> attributes, int format) {
408        String output = "";
409        try {
410
411            output = Shape3DHandler.RenderMilStd3dSymbol(id, name, description, symbolCode, controlPoints, altitudeMode,
412                    scale, bbox, modifiers, attributes, format);
413
414            //DEBUGGING
415            if (ErrorLogger.getLevel().intValue() <= Level.FINER.intValue()) {
416                System.out.println("");
417                StringBuilder sb = new StringBuilder();
418                sb.append("\nID: ").append(id).append("\n");
419                sb.append("Name: ").append(name).append("\n");
420                sb.append("Description: ").append(description).append("\n");
421                sb.append("SymbolID: ").append(symbolCode).append("\n");
422                sb.append("Scale: ").append(String.valueOf(scale)).append("\n");
423                sb.append("BBox: ").append(bbox).append("\n");
424                sb.append("Coords: ").append(controlPoints).append("\n");
425                sb.append("Modifiers: ").append(modifiers).append("\n");
426                ErrorLogger.LogMessage("WebRenderer", "RenderMilStd3dSymbol", sb.toString(), Level.FINER);
427            }
428            if (ErrorLogger.getLevel().intValue() <= Level.FINEST.intValue()) {
429                String briefOutput = output.replaceAll("</Placemark>", "</Placemark>\n");
430                briefOutput = output.replaceAll("(?s)<description[^>]*>.*?</description>", "<description></description>");
431                ErrorLogger.LogMessage("WebRenderer", "RenderMilStd3dSymbol", "Output:\n" + briefOutput, Level.FINEST);
432            }
433        } catch (Exception ea) {
434            output = "{\"type\":'error',error:'There was an error creating the 3D MilStdSymbol - " + ea.toString() + "'}";
435            ErrorLogger.LogException("WebRenderer", "RenderMilStd3dSymbol", ea, Level.WARNING);
436        }
437        return output;
438    }
439
440    /**
441         * Renders all MilStd 2525 multi-point symbols, creating MilStdSymbol that contains the
442         * information needed to draw the symbol on the map.
443     * DOES NOT support RADARC, CAKE, TRACK etc...
444         * ArrayList&lt;Point2D&gt; milStdSymbol.getSymbolShapes.get(index).getPolylines()
445         * and 
446         * ShapeInfo = milStdSymbol.getModifierShapes.get(index). 
447         * 
448         * 
449         * @param id
450         *            A unique identifier used to identify the symbol by Google map.
451         *            The id will be the folder name that contains the graphic.
452         * @param name
453         *            a string used to display to the user as the name of the
454         *            graphic being created.
455         * @param description
456         *            a brief description about the graphic being made and what it
457         *            represents.
458         * @param symbolCode
459         *            A 20-30 digit symbolID corresponding to one of the graphics
460         *            in the MIL-STD-2525D
461         * @param controlPoints
462         *            The vertices of the graphics that make up the graphic. Passed
463         *            in the format of a string, using decimal degrees separating
464         *            lat and lon by a comma, separating coordinates by a space. The
465         *            following format shall be used "x1,y1[,z1] [xn,yn[,zn]]..."
466         * @param altitudeMode
467         *            ignored
468         * @param scale
469         *            A number corresponding to how many meters one meter of our map
470         *            represents. A value "50000" would mean 1:50K which means for
471         *            every meter of our map it represents 50000 meters of real
472         *            world distance.
473     *            <a href="https://github.com/missioncommand/mil-sym-java/wiki/2525D--Renderer-Overview#3316-scale-for-3d">Scale Calculation Example</a>
474         * @param bbox
475         *            The viewable area of the map. Passed in the format of a string
476         *            "lowerLeftX,lowerLeftY,upperRightX,upperRightY." Not required
477         *            but can speed up rendering in some cases. example:
478         *            "-50.4,23.6,-42.2,24.2"
479         * @param modifiers
480         *            Used like:
481         *            modifiers.put(Modifiers.T_UNIQUE_DESIGNATION_1, "T");
482         *            Or
483         *            modifiers.put(Modifiers.AM_DISTANCE, "1000,2000,3000");
484         * @param attributes
485         *                        Used like:
486         *            attributes.put(MilStdAttributes.LineWidth, "3");
487         *            Or
488         *            attributes.put(MilStdAttributes.LineColor, "#00FF00");
489     * @return MilStdSymbol
490     */
491    public static MilStdSymbol RenderMultiPointAsMilStdSymbol(String id, String name, String description, String symbolCode,
492                        String controlPoints, String altitudeMode, double scale, String bbox, Map<String,String> modifiers, Map<String,String> attributes)
493    {
494                MilStdSymbol mSymbol = null;
495                try 
496                {
497            //catch duplicate symbols and redirect to original symbol.
498            symbolCode = interceptAndAdjustCode(symbolCode,modifiers,attributes);
499            
500                        mSymbol = MultiPointHandler.RenderSymbolAsMilStdSymbol(id, name, description, symbolCode,
501                    controlPoints, scale, bbox, modifiers, attributes);
502
503            //Uncomment to show sector1 modifiers as fill pattern
504//            int symbolSet = SymbolID.getEntityCode(symbolCode);
505//            if(symbolSet == 270707 || symbolSet == 270800 || symbolSet == 270801 || symbolSet == 151100) //Mined Areas
506//            {
507//                int size = RendererSettings.getInstance().getDefaultPixelSize();
508//
509//                ArrayList<ShapeInfo> shapes = mSymbol.getSymbolShapes();
510//                if(shapes.size() > 0){
511//                    ShapeInfo shape = shapes.get(0);
512//                    shape.setPatternFillImage(PatternFillRendererD.MakeSymbolPatternFill(symbolCode,size));
513//                    if(shape.getPatternFillImage() != null)
514//                        shape.setShader(new BitmapShader(shape.getPatternFillImage(), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
515//                }
516//            }
517                }
518                catch (Exception ea) 
519                {
520                        mSymbol=null;
521                        ErrorLogger.LogException("WebRenderer", "RenderMultiPointAsMilStdSymbol" + " - " + symbolCode, ea, Level.WARNING);
522                }
523                
524                //System.out.println("RenderMultiPointAsMilStdSymbol exit");
525                return mSymbol;
526    }
527
528    /**
529     * Renders basic shapes as symbols, creating MilStdSymbol that contains the
530     * information needed to draw the shape on the map.
531     * ArrayList&lt;Point2D&gt; milStdSymbol.getSymbolShapes.get(index).getPolylines()
532     * and
533     * ShapeInfo = milStdSymbol.getModifierShapes.get(index).
534     *
535     *
536     * @param id
537     *            A unique identifier used to identify the symbol by Google map.
538     *            The id will be the folder name that contains the graphic.
539     * @param name
540     *            a string used to display to the user as the name of the
541     *            graphic being created.
542     * @param description
543     *            a brief description about the graphic being made and what it
544     *            represents.
545     * @param basicShapeType
546     *            {@link armyc2.c5isr.JavaLineArray.BasicShapes}
547     * @param controlPoints
548     *            The vertices of the graphics that make up the graphic. Passed
549     *            in the format of a string, using decimal degrees separating
550     *            lat and lon by a comma, separating coordinates by a space. The
551     *            following format shall be used "x1,y1[,z1] [xn,yn[,zn]]..."
552     * @param altitudeMode
553     *            ignored
554     * @param scale
555     *            A number corresponding to how many meters one meter of our map
556     *            represents. A value "50000" would mean 1:50K which means for
557     *            every meter of our map it represents 50000 meters of real
558     *            world distance.
559     *            <a href="https://github.com/missioncommand/mil-sym-java/wiki/2525D--Renderer-Overview#3316-scale-for-3d">Scale Calculation Example</a>
560     * @param bbox
561     *            The viewable area of the map. Passed in the format of a string
562     *            "lowerLeftX,lowerLeftY,upperRightX,upperRightY." Not required
563     *            but can speed up rendering in some cases. example:
564     *            "-50.4,23.6,-42.2,24.2"
565     * @param modifiers
566     *            Used like:
567     *            modifiers.put(Modifiers.T_UNIQUE_DESIGNATION_1, "T");
568     *            Or
569     *            modifiers.put(Modifiers.AM_DISTANCE, "1000,2000,3000");
570     * @param attributes
571     *                    Used like:
572     *            attributes.put(MilStdAttributes.LineWidth, "3");
573     *            Or
574     *            attributes.put(MilStdAttributes.LineColor, "#00FF00");
575     * @return MilStdSymbol
576     */
577    public static MilStdSymbol RenderBasicShapeAsMilStdSymbol(String id, String name, String description, int basicShapeType,
578                                                              String controlPoints, String altitudeMode, double scale, String bbox, Map<String, String> modifiers, Map<String, String> attributes) {
579        MilStdSymbol mSymbol = null;
580        try {
581            if (SymbolUtilities.isBasicShape(basicShapeType))
582                mSymbol = MultiPointHandler.RenderBasicShapeAsMilStdSymbol(id, name, description, basicShapeType,
583                        controlPoints, scale, bbox, modifiers, attributes);
584        } catch (Exception ea) {
585            mSymbol = null;
586            ErrorLogger.LogException("WebRenderer", "RenderBasicShapeAsMilStdSymbol" + " - " + basicShapeType, ea, Level.WARNING);
587        }
588
589        return mSymbol;
590    }
591
592    /**
593     * Renders multipoint basic shapes, creating KML, GeoJSON or SVG that can be used to draw
594     * it on a Google map.
595     * @param id A unique identifier used to identify the symbol by Google map.
596     * The id will be the folder name that contains the graphic.
597     * @param name a string used to display to the user as the name of the
598     * graphic being created.
599     * @param description a brief description about the graphic being made and
600     * what it represents.
601     * @param basicShapeType {@link armyc2.c5isr.JavaLineArray.BasicShapes}
602     * @param controlPoints The vertices of the graphics that make up the
603     * graphic.  Passed in the format of a string, using decimal degrees
604     * separating lat and lon by a comma, separating coordinates by a space.
605     * The following format shall be used "x1,y1[,z1] [xn,yn[,zn]]..."
606     * @param altitudeMode ignored
607     * @param scale A number corresponding to how many meters one meter of our
608     * map represents. A value "50000" would mean 1:50K which means for every
609     * meter of our map it represents 50000 meters of real world distance.
610     * <a href="https://github.com/missioncommand/mil-sym-java/wiki/2525D--Renderer-Overview#3316-scale-for-3d">Scale Calculation Example</a>
611     * @param bbox The viewable area of the map.  Passed in the format of a
612     * string "lowerLeftX,lowerLeftY,upperRightX,upperRightY." Not required
613     * but can speed up rendering in some cases.
614     * example: "-50.4,23.6,-42.2,24.2"
615     * @param modifiers keyed using constants from Modifiers.
616     * Pass in comma delimited String for modifiers with multiple values like AM, AN &amp; X
617     * @param attributes keyed using constants from MilStdAttributes.
618     * @param format {@link WebRenderer#OUTPUT_FORMAT_KML}, {@link WebRenderer#OUTPUT_FORMAT_GEOJSON} or {@link WebRenderer#OUTPUT_FORMAT_GEOSVG}
619     * @return A KML, GeoJSON or SVG string representation of the graphic.
620     */
621    public static String RenderBasicShape(String id, String name, String description, int basicShapeType,
622                                          String controlPoints, String altitudeMode,
623                                          double scale, String bbox, Map<String, String> modifiers, Map<String, String> attributes, int format) {
624        String output = "";
625        try {
626            if (SymbolUtilities.isBasicShape(basicShapeType))
627                output = MultiPointHandler.RenderBasicShape(id, name, description, basicShapeType, controlPoints,
628                    scale, bbox, modifiers, attributes, format);
629        } catch (Exception ea) {
630            output = "{\"type\":'error',error:'There was an error creating the MilStdSymbol - " + ea.toString() + "'}";
631            ErrorLogger.LogException("WebRenderer", "RenderBasicShape", ea, Level.WARNING);
632        }
633        return output;
634    }
635
636    /**
637     * Renders basic 3D shapes, creating KML or GeoJSON that can be used to draw
638     * it on a Google map.
639     * @param id A unique identifier used to identify the symbol by Google map.
640     * The id will be the folder name that contains the graphic.
641     * @param name a string used to display to the user as the name of the
642     * graphic being created.
643     * @param description a brief description about the graphic being made and
644     * what it represents.
645     * @param basicShapeType {@link Basic3DShapes}
646     * @param controlPoints The vertices of the graphics that make up the
647     * graphic.  Passed in the format of a string, using decimal degrees
648     * separating lat and lon by a comma, separating coordinates by a space.
649     * The following format shall be used "x1,y1[,z1] [xn,yn[,zn]]..."
650     * @param altitudeMode Indicates whether the symbol should interpret
651     * altitudes as above sea level or above ground level. Options are
652     * "clampToGround", "relativeToGround" (from surface of earth), "absolute"
653     * (sea level), "relativeToSeaFloor" (from the bottom of major bodies of
654     * water).
655     * @param scale A number corresponding to how many meters one meter of our
656     * map represents. A value "50000" would mean 1:50K which means for every
657     * meter of our map it represents 50000 meters of real world distance.
658     * <a href="https://github.com/missioncommand/mil-sym-java/wiki/2525D--Renderer-Overview#3316-scale-for-3d">Scale Calculation Example</a>
659     * @param bbox The viewable area of the map.  Passed in the format of a
660     * string "lowerLeftX,lowerLeftY,upperRightX,upperRightY." Not required
661     * but can speed up rendering in some cases.
662     * example: "-50.4,23.6,-42.2,24.2"
663     * @param modifiers {@link Map}, keyed using constants from Modifiers.
664     * Pass in comma delimited String for modifiers with multiple values like AM, AN &amp; X
665     * @param attributes {@link Map}, keyed using constants from MilStdAttributes.
666     * @param format {@link WebRenderer#OUTPUT_FORMAT_KML}, {@link #OUTPUT_FORMAT_GEOJSON}
667     * @return A KML or GeoJSON string representation of the graphic.
668     */
669    public static String RenderBasic3DShape(String id, String name, String description, int basicShapeType,
670                                            String controlPoints, String altitudeMode,
671                                            double scale, String bbox, Map<String, String> modifiers, Map<String, String> attributes, int format) {
672        String output = "";
673        try {
674            JavaRendererUtilities.addAltModeToModifiersString(attributes, altitudeMode);
675            if (SymbolUtilities.isBasicShape(basicShapeType))
676                output = Shape3DHandler.RenderBasic3DShape(id, name, description, basicShapeType, controlPoints, altitudeMode,
677                        scale, bbox, modifiers, attributes, format);
678        } catch (Exception ea) {
679            output = "{\"type\":'error',error:'There was an error creating the 3D MilStdSymbol - " + ea.toString() + "'}";
680            ErrorLogger.LogException("WebRenderer", "RenderBasic3DShape", ea, Level.WARNING);
681        }
682        return output;
683    }
684    
685    /**
686     * Given a symbol code meant for a single point symbol, returns the
687     * anchor point at which to display that image based off the image returned
688     * from the URL of the SinglePointServer.
689     * 
690     * @param symbolID - the 20-30 digit symbolID of a single point MilStd2525
691     * symbol. 
692     * @return A pixel coordinate of the format "x,y".
693     * Returns an empty string if an error occurs.
694     * @deprecated 
695     */
696        public String getSinglePointAnchor(String symbolID) {
697        String anchorPoint = "";
698        Point2D anchor = new Point2D.Double();
699        anchorPoint = anchor.getX() + "," + anchor.getY();        
700        return anchorPoint;
701    }
702
703    /**
704     * Given a symbol code meant for a single point symbol, returns the
705     * anchor point at which to display that image based off the image returned
706     * from the URL of the SinglePointServer.
707     *
708     * @param symbolID - the 20-30 digit symbolID of a single point MilStd2525
709     * symbol.
710     * @return A pixel coordinate of the format "anchorX,anchorY,SymbolBoundsX,
711     * SymbolBoundsY,SymbolBoundsWidth,SymbolBoundsHeight,IconWidth,IconHeight".
712     * Anchor, represents the center point of the core symbol within the image.
713     * The image should be centered on this point.
714     * Symbol bounds represents the bounding rectangle of the core symbol within
715     * the image.
716     * IconWidth/Height represents the height and width of the image in its
717     * entirety.
718     * Returns an empty string if an error occurs.
719     * @deprecated
720     */
721    public static String getSinglePointInfo(String symbolID)
722    {
723        String info = "";
724        Point2D anchor = new Point2D.Double();
725        Rectangle2D symbolBounds = new Rectangle2D.Double();
726        return info;
727    }
728        
729    /**
730     * Returns true if we recommend clipping a particular symbol.
731     * Would return false for and Ambush but would return true for a Line of 
732     * Contact due to the decoration on the line.
733     * @param symbolID
734     * @return 
735     */
736    public static String ShouldClipMultipointSymbol(String symbolID)
737    {
738        if(MultiPointHandler.ShouldClipSymbol(symbolID))
739            return "true";
740        else
741            return "false";
742    }
743    
744     /**
745     * Given a symbol code meant for a single point symbol, returns the
746     * symbol as a byte array.
747     *
748     * @param symbolID - the 20-30 digit symbolID of a single point MilStd2525
749     * symbol.
750     * @return byte array.
751      * @deprecated
752     */
753    public static byte[] getSinglePointByteArray(String symbolID)
754    {
755        //return sps.getSinglePointByteArray(symbolID);
756        return null;
757    }
758
759    /**
760     * There are a handful of redundant symbols in APP6 that are duplicate symbols that could be properly rendered
761     * using the original symbol with the appropriate modifier changes.
762     * Here we intercept and adjust that values as needed.
763     * @param symbolID
764     * @param modifiers
765     * @param attributes
766     * @return
767     */
768    private static String interceptAndAdjustCode(String symbolID, Map<String, String> modifiers, Map<String, String> attributes)
769    {
770        if(SymbolID.getSymbolSet(symbolID)==SymbolID.SymbolSet_ControlMeasure)
771        {
772            String returnVal = symbolID;
773            int etc = SymbolID.getEntityCode(symbolID);
774            switch (etc)
775            {
776                case 151406://Axis of Advance for a Feint
777                    returnVal = SymbolID.setEntityCode(returnVal,151404);//SUpporting Atttack
778                    returnVal = SymbolID.setHQTFD(returnVal,SymbolID.HQTFD_FeintDummy);
779                    break;
780                case 140605://Direction of attack feint
781                    returnVal = SymbolID.setEntityCode(returnVal,140603);//Direction of Supporting Attack
782                    returnVal = SymbolID.setHQTFD(returnVal,SymbolID.HQTFD_FeintDummy);
783                    break;
784                case 270705://Dummy Minefield
785                    returnVal = SymbolID.setEntityCode(returnVal,270701);//Static Depiction
786                    returnVal = SymbolID.setHQTFD(returnVal,SymbolID.HQTFD_FeintDummy);
787                    break;
788                case 270706://Dummy Minefield, Dynamic
789                    returnVal = SymbolID.setEntityCode(returnVal,270707);//Dynamic Depiction
790                    returnVal = SymbolID.setHQTFD(returnVal,SymbolID.HQTFD_FeintDummy);
791                    break;
792                case 270900://Decoy Mined Area
793                    returnVal = SymbolID.setEntityCode(returnVal,270800);//Mined Area
794                    returnVal = SymbolID.setHQTFD(returnVal,SymbolID.HQTFD_FeintDummy);
795                    break;
796                case 270901://Decoy Mined Area, Fenced
797                    returnVal = SymbolID.setEntityCode(returnVal,270801);//Mined Area
798                    returnVal = SymbolID.setHQTFD(returnVal,SymbolID.HQTFD_FeintDummy);
799                    break;
800            }
801            return returnVal;
802        }
803        else return symbolID;
804    }
805}