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.SymbolUtilities;
018import armyc2.c5isr.web.render.utilities.JavaRendererUtilities;
019
020import java.util.Map;
021import java.util.logging.Level;
022import armyc2.c5isr.web.json.utilities.JSONArray;
023import armyc2.c5isr.web.json.utilities.JSONException;
024import armyc2.c5isr.web.json.utilities.JSONObject;
025
026/**
027 * Main class for rendering multi-point graphics such as Control Measures, Atmospheric, and Oceanographic.
028 */
029//@SuppressWarnings("unused")
030public final class WebRenderer /* extends Applet */ {
031
032    public static final int OUTPUT_FORMAT_KML = 0;
033    @Deprecated
034    public static final int OUTPUT_FORMAT_JSON = 1;
035    public static final int OUTPUT_FORMAT_GEOJSON = 2;
036    public static final int OUTPUT_FORMAT_GEOSVG = 3;
037
038
039    // Arbitrary default values of attributes
040    public static final double MIN_ALT_DEFAULT = 0.0D;
041    public static final double MAX_ALT_DEFAULT = 100.0D;
042    public static final double RADIUS1_DEFAULT = 50.0D;
043    public static final double RADIUS2_DEFAULT = 100.0D;
044    public static final double LEFT_AZIMUTH_DEFAULT = 0.0D;
045    public static final double RIGHT_AZIMUTH_DEFAULT = 90.0D;
046    
047    public static final String ERR_ATTRIBUTES_NOT_FORMATTED = "{\"type\":\"error\","
048            + "\"error\":\"The attribute paramaters are not formatted "
049            + "correctly";
050    
051    public static final String DEFAULT_ATTRIBUTES = "[{radius1:"
052            + RADIUS1_DEFAULT + ",radius2:"
053            + RADIUS2_DEFAULT + ",minalt:"
054            + MIN_ALT_DEFAULT + ",maxalt:"
055            + MAX_ALT_DEFAULT + ",rightAzimuth:"
056            + RIGHT_AZIMUTH_DEFAULT + ",leftAzimuth:"
057            + LEFT_AZIMUTH_DEFAULT + "}]";
058
059    
060    private static boolean _initSuccess = false;
061    
062
063    public static synchronized void init(Context context, String cacheDir) {
064
065        try
066        {
067                if(_initSuccess == false)
068                {
069                    MilStdIconRenderer.getInstance().init(context);
070                    //use WebRenderer.setLoggingLevel()
071                    
072                    //sets default value for single point symbology to have an outline.
073                    //outline color will be automatically determined based on line color
074                    //unless a color value is manually set.
075                    
076                    //Set Renderer Settings/////////////////////////////////////////////
077                    //RendererSettings.getInstance().setSinglePointSymbolOutlineWidth(1);
078                RendererSettings.getInstance().setTextBackgroundMethod(RendererSettings.TextBackgroundMethod_OUTLINE);
079                    //RendererSettings.getInstance().setTextBackgroundMethod(RendererSettings.TextBackgroundMethod_OUTLINE_QUICK);
080                    //RendererSettings.getInstance().setTextOutlineWidth(2);
081                    //RendererSettings.getInstance().setLabelForegroundColor(Color.BLACK.toARGB());
082                    //RendererSettings.getInstance().setLabelBackgroundColor(new Color(255, 255, 255, 200).toARGB());
083                    RendererSettings.getInstance().setModifierFont("arial", Font.PLAIN, 12);
084                    ErrorLogger.setLevel(Level.FINE);
085                    _initSuccess = true;
086                }
087            
088        }
089        catch(Exception exc)
090        {
091            ErrorLogger.LogException("WebRenderer", "init", exc, Level.WARNING);
092        }
093
094
095    }
096
097    
098    /**\
099     * Set minimum level at which an item can be logged.
100     * In descending order:
101     * OFF = Integer.MAX_VALUE
102     * Severe = 1000
103     * Warning = 900
104     * Info = 800
105     * Config = 700
106     * Fine = 500
107     * Finer = 400 
108     * Finest = 300
109     * All = Integer.MIN_VALUE
110     * Use like WebRenderer.setLoggingLevel(Level.INFO);
111     * or
112     * Use like WebRenderer.setLoggingLevel(800);
113     * @param level java.util.logging.level
114     */
115    public static void setLoggingLevel(Level level)
116    {
117        try
118        {
119            ErrorLogger.setLevel(level,true);
120            ErrorLogger.LogMessage("WebRenderer", "setLoggingLevel(Level)",
121                    "Logging level set to: " + ErrorLogger.getLevel().getName(), 
122                    Level.CONFIG);
123        }
124        catch(Exception exc)
125        {
126            ErrorLogger.LogException("WebRenderer", "setLoggingLevel(Level)", exc, Level.INFO);
127        }
128    }
129    
130    /**\
131     * Set minimum level at which an item can be logged.
132     * In descending order:
133     * OFF = Integer.MAX_VALUE
134     * Severe = 1000
135     * Warning = 900
136     * Info = 800
137     * Config = 700
138     * Fine = 500
139     * Finer = 400 
140     * Finest = 300
141     * All = Integer.MIN_VALUE
142     * Use like WebRenderer.setLoggingLevel(Level.INFO);
143     * or
144     * Use like WebRenderer.setLoggingLevel(800);
145     * @param level int
146     */
147    public static void setLoggingLevel(int level)
148    {
149        try
150        {
151            if(level > 1000)
152                  ErrorLogger.setLevel(Level.OFF,true);
153            else if(level > 900)
154                  ErrorLogger.setLevel(Level.SEVERE,true);
155            else if(level > 800)
156                  ErrorLogger.setLevel(Level.WARNING,true);
157            else if(level > 700)
158                  ErrorLogger.setLevel(Level.INFO,true);
159            else if(level > 500)
160                  ErrorLogger.setLevel(Level.CONFIG,true);
161            else if(level > 400)
162                  ErrorLogger.setLevel(Level.FINE,true);
163            else if(level > 300)
164                  ErrorLogger.setLevel(Level.FINER,true);
165            else if(level > Integer.MIN_VALUE)
166                  ErrorLogger.setLevel(Level.FINEST,true);
167            else
168                ErrorLogger.setLevel(Level.ALL,true);
169            
170            ErrorLogger.LogMessage("WebRenderer", "setLoggingLevel(int)",
171                    "Logging level set to: " + ErrorLogger.getLevel().getName(), 
172                    Level.CONFIG);
173        }
174        catch(Exception exc)
175        {
176            ErrorLogger.LogException("WebRenderer", "setLoggingLevel(int)", exc, Level.INFO);
177        }
178    }
179
180    /**
181     * Single Point Tactical Graphics are rendered from font files.
182     * The font size you specify here determines how big the symbols will 
183     * be rendered.  This should be set once at startup.
184     * @param size
185     */
186    public static void setTacticalGraphicPointSize(int size)
187    {
188//        sps.setTacticalGraphicPointSize(size);
189    }
190    
191    /**
192     * Units are rendered from font files.
193     * The font size you specify here determines how big the symbols will 
194     * be rendered.  This should be set once at startup. 
195     * @param size
196     */
197    public static void setUnitPointSize(int size)
198    {
199//        sps.setUnitPointSize(size);
200    }
201    
202    /**
203     * Modifier Text Color will by default match the line color.
204     * This will override all modifier text color.
205     * @param hexColor 
206     */
207/*    public static void setModifierTextColor(String hexColor)
208    {
209        Color textColor = RendererUtilities.getColorFromHexString(hexColor);
210        if(textColor==null)
211        {
212            textColor = Color.black;
213        }
214        RendererSettings.getInstance().setLabelForegroundColor(textColor.toARGB());
215    }*/
216
217
218    
219
220
221    /**
222     * Renders all multi-point symbols, creating KML that can be used to draw
223     * it on a Google map.  Multipoint symbols cannot be draw the same 
224     * at different scales. For instance, graphics with arrow heads will need to 
225     * redraw arrowheads when you zoom in on it.  Similarly, graphics like a 
226     * Forward Line of Troops drawn with half circles can improve performance if 
227     * clipped when the parts of the graphic that aren't on the screen.  To help 
228     * readjust graphics and increase performance, this function requires the 
229     * scale and bounding box to help calculate the new locations.
230     * @param id A unique identifier used to identify the symbol by Google map. 
231     * The id will be the folder name that contains the graphic.
232     * @param name a string used to display to the user as the name of the 
233     * graphic being created.
234     * @param description a brief description about the graphic being made and 
235     * what it represents.
236     * @param symbolCode A 20-30 digit symbolID corresponding to one of the
237     * graphics in the MIL-STD-2525D
238     * @param controlPoints The vertices of the graphics that make up the
239     * graphic.  Passed in the format of a string, using decimal degrees 
240     * separating lat and lon by a comma, separating coordinates by a space.  
241     * The following format shall be used "x1,y1[,z1] [xn,yn[,zn]]..."
242     * @param altitudeMode Indicates whether the symbol should interpret 
243     * altitudes as above sea level or above ground level. Options are 
244     * "clampToGround", "relativeToGround" (from surface of earth), "absolute" 
245     * (sea level), "relativeToSeaFloor" (from the bottom of major bodies of 
246     * water).
247     * @param scale A number corresponding to how many meters one meter of our 
248     * map represents. A value "50000" would mean 1:50K which means for every 
249     * meter of our map it represents 50000 meters of real world distance.
250     * @param bbox The viewable area of the map.  Passed in the format of a
251     * string "lowerLeftX,lowerLeftY,upperRightX,upperRightY." Not required
252     * but can speed up rendering in some cases.
253     * example: "-50.4,23.6,-42.2,24.2"
254     * @param modifiers keyed using constants from Modifiers.
255     * Pass in comma delimited String for modifiers with multiple values like AM, AN & X
256     * @param attributes keyed using constants from MilStdAttributes.
257     * @param format An enumeration: 2 for GeoJSON.
258     * @return A JSON string representation of the graphic.
259     */
260    public static String RenderSymbol(String id, String name, String description,
261                                      String symbolCode, String controlPoints, String altitudeMode,
262                                      double scale, String bbox, Map<String,String> modifiers, Map<String,String> attributes, int format) {
263        String output = "";
264        try {         
265                
266                JavaRendererUtilities.addAltModeToModifiersString(attributes,altitudeMode);
267        
268
269            output = MultiPointHandler.RenderSymbol(id, name, description, symbolCode, controlPoints,
270                    scale, bbox, modifiers, attributes, format);
271
272            //DEBUGGING
273            if(ErrorLogger.getLevel().intValue() <= Level.FINER.intValue())
274            {
275                System.out.println("");
276                StringBuilder sb = new StringBuilder();
277                sb.append("\nID: " + id + "\n");
278                sb.append("Name: " + name + "\n");
279                sb.append("Description: " + description + "\n");
280                sb.append("SymbolID: " + symbolCode + "\n");
281                sb.append("Scale: " + String.valueOf(scale) + "\n");
282                sb.append("BBox: " + bbox + "\n");
283                sb.append("Coords: " + controlPoints + "\n");
284                sb.append("Modifiers: " + modifiers + "\n");
285                ErrorLogger.LogMessage("WebRenderer", "RenderSymbol", sb.toString(),Level.FINER);
286            }
287            if(ErrorLogger.getLevel().intValue() <= Level.FINEST.intValue())
288            {
289                String briefOutput = output.replaceAll("</Placemark>", "</Placemark>\n");
290                briefOutput = output.replaceAll("(?s)<description[^>]*>.*?</description>", "<description></description>");
291                ErrorLogger.LogMessage("WebRenderer", "RenderSymbol", "Output:\n" + briefOutput,Level.FINEST);
292            }
293
294            
295            
296        } catch (Exception ea) {
297            
298            output = "{\"type\":'error',error:'There was an error creating the MilStdSymbol - " + ea.toString() + "'}";
299            ErrorLogger.LogException("WebRenderer", "RenderSymbol", ea, Level.WARNING);
300        }
301        
302        return output;
303    }
304    
305
306         
307
308
309    /**
310     * Renders all multi-point symbols, creating KML or JSON for the user to
311     * parse and render as they like.
312     * This function requires the bounding box to help calculate the new
313     * locations.
314     * @param id A unique identifier used to identify the symbol by Google map.
315     * The id will be the folder name that contains the graphic.
316     * @param name a string used to display to the user as the name of the 
317     * graphic being created.
318     * @param description a brief description about the graphic being made and 
319     * what it represents.
320     * @param symbolCode A 20-30 digit symbolID corresponding to one of the
321     * graphics in the MIL-STD-2525D
322     * @param controlPoints The vertices of the graphics that make up the
323     * graphic.  Passed in the format of a string, using decimal degrees
324     * separating lat and lon by a comma, separating coordinates by a space.
325     * The following format shall be used "x1,y1 [xn,yn]..."
326     * @param pixelWidth pixel dimensions of the viewable map area
327     * @param pixelHeight pixel dimensions of the viewable map area
328     * @param bbox The viewable area of the map.  Passed in the format of a
329     * string "lowerLeftX,lowerLeftY,upperRightX,upperRightY."
330     * example: "-50.4,23.6,-42.2,24.2"
331     * @param modifiers keyed using constants from Modifiers.
332     * Pass in comma delimited String for modifiers with multiple values like AM, AN &amp; X
333     * @param attributes keyed using constants from MilStdAttributes.
334     * @param format An enumeration: 2 for GeoJSON.
335     * @return A JSON (1) or KML (0) string representation of the graphic.
336     */
337    public static String RenderSymbol2D(String id, String name, String description, String symbolCode, String controlPoints,
338            int pixelWidth, int pixelHeight, String bbox, Map<String,String> modifiers, Map<String,String> attributes, int format)
339    {
340        String output = "";
341        try
342        {
343            output = MultiPointHandler.RenderSymbol2D(id, name, description, 
344                    symbolCode, controlPoints, pixelWidth, pixelHeight, bbox, 
345                    modifiers, attributes, format);
346        }
347        catch(Exception exc)
348        {
349            output = "{\"type\":'error',error:'There was an error creating the MilStdSymbol: " + symbolCode + " - " + exc.toString() + "'}";
350        }
351        return output;
352    }
353
354
355
356    /**
357         * Renders all MilStd 2525 multi-point symbols, creating MilStdSymbol that contains the
358         * information needed to draw the symbol on the map.
359     * DOES NOT support RADARC, CAKE, TRACK etc...
360         * ArrayList&lt;Point2D&gt; milStdSymbol.getSymbolShapes.get(index).getPolylines()
361         * and 
362         * ShapeInfo = milStdSymbol.getModifierShapes.get(index). 
363         * 
364         * 
365         * @param id
366         *            A unique identifier used to identify the symbol by Google map.
367         *            The id will be the folder name that contains the graphic.
368         * @param name
369         *            a string used to display to the user as the name of the
370         *            graphic being created.
371         * @param description
372         *            a brief description about the graphic being made and what it
373         *            represents.
374         * @param symbolCode
375         *            A 20-30 digit symbolID corresponding to one of the graphics
376         *            in the MIL-STD-2525D
377         * @param controlPoints
378         *            The vertices of the graphics that make up the graphic. Passed
379         *            in the format of a string, using decimal degrees separating
380         *            lat and lon by a comma, separating coordinates by a space. The
381         *            following format shall be used "x1,y1[,z1] [xn,yn[,zn]]..."
382         * @param altitudeMode
383         *            Indicates whether the symbol should interpret altitudes as
384         *            above sea level or above ground level. Options are
385         *            "clampToGround", "relativeToGround" (from surface of earth),
386         *            "absolute" (sea level), "relativeToSeaFloor" (from the bottom
387         *            of major bodies of water).
388         * @param scale
389         *            A number corresponding to how many meters one meter of our map
390         *            represents. A value "50000" would mean 1:50K which means for
391         *            every meter of our map it represents 50000 meters of real
392         *            world distance.
393         * @param bbox
394         *            The viewable area of the map. Passed in the format of a string
395         *            "lowerLeftX,lowerLeftY,upperRightX,upperRightY." Not required
396         *            but can speed up rendering in some cases. example:
397         *            "-50.4,23.6,-42.2,24.2"
398         * @param modifiers
399         *            Used like:
400         *            modifiers.put(Modifiers.T_UNIQUE_DESIGNATION_1, "T");
401         *            Or
402         *            modifiers.put(Modifiers.AM_DISTANCE, "1000,2000,3000");
403         * @param attributes
404         *                        Used like:
405         *            attributes.put(MilStdAttributes.LineWidth, "3");
406         *            Or
407         *            attributes.put(MilStdAttributes.LineColor, "#00FF00");
408     * @return MilStdSymbol
409     */
410    public static MilStdSymbol RenderMultiPointAsMilStdSymbol(String id, String name, String description, String symbolCode,
411                        String controlPoints, String altitudeMode, double scale, String bbox, Map<String,String> modifiers, Map<String,String> attributes)
412    {
413                MilStdSymbol mSymbol = null;
414                try 
415                {
416                        mSymbol = MultiPointHandler.RenderSymbolAsMilStdSymbol(id, name, description, symbolCode,
417                    controlPoints, scale, bbox, modifiers, attributes);
418
419            //Uncomment to show sector1 modifiers as fill pattern
420//            int symbolSet = SymbolID.getEntityCode(symbolCode);
421//            if(symbolSet == 270707 || symbolSet == 270800 || symbolSet == 270801 || symbolSet == 151100) //Mined Areas
422//            {
423//                int size = RendererSettings.getInstance().getDefaultPixelSize();
424//
425//                ArrayList<ShapeInfo> shapes = mSymbol.getSymbolShapes();
426//                if(shapes.size() > 0){
427//                    ShapeInfo shape = shapes.get(0);
428//                    shape.setPatternFillImage(PatternFillRendererD.MakeSymbolPatternFill(symbolCode,size));
429//                    if(shape.getPatternFillImage() != null)
430//                        shape.setShader(new BitmapShader(shape.getPatternFillImage(), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
431//                }
432//            }
433                }
434                catch (Exception ea) 
435                {
436                        mSymbol=null;
437                        ErrorLogger.LogException("WebRenderer", "RenderMultiPointAsMilStdSymbol" + " - " + symbolCode, ea, Level.WARNING);
438                }
439                
440                //System.out.println("RenderMultiPointAsMilStdSymbol exit");
441                return mSymbol;
442    }
443
444
445    
446    /**
447     * Given a symbol code meant for a single point symbol, returns the
448     * anchor point at which to display that image based off the image returned
449     * from the URL of the SinglePointServer.
450     * 
451     * @param symbolID - the 20-30 digit symbolID of a single point MilStd2525
452     * symbol. 
453     * @return A pixel coordinate of the format "x,y".
454     * Returns an empty string if an error occurs.
455     * @deprecated 
456     */
457        public String getSinglePointAnchor(String symbolID) {
458        String anchorPoint = "";
459        Point2D anchor = new Point2D.Double();
460        anchorPoint = anchor.getX() + "," + anchor.getY();        
461        return anchorPoint;
462    }
463
464    /**
465     * Given a symbol code meant for a single point symbol, returns the
466     * anchor point at which to display that image based off the image returned
467     * from the URL of the SinglePointServer.
468     *
469     * @param symbolID - the 20-30 digit symbolID of a single point MilStd2525
470     * symbol.
471     * @return A pixel coordinate of the format "anchorX,anchorY,SymbolBoundsX,
472     * SymbolBoundsY,SymbolBoundsWidth,SymbolBoundsHeight,IconWidth,IconHeight".
473     * Anchor, represents the center point of the core symbol within the image.
474     * The image should be centered on this point.
475     * Symbol bounds represents the bounding rectangle of the core symbol within
476     * the image.
477     * IconWidth/Height represents the height and width of the image in its
478     * entirety.
479     * Returns an empty string if an error occurs.
480     * @deprecated
481     */
482    public static String getSinglePointInfo(String symbolID)
483    {
484        String info = "";
485        Point2D anchor = new Point2D.Double();
486        Rectangle2D symbolBounds = new Rectangle2D.Double();
487        return info;
488    }
489        
490    /**
491     * Returns true if we recommend clipping a particular symbol.
492     * Would return false for and Ambush but would return true for a Line of 
493     * Contact due to the decoration on the line.
494     * @param symbolID
495     * @return 
496     */
497    public static String ShouldClipMultipointSymbol(String symbolID)
498    {
499        if(MultiPointHandler.ShouldClipSymbol(symbolID))
500            return "true";
501        else
502            return "false";
503    }
504    
505     /**
506     * Given a symbol code meant for a single point symbol, returns the
507     * symbol as a byte array.
508     *
509     * @param symbolID - the 20-30 digit symbolID of a single point MilStd2525
510     * symbol.
511     * @return byte array.
512      * @deprecated
513     */
514    public static byte[] getSinglePointByteArray(String symbolID)
515    {
516        //return sps.getSinglePointByteArray(symbolID);
517        return null;
518    }
519}