001/*
002 * To change this template, choose Tools | Templates
003 * and open the template in the editor.
004 */
005package armyc2.c5isr.renderer.utilities;
006
007import java.util.ArrayList;
008import java.util.HashMap;
009import java.util.Map;
010
011import armyc2.c5isr.graphics2d.Point2D;
012import armyc2.c5isr.graphics2d.TexturePaint;
013
014/**
015 * Object that holds information on how to draw a multipoint symbol after {@link armyc2.c5isr.web.render.WebRenderer#RenderMultiPointAsMilStdSymbol(String, String, String, String, String, String, double, String, Map, Map)} is called.
016 */
017public class MilStdSymbol
018{
019
020        //private SymbolDef _symbolDefinition = null;
021    //private UnitDef _unitDefinition = null;
022    /**
023     * modifiers
024     */
025    private Map<String,String> _Properties = null;
026
027    //for tactical graphics
028    private ArrayList<Double> _X_Altitude = null;
029    private ArrayList<Double> _AM_Distance = null;
030    private ArrayList<Double> _AN_Azimuth = null;
031
032    private String _symbolID = "";
033
034    /**
035     * unique ID for this symbol, for client use
036     */
037    private String _UUID = null;
038
039    private ArrayList<ShapeInfo> _SymbolShapes;
040
041    /**
042     * collection of shapes for the modifiers
043     */
044    private ArrayList<ShapeInfo> _ModifierShapes;
045
046    private ArrayList<Point2D> _Coordinates;
047
048    private int _UnitSize = 100;
049    private double _scale = 0;
050    private Boolean _KeepUnitRatio = true;
051
052    Integer _LineWidth = 3;
053    Color _LineColor = null;
054    Color _FillColor = null;
055    Color _TextColor = null;
056    Color _TextBackgroundColor = null;
057
058    double _Rotation = 0.0;//DEGREES
059
060    //outline singlepoint TGs
061    boolean _Outline = false;
062    //if null, renderer determines outline Color.
063    Color _OutLineColor = null;
064    int _OutLineWidth = 0;
065    TexturePaint _tp = null;
066    boolean _fs = true;
067
068    int _patternFillType = 0;
069
070    private double patternScale = 1;
071
072    private static String _AltitudeMode = "";
073
074    private static DistanceUnit _AltitudeUnit = null;
075
076    private static DistanceUnit _DistanceUnit = null;
077
078    private static boolean _useDashArray = true;
079
080    private static boolean _hideOptionalLabels = false;
081
082    private static boolean _DrawAffiliationModifierAsLabel = true;
083
084    private static boolean _UseLineInterpolation = false;
085
086    /**
087     * Text is not affected by scale changes
088     */
089    public static final int TextScaleSensitive_No = 0;
090    /**
091     * Text is affected only by significant scale changes
092     */
093    public static final int TextScaleSensitive_OnSlightZoomIn = 1;
094    /**
095     * Text is affected by zoom in scale changes
096     */
097    public static final int TextScaleSensitive_OnZoomIn = 2;
098    /**
099     * Text is affected by any scale changes
100     */
101    public static final int TextScaleSensitive_OnZoomInOut = 3;
102
103    /**
104     * Symbol is not affected by scale changes
105     */
106    public static final int SymbolScaleSensitive_No = 0;
107    /**
108     * Symbol has arrow heads that are affected by scale change
109     */
110    public static final int SymbolScaleSensitive_ArrowHeads = 1;
111    /**
112     * Symbol has lines details that are affected by scale change (like FLOT)
113     */
114    public static final int SymbolScaleSensitive_DecoratedLines = 2;
115    /**
116     * Symbol has pattern fills that are affected by scale if you're not using the fill pattern image
117     * ShapeInfo.getShader() or ShapeInfo.getPatternFillImage()
118     */
119    public static final int SymbolScaleSensitive_PatternFills = 3;
120
121    Object _Tag = null;
122
123    /*
124     * Used to hold metadata for each segment of the symbol for multi-point
125     * symbols. Each segment can contain one object.
126     */
127                //private Map _segmentData;
128                // Constants for dynamic properties
129/*
130     public static final String SYMBOL_ID = "Symbol ID";
131     //public static final String SOURCE = "Source";
132     //public static final String EDITOR_CLASS_TYPE = "Editor Class Type";
133     public static final String URN = "URN";
134     public static final String UIC = "UIC";
135     public static final String ANGLE_OF_ROTATION = "Angle of Rotation";
136     public static final String LENGTH = "Length";
137     public static final String WIDTH = "Width";
138     public static final String RADIUS = "Radius";
139     public static final String SEGMENT_DATA = "Segment Data";
140     */
141
142    /*
143     public static final String GEO_POINT = "point";
144     public static final String GEO_LINE = "line";
145     public static final String GEO_POLYGON = "area";
146     public static final String GEO_TEXT = "text";
147     public static final String GEO_CIRCLE = "circle";
148     public static final String GEO_RECTANGLE = "rectangle";
149     public static final String GEO_ARC = "arc";
150     public static final String GEO_SQUARE = "square";
151     */
152    /*
153     private static final String _COORDINATES = "Coordinates";
154     private static final String _GEOMETRY = "Geometry";
155     private static final String _FILL_COLOR = "Fill Color";
156     private static final String _FILL_ALPHA = "Fill Alpha";
157     private static final String _FILL_STYLE = "Fill Style";
158     private static final String _LINE_WIDTH = "Line Width";
159     private static final String _LINE_COLOR = "Line Color";
160     private static final String _LINE_ALPHA = "Line Alpha";
161     private static final String _TEXT_BACKGROUND_COLOR = "Background Color";
162     private static final String _TEXT_FOREGROUND_COLOR = "Foreground Color";
163     private static final String _USE_FILL = "Use Fill";
164     */
165    /*
166     protected static const _COORDINATES:String = "Coordinates";
167     protected static const _GEOMETRY:String = "Geometry";
168     protected static const _FILL_COLOR:String = "Fill Color";
169     protected static const _FILL_ALPHA:String = "Fill Alpha";
170     private int _FILL_STYLE:String = "Fill Style";
171     protected static const _LINE_WIDTH:String = 0;
172     private Color _LINE_COLOR = Color.BLACK;
173     private int _LINE_ALPHA:String = 0;
174     private Color _TEXT_BACKGROUND_COLOR = Color.WHITE;
175     private Color _TEXT_FOREGROUND_COLOR = Color.BLACK;
176     private bool _USE_FILL:String = "Use Fill";*/
177
178    /**
179     * Creates a new MilStdSymbol.
180     *
181     * @param symbolID code, 20-30 digits long that represents the symbol
182     * @param uniqueID for the client's use
183     * @param modifiers use keys from Modifiers.
184     * @param Coordinates
185     * modifiers
186     */
187    public MilStdSymbol(String symbolID, String uniqueID, ArrayList<Point2D> Coordinates, Map<String,String> modifiers)
188    {
189        this(symbolID, uniqueID, Coordinates, modifiers, true);
190    }
191
192    /**
193     *
194     * @param symbolID code, 20-30 digits long that represents the symbol
195     * @param uniqueID for the client's use
196     * @param modifiers use keys from Modifiers.
197     * @param Coordinates
198     * @param keepUnitRatio - default TRUE
199     * modifiers
200     */
201    public MilStdSymbol(String symbolID, String uniqueID, ArrayList<Point2D> Coordinates, Map<String,String> modifiers, Boolean keepUnitRatio)
202    {
203
204        if (modifiers == null)
205        {
206            _Properties = new HashMap<>();
207        }
208        else
209        {
210            _Properties = modifiers;
211        }
212
213        _UUID = uniqueID;
214        setCoordinates(Coordinates);
215
216        // Set the given symbol id
217        setSymbolID(symbolID);
218
219        // Set up default line fill and text colors
220        setLineColor(SymbolUtilities.getDefaultLineColor(_symbolID));
221        setTextColor(SymbolUtilities.getLineColorOfAffiliation(symbolID));
222        //if(SymbolUtilities.isWarfighting(_symbolID))
223        if (SymbolUtilities.hasDefaultFill(_symbolID))
224        {
225            setFillColor(SymbolUtilities.getFillColorOfAffiliation(_symbolID));
226        }
227            //if(SymbolUtilities.isNBC(_symbolID) && !(SymbolUtilities.isDeconPoint(symbolID)))
228        //    setFillColor(SymbolUtilities.getFillColorOfAffiliation(_symbolID));
229
230        _DrawAffiliationModifierAsLabel = RendererSettings.getInstance().getDrawAffiliationModifierAsLabel();
231
232        _UseLineInterpolation = RendererSettings.getInstance().getUseLineInterpolation();
233
234        _KeepUnitRatio = keepUnitRatio;
235    }
236
237    public TexturePaint getFillStyle()
238    {
239        return _tp;
240    }
241
242    public void setFillStyle(TexturePaint value)
243    {
244        _tp = value;
245    }
246
247    public boolean getUseFillPattern()
248    {
249        return _fs;
250    }
251
252    public void setUseFillPattern(boolean value)
253    {
254        _fs = value;
255    }
256
257    /**
258     * @deprecated
259     */
260    public int getPatternFillType()
261    {
262        return _patternFillType;
263    }
264
265    /**
266     * 0=Solid, 2=ForwardHatch, 3=BackwardHatch, 4=verticalHatch, 5=horizonalHatch, 8=CrossHatch
267     * Only affects Basic Shapes.  Will not apply to MilStd Symbology so as to not confuse some
268     * symbols with others.
269     * @param value
270     *
271     * @deprecated
272     */
273    public void setPatternFillType(int value)
274    {
275        _patternFillType = value;
276    }
277
278    public String getAltitudeMode()
279    {
280        return _AltitudeMode;
281    }
282
283    public void setAltitudeMode(String value)
284    {
285        _AltitudeMode = value;
286    }
287
288    public DistanceUnit getAltitudeUnit(){
289        return _AltitudeUnit;
290    }
291
292    public void setAltitudeUnit(DistanceUnit unit){
293        _AltitudeUnit = unit;
294    }
295
296    public DistanceUnit getDistanceUnit(){
297        return _DistanceUnit;
298    }
299
300    public void setDistanceUnit(DistanceUnit unit){
301        _DistanceUnit = unit;
302    }
303    
304    public boolean getUseDashArray()
305    {
306        return _useDashArray;
307    }
308
309    public void setUseDashArray(boolean value)
310    {
311        _useDashArray = value;
312    }
313
314    public boolean getHideOptionalLabels()
315    {
316        return _hideOptionalLabels;
317    }
318
319    public void setHideOptionalLabels(boolean value)
320    {
321        _hideOptionalLabels = value;
322    }
323
324    public void setUseLineInterpolation(boolean value)
325    {
326        _UseLineInterpolation = value;
327    }
328
329    public boolean getUseLineInterpolation()
330    {
331        return _UseLineInterpolation;
332    }
333
334    //Set size for area's internal icon (LAA, mine and CBRN areas)
335    public void setUnitSize(int pixelSize){_UnitSize = pixelSize;}
336
337    public int getUnitSize(){return _UnitSize;}
338
339    public void setKeepUnitRatio(boolean value) {_KeepUnitRatio = value;}
340
341    public boolean getKeepUnitRatio() {return _KeepUnitRatio;}
342
343    /**
344     * Determines how to draw the Affiliation Modifier. True to draw as modifier
345     * label in the "E/F" location. False to draw at the top right corner of the
346     * symbol
347     *
348     * @deprecated
349     */
350    public void setDrawAffiliationModifierAsLabel(boolean value)
351    {
352        _DrawAffiliationModifierAsLabel = value;
353    }
354
355    /**
356     * True to draw as modifier label in the "E/F" location. False to draw at
357     * the top right corner of the symbol
358     *
359     * @deprecated
360     */
361    public boolean getDrawAffiliationModifierAsLabel()
362    {
363        return _DrawAffiliationModifierAsLabel;
364    }
365
366    /**
367     *
368     * @return
369     */
370    public Map<String,String> getModifierMap()
371    {
372        return _Properties;
373    }
374
375    /**
376     *
377     * @param modifiers
378     */
379    public void setModifierMap(Map<String,String> modifiers)
380    {
381        _Properties = modifiers;
382    }
383
384    /**
385     *
386     * @param modifier
387     * @return
388     */
389    public String getModifier(String modifier)
390    {
391        if (_Properties.containsKey(modifier))
392        {
393            return _Properties.get(modifier);
394        }
395        else
396        {
397            return getModifier(modifier, 0);
398        }
399    }
400
401    /**
402     *
403     * @param modifier
404     * @param value
405     */
406    public void setModifier(String modifier, String value)
407    {
408        if (value.equals("") == false)
409        {
410            if (!(modifier == Modifiers.AM_DISTANCE)
411                    || modifier == (Modifiers.AN_AZIMUTH)
412                    || modifier == (Modifiers.X_ALTITUDE_DEPTH))
413            {
414                _Properties.put(modifier, value);
415            }
416            else
417            {
418                setModifier(modifier, value, 0);
419            }
420        }
421    }
422
423    /**
424     *
425     * @param modifier
426     * @param index
427     * @return
428     */
429    public String getModifier(String modifier, int index)
430    {
431        if (_Properties.containsKey(modifier))
432        {
433            return _Properties.get(modifier);
434        }
435        else if (modifier == (Modifiers.AM_DISTANCE)
436                || modifier == (Modifiers.AN_AZIMUTH)
437                || modifier == (Modifiers.X_ALTITUDE_DEPTH))
438        {
439            String value = String.valueOf(getModifier_AM_AN_X(modifier, index));
440            if (value != null && !value.equalsIgnoreCase("null") && !value.equalsIgnoreCase(""))
441            {
442                return value;
443            }
444            else
445            {
446                return null;
447            }
448        }
449        else
450        {
451            return null;
452        }
453
454    }
455
456    /**
457     *
458     * @param modifier
459     * @param index
460     * @return
461     */
462    public Double getModifier_AM_AN_X(String modifier, int index)
463    {
464        ArrayList<Double> modifiers = null;
465        if (modifier == (Modifiers.AM_DISTANCE))
466        {
467            modifiers = _AM_Distance;
468        }
469        else if (modifier == (Modifiers.AN_AZIMUTH))
470        {
471            modifiers = _AN_Azimuth;
472        }
473        else if (modifier == (Modifiers.X_ALTITUDE_DEPTH))
474        {
475            modifiers = _X_Altitude;
476        }
477        else
478        {
479            return null;
480        }
481
482        if (modifiers != null && modifiers.size() > index)
483        {
484            Double value = null;
485            value = modifiers.get(index);
486            if (value != null)
487            {
488                return value;
489            }
490            else
491            {
492                return null;
493            }
494        }
495        else
496        {
497            return null;
498        }
499    }
500
501    /**
502     * Modifiers must be added in order. No setting index 2 without first
503     * setting index 0 and 1. If setting out of order is attempted, the value
504     * will just be added to the end of the list.
505     *
506     * @param modifier
507     * @param value
508     * @param index
509     */
510    public void setModifier(String modifier, String value, int index)
511    {
512        if (value.equals("") == false)
513        {
514            if (!(modifier == (Modifiers.AM_DISTANCE)
515                    || modifier == (Modifiers.AN_AZIMUTH)
516                    || modifier == (Modifiers.X_ALTITUDE_DEPTH)))
517            {
518                _Properties.put(modifier, value);
519            }
520            else
521            {
522                Double dblValue = Double.valueOf(value);
523                if (dblValue != null)
524                {
525                    setModifier_AM_AN_X(modifier, dblValue, index);
526                }
527            }
528        }
529    }
530
531    public void setModifier_AM_AN_X(String modifier, Double value, int index)
532    {
533        if ((modifier == (Modifiers.AM_DISTANCE)
534                || modifier == (Modifiers.AN_AZIMUTH)
535                || modifier == (Modifiers.X_ALTITUDE_DEPTH)))
536        {
537            ArrayList<Double> modifiers = null;
538            if (modifier == (Modifiers.AM_DISTANCE))
539            {
540                if (_AM_Distance == null)
541                {
542                    _AM_Distance = new ArrayList<Double>();
543                }
544                modifiers = _AM_Distance;
545            }
546            else if (modifier == (Modifiers.AN_AZIMUTH))
547            {
548                if (_AN_Azimuth == null)
549                {
550                    _AN_Azimuth = new ArrayList<Double>();
551                }
552                modifiers = _AN_Azimuth;
553            }
554            else if (modifier == (Modifiers.X_ALTITUDE_DEPTH))
555            {
556                if (_X_Altitude == null)
557                {
558                    _X_Altitude = new ArrayList<Double>();
559                }
560                modifiers = _X_Altitude;
561            }
562            if (index + 1 > modifiers.size())
563            {
564                modifiers.add(value);
565            }
566            else
567            {
568                modifiers.set(index, value);
569            }
570        }
571    }
572
573    public ArrayList<Double> getModifiers_AM_AN_X(String modifier)
574    {
575        if (modifier == (Modifiers.AM_DISTANCE))
576        {
577            return _AM_Distance;
578        }
579        else if (modifier == (Modifiers.AN_AZIMUTH))
580        {
581            return _AN_Azimuth;
582        }
583        else if (modifier == (Modifiers.X_ALTITUDE_DEPTH))
584        {
585            return _X_Altitude;
586        }
587
588        return null;
589    }
590
591    public void setModifiers_AM_AN_X(String modifier, ArrayList<Double> modifiers)
592    {
593        if (modifier == (Modifiers.AM_DISTANCE))
594        {
595            _AM_Distance = modifiers;
596        }
597        else if (modifier == (Modifiers.AN_AZIMUTH))
598        {
599            _AN_Azimuth = modifiers;
600        }
601        else if (modifier == (Modifiers.X_ALTITUDE_DEPTH))
602        {
603            _X_Altitude = modifiers;
604        }
605    }
606
607    /**
608     *
609     * @param value
610     */
611    public void setFillColor(Color value)
612    {
613        _FillColor = value;
614    }
615
616    /**
617     *
618     * @return
619     */
620    public Color getFillColor()
621    {
622        return _FillColor;
623    }
624    
625    /**
626    *
627    * @param value
628    */
629   public void setTextColor(Color value)
630   {
631       _TextColor = value;
632       if(RendererSettings.getInstance().getTextBackgroundMethod() != RendererSettings.TextBackgroundMethod_NONE && _TextBackgroundColor == null)
633       {
634           //If text background enabled and a background color has not been set yet:
635          _TextBackgroundColor = RendererUtilities.getIdealOutlineColor(_TextColor);
636       }
637
638   }
639
640   /**
641    *
642    * @return
643    */
644   public Color getTextColor()
645   {
646       return _TextColor;
647   }
648   
649   /**
650   *
651   * @param value
652   */
653  public void setTextBackgroundColor(Color value)
654  {
655      _TextBackgroundColor = value;
656  }
657
658  /**
659   *
660   * @return
661   */
662  public Color getTextBackgroundColor()
663  {
664      return _TextBackgroundColor;
665  }
666
667    /**
668     *
669     * @param value
670     */
671    public void setLineWidth(int value)
672    {
673        _LineWidth = value;
674    }
675
676    /**
677     *
678     * @return
679     */
680    public int getLineWidth()
681    {
682        return _LineWidth;
683    }
684
685    /**
686     * If value is null or SymbolUtilities.isGreenProtectionGraphic() is true then value is ignored
687     *
688     * @param value
689     */
690    public void setLineColor(Color value)
691    {
692        if (SymbolUtilities.isGreenProtectionGraphic(getSymbolID())) {
693            _LineColor = AffiliationColors.ObstacleGreen;// new Color(0,166,81); // Green from SymbolUtilities.getLineColorOfAffiliation()
694        } else if (value != null) {
695                _LineColor = value;
696        }
697    }
698
699    /**
700     *
701     * @return
702     */
703    public Color getLineColor()
704    {
705        return _LineColor;
706    }
707
708    /**
709     * if null, renderer will use white or black for the outline based on the color
710     * of the symbol. Otherwise, it will used the passed color value.
711     *
712     * @param value
713     */
714    public void setOutlineColor(Color value)
715    {
716        _OutLineColor = value;
717    }
718
719    public Color getOutlineColor()
720    {
721        return _OutLineColor;
722    }
723
724    /**
725     * Extra value for client. defaults to null. Not used for rendering by
726     * JavaRenderer
727     *
728     * @param value
729     * @deprecated
730     */
731    public void setTag(Object value)
732    {
733        _Tag = value;
734    }
735
736    /**
737     * Extra value for client. defaults to null. Not used for rendering by
738     * JavaRenderer
739     *
740     * @return
741     * @deprecated
742     */
743    public Object getTag()
744    {
745        return _Tag;
746    }
747
748    /**
749     *
750     * @param value
751     */
752    public void setCoordinates(ArrayList<Point2D> value)
753    {
754        _Coordinates = value;
755    }
756
757    /**
758     *
759     * @return
760     */
761    public ArrayList<Point2D> getCoordinates()
762    {
763        return _Coordinates;
764    }
765
766    /**
767     * Shapes that represent the symbol modifiers
768     *
769     * @param value ArrayList&lt;Shape&gt;
770     */
771    public void setModifierShapes(ArrayList<ShapeInfo> value)
772    {
773        _ModifierShapes = value;
774    }
775
776    /**
777     * Shapes that represent the symbol modifiers
778     *
779     * @return
780     */
781    public ArrayList<ShapeInfo> getModifierShapes()
782    {
783        return _ModifierShapes;
784    }
785
786    /**
787     * the java shapes that make up the symbol
788     *
789     * @param value ArrayList&lt;ShapeInfo&gt;
790     */
791    public void setSymbolShapes(ArrayList<ShapeInfo> value)
792    {
793        _SymbolShapes = value;
794    }
795
796    /**
797     * the java shapes that make up the symbol
798     *
799     * @return
800     */
801    public ArrayList<ShapeInfo> getSymbolShapes()
802    {
803        return _SymbolShapes;
804    }
805
806    /**
807     * The Symbol Id of the MilStdSymbol.
808     *
809     * @return
810     */
811    public String getSymbolID()
812    {
813        return _symbolID;
814    }
815
816    /**
817     * Unique ID of the Symbol. For client use.
818     *
819     * @return
820     */
821    public String getUUID()
822    {
823        return _UUID;
824    }
825
826    /**
827     * Unique ID of the Symbol. For client use.
828     *
829     * @param ID
830     */
831    public void setUUID(String ID)
832    {
833        _UUID = ID;
834    }
835
836    /**
837     * Sets the Symbol ID for the symbol. Should be a 20-30 digit string from
838     * the milstd.
839     *
840     * @param value
841     */
842    public void setSymbolID(String value)
843    {
844
845        String current = _symbolID;
846
847        try
848        {
849            //set symbolID
850            if (value != null && !value.equals("") && !current.equals(value))
851            {
852                _symbolID = value;
853            }
854
855
856        }// End try
857        catch (Exception e)
858        {
859            // Log Error
860            ErrorLogger.LogException("MilStdSymbol", "setSymbolID" + " - Did not fall under TG or FE", e);
861        }
862    }   // End set SymbolID
863    private boolean _wasClipped=false;
864    /**
865     *
866     * @param value
867     * @deprecated see {@link #setWasClipped(boolean)}
868     */
869    public void set_WasClipped(boolean value)
870    {
871        _wasClipped=value;
872    }
873
874    /**
875     *
876     * @return boolean
877     * @deprecated see {@link #getWasClipped()}
878     */
879    public boolean get_WasClipped()
880    {
881        return _wasClipped;
882    }
883
884    public void setWasClipped(boolean value)
885    {
886        _wasClipped=value;
887    }
888    public boolean getWasClipped()
889    {
890        return _wasClipped;
891    }
892
893
894    /**
895     * Determines if the symbol has integral or modifier/amplifier text that would
896     * be impacted if the maps is zoomed in or out after initial draw.
897     * @return 0=not sensitive, 1=slightly little zoom in sensitive, 2=zoom in sensitive, 3=zoom in/out sensitive
898     */
899    public int isTextScaleSensitive()
900    {
901        ArrayList<ShapeInfo> modifiers = this.getModifierShapes();
902        if(_Properties == null)
903            return 0;//no scale sensitive text
904        if (_Properties.isEmpty())
905            return 0;
906        else if(SymbolID.getSymbolSet(_symbolID)==SymbolID.SymbolSet_ControlMeasure)
907        {
908            MSInfo msi = MSLookup.getInstance().getMSLInfo(_symbolID);
909            if(msi != null)
910            {
911                int dr = msi.getDrawRule();
912                String ec = String.valueOf(SymbolID.getEntityCode(_symbolID));
913                switch (dr)
914                {
915                    case DrawRules.AXIS1:
916                    case DrawRules.AXIS2:
917                        if(_Properties.containsKey(Modifiers.W_DTG_1) ||
918                                _Properties.containsKey(Modifiers.W1_DTG_2))
919                            return 3;
920                        else
921                            return 0;
922                    case DrawRules.CORRIDOR1:
923                        if(_Properties.size() > 1)
924                            return 3;
925                        else
926                            return 0;
927                    case DrawRules.LINE5://Bearing Lines (2201##), Linear Targets (2407##)
928                        if(ec.startsWith("2201"))
929                        {
930                            if(_Properties.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
931                                return 2;
932                            else
933                                return 0;
934                        }
935                        else if(ec.startsWith("2407"))
936                        {
937                            if(modifiers != null && !modifiers.isEmpty())
938                            {
939                                int size = modifiers.size();
940                                if(size == 1)
941                                    return 2;
942                                else//size > 1
943                                    return 3;
944                            }
945                            else
946                                return 0;
947                        }
948                        else
949                            return 0;
950                    case DrawRules.RECTANGULAR1:
951                        if(modifiers != null && modifiers.size() > 1 && ec.startsWith("24"))
952                            return 3;
953                        else
954                            return 0;
955                    case DrawRules.CIRCULAR1:
956                        if(modifiers != null && modifiers.size() > 1 && (ec.startsWith("2003") || ec.startsWith("24")))
957                            return 3;
958                        else
959                            return 0;
960                    case DrawRules.RECTANGULAR3:
961                        if(modifiers != null && !modifiers.isEmpty())
962                            return 2;
963                        else
964                            return 0;
965
966                    case DrawRules.CIRCULAR2:
967                    case DrawRules.ARC1:
968                        return 0;
969                    default:
970                        break;
971                }
972            }
973
974            int ec = (SymbolID.getEntityCode(_symbolID));
975            switch (ec)
976            {
977
978                //A Little Zoom in sensitive (1)
979                case 140300://Phase line, only 5% sensitive
980                case 140400://Forward Edge of Battle, only 5% sensitive
981                case 330100://Moving Convoy
982                case 330200://Halted Convoy
983                    return 1;
984
985                //Zoom in sensitive (2)
986                case 110200://Light Line
987                case 110300://Engineer Work Line
988                case 140700://Final Coordination Line
989                case 140900://Limit of Advance
990                case 141000://Line of Departure
991                case 141100://Line of Departure / Line of Contact
992                case 141200://Probable Line of Deployment
993                case 141400://Bridgehead Line
994                case 141500://Holding Line
995                case 141600://Release Line
996                case 141800://Handover Line
997                case 141900://Battle Handover Line
998                case 142000://Named Area of Interest Line (NAI)
999                case 190100://Identification, Friend-or-Foe (IFF) Off Line
1000                case 190200://Identification, Friend-or-Foe (IFF) On Line
1001                case 200401://Ship Area of Interest, Eclipse/Circle (AEGIS only)
1002                case 200402://Ship Area of Interest, Rectangle (AEGIS only)
1003                case 330300://Main Supply Route (MSR)
1004                case 330301://One Way Traffic
1005                case 330302://Two Way Traffic
1006                case 330303://Alternating Traffic
1007                case 330400://Alternate Supply Route (ASR)
1008                case 330401://One Way Traffic
1009                case 330402://Two Way Traffic
1010                case 330403://Alternating Traffic
1011                    return 2;
1012                case 120400://Airfield Zone
1013                case 142100://Mobility Corridor
1014                case 370100://Human Terrain
1015                    if(_Properties.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
1016                        return 2;
1017                    else
1018                        return 0;
1019                case 290100://Obstacle Line
1020                    if(_Properties.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1))
1021                        return 2;
1022                    else
1023                        return 0;
1024                case 140100://FLOT
1025                    if(SymbolID.getAffiliation(_symbolID)==SymbolID.StandardIdentity_Affiliation_Hostile_Faker)
1026                        return 2;
1027                    else
1028                        return 1;
1029
1030                    //Very Zoom in/out sensitive (multi-line text) (3)
1031                    //friendly and more than 1 text
1032                    //Hostile and more than 3 text assuming ENY is present
1033                case 110100://boundary line
1034                    if(_Properties.containsKey(Modifiers.T_UNIQUE_DESIGNATION_1) ||
1035                            _Properties.containsKey(Modifiers.T1_UNIQUE_DESIGNATION_2) ||
1036                            _Properties.containsKey(Modifiers.AS_COUNTRY))
1037                        return 3;
1038                    else
1039                        return 0;
1040
1041                case 150501://Joint Tactical Action Area (JTAA), 2 rows of text
1042                case 150502://Submarine Action Area (SAA), 2 rows of text
1043                case 150503://Submarine Generated Action Area (SGAA), 2 rows of text
1044                case 200300://No Attack (NOTACK) Zone (AEGIS only)
1045                case 140601://Friendly Aviation
1046                case 140602://Friendly Direction of Main Attack
1047                case 140603://Friendly Direction of Supporting Attack
1048                case 140605://Direction of Attack Feint
1049                    if(_Properties.containsKey(Modifiers.W_DTG_1) ||
1050                            _Properties.containsKey(Modifiers.W1_DTG_2))
1051                        return 3;
1052                    else
1053                        return 0;
1054                case 151100://Limited Access Area if sector 1 modifier present
1055                    if(SymbolID.getModifier1(_symbolID)!=0 || _Properties.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
1056                        return 3;
1057                    else
1058                        return 0;
1059
1060                case 152400://Restricted Terrain
1061                case 152500://Severly Restricted Terrain
1062                    if(modifiers != null && modifiers.size()>1)
1063                        return 3;
1064                    else
1065                        return 0;
1066
1067                    //Labels all contained in area but can drift away from each-other or overlap
1068                case 120700: //Generic
1069                case 170900: //High-Density Airspace Control Zone
1070                case 171000: //Restricted Operations Zone (ROZ)
1071                case 171100: //Air-to-Air Restricted Operations Zone (AARROZ)
1072                case 171200: //Unmanned Aircraft Restricted Operations Zone (UA-ROZ)
1073                case 171300: //Weapon Engagement Zone
1074                case 171400: //Fighter Engagement Zone (FEZ)
1075                case 171500: //Joint Engagement Zone (JEZ)
1076                case 171600: //Missile Engagement Zone (MEZ)
1077                case 171700: //Low (Altitude) Missile Engagement Zone (LOMEZ)
1078                case 171800: //High (Altitude) Missile Engagement Zone (HIMEZ)
1079                case 171900: //Short Range Air Defense Engagement Zone (SHORADEZ)
1080                case 172000: //Weapons Free Zone
1081                case 240101: //Airspace Coordination Area (ACA) - Irregular
1082                case 240201: //Free Fire Area (FFA) - Irregular
1083                case 240301: //No Fire Area (NFA) - Irregular
1084                case 240401: //Restricted Fire Area (RFA) - Irregular
1085                case 240806: //Smoke
1086                case 241001://Fire Support Area - Irregular
1087                case 241101: //Artillery Target Intelligence Zone (ATI), - Irregular
1088                case 241201: //Call For Fire Zone (CFFZ) - Irregular
1089                case 241301: //Censor Zone, - Irregular
1090                case 241401: //Critical Friendly Zone (CFZ), - Irregular
1091                case 241501: //Dead Space Area (DA), - Irregular
1092                case 241601: //Sensor Zone, Irregular
1093                case 241701: //Target Build-up Area, Irregular
1094                case 241801: //Target Value Area, Irregular
1095                case 241901: //Zone of Responsibility, Irregular
1096                case 242000: //Terminally Guided Munition Footprint (TGMF)
1097                case 242702: //Psyops Zone, Irregular
1098                case 242800: //Kill Zone
1099                case 242301: //Blue Kill Box, Irregular
1100                case 242304: //Purple Kill Box, Irregular
1101                case 270300: //Obstacle Free Zone
1102                case 290600: //Lane
1103                case 310100: //Detainee Holding Area
1104                case 310200: //Enemy Prisoner of War Holding Area
1105                case 310300: //Forward Arming and Refueling Point (FARP)
1106                case 310400: //Refugee Holding Area
1107                case 310800: //Corps Support Area (CSA)
1108                    if(modifiers != null && modifiers.size()>1)
1109                        return 3;
1110                    else
1111                        return 0;
1112
1113                    //CASES for areas with 4 tags like PAA
1114                case 242400: //Artillery Manoeuvre Area (AMA)
1115                case 240501: //Position Area for Artillery (PAA) - Irregular
1116                    if(modifiers != null && modifiers.size()>4)
1117                        return 3;
1118                    else
1119                        return 0;
1120
1121                case 110400://Generic
1122                case 260100://Fire Support Coordination Line (FSCL)
1123                case 260200://Coordinated Fire Line (CFL)
1124                case 260300://No Fire Line
1125                case 260400://Battlefield Coordination Line
1126                case 260500://Restrictive Fire Line
1127                case 300100://Intelligence Coordination Line (ICL)
1128                    if(_Properties.containsKey(Modifiers.W_DTG_1) ||
1129                            _Properties.containsKey(Modifiers.W1_DTG_2))
1130                        return 3;
1131                    else
1132                        return 2;
1133
1134                case 260600://Munition Flight Path
1135                case 340800://Delay
1136                    if(_Properties.containsKey(Modifiers.W_DTG_1) ||
1137                            _Properties.containsKey(Modifiers.W1_DTG_2))
1138                        return 2;
1139                    else
1140                        return 0;
1141
1142                case 270800://Mined Area
1143                    if(_Properties.containsKey(Modifiers.W_DTG_1) ||
1144                            _Properties.containsKey(Modifiers.H_ADDITIONAL_INFO_1))
1145                        return 2;
1146                    else
1147                        return 0;
1148
1149                case 220109://Navigational Rhumb Line
1150                    if(modifiers != null && modifiers.size() > 1)
1151                        return 3;
1152                    else
1153                        return 2;
1154
1155                case 271100://Bridge or Gap
1156                case 271300://Assault Crossing
1157                    if(_Properties.containsKey(Modifiers.W_DTG_1) ||
1158                            _Properties.containsKey(Modifiers.W1_DTG_2))
1159                        return 3;
1160                    else //TODO: Bridge or Fix placement and it will be a 0 in other cases
1161                        return 2;
1162
1163                default://No Scale Sensitive text
1164                    return 0;
1165            }
1166        }
1167
1168        return 0;
1169    }
1170
1171    /**
1172     * Checks if the symbol has features that make it scale aware and would require a refresh
1173     * on zooming in or out.
1174     * @return 0=No,1=arrowheads,2=decoratedLines,3=patternFills
1175     */
1176    public int isSymbolScaleSensitive()
1177    {
1178        //return SymbolUtilities.isScaleAware(this._symbolID);
1179        int ec = SymbolID.getEntityCode(_symbolID);
1180
1181        if(SymbolID.getSymbolSet(_symbolID)==SymbolID.SymbolSet_ControlMeasure) {
1182            switch (ec)
1183            {
1184                //ArrowHead or smaller detail
1185                case 152000://Attack By Fire
1186                case 152100://Attack By Fire
1187                case 152200://Search Area/Reconnaissance Area
1188                case 141700://Ambush
1189                case 140601://Airborne/Aviation
1190                case 140602://Direction of Main attack
1191                case 140603://Direction of Supporting attack
1192                case 140605://Direction of Supporting attack Feint
1193                case 142100://Mobility Corridor
1194                case 240701://Linear Target
1195                case 240702://Linear Smoke Target
1196                case 240703://Final Protective Fire
1197                case 270502://Disrupt
1198                case 270504://Turn
1199                case 270601://Obstacle Bypass Easy
1200                case 270602://Obstacle Bypass Difficult
1201                case 270603://Obstacle Bypass Impossible
1202                case 271100://Bridge or Gap?
1203                case 271300://Assault Crossing?
1204                case 280100://Abatis?
1205                case 290600://?Lane?
1206                case 290700://Ferry
1207                case 290800://Raft Site
1208                case 340200://Breach
1209                case 340300://Bypass
1210                case 340400://Canalize
1211                case 340500://Clear
1212                case 340800://Delay
1213                case 341000://Disrupt
1214                case 341200://Follow and Assume
1215                case 341300://Follow and Support
1216                    //case 341700://Occupy, details relative to size
1217                    //case 341800://Penetrate, details relative to size
1218                    //case 341900://Relief in Place (RIP), details relative to size
1219                    //case 342000://Retire/Retirement, details relative to size
1220                case 342100://Secure, details relative to size
1221                case 342201://Cover, details relative to size
1222                case 342202://Guard, details relative to size
1223                case 342203://Screen, details relative to size
1224                case 342300://Screen, details relative to size
1225                case 342400://Withdraw, details relative to size
1226                case 342500://Withdraw under pressure, details relative to size
1227                case 343000://Capture
1228                case 343200://Control
1229                case 343300://Demonstrate
1230                case 343400://Deny
1231                case 343500://Development
1232                case 343600://Escort
1233                case 343700://Exfiltration
1234                case 343800://Infiltration
1235                case 343900://Locate
1236                case 344000://Pursuit
1237                case 344100://Forward Passage of Lines
1238                case 344200://Rearward Passage of Lines
1239                case 344400://Disengage
1240                case 344500://Evacuate
1241                case 344600://Recover
1242                case 344700://Turn
1243                    return 1;//arrowhead
1244
1245                //Decorated Lines
1246                case 130701://Decision Line
1247                case 140100://FLOT
1248                case 140200://Line of Contact
1249                    //case 140500://?Principal Direction of Fire?
1250                case 151000://Fortified Area
1251                case 151800://Encirclement
1252                case 151203://Strong Point
1253                case 151202://Battle Position Prepared (P) but not Occupied
1254                case 151204://Contain
1255                case 151205://Retain
1256                case 151208://Mobile Defense
1257                case 152600://Area Defense
1258                case 152800://Mobility Defense
1259                case 270100://Obstacle Belt
1260                case 270200://Obstacle Zone
1261                case 270300://Obstacle Free Zone
1262                case 270400://Obstacle Restricted Zone
1263                    //case 270503://Fix?
1264                case 270801://Mined Area, Fenced
1265                case 282003://Overhead Wire
1266                case 290100://Obstacle Line
1267                case 290201://Ditch Under Construction
1268                case 290202://Ditch Completed
1269                case 290203://Ditch Reinforced
1270                case 290204://Antitank Wall
1271                case 290301://Wire Obstacles, Unspecified
1272                case 290302://Wire Obstacles, Single Fence
1273                case 290303://Wire Obstacles, Double Fence
1274                case 290304://Wire Obstacles, Double Apron Fence
1275                case 290305://Wire Obstacles, Low Wire Fence
1276                case 290306://Wire Obstacles, High Wire Fence
1277                case 290307://Wire Obstacles, Single Concertina
1278                case 290308://Wire Obstacles, Double Strand Concertina
1279                case 290309://Wire Obstacles, Triple Strand Concertina
1280                case 290900://Fortified Line
1281                case 291000://Fighting Position?
1282                case 330100://Moving Convoy
1283                case 330200://Halted Convoy
1284                case 330301://MSR One Way Traffic
1285                case 330302://MSR Two Way Traffic
1286                case 330303://MSR Alternating Traffic
1287                case 330401://ASR One Way Traffic
1288                case 330402://ASR Two Way Traffic
1289                case 330403://ASR Alternating Traffic
1290                case 341100://Fix
1291                    //case 341500://Isolate, most detail contained inside
1292                    //case 342600://Cordon and Knock, most detail contained inside
1293                    //case 342700://Cordon and Search, most detail contained inside
1294                    return 2;//decoration
1295
1296                //Areas with Pattern Fill
1297                case 151100://Limited Access Area
1298                case 172000://Weapons Free Zone
1299                case 152400://Restricted Terrain
1300                case 152500://Severely Restricted Terrain
1301                case 240301://NFA Irregular
1302                case 240302://NFA Rectangular
1303                case 240303://NFA Circular
1304                case 271700://Bio Contaminated Area
1305                case 271701://Bio Contaminated Area - Toxic
1306                case 271800://Chem Contaminated Area
1307                case 271801://Chem Contaminated Area - Toxic
1308                case 271900://Nuc Contaminated Area
1309                case 272000://Rad Contaminated Area
1310                case 272001://Rad Contaminated Area - Toxic
1311                    if(!this.getUseFillPattern())
1312                        return 3;//pattern fill
1313                    else
1314                        return 0;
1315                default:
1316                    return 0;
1317            }
1318        }
1319
1320        return 0;
1321    }
1322
1323    /**
1324     * Multipoint features and patterns scale with line width ({@link #getLineWidth()}).
1325     * {@link #patternScale} is the ratio of how much to increase features and patterns by with line width.
1326     * default value is 1.0. Can be set with {@link RendererSettings#setPatternScale(double)} and {@link MilStdAttributes#PatternScale}
1327     * @param scale
1328     */
1329    public void setPatternScale(double scale) {
1330        patternScale = scale;
1331    }
1332
1333    public double getPatternScale() {
1334        return patternScale;
1335    }
1336
1337}