001package armyc2.c5isr.JavaTacticalRenderer;
002
003import static armyc2.c5isr.JavaTacticalRenderer.clsUtility.GetLinetypeFromString;
004
005import android.graphics.Bitmap;
006
007import java.util.ArrayList;
008import java.util.HashMap;
009import java.util.Map;
010
011import armyc2.c5isr.JavaLineArray.Channels;
012import armyc2.c5isr.JavaLineArray.POINT2;
013import armyc2.c5isr.JavaLineArray.Shape2;
014import armyc2.c5isr.JavaLineArray.TacticalLines;
015import armyc2.c5isr.JavaLineArray.arraysupport;
016import armyc2.c5isr.JavaLineArray.lineutility;
017import armyc2.c5isr.graphics2d.AffineTransform;
018import armyc2.c5isr.graphics2d.BasicStroke;
019import armyc2.c5isr.graphics2d.BufferedImage;
020import armyc2.c5isr.graphics2d.Font;
021import armyc2.c5isr.graphics2d.FontMetrics;
022import armyc2.c5isr.graphics2d.FontRenderContext;
023import armyc2.c5isr.graphics2d.Graphics2D;
024import armyc2.c5isr.graphics2d.Line2D;
025import armyc2.c5isr.graphics2d.PathIterator;
026import armyc2.c5isr.graphics2d.Point;
027import armyc2.c5isr.graphics2d.Point2D;
028import armyc2.c5isr.graphics2d.Polygon;
029import armyc2.c5isr.graphics2d.Rectangle2D;
030import armyc2.c5isr.graphics2d.Shape;
031import armyc2.c5isr.graphics2d.TextLayout;
032import armyc2.c5isr.renderer.SinglePointRenderer;
033import armyc2.c5isr.renderer.utilities.Color;
034import armyc2.c5isr.renderer.utilities.EntityCode;
035import armyc2.c5isr.renderer.utilities.ErrorLogger;
036import armyc2.c5isr.renderer.utilities.GENCLookup;
037import armyc2.c5isr.renderer.utilities.IPointConversion;
038import armyc2.c5isr.renderer.utilities.ImageInfo;
039import armyc2.c5isr.renderer.utilities.MilStdAttributes;
040import armyc2.c5isr.renderer.utilities.Modifiers;
041import armyc2.c5isr.renderer.utilities.RendererException;
042import armyc2.c5isr.renderer.utilities.RendererSettings;
043import armyc2.c5isr.renderer.utilities.RendererUtilities;
044import armyc2.c5isr.renderer.utilities.ShapeInfo;
045import armyc2.c5isr.renderer.utilities.SymbolID;
046
047/**
048 * This class handles everything having to do with text for a
049 * tactical graphic. Note: labels are handled the same as text modifiers.
050 * 
051 */
052public class Modifier2 {
053    private POINT2[] textPath;
054    private String textID;
055    private String featureID;
056    private String text;
057
058    private Bitmap image;
059    private int iteration;
060    private int justify;
061    private int type;
062    private double lineFactor;
063    private static final String _className = "Modifier2";
064    @Deprecated
065    private boolean isIntegral = false;
066    private boolean fitsMBR = true;
067
068    Modifier2() {
069        textPath = new POINT2[2];
070    }
071
072    /**
073     * Put label next to pt0 on opposite side of line
074     */
075    private static final int toEnd = 1; // Put next to pt0 on opposite side of line
076    /**
077     * put label between both point and apply the angle between the two points
078     */
079    private static final int aboveMiddle = 2;    //use both points
080    /**
081     * one point, label always right-side-up
082     */
083    private static final int area = 3;   //use one point
084    /**
085     * one point, label always right-side-up
086     */
087    private static final int screen = 4;   //use one point, screen, cover, guard points
088    /**
089     * Put next to pt0, but above the line
090     */
091    private static final int aboveEnd = 5; // Put next to pt0 on line
092    /**
093     * between both points but perpendicular rotation of text
094     */
095    private static final int aboveMiddlePerpendicular = 6; //use both points
096    /**
097     * For Moving and Halted Convoy.
098     * At start of line behind arrowhead
099     */
100    private static final int aboveStartInside = 7; //place at the start inside the shape
101    /**
102     * For Moving and Halted Convoy.
103     * At back of line inside arrow shape.
104     */
105    private static final int aboveEndInside = 8;  //place at the end inside the shape
106    /**
107     * Image Modifier, uses one point
108     */
109    private static final int areaImage = 9;   //use one point
110    private static double fillAlphaCanObscureText = 50d;
111
112    private static boolean DoublesBack(POINT2 pt0, POINT2 pt1, POINT2 pt2) {
113        boolean result = true;
114        try {
115            double theta1 = Math.atan2(pt2.y - pt1.y, pt2.x - pt1.x);
116            double theta0 = Math.atan2(pt0.y - pt1.y, pt0.x - pt1.x);
117            double beta = Math.abs(theta0 - theta1);
118            if (beta > 0.1) {
119                result = false;
120            }
121
122        } catch (Exception exc) {
123            ErrorLogger.LogException(_className, "DoublesBack",
124                    new RendererException("Failed inside DoublesBack", exc));
125        }
126        return result;
127    }
128
129    /**
130     * Returns a generic label for the symbol per Mil-Std-2525
131     *
132     * @param tg
133     * @return
134     */
135    private static String GetCenterLabel(TGLight tg) {
136        String label = "";
137        try {
138            switch (tg.get_LineType()) {
139                case TacticalLines.SHIP_AOI_RECTANGULAR:
140                case TacticalLines.SHIP_AOI_CIRCULAR:
141                    label = "AOI";
142                    break;
143                case TacticalLines.DEFENDED_AREA_RECTANGULAR:
144                case TacticalLines.DEFENDED_AREA_CIRCULAR:
145                    label = "DA";
146                    break;
147                case TacticalLines.NOTACK:
148                    label = "N";
149                    break;
150                case TacticalLines.LAUNCH_AREA:
151                    label = "LA";
152                    break;
153                case TacticalLines.SL:
154                    label = "SL";
155                    break;
156                case TacticalLines.TC:
157                    label = "TC";
158                    break;
159                case TacticalLines.AARROZ:
160                    label = "AARROZ";
161                    break;
162                case TacticalLines.UAROZ:
163                    label = "UAROZ";
164                    break;
165                case TacticalLines.WEZ:
166                    label = "WEZ";
167                    break;
168                case TacticalLines.FEZ:
169                    label = "FEZ";
170                    break;
171                case TacticalLines.JEZ:
172                    label = "JEZ";
173                    break;
174                case TacticalLines.IFF_OFF:
175                    label = "IFF OFF";
176                    break;
177                case TacticalLines.IFF_ON:
178                    label = "IFF ON";
179                    break;
180                case TacticalLines.BCL_REVD:
181                case TacticalLines.BCL:
182                    label = "BCL";
183                    break;
184                case TacticalLines.ICL:
185                    label = "ICL";
186                    break;
187                case TacticalLines.FEBA:
188                    label = "FEBA";
189                    break;
190                case TacticalLines.BDZ:
191                    label = "BDZ";
192                    break;
193                case TacticalLines.JTAA:
194                    label = "JTAA";
195                    break;
196                case TacticalLines.SAA:
197                    label = "SAA";
198                    break;
199                case TacticalLines.SGAA:
200                    label = "SGAA";
201                    break;
202                case TacticalLines.ASSAULT:
203                    label = "ASLT";
204                    break;
205                case TacticalLines.SAAFR:
206                    label = "SAAFR";
207                    break;
208                case TacticalLines.AC:
209                    label = "AC";
210                    break;
211                case TacticalLines.SECURE:
212                case TacticalLines.SEIZE:
213                    label = "S";
214                    break;
215                case TacticalLines.EVACUATE:
216                    label = "E";
217                    break;
218                case TacticalLines.TURN:
219                    label = "T";
220                    break;
221                case TacticalLines.RETAIN:
222                    label = "R";
223                    break;
224                case TacticalLines.PENETRATE:
225                    label = "P";
226                    break;
227                case TacticalLines.OCCUPY:
228                    label = "O";
229                    break;
230                case TacticalLines.ISOLATE:
231                    label = "I";
232                    break;
233                case TacticalLines.AREA_DEFENSE:
234                    label = "AD";
235                    break;
236                case TacticalLines.FIX:
237                    label = "F";
238                    break;
239                case TacticalLines.DISRUPT:
240                    label = "D";
241                    break;
242                case TacticalLines.CAPTURE:
243                case TacticalLines.CANALIZE:
244                case TacticalLines.CLEAR:
245                case TacticalLines.CONTROL:
246                    label = "C";
247                    break;
248                case TacticalLines.BREACH:
249                case TacticalLines.BYPASS:
250                    label = "B";
251                    break;
252                case TacticalLines.CORDONKNOCK:
253                    label = "C/K";
254                    break;
255                case TacticalLines.CORDONSEARCH:
256                    label = "C/S";
257                    break;
258                case TacticalLines.UXO:
259                    label = "UXO";
260                    break;
261                case TacticalLines.RETIRE:
262                    label = "R";
263                    break;
264                case TacticalLines.PURSUIT:
265                    label = "P";
266                    break;
267                case TacticalLines.ENVELOPMENT:
268                    label = "E";
269                    break;
270                case TacticalLines.FPOL:
271                    label = "P(F)";
272                    break;
273                case TacticalLines.RPOL:
274                    label = "P(R)";
275                    break;
276                case TacticalLines.BRDGHD:
277                case TacticalLines.BRDGHD_GE:
278                    if (SymbolID.getVersion(tg.get_SymbolId()) >= SymbolID.Version_2525E)
279                        label = "BL";
280                    else
281                        label = "B";
282                    break;
283                case TacticalLines.HOLD:
284                case TacticalLines.HOLD_GE:
285                    //label="HOLDING LINE";
286                    label = "HL";
287                    break;
288                case TacticalLines.PL:
289                    label = "PL";
290                    break;
291                case TacticalLines.LL:
292                    label = "LL";
293                    break;
294                case TacticalLines.LOCATE:
295                    label = "LOC";
296                    break;
297                case TacticalLines.EWL:
298                    label = "EWL";
299                    break;
300                case TacticalLines.SCREEN:
301                    label = "S";
302                    break;
303                case TacticalLines.COVER:
304                    label = "C";
305                    break;
306                case TacticalLines.GUARD:
307                    label = "G";
308                    break;
309                case TacticalLines.RIP:
310                    label = "RIP";
311                    break;
312                case TacticalLines.MOBILE_DEFENSE:
313                    label = "MD";
314                    break;
315                case TacticalLines.DEMONSTRATE:
316                    label = "DEM";
317                    break;
318                case TacticalLines.WITHDRAW:
319                    label = "W";
320                    break;
321                case TacticalLines.DISENGAGE:
322                    label = "DIS";
323                    break;
324                case TacticalLines.WDRAWUP:
325                    label = "WP";
326                    break;
327                case TacticalLines.CATK:
328                case TacticalLines.CATKBYFIRE:
329                    label = "CATK";
330                    break;
331                case TacticalLines.FLOT:
332                    label = "FLOT";
333                    break;
334                case TacticalLines.LC:
335                    label = "LC";
336                    break;
337                case TacticalLines.ASSY:
338                    label = "AA";
339                    break;
340                case TacticalLines.EA:
341                    label = "EA";
342                    break;
343                case TacticalLines.DZ:
344                    label = "DZ";
345                    break;
346                case TacticalLines.EZ:
347                    label = "EZ";
348                    break;
349                case TacticalLines.LZ:
350                    label = "LZ";
351                    break;
352                case TacticalLines.LAA:
353                    label = "LAA";
354                    break;
355                case TacticalLines.PZ:
356                    label = "PZ";
357                    break;
358                case TacticalLines.MRR:
359                    label = "MRR";
360                    break;
361                case TacticalLines.SC:
362                    label = "SC";
363                    break;
364                case TacticalLines.LLTR:
365                    label = "LLTR";
366                    break;
367                case TacticalLines.ROZ:
368                    label = "ROZ";
369                    break;
370                case TacticalLines.FAADZ:
371                    label = "SHORADEZ";
372                    break;
373                case TacticalLines.HIDACZ:
374                    label = "HIDACZ";
375                    break;
376                case TacticalLines.MEZ:
377                    label = "MEZ";
378                    break;
379                case TacticalLines.LOMEZ:
380                    label = "LOMEZ";
381                    break;
382                case TacticalLines.HIMEZ:
383                    label = "HIMEZ";
384                    break;
385                case TacticalLines.WFZ_REVD:
386                case TacticalLines.WFZ:
387                    label = "WFZ";
388                    break;
389                case TacticalLines.MINED:
390                case TacticalLines.FENCED:
391                    label = "M";
392                    break;
393                case TacticalLines.PNO:
394                    label = "(P)";
395                    break;
396                case TacticalLines.OBJ:
397                    label = "OBJ";
398                    break;
399                case TacticalLines.NAI:
400                    label = "NAI";
401                    break;
402                case TacticalLines.TAI:
403                    label = "TAI";
404                    break;
405                case TacticalLines.BASE_CAMP_REVD:
406                case TacticalLines.BASE_CAMP:
407                    label = "BC";
408                    break;
409                case TacticalLines.GUERILLA_BASE_REVD:
410                case TacticalLines.GUERILLA_BASE:
411                    label = "GB";
412                    break;
413                case TacticalLines.LINTGTS:
414                    label = "SMOKE";
415                    break;
416                case TacticalLines.FPF:
417                    label = "FPF";
418                    break;
419                case TacticalLines.ATKPOS:
420                    label = "ATK";
421                    break;
422                case TacticalLines.FCL:
423                    label = "FCL";
424                    break;
425                case TacticalLines.LOA:
426                    label = "LOA";
427                    break;
428                case TacticalLines.LOD:
429                    label = "LD";
430                    break;
431                case TacticalLines.PLD:
432                    label = "PLD";
433                    break;
434                case TacticalLines.DELAY:
435                case TacticalLines.DENY:
436                    label = "D";
437                    break;
438                case TacticalLines.RELEASE:
439                    label = "RL";
440                    break;
441                case TacticalLines.HOL:
442                    label = "HOL";
443                    break;
444                case TacticalLines.BHL:
445                    label = "BHL";
446                    break;
447                case TacticalLines.SMOKE:
448                    label = "SMOKE";
449                    break;
450                case TacticalLines.NFL:
451                    label = "NFL";
452                    break;
453                case TacticalLines.MFP:
454                    label = "MFP";
455                    break;
456                case TacticalLines.FSCL:
457                    label = "FSCL";
458                    break;
459                case TacticalLines.CFL:
460                    label = "CFL";
461                    break;
462                case TacticalLines.RFL:
463                    label = "RFL";
464                    break;
465                case TacticalLines.AO:
466                    label = "AO";
467                    break;
468                case TacticalLines.BOMB:
469                    label = "BOMB";
470                    break;
471                case TacticalLines.TGMF:
472                    label = "TGMF";
473                    break;
474                case TacticalLines.FSA:
475                    label = "FSA";
476                    break;
477                case TacticalLines.FSA_CIRCULAR:
478                case TacticalLines.FSA_RECTANGULAR:
479                    label = "FSA";
480                    break;
481                case TacticalLines.ACA:
482                case TacticalLines.ACA_CIRCULAR:
483                case TacticalLines.ACA_RECTANGULAR:
484                    label = "ACA";
485                    break;
486                case TacticalLines.FFA:
487                case TacticalLines.FFA_CIRCULAR:
488                case TacticalLines.FFA_RECTANGULAR:
489                    label = "FFA";
490                    break;
491                case TacticalLines.NFA:
492                case TacticalLines.NFA_CIRCULAR:
493                case TacticalLines.NFA_RECTANGULAR:
494                    label = "NFA";
495                    break;
496                case TacticalLines.RFA:
497                case TacticalLines.RFA_CIRCULAR:
498                case TacticalLines.RFA_RECTANGULAR:
499                    label = "RFA";
500                    break;
501                case TacticalLines.ATI:
502                case TacticalLines.ATI_CIRCULAR:
503                case TacticalLines.ATI_RECTANGULAR:
504                    if (SymbolID.getVersion(tg.get_SymbolId()) >= SymbolID.Version_2525Ech1)
505                        label = "ATIZ";
506                    else
507                        label = "ATI ZONE";
508                    break;
509                case TacticalLines.PAA:
510                case TacticalLines.PAA_CIRCULAR:
511                case TacticalLines.PAA_RECTANGULAR:
512                    label = "PAA";
513                    break;
514                case TacticalLines.CFFZ:
515                case TacticalLines.CFFZ_CIRCULAR:
516                case TacticalLines.CFFZ_RECTANGULAR:
517                    label = "CFF ZONE";
518                    break;
519                case TacticalLines.CFZ:
520                case TacticalLines.CFZ_CIRCULAR:
521                case TacticalLines.CFZ_RECTANGULAR:
522                    label = "CF ZONE";
523                    break;
524                case TacticalLines.SENSOR:
525                case TacticalLines.SENSOR_CIRCULAR:
526                case TacticalLines.SENSOR_RECTANGULAR:
527                    label = "SENSOR ZONE";
528                    break;
529                case TacticalLines.CENSOR:
530                case TacticalLines.CENSOR_CIRCULAR:
531                case TacticalLines.CENSOR_RECTANGULAR:
532                    label = "CENSOR ZONE";
533                    break;
534                case TacticalLines.DA:
535                case TacticalLines.DA_CIRCULAR:
536                case TacticalLines.DA_RECTANGULAR:
537                    label = "DA";
538                    break;
539                case TacticalLines.ZOR:
540                case TacticalLines.ZOR_CIRCULAR:
541                case TacticalLines.ZOR_RECTANGULAR:
542                    label = "ZOR";
543                    break;
544                case TacticalLines.TBA:
545                case TacticalLines.TBA_CIRCULAR:
546                case TacticalLines.TBA_RECTANGULAR:
547                    label = "TBA";
548                    break;
549                case TacticalLines.TVAR:
550                case TacticalLines.TVAR_CIRCULAR:
551                case TacticalLines.TVAR_RECTANGULAR:
552                    label = "TVAR";
553                    break;
554                case TacticalLines.KILLBOXBLUE:
555                case TacticalLines.KILLBOXBLUE_CIRCULAR:
556                case TacticalLines.KILLBOXBLUE_RECTANGULAR:
557                    label = "BKB";
558                    break;
559                case TacticalLines.KILLBOXPURPLE:
560                case TacticalLines.KILLBOXPURPLE_CIRCULAR:
561                case TacticalLines.KILLBOXPURPLE_RECTANGULAR:
562                    label = "PKB";
563                    break;
564                case TacticalLines.MSR:
565                case TacticalLines.MSR_ONEWAY:
566                case TacticalLines.MSR_TWOWAY:
567                case TacticalLines.MSR_ALT:
568                    label = "MSR";
569                    break;
570                case TacticalLines.ASR:
571                case TacticalLines.ASR_ONEWAY:
572                case TacticalLines.ASR_TWOWAY:
573                case TacticalLines.ASR_ALT:
574                    label = "ASR";
575                    break;
576                case TacticalLines.TRAFFIC_ROUTE:
577                case TacticalLines.TRAFFIC_ROUTE_ONEWAY:
578                case TacticalLines.TRAFFIC_ROUTE_ALT:
579                    label = "ROUTE";
580                    break;
581                case TacticalLines.LDLC:
582                    label = "LD/LC";
583                    break;
584                case TacticalLines.AIRHEAD:
585                    label = "AIRHEAD LINE";
586                    break;
587                case TacticalLines.BLOCK:
588                case TacticalLines.BEARING:
589                    label = "B";
590                    break;
591                case TacticalLines.BEARING_J:
592                    label = "J";
593                    break;
594                case TacticalLines.BEARING_RDF:
595                    label = "RDF";
596                    break;
597                case TacticalLines.ELECTRO:
598                case TacticalLines.ESCORT:
599                    label = "E";
600                    break;
601                case TacticalLines.BEARING_EW:
602                    label = "EW";
603                    break;
604                case TacticalLines.ACOUSTIC:
605                case TacticalLines.ACOUSTIC_AMB:
606                    label = "A";
607                    break;
608                case TacticalLines.TORPEDO:
609                    label = "T";
610                    break;
611                case TacticalLines.OPTICAL:
612                    label = "O";
613                    break;
614                case TacticalLines.DHA:
615                    label = "DHA";
616                    break;
617                case TacticalLines.KILL_ZONE:
618                    label = "KILL ZONE";
619                    break;
620                case TacticalLines.FARP:
621                    label = "FARP";
622                    break;
623                case TacticalLines.BSA:
624                    label = "BSA";
625                    break;
626                case TacticalLines.DSA:
627                    label = "DSA";
628                    break;
629                case TacticalLines.CSA:
630                    label = "CSA";
631                    break;
632                case TacticalLines.RSA:
633                    label = "RSA";
634                    break;
635                case TacticalLines.CONTAIN:
636                    label = "C";
637                    break;
638                case TacticalLines.OBSFAREA:
639                    label = "FREE";
640                    break;
641                case TacticalLines.TRIP:
642                    label = "t";
643                    break;
644                case TacticalLines.EXFILTRATION:
645                    label = "EX";
646                    break;
647                case TacticalLines.INFILTRATION:
648                    label = "IN";
649                    break;
650                default:
651                    break;
652            }
653        } catch (Exception exc) {
654            //clsUtility.WriteFile("Error in Modifier2.GetCenterLabel");
655            ErrorLogger.LogException(_className, "GetCenterLabel",
656                    new RendererException("Failed inside GetCenterLabel", exc));
657        }
658        return label;
659    }
660    //non CPOF clients using best fit need these accessors
661
662    public POINT2[] get_TextPath() {
663        return textPath;
664    }
665
666    protected void set_TextPath(POINT2[] value) {
667        textPath = value;
668    }
669
670    @Deprecated
671    protected void set_IsIntegral(boolean value) {
672        isIntegral = value;
673    }
674
675    @Deprecated
676    protected boolean get_IsIntegral() {
677        return isIntegral;
678    }
679
680    private static void AddOffsetModifier(TGLight tg,
681            String text,
682            int type,
683            double lineFactor,
684            int startIndex,
685            int endIndex,
686            double spaces,
687            String rightOrLeft) {
688        if (rightOrLeft == null || tg.Pixels == null || tg.Pixels.size() < 2 || endIndex >= tg.Pixels.size()) {
689            return;
690        }
691
692        POINT2 pt0 = tg.Pixels.get(startIndex);
693        POINT2 pt1 = tg.Pixels.get(endIndex);
694        if (rightOrLeft.equals("left")) {
695            pt0.x -= spaces;
696            pt1.x -= spaces;
697        } else {
698            pt0.x += spaces;
699            pt1.x += spaces;
700        }
701        AddModifier2(tg, text, type, lineFactor, pt0, pt1, false);
702    }
703
704    /**
705     *
706     * @param tg
707     * @param text
708     * @param type
709     * @param lineFactor
710     * @param ptStart
711     * @param ptEnd
712     */
713    private static void AddModifier(TGLight tg,
714            String text,
715            int type,
716            double lineFactor,
717            POINT2 ptStart,
718            POINT2 ptEnd) {
719        if (tg.Pixels == null || tg.Pixels.size() < 2) {
720            return;
721        }
722        AddModifier2(tg, text, type, lineFactor, ptStart, ptEnd, false);
723    }
724
725    private static void AddModifier2(TGLight tg,
726            String text,
727            int type,
728            double lineFactor,
729            POINT2 pt0,
730            POINT2 pt1,
731            boolean isIntegral) {
732        AddModifier2(tg, text, type, lineFactor, pt0, pt1, isIntegral, null);
733    }
734
735    private static void AddModifier2(TGLight tg,
736            String text,
737            int type,
738            double lineFactor,
739            POINT2 pt0,
740            POINT2 pt1,
741            boolean isIntegral,
742            String modifierType) {
743        try {
744            if (text == null || text.equals("")) {
745                return;
746            }
747
748            Modifier2 modifier = new Modifier2();
749            modifier.set_IsIntegral(isIntegral);
750            modifier.text = text;
751            modifier.type = type;
752            modifier.lineFactor = lineFactor;
753            modifier.textPath[0] = pt0;
754            modifier.textPath[1] = pt1;
755            modifier.textID = modifierType;
756            tg.modifiers.add(modifier);
757        } catch (Exception exc) {
758            ErrorLogger.LogException(_className, "AddModifier",
759                    new RendererException("Failed inside AddModifier", exc));
760        }
761    }
762
763    private static void AddIntegralModifier(TGLight tg,
764            String text,
765            int type,
766            double lineFactor,
767            int startIndex,
768            int endIndex) {
769        AddIntegralModifier(tg, text, type, lineFactor, startIndex, endIndex, true);
770    }
771
772    private static void AddIntegralModifier(TGLight tg,
773            String text,
774            int type,
775            double lineFactor,
776            int startIndex,
777            int endIndex,
778            Boolean isIntegral) {
779        AddIntegralModifier(tg, text, type, lineFactor, startIndex, endIndex, isIntegral, null);
780    }
781
782    private static void AddIntegralModifier(TGLight tg,
783            String text,
784            int type,
785            double lineFactor,
786            int startIndex,
787            int endIndex,
788            Boolean isIntegral,
789            String modifierType) {
790        if (tg.Pixels == null || tg.Pixels.isEmpty() || endIndex >= tg.Pixels.size()) {
791            return;
792        }
793        AddIntegralAreaModifier(tg, text, type, lineFactor, tg.Pixels.get(startIndex), tg.Pixels.get(endIndex), isIntegral, modifierType);
794    }
795
796    /**
797     * Creates and adds center modifiers for generic areas
798     *
799     * @param tg
800     * @param text
801     * @param type
802     * @param lineFactor
803     * @param pt0
804     * @param pt1
805     */
806    private static void AddAreaModifier(TGLight tg,
807            String text,
808            int type,
809            double lineFactor,
810            POINT2 pt0,
811            POINT2 pt1) {
812        AddIntegralAreaModifier(tg, text, type, lineFactor, pt0, pt1, true);
813    }
814
815    /**
816     * sets modifier.textId to the modifier type, e.g. label, T, T1, etc.
817     *
818     * @param tg
819     * @param text
820     * @param type
821     * @param lineFactor
822     * @param pt0
823     * @param pt1
824     * @param modifierType
825     */
826    private static void AddAreaModifier(TGLight tg,
827            String text,
828            int type,
829            double lineFactor,
830            POINT2 pt0,
831            POINT2 pt1,
832            String modifierType) {
833        AddIntegralAreaModifier(tg, text, type, lineFactor, pt0, pt1, true, modifierType);
834    }
835
836    private static void AddIntegralAreaModifier(TGLight tg,
837            String text,
838            int type,
839            double lineFactor,
840            POINT2 pt0,
841            POINT2 pt1,
842            Boolean isIntegral) {
843        AddIntegralAreaModifier(tg,text,type,lineFactor,pt0, pt1, isIntegral, null);
844    }
845
846    private static void AddIntegralAreaModifier(TGLight tg,
847            Bitmap image,
848            int type,
849            double lineFactor,
850            POINT2 pt0,
851            POINT2 pt1,
852            Boolean isIntegral) {
853        try {
854            if (image == null || image.equals("")) {
855                return;
856            }
857
858            Modifier2 modifier = new Modifier2();
859            modifier.set_IsIntegral(isIntegral);
860            modifier.image = image;
861            if (image == null || image.equals("")) {
862                return;
863            }
864
865            if (pt0 == null || pt1 == null) {
866                return;
867            }
868
869            modifier.type = type;
870            modifier.lineFactor = lineFactor;
871            modifier.textPath[0] = pt0;
872            modifier.textPath[1] = pt1;
873            tg.modifiers.add(modifier);
874        } catch (Exception exc) {
875            ErrorLogger.LogException(_className, "AddAreaModifier",
876                    new RendererException("Failed inside AddAreaModifier", exc));
877        }
878    }
879
880    private static void AddIntegralAreaModifier(TGLight tg,
881            String text,
882            int type,
883            double lineFactor,
884            POINT2 pt0,
885            POINT2 pt1,
886            Boolean isIntegral,
887            String modifierType) {
888        if (pt0 == null || pt1 == null) {
889            return;
890        }
891        AddModifier2(tg, text, type, lineFactor, pt0, pt1, isIntegral, modifierType);
892    }
893
894    /**
895     * Returns symbol MBR. Assumes points have been initialized with value of
896     * 0th point
897     *
898     * @param tg the tactical graphic object
899     * @param ptUl OUT - MBR upper left
900     * @param ptUr OUT - MBR upper right
901     * @param ptLr OUT - MBR lower right
902     * @param ptLl OUT - MBR lower left
903     */
904    public static void GetMBR(TGLight tg,
905            POINT2 ptUl,
906            POINT2 ptUr,
907            POINT2 ptLr,
908            POINT2 ptLl) {
909        try {
910            int j = 0;
911            double x = 0;
912            double y = 0;
913            ptUl.x = tg.Pixels.get(0).x;
914            ptUl.y = tg.Pixels.get(0).y;
915            ptUr.x = tg.Pixels.get(0).x;
916            ptUr.y = tg.Pixels.get(0).y;
917            ptLl.x = tg.Pixels.get(0).x;
918            ptLl.y = tg.Pixels.get(0).y;
919            ptLr.x = tg.Pixels.get(0).x;
920            ptLr.y = tg.Pixels.get(0).y;
921            int n = tg.Pixels.size();
922            //for (j = 1; j < tg.Pixels.size(); j++) 
923            for (j = 1; j < n; j++) {
924                x = tg.Pixels.get(j).x;
925                y = tg.Pixels.get(j).y;
926                if (x < ptLl.x) {
927                    ptLl.x = x;
928                    ptUl.x = x;
929                }
930                if (x > ptLr.x) {
931                    ptLr.x = x;
932                    ptUr.x = x;
933                }
934                if (y > ptLl.y) {
935                    ptLl.y = y;
936                    ptLr.y = y;
937                }
938                if (y < ptUl.y) {
939                    ptUl.y = y;
940                    ptUr.y = y;
941                }
942            }
943        } catch (Exception exc) {
944            ErrorLogger.LogException(_className, "GetMBR",
945                    new RendererException("Failed inside GetMBR", exc));
946        }
947    }
948
949    /**
950     * Tests segment of a Boundary
951     *
952     * @param tg
953     * @param g2d
954     * @param middleSegment
955     * @return
956     */
957    private static boolean GetBoundarySegmentTooShort(TGLight tg,
958            Graphics2D g2d,
959            int middleSegment) {
960        boolean lineTooShort = false;
961        try {
962            //int middleSegment = tg.Pixels.size() / 2 - 1;
963            g2d.setFont(tg.get_Font());
964            FontMetrics metrics = g2d.getFontMetrics();
965            String echelonSymbol = null;
966            int stringWidthEchelonSymbol = 0;
967
968            POINT2 pt0 = tg.Pixels.get(middleSegment);
969            POINT2 pt1 = tg.Pixels.get(middleSegment + 1);
970            double dist = lineutility.CalcDistanceDouble(pt0, pt1);
971
972            echelonSymbol = tg.get_EchelonSymbol();
973
974            if (echelonSymbol != null) {
975                stringWidthEchelonSymbol = metrics.stringWidth(echelonSymbol);
976            }
977
978            int tWidth = 0, t1Width = 0;
979            if (tg.get_Name() != null && !tg.get_Name().isEmpty()) {
980                tWidth = metrics.stringWidth(tg.get_Name());
981            }
982            if (tg.get_T1() != null && !tg.get_T1().isEmpty()) {
983                t1Width = metrics.stringWidth(tg.get_T1());
984            }
985
986            int totalWidth = stringWidthEchelonSymbol;
987            if (totalWidth < tWidth) {
988                totalWidth = tWidth;
989            }
990            if (totalWidth < t1Width) {
991                totalWidth = t1Width;
992            }
993
994            switch (tg.get_LineType()) {
995                case TacticalLines.BOUNDARY:
996                    if (dist < 1.25 * (totalWidth)) {
997                        lineTooShort = true;
998                    }
999                    break;
1000                default:
1001                    break;
1002            }
1003        } catch (Exception exc) {
1004            ErrorLogger.LogException(_className, "GetBoundaryLineTooShort",
1005                    new RendererException("Failed inside GetBoundaryLineTooShort", exc));
1006        }
1007        return lineTooShort;
1008    }
1009
1010    /**
1011     * Handles the line breaks for Boundary and Engineer Work Line
1012     *
1013     * @param tg
1014     * @param g2d
1015     */
1016    private static void AddBoundaryModifiers(TGLight tg,
1017            Graphics2D g2d,
1018            Object clipBounds) {
1019        try {
1020            int j = 0;
1021            double csFactor = 1d;
1022            Boolean foundSegment = false;
1023            POINT2 pt0 = null, pt1 = null, ptLast = null;
1024            double TLineFactor = 0, T1LineFactor = 0;
1025            Boolean lineTooShort = false;
1026            String countryCode = "";
1027            if(!tg.get_AS().equals("")) {
1028                countryCode = " (" + tg.get_AS() + ")";
1029            }
1030            if (tg.get_Client().equals("cpof3d")) {
1031                csFactor = 0.85d;
1032            }
1033
1034            int middleSegment = getVisibleMiddleSegment(tg, clipBounds);
1035            //for (j = 0; j < tg.Pixels.size() - 1; j++) {
1036            for (j = middleSegment; j == middleSegment; j++) {
1037                /* if (tg.get_Client().equalsIgnoreCase("ge")) {
1038                    if (j != middleSegment) {
1039                        continue;
1040                    }
1041                }*/
1042
1043                pt0 = tg.Pixels.get(j);
1044                pt1 = tg.Pixels.get(j + 1);
1045                if (pt0.x < pt1.x) {
1046                    TLineFactor = -1.3;
1047                    T1LineFactor = 1;
1048                } else if (pt0.x == pt1.x) {
1049                    if (pt1.y < pt0.y) {
1050                        TLineFactor = -1;
1051                        T1LineFactor = 1;
1052                    } else {
1053                        TLineFactor = 1;
1054                        T1LineFactor = -1;
1055                    }
1056                } else {
1057                    TLineFactor = 1;
1058                    T1LineFactor = -1.3;
1059                }
1060                //is the segment too short?
1061                lineTooShort = GetBoundarySegmentTooShort(tg, g2d, j);
1062
1063                if (lineTooShort == false) {
1064                    foundSegment = true;
1065                    AddIntegralModifier(tg, tg.get_Name() + countryCode, aboveMiddle, TLineFactor * csFactor, j, j + 1, true);
1066                    //the echelon symbol
1067                    if (tg.get_EchelonSymbol() != null && !tg.get_EchelonSymbol().equals("")) {
1068                        AddIntegralModifier(tg, tg.get_EchelonSymbol(), aboveMiddle, -0.20 * csFactor, j, j + 1, true);
1069                    }
1070                    //the T1 modifier
1071                    AddIntegralModifier(tg, tg.get_T1(), aboveMiddle, T1LineFactor * csFactor, j, j + 1, true);
1072                }
1073            }//end for loop
1074            if (foundSegment == false) {
1075                pt0 = new POINT2();
1076                pt1 = new POINT2();
1077                // Get boundary middle segment
1078                final String echelonSymbol = tg.get_EchelonSymbol();
1079                final FontMetrics metrics = g2d.getFontMetrics();
1080                double modDist = 0;
1081
1082                if (echelonSymbol != null) {
1083                    modDist = 1.5 * metrics.stringWidth(echelonSymbol);
1084                }
1085
1086                final double segDist = lineutility.CalcDistanceDouble(tg.Pixels.get(middleSegment), tg.Pixels.get(middleSegment + 1));
1087
1088                g2d.setFont(tg.get_Font());
1089                POINT2 midpt = lineutility.MidPointDouble(tg.Pixels.get(middleSegment), tg.Pixels.get(middleSegment + 1), 0);
1090                POINT2 ptTemp = null;
1091                if (segDist < modDist) {
1092                    ptTemp = lineutility.ExtendAlongLineDouble(midpt, tg.Pixels.get(middleSegment), modDist / 2);
1093                    pt0.x = ptTemp.x;
1094                    pt0.y = ptTemp.y;
1095                    ptTemp = lineutility.ExtendAlongLineDouble(midpt, tg.Pixels.get(middleSegment + 1), modDist / 2);
1096                } else {
1097                    ptTemp = tg.Pixels.get(middleSegment);
1098                    pt0.x = ptTemp.x;
1099                    pt0.y = ptTemp.y;
1100                    ptTemp = tg.Pixels.get(middleSegment + 1);
1101                }
1102                pt1.x = ptTemp.x;
1103                pt1.y = ptTemp.y;
1104
1105                AddIntegralModifier(tg, tg.get_Name() + countryCode, aboveMiddle, TLineFactor * csFactor, middleSegment, middleSegment + 1, true);
1106                //the echelon symbol
1107                if (echelonSymbol != null && !echelonSymbol.equals("")) {
1108                    AddIntegralModifier(tg, echelonSymbol, aboveMiddle, -0.2020 * csFactor, middleSegment, middleSegment + 1, true);
1109                }
1110                //the T1 modifier
1111                AddIntegralModifier(tg, tg.get_T1(), aboveMiddle, T1LineFactor * csFactor, middleSegment, middleSegment + 1, true);
1112            }//end if foundSegment==false
1113        } catch (Exception exc) {
1114            ErrorLogger.LogException(_className, "AddBoundaryModifiers",
1115                    new RendererException("Failed inside AddBoundaryModifiers", exc));
1116        }
1117    }
1118
1119    /**
1120     * added for USAS
1121     *
1122     * @param tg
1123     * @param metrics
1124     * @deprecated
1125     */
1126    private static void AddNameAboveDTG(TGLight tg, FontMetrics metrics) {
1127        try {
1128            double csFactor = 1;
1129            if (tg.get_Client().equals("cpof3d")) {
1130                csFactor = 0.667;
1131            }
1132            String label = GetCenterLabel(tg);
1133            POINT2 pt0 = new POINT2(tg.Pixels.get(0));
1134            POINT2 pt1 = new POINT2(tg.Pixels.get(1));
1135            int lastIndex = tg.Pixels.size() - 1;
1136            int nextToLastIndex = tg.Pixels.size() - 2;
1137            POINT2 ptLast = new POINT2(tg.Pixels.get(lastIndex));
1138            POINT2 ptNextToLast = new POINT2(tg.Pixels.get(nextToLastIndex));
1139            shiftModifierPath(tg, pt0, pt1, ptLast, ptNextToLast);
1140            double stringWidth = metrics.stringWidth(label + " " + tg.get_Name());
1141            AddIntegralAreaModifier(tg, label + " " + tg.get_Name(), toEnd, 0, pt0, pt1, false);
1142            pt1 = lineutility.ExtendAlongLineDouble(tg.Pixels.get(0), tg.Pixels.get(1), -1.5 * stringWidth);
1143            AddModifier2(tg, tg.get_DTG(), aboveMiddle, 0.7 * csFactor, pt0, pt1, false);
1144            AddModifier2(tg, tg.get_DTG1(), aboveMiddle, 1.7 * csFactor, pt0, pt1, false);
1145            AddIntegralAreaModifier(tg, label + " " + tg.get_Name(), toEnd, 0, ptLast, ptNextToLast, false);
1146            pt0 = tg.Pixels.get(lastIndex);
1147            pt1 = lineutility.ExtendAlongLineDouble(tg.Pixels.get(lastIndex), tg.Pixels.get(nextToLastIndex), -1.5 * stringWidth);
1148            AddModifier2(tg, tg.get_DTG(), aboveMiddle, 0.7 * csFactor, pt0, pt1, false);
1149            AddModifier2(tg, tg.get_DTG1(), aboveMiddle, 1.7 * csFactor, pt0, pt1, false);
1150        } catch (Exception exc) {
1151            ErrorLogger.LogException(_className, "AddNameAboveDTG",
1152                    new RendererException("Failed inside AddNameAboveDTG", exc));
1153        }
1154    }
1155
1156    /**
1157     * shifts the path for modifiers that use toEnd to prevent vertical paths
1158     *
1159     * @param tg
1160     * @param pt0
1161     * @param pt1
1162     * @param ptLast
1163     * @param ptNextToLast
1164     */
1165    private static void shiftModifierPath(TGLight tg,
1166            POINT2 pt0,
1167            POINT2 pt1,
1168            POINT2 ptLast,
1169            POINT2 ptNextToLast) {
1170        try {
1171            POINT2 p0 = null, p1 = null;
1172            double last = -1.0;
1173            switch (tg.get_LineType()) {
1174                case TacticalLines.BOUNDARY:
1175                    for (int j = 0; j < tg.Pixels.size() - 1; j++) {
1176                        p0 = tg.Pixels.get(j);
1177                        p1 = tg.Pixels.get(j + 1);
1178                        //if(p0.x==p1.x)
1179                        if (Math.abs(p0.x - p1.x) < 1) {
1180                            p1.x += last;
1181                            last = -last;
1182                        }
1183                    }
1184                    break;
1185                case TacticalLines.PDF:
1186                case TacticalLines.PL:
1187                case TacticalLines.DECISION_LINE:
1188                case TacticalLines.FEBA:
1189                case TacticalLines.LOA:
1190                case TacticalLines.LOD:
1191                case TacticalLines.RELEASE:
1192                case TacticalLines.HOL:
1193                case TacticalLines.BHL:
1194                case TacticalLines.LDLC:
1195                case TacticalLines.LL:
1196                case TacticalLines.EWL:
1197                case TacticalLines.FCL:
1198                case TacticalLines.PLD:
1199                case TacticalLines.NFL:
1200                case TacticalLines.FLOT:
1201                case TacticalLines.LC:
1202                case TacticalLines.HOLD:
1203                case TacticalLines.BRDGHD:
1204                case TacticalLines.HOLD_GE:
1205                case TacticalLines.BRDGHD_GE:
1206                    //if (pt0 != null && pt1 != null && pt0.x == pt1.x) 
1207                    if (pt0 != null && pt1 != null && Math.abs(pt0.x - pt1.x) < 1) {
1208                        pt1.x += 1;
1209                    }
1210                    //if (ptLast != null && ptNextToLast != null && ptNextToLast.x == ptLast.x) 
1211                    if (ptLast != null && ptNextToLast != null && Math.abs(ptNextToLast.x - ptLast.x) < 1) {
1212                        ptNextToLast.x += 1;
1213                    }
1214                    break;
1215                default:
1216                    return;
1217            }
1218        } catch (Exception exc) {
1219            ErrorLogger.LogException(_className, "shiftModifierPath",
1220                    new RendererException("Failed inside shiftModifierPath", exc));
1221        }
1222    }
1223
1224    /**
1225     * Adds two or four labels on area outline
1226     *
1227     * @param label
1228     * @param tg
1229     * @param twoLabelOnly - when true only two labels are added to line (east and west most segment midpoints)
1230     *                     when false, four labels are added to line (north, south, east and west most segment midpoints)
1231     */
1232    private static void addModifierOnLine(String label, TGLight tg, boolean twoLabelOnly) {
1233        if (label == null || label.isEmpty() || tg.Pixels.isEmpty()) {
1234            return;
1235        }
1236        try {
1237            POINT2 leftPt = lineutility.MidPointDouble(tg.Pixels.get(0), tg.Pixels.get(1), 0);
1238            POINT2 rightPt = lineutility.MidPointDouble(tg.Pixels.get(0), tg.Pixels.get(1), 0);
1239            POINT2 topPt = lineutility.MidPointDouble(tg.Pixels.get(0), tg.Pixels.get(1), 0);
1240            POINT2 bottomPt = lineutility.MidPointDouble(tg.Pixels.get(0), tg.Pixels.get(1), 0);
1241            for (int j = 1; j < tg.Pixels.size() - 1; j++) {
1242                POINT2 midPt = lineutility.MidPointDouble(tg.Pixels.get(j), tg.Pixels.get(j + 1), 0);
1243                if (midPt.x <= leftPt.x) {
1244                    leftPt = midPt;
1245                }
1246                if (midPt.x >= rightPt.x) {
1247                    rightPt = midPt;
1248                }
1249                if (midPt.y <= topPt.y) {
1250                    topPt = midPt;
1251                }
1252                if (midPt.y >= bottomPt.y) {
1253                    bottomPt = midPt;
1254                }
1255            }
1256
1257            if (leftPt != rightPt)
1258                AddAreaModifier(tg, label, aboveMiddle, 0, leftPt, leftPt);
1259            AddAreaModifier(tg, label, aboveMiddle, 0, rightPt, rightPt);
1260            if (!twoLabelOnly) {
1261                if (bottomPt != leftPt && bottomPt != rightPt)
1262                    AddAreaModifier(tg, label, aboveMiddle, 0, bottomPt, bottomPt);
1263                if (topPt != leftPt && topPt != rightPt && topPt != bottomPt)
1264                    AddAreaModifier(tg, label, aboveMiddle, 0, topPt, topPt);
1265            }
1266        } catch (Exception exc) {
1267            ErrorLogger.LogException(_className, "addModifierOnLine",
1268                    new RendererException("Failed inside addModifierOnLine", exc));
1269        }
1270    }
1271
1272    private static void addModifierOnLine(String label, TGLight tg) {
1273        addModifierOnLine(label, tg, false);
1274    }
1275
1276    /**
1277     * Adds N modifier on area outline
1278     */
1279    private static void addNModifier(TGLight tg) {
1280        if (tg.isHostile()) {
1281            addModifierOnLine(tg.get_N(), tg, true);
1282        }
1283    }
1284
1285    private static void addModifierBottomSegment(TGLight tg, String text) {
1286        int index = 0;
1287        double y = tg.Pixels.get(index).y + tg.Pixels.get(index + 1).y;
1288        for (int i = 1; i < tg.Pixels.size() - 1; i++) {
1289            if (tg.Pixels.get(i).y + tg.Pixels.get(i + 1).y > y) {
1290                index = i;
1291                y = tg.Pixels.get(index).y + tg.Pixels.get(index + 1).y;
1292            }
1293        }
1294        AddIntegralModifier(tg, text, aboveMiddle, 0, index, index + 1, false);
1295    }
1296
1297    private static void addModifierTopSegment(TGLight tg, String text) {
1298        int index = 0;
1299        double y = tg.Pixels.get(index).y + tg.Pixels.get(index + 1).y;
1300        for (int i = 1; i < tg.Pixels.size() - 1; i++) {
1301            if (tg.Pixels.get(i).y + tg.Pixels.get(i + 1).y < y) {
1302                index = i;
1303                y = tg.Pixels.get(index).y + tg.Pixels.get(index + 1).y;
1304            }
1305        }
1306        AddIntegralModifier(tg, text, aboveMiddle, 0, index, index + 1, false);
1307    }
1308
1309    private static void addDTG(TGLight tg, int type, double lineFactor1, double lineFactor2, POINT2 pt0, POINT2 pt1, FontMetrics metrics) {
1310        if (pt0 == null || pt1 == null)
1311            return;
1312
1313        double maxDTGWidth;
1314        if (pt0.x == pt1.x && pt0.y == pt1.y) {
1315            POINT2 ptUl = new POINT2(), ptUr = new POINT2(), ptLr = new POINT2(), ptLl = new POINT2();
1316            GetMBR(tg, ptUl, ptUr, ptLr, ptLl);
1317            maxDTGWidth = lineutility.CalcDistanceDouble(ptUl, ptUr);
1318        } else {
1319            maxDTGWidth = lineutility.CalcDistanceDouble(pt0, pt1);
1320        }
1321
1322        String dash = "";
1323        if (tg.get_DTG() != null && tg.get_DTG1() != null && !tg.get_DTG().isEmpty() && !tg.get_DTG1().isEmpty()) {
1324            dash = " - ";
1325        }
1326
1327        String combinedDTG = tg.get_DTG() + dash + tg.get_DTG1();
1328
1329        double stringWidth = metrics.stringWidth(combinedDTG);
1330
1331        if (stringWidth < maxDTGWidth) {
1332            // Add on one line
1333            AddModifier(tg, combinedDTG, type, lineFactor1, pt0, pt1);
1334        } else {
1335            // add on two lines
1336            // Use min and max on lineFactors. Always want W1 on top. This fixes when lineFactor < 0 W1 should use lineFactor1
1337            AddModifier(tg, tg.get_DTG() + dash, type, Math.min(lineFactor1, lineFactor2), pt0, pt1);
1338            AddModifier(tg, tg.get_DTG1(), type, Math.max(lineFactor1, lineFactor2), pt0, pt1);
1339        }
1340    }
1341
1342    private static int getVisibleMiddleSegment(TGLight tg, Object clipBounds) {
1343        int middleSegment = -1;
1344        try {
1345            Polygon clipBoundsPoly = null;
1346            Rectangle2D clipRect = null;
1347            boolean useClipRect; // true if clipBounds is Rectangle2D otherwise use clipBoundsPoly
1348            POINT2 pt0 = null, pt1 = null;
1349            double dist = 0;
1350            POINT2 lastPt = null;
1351            long lineType = tg.get_LineType();
1352            //we want the middle segment to be visible
1353            middleSegment = (tg.Pixels.size() + 1) / 2 - 1;
1354
1355            boolean foundVisibleSegment = false;
1356            if (clipBounds == null) {
1357                return middleSegment;
1358            }
1359
1360            if (ArrayList.class.isAssignableFrom(clipBounds.getClass())) {
1361                useClipRect = false;
1362                clipBoundsPoly = new Polygon();
1363                ArrayList<Point2D> clipArray = (ArrayList<Point2D>) clipBounds;
1364                for (int j = 0; j < clipArray.size(); j++) {
1365                    int x = (int) (clipArray.get(j)).getX();
1366                    int y = (int) (clipArray.get(j)).getY();
1367                    clipBoundsPoly.addPoint(x, y);
1368                }
1369            } else if (Rectangle2D.class.isAssignableFrom(clipBounds.getClass())) {
1370                useClipRect = true;
1371                clipRect = (Rectangle2D) clipBounds;
1372            } else {
1373                return middleSegment;
1374            }
1375
1376            //walk through the segments to find the first visible segment from the middle
1377            for (int j = middleSegment; j < tg.Pixels.size() - 1; j++) {
1378                pt0 = tg.Pixels.get(j);
1379                pt1 = tg.Pixels.get(j + 1);
1380                dist = lineutility.CalcDistanceDouble(pt0, pt1);
1381                if (dist < 5) {
1382                    continue;
1383                }
1384                //diagnostic
1385                if (j > 0 && lineType == TacticalLines.BOUNDARY) {
1386                    if (lastPt == null) {
1387                        lastPt = tg.Pixels.get(j - 1);
1388                    }
1389                    if (DoublesBack(lastPt, pt0, pt1)) {
1390                        continue;
1391                    }
1392
1393                    lastPt = null;
1394                }
1395                //if either of the points is within the bound then most of the segment is visible
1396                if (!useClipRect) {
1397                    if (clipBoundsPoly.contains(pt0.x, pt0.y) || clipBoundsPoly.contains(pt1.x, pt1.y)) {
1398                        middleSegment = j;
1399                        foundVisibleSegment = true;
1400                        break;
1401                    }
1402                } else {
1403                    if (clipRect.contains(pt0.x, pt0.y) || clipRect.contains(pt1.x, pt1.y)) {
1404                        middleSegment = j;
1405                        foundVisibleSegment = true;
1406                        break;
1407                    }
1408                }
1409            }
1410
1411            if (!foundVisibleSegment) {
1412                for (int j = middleSegment; j > 0; j--) {
1413                    pt0 = tg.Pixels.get(j);
1414                    pt1 = tg.Pixels.get(j - 1);
1415                    dist = lineutility.CalcDistanceDouble(pt0, pt1);
1416                    if (dist < 5) {
1417                        continue;
1418                    }
1419                    //diagnostic
1420                    if (lineType == TacticalLines.BOUNDARY) {
1421                        if (lastPt == null) {
1422                            lastPt = tg.Pixels.get(j - 1);
1423                        }
1424
1425                        if ( DoublesBack(lastPt, pt0, pt1)) {
1426                            continue;
1427                        }
1428
1429                        lastPt = null;
1430                    }
1431                    //if either of the points is within the bound then most of the segment is visible
1432                    if (!useClipRect) {
1433                        if (clipBoundsPoly.contains(pt0.x, pt0.y) || clipBoundsPoly.contains(pt1.x, pt1.y)) {
1434                            middleSegment = j - 1;
1435                            foundVisibleSegment = true;
1436                            break;
1437                        }
1438                    } else {
1439                        if (clipRect.contains(pt0.x, pt0.y) || clipRect.contains(pt1.x, pt1.y)) {
1440                            middleSegment = j - 1;
1441                            foundVisibleSegment = true;
1442                            break;
1443                        }
1444                    }
1445                }
1446            }
1447
1448            if (!foundVisibleSegment) {
1449                middleSegment = tg.Pixels.size() / 2 - 1;
1450            }
1451        } catch (Exception exc) {
1452            ErrorLogger.LogException(_className, "getMiddleSegment",
1453                    new RendererException("Failed inside getMiddleSegment", exc));
1454        }
1455        return middleSegment;
1456    }
1457
1458    /**
1459     * called repeatedly by RemoveModifiers to remove modifiers which fall
1460     * outside the symbol MBR
1461     *
1462     * @param tg
1463     * @param modifierType
1464     */
1465    private static void removeModifier(TGLight tg,
1466            String modifierType) {
1467        try {
1468            int j = 0;
1469            Modifier2 modifier = null;
1470            int n = tg.Pixels.size();
1471            //for (j = 0; j < tg.modifiers.size(); j++) 
1472            for (j = 0; j < n; j++) {
1473                modifier = tg.modifiers.get(j);
1474
1475                if (modifier.textID == null) {
1476                    continue;
1477                }
1478
1479                if (modifier.textID.equalsIgnoreCase(modifierType)) {
1480                    tg.modifiers.remove(modifier);
1481                    break;
1482                }
1483            }
1484        } catch (Exception exc) {
1485            ErrorLogger.LogException(_className, "removeModifier",
1486                    new RendererException("Failed inside removeModifier", exc));
1487        }
1488    }
1489
1490    /**
1491     * removes text modifiers for CPOF tactical areas which do not fit inside
1492     * the symbol MBR
1493     *
1494     * @param tg
1495     * @param g2d
1496     * @param isTextFlipped true if text is flipped from the last segment
1497     * orientation
1498     * @param iteration the instance count for this modifier
1499     */
1500    public static void RemoveModifiers(TGLight tg,
1501            Graphics2D g2d,
1502            boolean isTextFlipped,
1503            int iteration) {
1504        try {
1505            //CPOF clients only
1506            if (!tg.get_Client().equalsIgnoreCase("cpof2d") && !tg.get_Client().equalsIgnoreCase("cpof3d")) {
1507                return;
1508            }
1509
1510            int j = 0;
1511            Polygon mbrPoly = null;
1512            //if it's a change 1 rectangular area then use the pixels instead of the mbr
1513            //because those use aboveMiddle to build angular text
1514            switch (tg.get_LineType()) {
1515                case TacticalLines.RECTANGULAR:
1516                case TacticalLines.CUED_ACQUISITION:
1517                case TacticalLines.ACA_RECTANGULAR: //aboveMiddle modifiers: slanted text
1518                case TacticalLines.FFA_RECTANGULAR:
1519                case TacticalLines.NFA_RECTANGULAR:
1520                case TacticalLines.RFA_RECTANGULAR:
1521                case TacticalLines.KILLBOXBLUE_RECTANGULAR:
1522                case TacticalLines.KILLBOXPURPLE_RECTANGULAR:
1523                case TacticalLines.FSA_RECTANGULAR:
1524                case TacticalLines.SHIP_AOI_RECTANGULAR:
1525                case TacticalLines.DEFENDED_AREA_RECTANGULAR:
1526                case TacticalLines.ATI_RECTANGULAR:
1527                case TacticalLines.CFFZ_RECTANGULAR:
1528                case TacticalLines.SENSOR_RECTANGULAR:
1529                case TacticalLines.CENSOR_RECTANGULAR:
1530                case TacticalLines.DA_RECTANGULAR:
1531                case TacticalLines.CFZ_RECTANGULAR:
1532                case TacticalLines.ZOR_RECTANGULAR:
1533                case TacticalLines.TBA_RECTANGULAR:
1534                case TacticalLines.TVAR_RECTANGULAR:
1535                case TacticalLines.ACA_CIRCULAR:
1536                case TacticalLines.CIRCULAR:
1537                case TacticalLines.BDZ:
1538                case TacticalLines.FSA_CIRCULAR:
1539                case TacticalLines.NOTACK:
1540                case TacticalLines.ATI_CIRCULAR:
1541                case TacticalLines.CFFZ_CIRCULAR:
1542                case TacticalLines.SENSOR_CIRCULAR:
1543                case TacticalLines.CENSOR_CIRCULAR:
1544                case TacticalLines.DA_CIRCULAR:
1545                case TacticalLines.CFZ_CIRCULAR:
1546                case TacticalLines.ZOR_CIRCULAR:
1547                case TacticalLines.TBA_CIRCULAR:
1548                case TacticalLines.TVAR_CIRCULAR:
1549                case TacticalLines.FFA_CIRCULAR:
1550                case TacticalLines.NFA_CIRCULAR:
1551                case TacticalLines.RFA_CIRCULAR:
1552                case TacticalLines.KILLBOXBLUE_CIRCULAR:
1553                case TacticalLines.KILLBOXPURPLE_CIRCULAR:
1554                    if (tg.modifiers == null || tg.modifiers.isEmpty() || iteration != 1) {
1555                        return;
1556                    }
1557
1558                    mbrPoly = new Polygon();
1559                    int n = tg.Pixels.size();
1560                    //for (j = 0; j < tg.Pixels.size(); j++) 
1561                    for (j = 0; j < n; j++) {
1562                        mbrPoly.addPoint((int) tg.Pixels.get(j).x, (int) tg.Pixels.get(j).y);
1563                    }
1564
1565                    break;
1566                default:    //area modifiers: horizontal text
1567                    if (clsUtility.isClosedPolygon(tg.get_LineType()) == false || iteration != 0) {
1568                        return;
1569                    }
1570                    if (tg.modifiers == null || tg.modifiers.isEmpty()) {
1571                        return;
1572                    }
1573
1574                    mbrPoly = new Polygon();
1575                    int t = tg.Pixels.size();
1576                    //for (j = 0; j < tg.Pixels.size(); j++) 
1577                    for (j = 0; j < t; j++) {
1578                        mbrPoly.addPoint((int) tg.Pixels.get(j).x, (int) tg.Pixels.get(j).y);
1579                    }
1580            }
1581
1582            Font font = null;
1583            font = tg.get_Font();    //might have to change this
1584            if (font == null) {
1585                font = g2d.getFont();
1586            }
1587            g2d.setFont(font);
1588            FontMetrics metrics = g2d.getFontMetrics();
1589
1590            double stringWidth = 0, stringHeight = 0;
1591            boolean wfits = true, w1fits = true, ww1fits = true, hfits = true, h1fits = true, h2fits = true;
1592            Modifier2 modifier = null;
1593            String modifierType = "";
1594            String s = "";
1595            POINT2 pt0 = null, pt1 = null, pt2 = null, pt3 = null, pt4 = null;
1596            double lineFactor = 0;
1597            double x = 0, y = 0;
1598            double x1 = 0, y1 = 0, x2 = 0, y2 = 0;            //logic as follows:
1599            //we have to loop through to determine if each modifiers fits and set its fitsMBR member
1600            //then run a 2nd loop to remove groups of modifiers based on whether any of the others do not fit
1601            //e.g. if W does not fit then remove W and W1 modifiers
1602            int n = tg.modifiers.size();
1603            //for (j = 0; j < tg.modifiers.size(); j++) 
1604            for (j = 0; j < n; j++) {
1605                modifier = tg.modifiers.get(j);
1606                if (modifier.textID == null || modifier.textID.isEmpty()) {
1607                    continue;
1608                }
1609
1610                modifierType = modifier.textID;
1611                lineFactor = modifier.lineFactor;
1612
1613                if (isTextFlipped) {
1614                    lineFactor = -lineFactor;
1615                }
1616
1617                s = modifier.text;
1618                if (s == null || s.equals("")) {
1619                    continue;
1620                }
1621                stringWidth = (double) metrics.stringWidth(s) + 1;
1622                stringHeight = (double) font.getSize();
1623
1624                if (modifier.type == area) {
1625                    pt0 = modifier.textPath[0];
1626                    x1 = pt0.x;
1627                    y1 = pt0.y;
1628                    x = (int) x1 - (int) stringWidth / 2;
1629                    y = (int) y1 + (int) (stringHeight / 2) + (int) (1.25 * lineFactor * stringHeight);
1630                    //pt1 = modifier.textPath[1];
1631                    x2 = (int) x1 + (int) stringWidth / 2;
1632                    y2 = (int) y1 + (int) (stringHeight / 2) + (int) (1.25 * lineFactor * stringHeight);
1633                    if (mbrPoly.contains(x, y) && mbrPoly.contains(x2, y2)) {
1634                        modifier.fitsMBR = true;
1635                    } else {
1636                        modifier.fitsMBR = false;
1637                    }
1638                } else if (modifier.type == aboveMiddle) {
1639                    pt0 = modifier.textPath[0];
1640                    pt1 = modifier.textPath[1];
1641                    //double dist=lineutility.CalcDistanceDouble(pt0, pt1);
1642                    POINT2 ptCenter = lineutility.MidPointDouble(pt0, pt1, 0);
1643                    pt0 = lineutility.ExtendAlongLineDouble(ptCenter, pt0, stringWidth / 2);
1644                    pt1 = lineutility.ExtendAlongLineDouble(ptCenter, pt1, stringWidth / 2);
1645
1646                    if (lineFactor >= 0) {
1647                        pt2 = lineutility.ExtendDirectedLine(ptCenter, pt0, pt0, 3, Math.abs((lineFactor) * stringHeight));
1648                    } else {
1649                        pt2 = lineutility.ExtendDirectedLine(ptCenter, pt0, pt0, 2, Math.abs((lineFactor) * stringHeight));
1650                    }
1651
1652                    if (lineFactor >= 0) {
1653                        pt3 = lineutility.ExtendDirectedLine(ptCenter, pt1, pt1, 3, Math.abs((lineFactor) * stringHeight));
1654                    } else {
1655                        pt3 = lineutility.ExtendDirectedLine(ptCenter, pt1, pt1, 2, Math.abs((lineFactor) * stringHeight));
1656                    }
1657
1658                    x1 = pt2.x;
1659                    y1 = pt2.y;
1660                    x2 = pt3.x;
1661                    y2 = pt3.y;
1662                    if (mbrPoly.contains(x1, y1) && mbrPoly.contains(x2, y2)) {
1663                        modifier.fitsMBR = true;
1664                    } else {
1665                        modifier.fitsMBR = false;
1666                    }
1667                } else {
1668                    modifier.fitsMBR = true;
1669                }
1670            }
1671            n = tg.modifiers.size();
1672            //for (j = 0; j < tg.modifiers.size(); j++) 
1673            for (j = 0; j < n; j++) {
1674                modifier = tg.modifiers.get(j);
1675                if (modifier.textID == null || modifier.textID.isEmpty()) {
1676                    continue;
1677                }
1678
1679                if (modifier.fitsMBR == false) {
1680                    if (modifier.textID.equalsIgnoreCase("W")) {
1681                        wfits = false;
1682                    } else if (modifier.textID.equalsIgnoreCase("W1")) {
1683                        w1fits = false;
1684                    } else if (modifier.textID.equalsIgnoreCase("W+W1")) {
1685                        ww1fits = false;
1686                    } else if (modifier.textID.equalsIgnoreCase("H")) {
1687                        hfits = false;
1688                    } else if (modifier.textID.equalsIgnoreCase("H1")) {
1689                        h1fits = false;
1690                    } else if (modifier.textID.equalsIgnoreCase("H2")) {
1691                        h2fits = false;
1692                    }
1693                }
1694            }
1695            if (wfits == false || w1fits == false) {
1696                removeModifier(tg, "W");
1697                removeModifier(tg, "W1");
1698            }
1699            if (ww1fits == false) {
1700                removeModifier(tg, "W+W1");
1701            }
1702            if (hfits == false || h1fits == false || h2fits == false) {
1703                removeModifier(tg, "H");
1704                removeModifier(tg, "H1");
1705                removeModifier(tg, "H2");
1706            }
1707
1708        } catch (Exception exc) {
1709            ErrorLogger.LogException(_className, "RemoveModifeirs",
1710                    new RendererException("Failed inside RemoveModifiers", exc));
1711        }
1712    }
1713
1714    /**
1715     * Calculates a segment in the pixels middle by length to hold a string.
1716     *
1717     * @param tg
1718     * @param stringWidth
1719     * @param segPt0
1720     * @param segPt1
1721     */
1722    private static void getPixelsMiddleSegment(TGLight tg,
1723            double stringWidth,
1724            POINT2 segPt0,
1725            POINT2 segPt1) {
1726        try {
1727            switch (tg.get_LineType()) {
1728                case TacticalLines.CFL:
1729                    break;
1730                default:
1731                    return;
1732            }
1733            int totalLength = 0;
1734            int j = 0;
1735            double dist = 0;
1736            double mid = 0;
1737            double remainder = 0;
1738            POINT2 pt0 = null, pt1 = null, pt2 = null, pt3 = null;
1739            POINT2 midPt = null;
1740            //first get the total length of all the segments
1741            int n = tg.Pixels.size();
1742            //for (j = 0; j < tg.Pixels.size() - 1; j++) 
1743            for (j = 0; j < n - 1; j++) {
1744                dist = lineutility.CalcDistanceDouble(tg.Pixels.get(j), tg.Pixels.get(j + 1));
1745                totalLength += dist;
1746            }
1747            mid = totalLength / 2;
1748            totalLength = 0;
1749            //walk thru the segments to find the middle
1750            //for (j = 0; j < tg.Pixels.size() - 1; j++) 
1751            for (j = 0; j < n - 1; j++) {
1752                dist = lineutility.CalcDistanceDouble(tg.Pixels.get(j), tg.Pixels.get(j + 1));
1753                totalLength += dist;
1754                if (totalLength >= mid)//current segment contains the middle
1755                {
1756                    remainder = totalLength - mid;
1757                    pt0 = tg.Pixels.get(j);
1758                    pt1 = tg.Pixels.get(j + 1);
1759                    //calculate the pixels mid point
1760                    midPt = lineutility.ExtendAlongLineDouble2(pt1, pt0, remainder);
1761                    pt2 = lineutility.ExtendAlongLineDouble2(midPt, pt0, stringWidth / 2);
1762                    pt3 = lineutility.ExtendAlongLineDouble2(midPt, pt1, stringWidth / 2);
1763                    segPt0.x = pt2.x;
1764                    segPt0.y = pt2.y;
1765                    segPt1.x = pt3.x;
1766                    segPt1.y = pt3.y;
1767                    break;
1768                }
1769            }
1770        } catch (Exception exc) {
1771            ErrorLogger.LogException(_className, "getPixelsMidpoint",
1772                    new RendererException("Failed inside getPixelsMidpoint", exc));
1773        }
1774    }
1775
1776    private static double getChange1Height(TGLight tg) {
1777        double height = 0;
1778        try {
1779            switch (tg.get_LineType()) {
1780                //case TacticalLines.PAA_RECTANGULAR:
1781                case TacticalLines.FSA_RECTANGULAR:
1782                case TacticalLines.SHIP_AOI_RECTANGULAR:
1783                case TacticalLines.DEFENDED_AREA_RECTANGULAR:
1784                case TacticalLines.FFA_RECTANGULAR:
1785                case TacticalLines.ACA_RECTANGULAR:
1786                case TacticalLines.NFA_RECTANGULAR:
1787                case TacticalLines.RFA_RECTANGULAR:
1788                case TacticalLines.ATI_RECTANGULAR:
1789                case TacticalLines.CFFZ_RECTANGULAR:
1790                case TacticalLines.SENSOR_RECTANGULAR:
1791                case TacticalLines.CENSOR_RECTANGULAR:
1792                case TacticalLines.DA_RECTANGULAR:
1793                case TacticalLines.CFZ_RECTANGULAR:
1794                case TacticalLines.ZOR_RECTANGULAR:
1795                case TacticalLines.TBA_RECTANGULAR:
1796                case TacticalLines.TVAR_RECTANGULAR:
1797                case TacticalLines.KILLBOXBLUE_RECTANGULAR:
1798                case TacticalLines.KILLBOXPURPLE_RECTANGULAR:
1799                    break;
1800                default:
1801                    return 0;
1802            }
1803            double x1 = tg.Pixels.get(0).x;
1804            double y1 = tg.Pixels.get(0).y;
1805            double x2 = tg.Pixels.get(1).x;
1806            double y2 = tg.Pixels.get(1).y;
1807            double deltax = x2 - x1;
1808            double deltay = y2 - y1;
1809            height = Math.sqrt(deltax * deltax + deltay * deltay);
1810        } catch (Exception exc) {
1811            ErrorLogger.LogException(_className, "getChange1Height",
1812                    new RendererException("Failed inside getChange1Height", exc));
1813        }
1814        return height;
1815    }
1816
1817    /**
1818     * scale the line factor for closed areas
1819     *
1820     * @param tg
1821     */
1822    private static void scaleModifiers(TGLight tg) {
1823        try {
1824            if (RendererSettings.getInstance().getAutoCollapseModifiers() == false) {
1825                return;
1826            }
1827            if (!tg.get_Client().equalsIgnoreCase("ge")) {
1828                return;
1829            }
1830            //exit if there are no modifiers or it's not a closed area
1831            if (tg.modifiers == null || tg.modifiers.isEmpty()) {
1832                return;
1833            }
1834            int linetype = tg.get_LineType();
1835            boolean isClosedPolygon = clsUtility.isClosedPolygon(linetype);
1836            boolean isChange1Area = clsUtility.IsChange1Area(linetype);
1837            if (!isClosedPolygon && !isChange1Area) {
1838                return;
1839            }
1840            switch(linetype)
1841            {
1842                case TacticalLines.PAA_CIRCULAR:
1843                case TacticalLines.PAA_RECTANGULAR:
1844                case TacticalLines.RECTANGULAR_TARGET:
1845                case TacticalLines.RANGE_FAN:
1846                case TacticalLines.RANGE_FAN_SECTOR:
1847                case TacticalLines.RADAR_SEARCH:
1848                    return;
1849                default:
1850                    break;
1851            }
1852            POINT2 ptUl = new POINT2(), ptUr = new POINT2(), ptLr = new POINT2(), ptLl = new POINT2();
1853            GetMBR(tg, ptUl, ptUr, ptLr, ptLl);
1854            int sz = tg.get_Font().getSize();
1855            //heightMBR is half the MBR height
1856            //double heightMBR=Math.abs(ptLr.y-ptUr.y)/2;
1857            double heightMBR = 0;
1858            double change1Height = getChange1Height(tg);
1859            if (change1Height <= 0) {
1860                heightMBR = Math.abs(ptLr.y - ptUr.y) / 2;
1861            } else {
1862                heightMBR = change1Height;
1863            }
1864
1865            double heightModifiers = 0;
1866            ArrayList<Modifier2> modifiers = tg.modifiers;
1867            Modifier2 modifier = null;
1868            double minLF = Integer.MAX_VALUE;
1869            int j = 0;
1870            boolean isValid = false;
1871            for (j = 0; j < modifiers.size(); j++) {
1872                modifier = modifiers.get(j);
1873                //if(modifier.type == area)
1874                //type3Area=true;
1875                if (modifier.type == toEnd) {
1876                    continue;
1877                }
1878                if (modifier.type == aboveMiddle && isChange1Area == false) {
1879                    continue;
1880                }
1881                if (modifier.lineFactor < minLF) {
1882                    minLF = modifier.lineFactor;
1883                }
1884                isValid = true;
1885            }
1886            //if there are no 'area' modifiers then exit early
1887            if (!isValid) {
1888                return;
1889            }
1890
1891            heightModifiers = Math.abs(minLF) * sz;
1892            boolean expandModifiers = false, shrinkModifiers = false;
1893            if (heightModifiers > heightMBR) {
1894                shrinkModifiers = true;
1895            } else if (heightModifiers < 0.5 * heightMBR) {
1896                expandModifiers = true;
1897            }
1898
1899            boolean addEllipsis = false;
1900            //modifierE is ellipses modifier
1901            Modifier2 modifierE = new Modifier2();
1902            if (expandModifiers) {
1903                double factor = heightMBR / heightModifiers;
1904                factor = 1 + (factor - 1) / 4;
1905                if (factor > 2) {
1906                    factor = 2;
1907                }
1908                for (j = 0; j < modifiers.size(); j++) {
1909                    modifier = modifiers.get(j);
1910                    if(modifier.type==aboveMiddle)
1911                    {
1912                        if(isChange1Area==false)
1913                            continue;
1914                    }
1915                    else if(modifier.type!=area)
1916                            continue;
1917                    
1918                    modifier.lineFactor *= factor;
1919                }
1920            } else if (shrinkModifiers) {
1921                double deltaLF = (heightModifiers - heightMBR) / sz;
1922                double newLF = 0;
1923                //use maxLF for the ellipsis modifier
1924                double maxLF = 0;
1925                for (j = 0; j < modifiers.size(); j++) {
1926                    modifier = modifiers.get(j);
1927                    if(modifier.type==aboveMiddle)
1928                    {
1929                        if(isChange1Area==false)
1930                            continue;
1931                    }
1932                    else if(modifier.type!=area)
1933                            continue;
1934                    newLF = modifier.lineFactor + deltaLF;
1935                    if (Math.abs(newLF * sz) >= heightMBR) {
1936                        //flag the modifier to remove
1937                        if (modifier.lineFactor > minLF) {
1938                            modifierE.type = modifier.type;
1939                            modifier.type = 7;
1940                            if (!modifier.text.isEmpty()) {
1941                                addEllipsis = true;
1942                            }
1943                        }
1944                        modifier.lineFactor = newLF;
1945                        //modifierE.type=area;
1946                        //modifierE.type=modifier.type;
1947                        modifierE.textPath = modifier.textPath;
1948                        continue;
1949                    }
1950                    modifier.lineFactor = newLF;
1951                }
1952                ArrayList<Modifier2> modifiers2 = new ArrayList();
1953                for (j = 0; j < modifiers.size(); j++) {
1954                    modifier = modifiers.get(j);
1955                    if (modifier.type != 7) {
1956                        if (modifier.lineFactor > maxLF) {
1957                            maxLF = modifier.lineFactor;
1958                        }
1959                        modifiers2.add(modifier);
1960                    }
1961                }
1962                if (addEllipsis) {
1963                    Character letter = (char) 9679;
1964                    String s = Character.toString(letter);
1965                    String echelonSymbol = s + s + s;
1966                    modifierE.text = echelonSymbol;
1967                    modifierE.lineFactor = maxLF + 1;
1968                    modifiers2.add(modifierE);
1969                }
1970                tg.modifiers = modifiers2;
1971            }   //end shrink modifiers
1972        } catch (Exception exc) {
1973            ErrorLogger.LogException(_className, "scaleModifiers",
1974                    new RendererException("Failed inside scaleModifiers", exc));
1975        }
1976    }
1977
1978    /**
1979     * Calculate modifiers identical to addModifiers except use geodesic
1980     * calculations for the center point.
1981     *
1982     * @param tg
1983     * @param g2d
1984     * @param clipBounds
1985     * @param converter
1986     */
1987    public static void AddModifiersGeo(TGLight tg,
1988            Graphics2D g2d,
1989            Object clipBounds,
1990            IPointConversion converter) {
1991        try {
1992            //exit early for those not affected
1993            if (tg.Pixels == null || tg.Pixels.isEmpty()) {
1994                return;
1995            }
1996            ArrayList<POINT2> origPoints = null;
1997            Font font = tg.get_Font();
1998            if (font == null) {
1999                font = g2d.getFont();
2000            }
2001            g2d.setFont(font);
2002
2003            boolean shiftLines = Channels.getShiftLines();
2004            boolean usas = false, foundSegment = false;
2005            double csFactor = 1d, dist = 0, dist2 = 0;//this will be used for text spacing the 3d map (CommandCight)
2006            POINT2 midPt = null;
2007            int northestPtIndex = 0;
2008            int southestPtIndex = 0;
2009            POINT2 northestPt = null;
2010            POINT2 southestPt = null;
2011
2012            Rectangle2D clipRect = null;
2013            ArrayList<Point2D> clipArray = null;
2014            if (clipBounds != null && ArrayList.class.isAssignableFrom(clipBounds.getClass())) {
2015                clipArray = (ArrayList<Point2D>) clipBounds;
2016            }
2017            if (clipBounds != null && Rectangle2D.Double.class.isAssignableFrom(clipBounds.getClass())) {
2018                clipRect = (Rectangle2D.Double) clipBounds;
2019            }
2020
2021            FontMetrics metrics = g2d.getFontMetrics();
2022            int stringWidth = 0, stringWidth2 = 0;
2023            String WDash = ""; // Dash between W and W1 if they're not empty
2024            String TSpace = "", TDash = ""; // Space or dash between label and T modifier if T isn't empty
2025            if (tg.get_DTG() != null && tg.get_DTG1() != null && !tg.get_DTG().isEmpty() && !tg.get_DTG1().isEmpty()) {
2026                WDash = " - ";
2027            }
2028            if (tg.get_Name() != null && !tg.get_Name().isEmpty()) {
2029                TSpace = " ";
2030                TDash = " - ";
2031            }
2032
2033            if (tg.get_Client().equals("cpof3d")) {
2034                csFactor = 0.9d;
2035            }
2036                        
2037            switch (tg.get_LineType()) {
2038                case TacticalLines.SERIES:
2039                case TacticalLines.STRIKWARN:
2040                case TacticalLines.MSR:
2041                case TacticalLines.MSR_ONEWAY:
2042                case TacticalLines.MSR_TWOWAY:
2043                case TacticalLines.MSR_ALT:
2044                case TacticalLines.ASR:
2045                case TacticalLines.ASR_ONEWAY:
2046                case TacticalLines.ASR_TWOWAY:
2047                case TacticalLines.ASR_ALT:
2048                case TacticalLines.TRAFFIC_ROUTE:
2049                case TacticalLines.TRAFFIC_ROUTE_ONEWAY:
2050                case TacticalLines.TRAFFIC_ROUTE_ALT:
2051                case TacticalLines.DHA_REVD:
2052                case TacticalLines.DHA:
2053                case TacticalLines.KILL_ZONE:
2054                case TacticalLines.EPW:
2055                case TacticalLines.UXO:
2056                case TacticalLines.FARP:
2057                case TacticalLines.BSA:
2058                case TacticalLines.DSA:
2059                case TacticalLines.CSA:
2060                case TacticalLines.RSA:
2061                case TacticalLines.THUNDERSTORMS:
2062                case TacticalLines.ICING:
2063                case TacticalLines.FREEFORM:
2064                case TacticalLines.RHA:
2065                case TacticalLines.LINTGT:
2066                case TacticalLines.LINTGTS:
2067                case TacticalLines.FPF:
2068                case TacticalLines.GAP:
2069                case TacticalLines.DEPICT:
2070                case TacticalLines.AIRHEAD:
2071                case TacticalLines.FSA:
2072                case TacticalLines.DIRATKAIR:
2073                case TacticalLines.OBJ:
2074                case TacticalLines.AO:
2075                case TacticalLines.ACA:
2076                case TacticalLines.FFA:
2077                case TacticalLines.PAA:
2078                case TacticalLines.NFA:
2079                case TacticalLines.RFA:
2080                case TacticalLines.ATI:
2081                case TacticalLines.CFFZ:
2082                case TacticalLines.CFZ:
2083                case TacticalLines.TBA:
2084                case TacticalLines.TVAR:
2085                case TacticalLines.KILLBOXBLUE:
2086                case TacticalLines.KILLBOXPURPLE:
2087                case TacticalLines.ZOR:
2088                case TacticalLines.DA:
2089                case TacticalLines.SENSOR:
2090                case TacticalLines.CENSOR:
2091                case TacticalLines.SMOKE:
2092                case TacticalLines.BATTLE:
2093                case TacticalLines.PNO:
2094                case TacticalLines.PDF:
2095                case TacticalLines.NAI:
2096                case TacticalLines.TAI:
2097                case TacticalLines.BASE_CAMP_REVD:
2098                case TacticalLines.BASE_CAMP:
2099                case TacticalLines.GUERILLA_BASE_REVD:
2100                case TacticalLines.GUERILLA_BASE:
2101                case TacticalLines.GENERIC_AREA:
2102                case TacticalLines.ATKPOS:
2103                case TacticalLines.ASSAULT:
2104                case TacticalLines.WFZ_REVD:
2105                case TacticalLines.WFZ:
2106                case TacticalLines.OBSFAREA:
2107                case TacticalLines.OBSAREA:
2108                case TacticalLines.ROZ:
2109                case TacticalLines.AARROZ:
2110                case TacticalLines.UAROZ:
2111                case TacticalLines.WEZ:
2112                case TacticalLines.FEZ:
2113                case TacticalLines.JEZ:
2114                case TacticalLines.FAADZ:
2115                case TacticalLines.HIDACZ:
2116                case TacticalLines.MEZ:
2117                case TacticalLines.LOMEZ:
2118                case TacticalLines.HIMEZ:
2119                case TacticalLines.SAAFR:
2120                case TacticalLines.AC:
2121                case TacticalLines.MRR:
2122                case TacticalLines.SL:
2123                case TacticalLines.TC:
2124                case TacticalLines.SC:
2125                case TacticalLines.LLTR:
2126                case TacticalLines.AIRFIELD:
2127                case TacticalLines.GENERAL:
2128                case TacticalLines.JTAA:
2129                case TacticalLines.SAA:
2130                case TacticalLines.SGAA:
2131                case TacticalLines.FORT_REVD:
2132                case TacticalLines.FORT:
2133                case TacticalLines.ENCIRCLE:
2134                case TacticalLines.ASSY:
2135                case TacticalLines.EA:
2136                case TacticalLines.DZ:
2137                case TacticalLines.EZ:
2138                case TacticalLines.LZ:
2139                case TacticalLines.PZ:
2140                case TacticalLines.LAA:
2141                case TacticalLines.BOUNDARY:
2142                case TacticalLines.MINED:
2143                case TacticalLines.FENCED:
2144                case TacticalLines.PL:
2145                case TacticalLines.DECISION_LINE:
2146                case TacticalLines.FEBA:
2147                case TacticalLines.FCL:
2148                case TacticalLines.HOLD:
2149                case TacticalLines.BRDGHD:
2150                case TacticalLines.HOLD_GE:
2151                case TacticalLines.BRDGHD_GE:
2152                case TacticalLines.LOA:
2153                case TacticalLines.LOD:
2154                case TacticalLines.LL:
2155                case TacticalLines.EWL:
2156                case TacticalLines.RELEASE:
2157                case TacticalLines.HOL:
2158                case TacticalLines.BHL:
2159                case TacticalLines.LDLC:
2160                case TacticalLines.PLD:
2161                case TacticalLines.NFL:
2162                case TacticalLines.MFP:
2163                case TacticalLines.FSCL:
2164                case TacticalLines.BCL_REVD:
2165                case TacticalLines.BCL:
2166                case TacticalLines.ICL:
2167                case TacticalLines.IFF_OFF:
2168                case TacticalLines.IFF_ON:
2169                case TacticalLines.GENERIC_LINE:
2170                case TacticalLines.CFL:
2171                case TacticalLines.TRIP:
2172                case TacticalLines.RFL:
2173                case TacticalLines.FLOT:
2174                case TacticalLines.LC:
2175                case TacticalLines.CATK:
2176                case TacticalLines.CATKBYFIRE:
2177                case TacticalLines.IL:
2178                case TacticalLines.DRCL:
2179                case TacticalLines.RETIRE:
2180                case TacticalLines.PURSUIT:
2181                case TacticalLines.FPOL:
2182                case TacticalLines.RPOL:
2183                case TacticalLines.WITHDRAW:
2184                case TacticalLines.DISENGAGE:
2185                case TacticalLines.WDRAWUP:
2186                case TacticalLines.BEARING:
2187                case TacticalLines.BEARING_J:
2188                case TacticalLines.BEARING_RDF:
2189                case TacticalLines.ELECTRO:
2190                case TacticalLines.BEARING_EW:
2191                case TacticalLines.ACOUSTIC:
2192                case TacticalLines.ACOUSTIC_AMB:
2193                case TacticalLines.TORPEDO:
2194                case TacticalLines.OPTICAL:
2195                case TacticalLines.RIP:
2196                case TacticalLines.DEMONSTRATE:
2197                case TacticalLines.BOMB:
2198                case TacticalLines.ZONE:
2199                case TacticalLines.AT:
2200                case TacticalLines.STRONG:
2201                case TacticalLines.MSDZ:
2202                case TacticalLines.SCREEN:
2203                case TacticalLines.COVER:
2204                case TacticalLines.GUARD:
2205                case TacticalLines.DELAY:
2206                case TacticalLines.TGMF:
2207                case TacticalLines.BIO:
2208                case TacticalLines.BIOT://APP6/E
2209                case TacticalLines.CHEM:
2210                case TacticalLines.CHEMT://APP6/E
2211                case TacticalLines.NUC:
2212                case TacticalLines.RAD:
2213                case TacticalLines.RADT://APP6/E
2214                case TacticalLines.MINE_LINE:
2215                case TacticalLines.ANCHORAGE_LINE:
2216                case TacticalLines.ANCHORAGE_AREA:
2217                case TacticalLines.SPT:
2218                case TacticalLines.FRONTAL_ATTACK:
2219                case TacticalLines.TURNING_MOVEMENT:
2220                case TacticalLines.MOVEMENT_TO_CONTACT:
2221                case TacticalLines.AIRAOA:
2222                case TacticalLines.AAAAA:
2223                case TacticalLines.MAIN:
2224                case TacticalLines.DIRATKSPT:
2225                case TacticalLines.DIRATKGND:
2226                case TacticalLines.LAUNCH_AREA:
2227                case TacticalLines.DEFENDED_AREA_CIRCULAR:
2228                case TacticalLines.RECTANGULAR:
2229                case TacticalLines.CIRCULAR:
2230                case TacticalLines.RECTANGULAR_TARGET:
2231                case TacticalLines.LINE:
2232                case TacticalLines.ASLTXING:
2233                case TacticalLines.BS_LINE:
2234                case TacticalLines.BS_AREA:
2235                case TacticalLines.BBS_LINE:
2236                case TacticalLines.BBS_AREA:
2237                case TacticalLines.PBS_CIRCLE:
2238                case TacticalLines.PBS_ELLIPSE:
2239                case TacticalLines.PBS_RECTANGLE:
2240                case TacticalLines.BBS_POINT:
2241                    origPoints = lineutility.getDeepCopy(tg.Pixels);
2242                    break;
2243                default:    //exit early for those not applicable
2244                    return;
2245            }
2246
2247            int linetype = tg.get_LineType();
2248            int j = 0, k = 0;
2249            double x = 0, y = 0;
2250
2251            int lastIndex = tg.Pixels.size() - 1;
2252            int nextToLastIndex = tg.Pixels.size() - 2;
2253            POINT2 pt0 = new POINT2(tg.Pixels.get(0));
2254            POINT2 pt1 = null;
2255            POINT2 pt2 = null, pt3 = null;
2256            POINT2 ptLast = new POINT2(tg.Pixels.get(lastIndex));
2257            POINT2 ptNextToLast = null;
2258            double DPIScaleFactor = RendererSettings.getInstance().getDeviceDPI() / 96.0;
2259
2260            if (lastIndex > 0) {
2261                ptNextToLast = new POINT2(tg.Pixels.get(nextToLastIndex));
2262            }
2263
2264            if (tg.Pixels.size() > 1) {
2265                pt1 = new POINT2(tg.Pixels.get(1));
2266            }
2267
2268            //prevent vertical paths for modifiers that use toEnd
2269            shiftModifierPath(tg, pt0, pt1, ptLast, ptNextToLast);
2270
2271            String label = GetCenterLabel(tg);
2272            String v=tg.get_V();
2273            String ap=tg.get_AP();
2274            Object[] pts = tg.Pixels.toArray();
2275            //need this for areas and some lines
2276            POINT2 ptCenter = null;
2277            if (converter != null) //cpof uses latlonconverter so cpof passes null for this
2278            {
2279                ptCenter = mdlGeodesic.geodesic_center(tg.LatLongs);
2280                if (ptCenter != null) {
2281                    Point2D pt22 = converter.GeoToPixels(new Point2D.Double(ptCenter.x, ptCenter.y));
2282                    ptCenter.x = pt22.getX();
2283                    ptCenter.y = pt22.getY();
2284                } else {
2285                    ptCenter = lineutility.CalcCenterPointDouble2(pts, pts.length);
2286                }
2287            } else {
2288                ptCenter = lineutility.CalcCenterPointDouble2(pts, pts.length);
2289            }
2290
2291            int middleSegment = (tg.Pixels.size() + 1) / 2 - 1;
2292            int middleSegment2 = 0;
2293
2294            if (clipRect != null) {
2295                middleSegment = getVisibleMiddleSegment(tg, clipRect);
2296            } else if (clipArray != null) {
2297                middleSegment = getVisibleMiddleSegment(tg, clipArray);
2298            }
2299            if (tg.Pixels.size() > 2) {
2300                pt2 = tg.Pixels.get(2);
2301            }
2302            if (tg.Pixels.size() > 3) {
2303                pt3 = tg.Pixels.get(3);
2304            }
2305            double TLineFactor = 0, T1LineFactor = 0;
2306            POINT2 lr = new POINT2(tg.Pixels.get(0));
2307            POINT2 ll = new POINT2(tg.Pixels.get(0));
2308            POINT2 ul = new POINT2(tg.Pixels.get(0));
2309            POINT2 ur = new POINT2(tg.Pixels.get(0));
2310            int index = 0;
2311            int nextIndex = 0;
2312            int size = tg.Pixels.size();
2313            Line2D line = null;
2314                        
2315                        double dAngle0, dAngle1;
2316            int stringHeight;
2317
2318            switch (linetype) {
2319                case TacticalLines.PL:
2320                    AddIntegralAreaModifier(tg, label + TSpace + tg.get_Name(), toEnd, T1LineFactor, pt0, pt1, false);
2321                    AddIntegralAreaModifier(tg, label + TSpace + tg.get_Name(), toEnd, T1LineFactor, ptLast, ptNextToLast, false);
2322                    break;
2323                case TacticalLines.DECISION_LINE:
2324                    if(tg.get_AS() == null || !tg.get_AS().isEmpty())
2325                        tg.set_AS(GENCLookup.getInstance().get3CharCode(SymbolID.getCountryCode(tg.get_SymbolId())));
2326                    Bitmap bi =  getImageModifier(tg);
2327
2328                    POINT2 ptDP1 = lineutility.ExtendLine2Double(pt1,pt0,bi.getWidth()/2,0);
2329                    POINT2 ptDP2 = lineutility.ExtendLine2Double(ptNextToLast, ptLast,bi.getWidth()/2,0);
2330
2331                    AddIntegralAreaModifier(tg,bi,toEnd,0,ptDP1,ptDP1,false);
2332                    AddIntegralAreaModifier(tg,bi,toEnd,0,ptDP2,ptDP2,false);
2333                    break;
2334                case TacticalLines.BS_LINE:
2335                case TacticalLines.BBS_LINE:
2336                    if (tg.get_T1() == null || tg.get_T1().isEmpty()) {
2337                        AddIntegralAreaModifier(tg, tg.get_Name(), toEnd, T1LineFactor, pt0, pt1, false);
2338                        AddIntegralAreaModifier(tg, tg.get_Name(), toEnd, T1LineFactor, ptLast, ptNextToLast, false);
2339                    } else {
2340                        if (tg.get_T1().equalsIgnoreCase("1")) {
2341                            for (j = 0; j < tg.Pixels.size() - 1; j++) {
2342                                AddIntegralAreaModifier(tg, tg.get_Name(), aboveMiddle, 0, tg.Pixels.get(j), tg.Pixels.get(j + 1), false);
2343                            }
2344                        } else if (tg.get_T1().equalsIgnoreCase("2")) {
2345                            AddIntegralAreaModifier(tg, tg.get_Name(), toEnd, T1LineFactor, pt0, pt1, false);
2346                            AddIntegralAreaModifier(tg, tg.get_Name(), toEnd, T1LineFactor, ptLast, ptNextToLast, false);
2347                        } else if (tg.get_T1().equalsIgnoreCase("3")) {
2348                            //either end of the polyline
2349                            dist = lineutility.CalcDistanceDouble(pt0, pt1);
2350                            stringWidth = metrics.stringWidth(tg.get_Name());
2351                            stringWidth /= 2;
2352                            pt2 = lineutility.ExtendAlongLineDouble2(pt1, pt0, dist + stringWidth);
2353                            AddIntegralAreaModifier(tg, tg.get_Name(), area, 0, pt2, pt2, false);
2354                            dist = lineutility.CalcDistanceDouble(ptNextToLast, ptLast);
2355                            pt2 = lineutility.ExtendAlongLineDouble2(ptNextToLast, ptLast, dist + stringWidth);
2356                            AddIntegralAreaModifier(tg, tg.get_Name(), area, 0, pt2, pt2, false);
2357                            //the intermediate points
2358                            for (j = 1; j < tg.Pixels.size() - 1; j++) {
2359                                AddIntegralAreaModifier(tg, tg.get_Name(), area, 0, tg.Pixels.get(j), tg.Pixels.get(j), false);
2360                            }
2361                        } else //t1 is set inadvertantly or for other graphics
2362                        {
2363                            AddIntegralAreaModifier(tg, tg.get_Name(), toEnd, T1LineFactor, pt0, pt1, false);
2364                            AddIntegralAreaModifier(tg, tg.get_Name(), toEnd, T1LineFactor, ptLast, ptNextToLast, false);
2365                        }
2366                    }
2367                    break;
2368                case TacticalLines.BS_AREA:
2369                case TacticalLines.BBS_AREA:
2370                    AddIntegralAreaModifier(tg, tg.get_Name(), area, 0, ptCenter, ptCenter, false);
2371                    break;
2372                case TacticalLines.FEBA:
2373                    AddIntegralAreaModifier(tg, label, toEnd, 0, pt0, pt1, false);
2374                    AddIntegralAreaModifier(tg, label, toEnd, 0, ptLast, ptNextToLast, false);
2375                    break;
2376                // T before label
2377                case TacticalLines.FSCL:
2378                    pt0 = tg.Pixels.get(0);
2379                    pt1 = tg.Pixels.get(1);
2380                    pt2 = tg.Pixels.get(tg.Pixels.size() - 1);
2381                    pt3 = tg.Pixels.get(tg.Pixels.size() - 2);
2382                    dist = lineutility.CalcDistanceDouble(pt0, pt1);
2383                    dist2 = lineutility.CalcDistanceDouble(pt2, pt3);
2384                    stringWidth = (int) ((double) metrics.stringWidth(tg.get_Name() + " " + label));
2385                    stringWidth2 = (int) ((double) metrics.stringWidth(tg.get_DTG()));
2386                    if (stringWidth2 > stringWidth) {
2387                        stringWidth = stringWidth2;
2388                    }
2389
2390                    if (tg.Pixels.size() == 2) //one segment
2391                    {
2392                        pt1 = lineutility.ExtendAlongLineDouble(pt0, pt1, stringWidth);
2393                        AddModifier2(tg, tg.get_Name() + " " + label , aboveMiddle, -0.7 * csFactor, pt0, pt1, false);
2394                        AddModifier2(tg, tg.get_DTG() + WDash, aboveMiddle, 0.7 * csFactor, pt0, pt1, false);
2395                        AddModifier2(tg, tg.get_DTG1(), aboveMiddle, 1.7 * csFactor, pt0, pt1, false);
2396                        if (dist > 3.5 * stringWidth)//was 28stringwidth+5
2397                        {
2398                            pt0 = tg.Pixels.get(tg.Pixels.size() - 1);
2399                            pt1 = tg.Pixels.get(tg.Pixels.size() - 2);
2400                            pt1 = lineutility.ExtendAlongLineDouble(pt0, pt1, stringWidth);
2401                            AddModifier2(tg, tg.get_Name() + " " + label, aboveMiddle, -0.7 * csFactor, pt0, pt1, false);
2402                            AddModifier2(tg, tg.get_DTG() + WDash, aboveMiddle, 0.7 * csFactor, pt0, pt1, false);
2403                            AddModifier2(tg, tg.get_DTG1(), aboveMiddle, 1.7 * csFactor, pt0, pt1, false);
2404                        }
2405                    } else //more than one semgent
2406                    {
2407                        double dist3 = lineutility.CalcDistanceDouble(pt0, pt2);
2408                        if (dist > stringWidth + 5 || dist >= dist2 || dist3 > stringWidth + 5) {
2409                            pt1 = lineutility.ExtendAlongLineDouble(pt0, pt1, stringWidth);
2410                            AddModifier2(tg, tg.get_Name() + " " + label, aboveMiddle, -0.7 * csFactor, pt0, pt1, false);
2411                            AddModifier2(tg, tg.get_DTG() + WDash, aboveMiddle, 0.7 * csFactor, pt0, pt1, false);
2412                            AddModifier2(tg, tg.get_DTG1(), aboveMiddle, 1.7 * csFactor, pt0, pt1, false);
2413                        }
2414                        if (dist2 > stringWidth + 5 || dist2 > dist || dist3 > stringWidth + 5) {
2415                            pt0 = tg.Pixels.get(tg.Pixels.size() - 1);
2416                            pt1 = tg.Pixels.get(tg.Pixels.size() - 2);
2417                            pt1 = lineutility.ExtendAlongLineDouble(pt0, pt1, stringWidth);
2418                            AddModifier2(tg, tg.get_Name() + " " + label, aboveMiddle, -0.7 * csFactor, pt0, pt1, false);
2419                            AddModifier2(tg, tg.get_DTG() + WDash, aboveMiddle, 0.7 * csFactor, pt0, pt1, false);
2420                            AddModifier2(tg, tg.get_DTG1(), aboveMiddle, 1.7 * csFactor, pt0, pt1, false);
2421                        }
2422                    }
2423                    break;
2424                // T after label
2425                case TacticalLines.ICL:
2426                case TacticalLines.NFL:
2427                case TacticalLines.BCL_REVD:
2428                case TacticalLines.RFL:
2429                case TacticalLines.BCL:
2430                    pt0 = tg.Pixels.get(0);
2431                    pt1 = tg.Pixels.get(1);
2432                    pt2 = tg.Pixels.get(tg.Pixels.size() - 1);
2433                    pt3 = tg.Pixels.get(tg.Pixels.size() - 2);
2434                    dist = lineutility.CalcDistanceDouble(pt0, pt1);
2435                    dist2 = lineutility.CalcDistanceDouble(pt2, pt3);
2436                    String TMod = ""; // Don't add parenthesis if T modifier is empty
2437
2438
2439                    int version = SymbolID.getVersion(tg.get_SymbolId());
2440                    if(version < SymbolID.Version_2525E) {
2441                        TMod = tg.get_Name();
2442                        stringWidth = (int) ((double) metrics.stringWidth(TMod + " " + label));
2443                    }
2444                    else if(version == SymbolID.Version_2525E || version == SymbolID.Version_2525Ech1) {
2445                        if(linetype == TacticalLines.BCL) {
2446                            if (tg.get_Name() != null && !tg.get_Name().isEmpty())
2447                                TMod = " (" + tg.get_Name() + ")";
2448                            stringWidth = (int) ((double) metrics.stringWidth(label + TMod));
2449                        }
2450                        else
2451                        {
2452                            TMod = tg.get_Name();
2453                            stringWidth = (int) ((double) metrics.stringWidth(tg.get_Name() + " " + label));
2454                        }
2455                    }
2456                    else if((version == SymbolID.Version_APP6Ech2)) {
2457                        if (tg.get_Name() != null && !tg.get_Name().isEmpty())
2458                            TMod += " " + tg.get_Name();
2459                        if(tg.get_AS() != null && !tg.get_AS().isEmpty())
2460                            TMod += " (" + tg.get_AS() + ")";
2461                        stringWidth = (int) ((double) metrics.stringWidth(label + TMod));
2462
2463                    }
2464
2465                    stringWidth2 = (int) ((double) metrics.stringWidth(tg.get_DTG()));
2466                    if (stringWidth2 > stringWidth) {
2467                        stringWidth = stringWidth2;
2468                    }
2469
2470                    if (tg.Pixels.size() == 2) //one segment
2471                    {
2472                        pt1 = lineutility.ExtendAlongLineDouble(pt0, pt1, stringWidth);
2473                        AddModifier2(tg, label + TSpace + TMod, aboveMiddle, -0.7 * csFactor, pt0, pt1, false);
2474                        AddModifier2(tg, tg.get_DTG() + WDash, aboveMiddle, 0.7 * csFactor, pt0, pt1, false);
2475                        AddModifier2(tg, tg.get_DTG1(), aboveMiddle, 1.7 * csFactor, pt0, pt1, false);
2476                        if (dist > 3.5 * stringWidth)//was 28stringwidth+5
2477                        {
2478                            pt0 = tg.Pixels.get(tg.Pixels.size() - 1);
2479                            pt1 = tg.Pixels.get(tg.Pixels.size() - 2);
2480                            pt1 = lineutility.ExtendAlongLineDouble(pt0, pt1, stringWidth);
2481                            AddModifier2(tg, label + TSpace + TMod, aboveMiddle, -0.7 * csFactor, pt0, pt1, false);
2482                            AddModifier2(tg, tg.get_DTG() + WDash, aboveMiddle, 0.7 * csFactor, pt0, pt1, false);
2483                            AddModifier2(tg, tg.get_DTG1(), aboveMiddle, 1.7 * csFactor, pt0, pt1, false);
2484                        }
2485                    } else //more than one semgent
2486                    {
2487                        double dist3 = lineutility.CalcDistanceDouble(pt0, pt2);
2488                        if (dist > stringWidth + 5 || dist >= dist2 || dist3 > stringWidth + 5) {
2489                            pt1 = lineutility.ExtendAlongLineDouble(pt0, pt1, stringWidth);
2490                            AddModifier2(tg, label + TSpace + TMod, aboveMiddle, -0.7 * csFactor, pt0, pt1, false);
2491                            AddModifier2(tg, tg.get_DTG() + WDash, aboveMiddle, 0.7 * csFactor, pt0, pt1, false);
2492                            AddModifier2(tg, tg.get_DTG1(), aboveMiddle, 1.7 * csFactor, pt0, pt1, false);
2493                        }
2494                        if (dist2 > stringWidth + 5 || dist2 > dist || dist3 > stringWidth + 5) {
2495                            pt0 = tg.Pixels.get(tg.Pixels.size() - 1);
2496                            pt1 = tg.Pixels.get(tg.Pixels.size() - 2);
2497                            pt1 = lineutility.ExtendAlongLineDouble(pt0, pt1, stringWidth);
2498                            AddModifier2(tg, label + TSpace + TMod, aboveMiddle, -0.7 * csFactor, pt0, pt1, false);
2499                            AddModifier2(tg, tg.get_DTG() + WDash, aboveMiddle, 0.7 * csFactor, pt0, pt1, false);
2500                            AddModifier2(tg, tg.get_DTG1(), aboveMiddle, 1.7 * csFactor, pt0, pt1, false);
2501                        }
2502                    }
2503                    break;
2504                case TacticalLines.DIRATKSPT:
2505                case TacticalLines.DIRATKAIR:
2506                case TacticalLines.DIRATKGND:
2507                    midPt = lineutility.MidPointDouble(pt0, pt1, 0);
2508                    //midPt=lineutility.MidPointDouble(pt0, midPt, 0);
2509                    AddIntegralAreaModifier(tg, tg.get_Name(), aboveMiddle, 0, pt0, midPt, false);
2510                    addDTG(tg, aboveMiddle, csFactor, 2 * csFactor, pt0, pt1, metrics);
2511                    break;
2512                case TacticalLines.SPT:
2513                case TacticalLines.FRONTAL_ATTACK:
2514                case TacticalLines.TURNING_MOVEMENT:
2515                case TacticalLines.MOVEMENT_TO_CONTACT:
2516                case TacticalLines.AIRAOA:
2517                case TacticalLines.AAAAA:
2518                case TacticalLines.MAIN:
2519                    if (tg.Pixels.size() == 3) //one segment
2520                    {
2521                        midPt = lineutility.MidPointDouble(pt0, pt1, 0);
2522                        AddIntegralAreaModifier(tg, tg.get_DTG() + WDash, aboveMiddle, 0, midPt, midPt, false);
2523                        AddIntegralAreaModifier(tg, tg.get_DTG1(), aboveMiddle, csFactor, midPt, midPt, false);
2524                        AddIntegralAreaModifier(tg, tg.get_Name(), aboveMiddle, 2 * csFactor, midPt, midPt, false);
2525
2526                    } else if (tg.Pixels.size() == 4) //2 segments
2527                    {
2528                        midPt = lineutility.MidPointDouble(pt1, pt2, 0);
2529                        AddIntegralAreaModifier(tg,tg.get_DTG() + WDash, aboveMiddle, 0, midPt, midPt, false);
2530                        AddIntegralAreaModifier(tg, tg.get_DTG1(), aboveMiddle, csFactor, midPt, midPt, false);
2531                        AddIntegralAreaModifier(tg, tg.get_Name(), aboveMiddle, 2 * csFactor, midPt, midPt, false);
2532                    } else // 3 or more segments
2533                    {
2534                        midPt = lineutility.MidPointDouble(pt1, pt2, 0);
2535                        AddIntegralAreaModifier(tg, tg.get_DTG() + WDash, aboveMiddle, -csFactor / 2, midPt, midPt, false);
2536                        AddIntegralAreaModifier(tg, tg.get_DTG1(), aboveMiddle, csFactor / 2, midPt, midPt, false);
2537                        midPt = lineutility.MidPointDouble(pt2, pt3, 0);
2538                        AddIntegralAreaModifier(tg, tg.get_Name(), aboveMiddle, -csFactor / 2, midPt, midPt, false);
2539                    }
2540                case TacticalLines.LL:
2541                case TacticalLines.LOD:
2542                case TacticalLines.LDLC:
2543                case TacticalLines.PLD:
2544                case TacticalLines.RELEASE:
2545                case TacticalLines.HOL:
2546                case TacticalLines.BHL:
2547                case TacticalLines.FCL:
2548                case TacticalLines.HOLD:
2549                case TacticalLines.BRDGHD:
2550                case TacticalLines.HOLD_GE:
2551                case TacticalLines.BRDGHD_GE:
2552                case TacticalLines.LOA:
2553                case TacticalLines.IFF_OFF:
2554                case TacticalLines.IFF_ON:
2555                    AddIntegralAreaModifier(tg, label, aboveEnd, -csFactor, pt0, pt1, false);
2556                    AddIntegralAreaModifier(tg, label, aboveEnd, -csFactor, ptLast, ptNextToLast, false);
2557                    break;
2558                case TacticalLines.EWL:
2559                    AddIntegralAreaModifier(tg, label, aboveEnd, -csFactor, pt0, pt1, false);
2560                    AddIntegralAreaModifier(tg, label, aboveEnd, -csFactor, ptLast, ptNextToLast, false);
2561                    tg.set_EchelonSymbol("");
2562                    if (clipRect != null) {
2563                        AddBoundaryModifiers(tg, g2d, clipRect);
2564                    } else {
2565                        AddBoundaryModifiers(tg, g2d, clipArray);
2566                    }
2567                    break;
2568                case TacticalLines.AIRFIELD:
2569                    ur = new POINT2();
2570                    ul = new POINT2();
2571                    ll = new POINT2();
2572                    lr = new POINT2();
2573                    Modifier2.GetMBR(tg, ul, ur, lr, ll);
2574                    stringWidth = metrics.stringWidth(tg.get_H());
2575                    pt0.x = ur.x + stringWidth / 2 + 1;
2576                    //pt0.x=ptUr.x+1;
2577                    //pt0.y=(ptUr.y+ptLr.y)/2-metrics.getFont().getSize()
2578                    pt0.y = (ur.y + lr.y) / 2 - font.getSize();
2579                    AddIntegralAreaModifier(tg, tg.get_H(), area, csFactor, pt0, pt0, false);
2580                    break;
2581                case TacticalLines.LAUNCH_AREA:
2582                case TacticalLines.DEFENDED_AREA_CIRCULAR:
2583                    AddIntegralAreaModifier(tg, label + TDash + tg.get_Name(), area, 0, ptCenter, ptCenter, false);
2584                    break;
2585                case TacticalLines.JTAA:
2586                case TacticalLines.SAA:
2587                case TacticalLines.SGAA:
2588                    addNModifier(tg);
2589                    AddIntegralAreaModifier(tg, label + TDash + tg.get_Name(), area, 0, ptCenter, ptCenter, false);
2590                    addDTG(tg, area, csFactor, 2 * csFactor, ptCenter, ptCenter, metrics);
2591                    break;
2592                case TacticalLines.FORT:
2593                case TacticalLines.ZONE:
2594                    AddIntegralAreaModifier(tg, tg.get_Name(), area, 0, ptCenter, ptCenter, false);
2595                    break;
2596                case TacticalLines.BDZ:
2597                    AddIntegralAreaModifier(tg, label, area, 0, pt0, pt0, false);
2598                    break;
2599                case TacticalLines.ASSAULT:
2600                case TacticalLines.ATKPOS:
2601                case TacticalLines.OBJ:
2602                case TacticalLines.NAI:
2603                case TacticalLines.TAI:
2604                case TacticalLines.BASE_CAMP_REVD:
2605                case TacticalLines.GUERILLA_BASE_REVD:
2606                case TacticalLines.ASSY:
2607                case TacticalLines.EA:
2608                case TacticalLines.DZ:
2609                case TacticalLines.EZ:
2610                case TacticalLines.LZ:
2611                case TacticalLines.PZ:
2612                case TacticalLines.AO:
2613                    AddIntegralAreaModifier(tg, label + TSpace + tg.get_Name(), area, 0, ptCenter, ptCenter, false);
2614                    break;
2615                case TacticalLines.BASE_CAMP:
2616                case TacticalLines.GUERILLA_BASE:
2617                    AddIntegralAreaModifier(tg, label + TSpace + tg.get_Name(), area, -1 * csFactor, ptCenter, ptCenter, false);
2618                    AddModifier(tg, tg.get_H(), area, 0, ptCenter, ptCenter);
2619                    addDTG(tg, area, 1 * csFactor, 2 * csFactor, ptCenter, ptCenter, metrics);
2620                    addNModifier(tg);
2621                    addModifierBottomSegment(tg, tg.get_EchelonSymbol());
2622                    break;
2623                case TacticalLines.GENERIC_AREA:
2624                    AddIntegralAreaModifier(tg, tg.get_H() + " " + tg.get_Name(), area, -0.5 * csFactor, ptCenter, ptCenter, false);
2625                    addDTG(tg, area, 0.5 * csFactor, 1.5 * csFactor, ptCenter, ptCenter, metrics);
2626                    addNModifier(tg);
2627                    break;
2628                case TacticalLines.AIRHEAD:
2629                    GetMBR(tg, ul, ur, lr, ll);
2630                    AddIntegralAreaModifier(tg, label, aboveMiddle, csFactor, ll, lr, false);
2631                    break;
2632                case TacticalLines.AC:
2633                case TacticalLines.LLTR:
2634                case TacticalLines.MRR:
2635                case TacticalLines.SL:
2636                case TacticalLines.TC:
2637                case TacticalLines.SAAFR:
2638                case TacticalLines.SC:
2639                    AddIntegralModifier(tg, "Name: " + tg.get_Name(), aboveMiddle, -7 * csFactor, middleSegment, middleSegment + 1, false);
2640                    AddIntegralModifier(tg, "Width: " + removeDecimal(tg.get_AM()), aboveMiddle, -6 * csFactor, middleSegment, middleSegment + 1, false);
2641                    AddIntegralModifier(tg, "Min Alt: " + tg.get_X(), aboveMiddle, -5 * csFactor, middleSegment, middleSegment + 1, false);
2642                    AddIntegralModifier(tg, "Max Alt: " + tg.get_X1(), aboveMiddle, -4 * csFactor, middleSegment, middleSegment + 1, false);
2643                    AddIntegralModifier(tg, "DTG Start: " + tg.get_DTG(), aboveMiddle, -3 * csFactor, middleSegment, middleSegment + 1, false);
2644                    AddIntegralModifier(tg, "DTG End: " + tg.get_DTG1(), aboveMiddle, -2 * csFactor, middleSegment, middleSegment + 1, false);
2645                    AddIntegralModifier(tg, label + TSpace + tg.get_Name(), aboveMiddle, 0, middleSegment, middleSegment + 1, false);
2646                    break;
2647                case TacticalLines.BEARING_J:
2648                case TacticalLines.BEARING_RDF:
2649                case TacticalLines.BEARING:
2650                case TacticalLines.ELECTRO:
2651                case TacticalLines.BEARING_EW:
2652                case TacticalLines.ACOUSTIC:
2653                case TacticalLines.ACOUSTIC_AMB:
2654                case TacticalLines.TORPEDO:
2655                case TacticalLines.OPTICAL:
2656                    midPt = lineutility.MidPointDouble(pt0, pt1, 0);
2657                    AddIntegralAreaModifier(tg, label, aboveMiddle, 0, midPt, midPt, true);
2658                    pt3 = lineutility.ExtendDirectedLine(pt0, pt1, pt1, 3, font.getSize() / 2.0);
2659                    AddIntegralAreaModifier(tg, tg.get_H(), aboveMiddle, 1, pt3, pt3, true);
2660                    break;
2661                case TacticalLines.ACA:
2662                    AddIntegralAreaModifier(tg, label + TSpace + tg.get_Name(), area, -3 * csFactor, ptCenter, ptCenter, false);
2663                    AddIntegralAreaModifier(tg, tg.get_T1(), area, -2 * csFactor, ptCenter, ptCenter, false);
2664                    AddIntegralAreaModifier(tg, "MIN ALT: " + tg.get_X(), area, -1 * csFactor, ptCenter, ptCenter, false, "H");
2665                    AddIntegralAreaModifier(tg, "MAX ALT: " + tg.get_X1(), area, 0, ptCenter, ptCenter, false, "H1");
2666                    AddIntegralAreaModifier(tg, "GRID " + tg.get_Location(), area, 1 * csFactor, ptCenter, ptCenter, false, "H2");
2667                    AddModifier2(tg, "EFF " + tg.get_DTG() + WDash, area, 2 * csFactor, ptCenter, ptCenter, false, "W");
2668                    AddModifier2(tg, tg.get_DTG1(), area, 3 * csFactor, ptCenter, ptCenter, false, "W1");
2669                    break;
2670                case TacticalLines.MFP:
2671                    pt0 = tg.Pixels.get(middleSegment);
2672                    pt1 = tg.Pixels.get(middleSegment + 1);
2673                    AddIntegralModifier(tg, label, aboveMiddle, 0, middleSegment, middleSegment + 1, true);
2674                    AddIntegralModifier(tg, tg.get_DTG() + WDash, aboveEnd, 1 * csFactor, 0, 1, false);
2675                    AddIntegralModifier(tg, tg.get_DTG1(), aboveEnd, 2 * csFactor, 0, 1, false);
2676                    break;
2677                case TacticalLines.LINTGT:
2678                    AddIntegralModifier(tg, ap, aboveMiddle, -0.7 * csFactor, middleSegment, middleSegment + 1, false);
2679                    break;
2680                case TacticalLines.LINTGTS:
2681                    AddIntegralModifier(tg, ap, aboveMiddle, -0.7 * csFactor, middleSegment, middleSegment + 1, false);
2682                    AddIntegralModifier(tg, label, aboveMiddle, 0.7 * csFactor, middleSegment, middleSegment + 1, false);
2683                    break;
2684                case TacticalLines.FPF:
2685                    AddIntegralModifier(tg, ap, aboveMiddle, -0.7 * csFactor, 0, 1, false);
2686                    AddIntegralModifier(tg, label, aboveMiddle, .7 * csFactor, 0, 1, false);
2687                    AddIntegralModifier(tg, tg.get_T1(), aboveMiddle, 1.7 * csFactor, 0, 1, false);
2688                    AddIntegralModifier(tg, v, aboveMiddle, 2.7 * csFactor, 0, 1, false);
2689                    break;
2690                case TacticalLines.AT:
2691                    AddIntegralAreaModifier(tg, ap, area, 0, ptCenter, ptCenter, false);
2692                    break;
2693                case TacticalLines.RECTANGULAR:
2694                case TacticalLines.CIRCULAR:
2695                    AddIntegralAreaModifier(tg, ap, area, 0, pt0, pt0, false);
2696                    break;
2697                case TacticalLines.PBS_CIRCLE:
2698                case TacticalLines.PBS_ELLIPSE:
2699                case TacticalLines.PBS_RECTANGLE:
2700                case TacticalLines.BBS_POINT:
2701                    AddIntegralAreaModifier(tg, tg.get_Name(), area, 0, pt0, pt0, false);
2702                    break;
2703                case TacticalLines.RECTANGULAR_TARGET:
2704                    stringWidth = metrics.stringWidth(tg.get_Name());
2705                    POINT2 offsetCenterPoint = new POINT2(ptCenter.x + ((double) stringWidth) / 2.0, ptCenter.y);
2706                    AddIntegralAreaModifier(tg, tg.get_Name(), area, -1 * csFactor, offsetCenterPoint, offsetCenterPoint, false);
2707                    break;
2708                case TacticalLines.SMOKE:
2709                    AddIntegralAreaModifier(tg, ap, area, -csFactor, ptCenter, ptCenter, false);
2710                    AddIntegralAreaModifier(tg, label, area, 0, ptCenter, ptCenter, false);
2711                    addDTG(tg, area, 1 * csFactor, 2 * csFactor, ptCenter, ptCenter, metrics);
2712                    break;
2713                case TacticalLines.LINE:
2714                    AddIntegralModifier(tg, tg.get_Name(), aboveMiddle, csFactor, middleSegment, middleSegment + 1, false);
2715                    break;
2716                case TacticalLines.MINED:
2717                    if (tg.isHostile()) {
2718                        pt1 = lineutility.MidPointDouble(pt0, pt1, 0);
2719                        AddIntegralAreaModifier(tg, tg.get_N(), aboveMiddle, 0, pt0, pt1, true);
2720                        if (middleSegment != 0) {
2721                            pt0 = tg.Pixels.get(middleSegment);
2722                            pt1 = tg.Pixels.get(middleSegment + 1);
2723                            pt1 = lineutility.MidPointDouble(pt0, pt1, 0);
2724                            AddIntegralAreaModifier(tg, tg.get_N(), aboveMiddle, 0, pt0, pt1, true);
2725                        }
2726                    }
2727                    GetMBR(tg, ul, ur, lr, ll);
2728                    AddIntegralAreaModifier(tg, tg.get_H(), aboveMiddle, -1.5 * csFactor, ul, ur, false);
2729                    AddIntegralAreaModifier(tg, tg.get_DTG(), aboveMiddle, 1.5 * csFactor, ll, lr, false);
2730                    addModifierOnLine("M", tg);
2731                    AddIntegralAreaModifier(tg, getImageModifier(tg), areaImage, 0, ptCenter, ptCenter, false);
2732                    break;
2733                case TacticalLines.FENCED:
2734                    if (tg.isHostile()) {
2735                        pt1 = lineutility.MidPointDouble(pt0, pt1, 0);
2736                        AddIntegralAreaModifier(tg, tg.get_N(), aboveMiddle, 0, pt0, pt1, true);
2737                        if (middleSegment != 0) {
2738                            pt0 = tg.Pixels.get(middleSegment);
2739                            pt1 = tg.Pixels.get(middleSegment + 1);
2740                            pt1 = lineutility.MidPointDouble(pt0, pt1, 0);
2741                            AddIntegralAreaModifier(tg, tg.get_N(), aboveMiddle, 0, pt0, pt1, true);
2742                        }
2743                    }
2744                    addModifierOnLine("M", tg);
2745                    AddIntegralAreaModifier(tg, getImageModifier(tg), areaImage, 0, ptCenter, ptCenter, false);
2746                    break;
2747                case TacticalLines.ASLTXING:
2748                    if (tg.Pixels.get(1).y > tg.Pixels.get(0).y) {
2749                        pt0 = tg.Pixels.get(1);
2750                        pt1 = tg.Pixels.get(3);
2751                        pt2 = tg.Pixels.get(0);
2752                        pt3 = tg.Pixels.get(2);
2753                    } else {
2754                        pt0 = tg.Pixels.get(0);
2755                        pt1 = tg.Pixels.get(2);
2756                        pt2 = tg.Pixels.get(1);
2757                        pt3 = tg.Pixels.get(3);
2758                    }
2759                    pt2 = lineutility.ExtendAlongLineDouble2(pt0, pt2, -20);
2760                    pt3 = lineutility.ExtendAlongLineDouble2(pt1, pt3, -20);
2761                    addDTG(tg, aboveMiddle, 0, csFactor, pt2, pt3, metrics);
2762                    break;
2763                case TacticalLines.SERIES:
2764                case TacticalLines.DRCL:
2765                    addModifierTopSegment(tg, tg.get_Name());
2766                    break;
2767                case TacticalLines.STRIKWARN:
2768                    AddIntegralModifier(tg, "1", aboveMiddle, 0, index, index + 1, true);
2769                    AddIntegralModifier(tg, "2", aboveMiddle, 0, size/2, size/2 + 1, true);
2770                    break;
2771                case TacticalLines.SCREEN:
2772                case TacticalLines.COVER:
2773                case TacticalLines.GUARD:
2774                    if (tg.Pixels.size() == 4) {
2775                        pt1 = new POINT2(tg.Pixels.get(1));
2776                        pt2 = new POINT2(tg.Pixels.get(2));
2777                        AddIntegralAreaModifier(tg, label, area, 0, pt1, pt1, true);
2778                        AddIntegralAreaModifier(tg, label, area, 0, pt2, pt2, true);
2779                    } else {
2780                        stringHeight = (int) (0.5 * (double) font.getSize());
2781                        dAngle0 = Math.atan2(tg.Pixels.get(0).y - tg.Pixels.get(1).y, tg.Pixels.get(0).x - tg.Pixels.get(1).x);
2782                        dAngle1 = Math.atan2(tg.Pixels.get(0).y - tg.Pixels.get(2).y, tg.Pixels.get(0).x - tg.Pixels.get(2).x);
2783                        pt0 = new POINT2(tg.Pixels.get(0));
2784                        pt0.x -= 30 * Math.cos(dAngle0);
2785                        pt0.y -= 30 * Math.sin(dAngle0) + stringHeight;
2786                        pt1 = new POINT2(tg.Pixels.get(0));
2787                        pt1.x -= 30 * Math.cos(dAngle1);
2788                        pt1.y -= 30 * Math.sin(dAngle1) + stringHeight;
2789                        AddIntegralAreaModifier(tg, label, area, 0, pt0, pt0, true);
2790                        AddIntegralAreaModifier(tg, label, area, 0, pt1, pt1, true);
2791                    }
2792                    break;
2793                case TacticalLines.MSR_ONEWAY:
2794                case TacticalLines.ASR_ONEWAY:
2795                case TacticalLines.TRAFFIC_ROUTE_ONEWAY:
2796                case TacticalLines.MSR_TWOWAY:
2797                case TacticalLines.ASR_TWOWAY:
2798                case TacticalLines.MSR_ALT:
2799                case TacticalLines.ASR_ALT:
2800                case TacticalLines.TRAFFIC_ROUTE_ALT:
2801                    stringWidth = (int) (1.5 * (double) metrics.stringWidth(label + TSpace + tg.get_Name()));
2802                    double arrowOffset = 10 * DPIScaleFactor;
2803                    if (linetype == TacticalLines.MSR_TWOWAY || linetype == TacticalLines.ASR_TWOWAY)
2804                        arrowOffset = 25 * DPIScaleFactor;
2805                    boolean isAlt = linetype == TacticalLines.MSR_ALT || linetype == TacticalLines.ASR_ALT || linetype == TacticalLines.TRAFFIC_ROUTE_ALT;
2806                    if (isAlt) {
2807                        stringWidth2 = (int) (1.5 * (double) metrics.stringWidth("ALT"));
2808                        if (stringWidth2 > stringWidth) {
2809                            stringWidth = stringWidth2;
2810                        }
2811                    }
2812
2813                    foundSegment = false;
2814                    //acevedo - 11/30/2017 - adding option to render only 2 labels.
2815                    if (RendererSettings.getInstance().getTwoLabelOnly() == false) {
2816                        for (j = 0; j < tg.Pixels.size() - 1; j++) {
2817                            pt0 = tg.Pixels.get(j);
2818                            pt1 = tg.Pixels.get(j + 1);
2819                            dist = lineutility.CalcDistanceDouble(pt0, pt1);
2820                            int arrowSide = arraysupport.SupplyRouteArrowSide(pt0, pt1);
2821                            if (dist < stringWidth) {
2822                                continue;
2823                            } else {
2824                                if (arrowSide == 1 || arrowSide == 2) {
2825                                    // Shift points to account for arrow shift with DPI
2826                                    pt0 = lineutility.ExtendDirectedLine(pt1, pt0, pt0, arrowSide, arrowOffset);
2827                                    pt1 = lineutility.ExtendDirectedLine(pt1, pt0, pt1, arrowSide, arrowOffset);
2828                                    AddModifier(tg, label + TSpace + tg.get_Name(), aboveMiddle, -1.7 * csFactor, pt0, pt1);
2829                                    if (isAlt)
2830                                        AddModifier(tg, "ALT", aboveMiddle, 0, pt0, pt1);
2831                                } else {
2832                                    AddModifier(tg, label + TSpace + tg.get_Name(), aboveMiddle, -0.7 * csFactor, pt0, pt1);
2833                                    if (isAlt) {
2834                                        pt0 = lineutility.ExtendDirectedLine(pt1, pt0, pt0, arrowSide, arrowOffset);
2835                                        pt1 = lineutility.ExtendDirectedLine(pt1, pt0, pt1, arrowSide, arrowOffset);
2836                                        AddModifier(tg, "ALT", aboveMiddle, 0, pt0, pt1);
2837                                    }
2838                                }
2839                                foundSegment = true;
2840                            }
2841                        }
2842                        if (foundSegment == false) {
2843                            pt0 = tg.Pixels.get(middleSegment);
2844                            pt1 = tg.Pixels.get(middleSegment + 1);
2845                            int arrowSide = arraysupport.SupplyRouteArrowSide(pt0, pt1);
2846                            if (arrowSide == 1 || arrowSide == 2) {
2847                                // Shift points to account for arrow shift with DPI
2848                                pt0 = lineutility.ExtendDirectedLine(pt1, pt0, pt0, arrowSide, arrowOffset);
2849                                pt1 = lineutility.ExtendDirectedLine(pt1, pt0, pt1, arrowSide, arrowOffset);
2850                                AddModifier(tg, label + TSpace + tg.get_Name(), aboveMiddle, -1.7 * csFactor, pt0, pt1);
2851                                if (isAlt)
2852                                    AddModifier(tg, "ALT", aboveMiddle, 0, pt0, pt1);
2853                            } else {
2854                                AddModifier(tg, label + TSpace + tg.get_Name(), aboveMiddle, -0.7 * csFactor, pt0, pt1);
2855                                if (isAlt) {
2856                                    pt0 = lineutility.ExtendDirectedLine(pt1, pt0, pt0, arrowSide, arrowOffset);
2857                                    pt1 = lineutility.ExtendDirectedLine(pt1, pt0, pt1, arrowSide, arrowOffset);
2858                                    AddModifier(tg, "ALT", aboveMiddle, 0, pt0, pt1);
2859                                }
2860                            }
2861                        }
2862                    }
2863                    else {
2864                        // 2 labels one to the north and the other to the south of graphic.
2865                        northestPtIndex = 0;
2866                        northestPt = tg.Pixels.get(northestPtIndex);
2867                        southestPtIndex = 0;
2868                        southestPt = tg.Pixels.get(southestPtIndex);
2869
2870                        for (j = 0; j < tg.Pixels.size() - 1; j++) {
2871                            pt0 = tg.Pixels.get(j);
2872                            if (pt0.y >= northestPt.y) {
2873                                northestPt = pt0;
2874                                northestPtIndex = j;
2875                            }
2876                            if (pt0.y <= southestPt.y) {
2877                                southestPt = pt0;
2878                                southestPtIndex = j;
2879                            }
2880                        }
2881
2882                        AddIntegralModifier(tg, label + TSpace + tg.get_Name(), aboveMiddle, -1.7 * csFactor, northestPtIndex, northestPtIndex + 1, false);
2883                        if (isAlt)
2884                            AddIntegralModifier(tg, "ALT", aboveMiddle, -0.7 * csFactor, northestPtIndex, northestPtIndex + 1, false);
2885
2886                        if (northestPtIndex != southestPtIndex) {
2887                            AddIntegralModifier(tg, label + TSpace + tg.get_Name(), aboveMiddle, -1.7 * csFactor, southestPtIndex, southestPtIndex + 1, false);
2888                            if (isAlt)
2889                                AddIntegralModifier(tg, "ALT", aboveMiddle, -0.7 * csFactor, southestPtIndex, southestPtIndex + 1, false);
2890                        }
2891                    }//else
2892                    break;
2893                case TacticalLines.DHA_REVD:
2894                    AddIntegralAreaModifier(tg, "DETAINEE", area, -1.5 * csFactor, ptCenter, ptCenter, false);
2895                    AddIntegralAreaModifier(tg, "HOLDING", area, -0.5 * csFactor, ptCenter, ptCenter, false);
2896                    AddIntegralAreaModifier(tg, "AREA", area, 0.5 * csFactor, ptCenter, ptCenter, false);
2897                    AddIntegralAreaModifier(tg, tg.get_Name(), area, 1.5 * csFactor, ptCenter, ptCenter, false);
2898                    break;
2899                case TacticalLines.EPW:
2900                    AddIntegralAreaModifier(tg, "EPW", area, -1.5 * csFactor, ptCenter, ptCenter, false);
2901                    AddIntegralAreaModifier(tg, "HOLDING", area, -0.5 * csFactor, ptCenter, ptCenter, false);
2902                    AddIntegralAreaModifier(tg, "AREA", area, 0.5 * csFactor, ptCenter, ptCenter, false);
2903                    AddIntegralAreaModifier(tg, tg.get_Name(), area, 1.5 * csFactor, ptCenter, ptCenter, false);
2904                    break;
2905                case TacticalLines.UXO:
2906                    addModifierOnLine("UXO", tg, true);
2907                    break;
2908                case TacticalLines.GENERAL:
2909                    addNModifier(tg);
2910                    break;
2911                case TacticalLines.DHA:
2912                case TacticalLines.KILL_ZONE:
2913                case TacticalLines.FARP:
2914                    AddIntegralAreaModifier(tg, label, area, -0.5 * csFactor, ptCenter, ptCenter, false);
2915                    AddIntegralAreaModifier(tg, tg.get_Name(), area, 0.5 * csFactor, ptCenter, ptCenter, false);
2916                    break;
2917                case TacticalLines.BSA:
2918                case TacticalLines.DSA:
2919                case TacticalLines.CSA:
2920                case TacticalLines.RSA:
2921                    AddIntegralAreaModifier(tg, label, area, 0, ptCenter, ptCenter, false);
2922                    break;
2923                case TacticalLines.RHA:
2924                    AddIntegralAreaModifier(tg, "REFUGEE", area, -1.5 * csFactor, ptCenter, ptCenter, false);
2925                    AddIntegralAreaModifier(tg, "HOLDING", area, -0.5 * csFactor, ptCenter, ptCenter, false);
2926                    AddIntegralAreaModifier(tg, "AREA", area, 0.5 * csFactor, ptCenter, ptCenter, false);
2927                    AddIntegralAreaModifier(tg, tg.get_Name(), area, 1.5 * csFactor, ptCenter, ptCenter, false);
2928                    break;
2929                case TacticalLines.MSR:
2930                case TacticalLines.ASR:
2931                case TacticalLines.TRAFFIC_ROUTE:
2932                    //AddIntegralModifier(tg, label + tg.get_Name(), aboveMiddle, -1*csFactor, middleSegment, middleSegment + 1,false);
2933                    foundSegment = false;
2934                    //acevedo - 11/30/2017 - adding option to render only 2 labels.
2935                    if (RendererSettings.getInstance().getTwoLabelOnly() == false) {
2936                        for (j = 0; j < tg.Pixels.size() - 1; j++) {
2937                            pt0 = tg.Pixels.get(j);
2938                            pt1 = tg.Pixels.get(j + 1);
2939                            stringWidth = (int) (1.5 * (double) metrics.stringWidth(label + TSpace + tg.get_Name()));
2940                            dist = lineutility.CalcDistanceDouble(pt0, pt1);
2941                            if (dist < stringWidth) {
2942                                continue;
2943                            } else {
2944                                AddIntegralModifier(tg, label + TSpace + tg.get_Name(), aboveMiddle, -1 * csFactor, j, j + 1, false);
2945                                foundSegment = true;
2946                            }
2947                        }
2948                        if (foundSegment == false) {
2949                            AddIntegralModifier(tg, label + TSpace + tg.get_Name(), aboveMiddle, -1 * csFactor, middleSegment, middleSegment + 1, false);
2950                        }
2951                    }
2952                    else {
2953                        // 2 labels one to the north and the other to the south of graphic.
2954                        for (j = 0; j < tg.Pixels.size()  ; j++) {
2955                            pt0 = tg.Pixels.get(j);
2956
2957                            if (northestPt == null)
2958                            {
2959                                northestPt = pt0;
2960                                northestPtIndex = j;
2961                            }
2962                            if (southestPt == null)
2963                            {
2964                                southestPt = pt0;
2965                                southestPtIndex = j;
2966                            }
2967                            if (pt0.y >= northestPt.y)
2968                            {
2969                                northestPt = pt0;
2970                                northestPtIndex = j;
2971                            }
2972
2973                            if (pt0.y <= southestPt.y)
2974                            {
2975                                southestPt = pt0;
2976                                southestPtIndex = j;
2977                            }
2978                        }//for
2979                        middleSegment = northestPtIndex;
2980                        middleSegment2 = southestPtIndex;
2981
2982                        if (middleSegment  == tg.Pixels.size() -1) {
2983                            middleSegment-=1;
2984                        }
2985                        if (middleSegment2  == tg.Pixels.size() -1) {
2986                            middleSegment2-=1;
2987                        }
2988                        if (middleSegment == middleSegment2) {
2989                            middleSegment2-=1;
2990                        }
2991
2992                       // if (middleSegment != middleSegment2) {
2993                        AddIntegralModifier(tg, label + TSpace + tg.get_Name(), aboveMiddle, 0, middleSegment, middleSegment + 1, false);
2994                        //}
2995                        AddIntegralModifier(tg, label + TSpace + tg.get_Name(), aboveMiddle, 0, middleSegment2, middleSegment2 + 1, false);
2996
2997                    }//else
2998                    break;
2999                case TacticalLines.TRIP:
3000                    foundSegment = false;
3001                    stringWidth = (int) (1.5 * (double) metrics.stringWidth(label));
3002                    for (j = 0; j < tg.Pixels.size() - 1; j++) {
3003                        pt0 = tg.Pixels.get(j);
3004                        pt1 = tg.Pixels.get(j + 1);
3005                        midPt = lineutility.MidPointDouble(pt0, pt1, 0);
3006                        dist = lineutility.CalcDistanceDouble(pt0, pt1);
3007                        if (dist > stringWidth) {
3008                            AddModifier2(tg, label, aboveMiddle, -0.7 * csFactor, midPt, midPt, false);
3009                            foundSegment = true;
3010                        }
3011                    }
3012                    if (!foundSegment) {
3013                        midPt = lineutility.MidPointDouble(tg.Pixels.get(middleSegment), tg.Pixels.get(middleSegment + 1), 0);
3014                        AddModifier2(tg, label, aboveMiddle, -0.7 * csFactor, midPt, midPt, false);
3015                    }
3016                    break;
3017                case TacticalLines.GAP:
3018                    if (tg.Pixels.get(1).y > tg.Pixels.get(0).y) {
3019                        pt0 = tg.Pixels.get(1);
3020                        pt1 = tg.Pixels.get(3);
3021                        pt2 = tg.Pixels.get(0);
3022                        pt3 = tg.Pixels.get(2);
3023                    } else {
3024                        pt0 = tg.Pixels.get(0);
3025                        pt1 = tg.Pixels.get(2);
3026                        pt2 = tg.Pixels.get(1);
3027                        pt3 = tg.Pixels.get(3);
3028                    }
3029                    pt2 = lineutility.ExtendAlongLineDouble2(pt0, pt2, -20);
3030                    pt3 = lineutility.ExtendAlongLineDouble2(pt1, pt3, -20);
3031                    AddIntegralAreaModifier(tg, tg.get_Name(), aboveMiddle, 0, pt0, pt1, false);
3032                    addDTG(tg, aboveMiddle, 0, csFactor, pt2, pt3, metrics);
3033                    break;
3034                case TacticalLines.BIO:
3035                case TacticalLines.BIOT:
3036                case TacticalLines.CHEM:
3037                case TacticalLines.CHEMT:
3038                case TacticalLines.NUC:
3039                case TacticalLines.RAD:
3040                case TacticalLines.RADT:
3041                    AddIntegralAreaModifier(tg, getImageModifier(tg), areaImage, 0, ptCenter, ptCenter, false);
3042                    break;
3043                case TacticalLines.ANCHORAGE_LINE:
3044                    AddIntegralAreaModifier(tg, getImageModifier(tg), aboveMiddle, -0.15 * csFactor, tg.Pixels.get(middleSegment), tg.Pixels.get(middleSegment+1), false);
3045                    break;
3046                case TacticalLines.ANCHORAGE_AREA:
3047                    // Add anchor on segment with lowest midpoint
3048                    y = pt0.y + pt1.y;
3049                    index = 0;
3050                    for (j = 1; j < size - 1; j++) {
3051                        if (y < tg.Pixels.get(j).y + tg.Pixels.get(j + 1).y) {
3052                            index = j;
3053                            y = tg.Pixels.get(index).y + tg.Pixels.get(index + 1).y;
3054                        }
3055                    }
3056                    AddIntegralAreaModifier(tg, getImageModifier(tg), aboveMiddle, -0.25 * csFactor, tg.Pixels.get(index), tg.Pixels.get(index + 1), false);
3057                    break;
3058                case TacticalLines.MINE_LINE:
3059                    AddIntegralAreaModifier(tg, getImageModifier(tg), aboveMiddle, -0.2 * csFactor, tg.Pixels.get(middleSegment), tg.Pixels.get(middleSegment + 1), false);
3060                    if (tg.isHostile()) {
3061                        AddIntegralAreaModifier(tg, tg.get_N(), toEnd, 0.0, pt0, pt1, false);
3062                        AddIntegralAreaModifier(tg, tg.get_N(), toEnd, 0.0, ptLast, ptNextToLast, false);
3063                    }
3064                    break;
3065                case TacticalLines.DEPICT:
3066                    GetMBR(tg, ul, ur, lr, ll);
3067                    addNModifier(tg);
3068                    AddIntegralAreaModifier(tg, getImageModifier(tg), areaImage, 0, ptCenter, ptCenter, false);
3069                    break;
3070                case TacticalLines.FFA:
3071                case TacticalLines.RFA:
3072                case TacticalLines.NFA:
3073                    AddIntegralAreaModifier(tg, label, area, -1 * csFactor, ptCenter, ptCenter, false);
3074                    AddIntegralAreaModifier(tg, tg.get_Name(), area, 0, ptCenter, ptCenter, false);
3075                    addDTG(tg, area, 1 * csFactor, 2 * csFactor, ptCenter, ptCenter, metrics);
3076                    break;
3077                case TacticalLines.PAA:
3078                    addModifierOnLine("PAA", tg);
3079                    AddIntegralAreaModifier(tg, tg.get_Name(), area, -0.5 * csFactor, ptCenter, ptCenter, false);
3080                    addDTG(tg, area, 0.5 * csFactor, 1.5 * csFactor, ptCenter, ptCenter, metrics);
3081                    break;
3082                case TacticalLines.FSA:
3083                    AddIntegralAreaModifier(tg, label + TSpace + tg.get_Name(), area, -0.5 * csFactor, ptCenter, ptCenter, false);
3084                    addDTG(tg, area, 0.5 * csFactor, 1.5 * csFactor, ptCenter, ptCenter, metrics);
3085                    break;
3086                case TacticalLines.ATI:
3087                case TacticalLines.CFFZ:
3088                case TacticalLines.CFZ:
3089                case TacticalLines.TBA:
3090                case TacticalLines.TVAR:
3091                case TacticalLines.ZOR:
3092                case TacticalLines.DA:
3093                case TacticalLines.SENSOR:
3094                case TacticalLines.CENSOR:
3095                case TacticalLines.KILLBOXBLUE:
3096                case TacticalLines.KILLBOXPURPLE:
3097                    AddIntegralAreaModifier(tg, label, area, -0.5 * csFactor, ptCenter, ptCenter, false);
3098                    AddIntegralAreaModifier(tg, tg.get_Name(), area, 0.5 * csFactor, ptCenter, ptCenter, false);
3099                    GetMBR(tg, ul, ur, lr, ll);
3100                    POINT2 ptLeft = ul;
3101                    POINT2 ptRight = ur;
3102                    if (tg.get_Client().equalsIgnoreCase("ge")) {
3103                        ptLeft.x -= font.getSize() / 2;
3104                        ptRight.x -= font.getSize() / 2;
3105                    }
3106                    AddIntegralAreaModifier(tg, tg.get_DTG() + WDash, toEnd, 0.5 * csFactor, ptLeft, ptRight, false, "W");
3107                    AddIntegralAreaModifier(tg, tg.get_DTG1(), toEnd, 1.5 * csFactor, ptLeft, ptRight, false, "W1");
3108                    break;
3109                case TacticalLines.BATTLE:
3110                case TacticalLines.STRONG:
3111                    AddIntegralAreaModifier(tg, tg.get_Name(), area, 0, ptCenter, ptCenter, false);
3112                    addModifierBottomSegment(tg, tg.get_EchelonSymbol());
3113                    break;
3114                case TacticalLines.PNO:
3115                    AddIntegralAreaModifier(tg, label + TSpace + tg.get_Name(), area, 0, ptCenter, ptCenter, false);
3116                    addModifierBottomSegment(tg, tg.get_EchelonSymbol());
3117                    addNModifier(tg);
3118                    break;
3119                case TacticalLines.WFZ_REVD:
3120                    AddIntegralAreaModifier(tg, label, area, -1.5 * csFactor, ptCenter, ptCenter, true);
3121                    AddIntegralAreaModifier(tg, tg.get_Name(), area, -0.5 * csFactor, ptCenter, ptCenter, true);
3122                    AddIntegralAreaModifier(tg, "TIME FROM: " + tg.get_DTG(), area, 0.5 * csFactor, ptCenter, ptCenter, true, "W");
3123                    AddIntegralAreaModifier(tg, "TIME TO: " + tg.get_DTG1(), area, 1.5 * csFactor, ptCenter, ptCenter, true, "W1");
3124                    break;
3125                case TacticalLines.WFZ:
3126                    AddIntegralAreaModifier(tg, label, area, -2.5 * csFactor, ptCenter, ptCenter, true);
3127                    AddIntegralAreaModifier(tg, tg.get_Name(), area, -1.5 * csFactor, ptCenter, ptCenter, true);
3128                    AddIntegralAreaModifier(tg, "TIME FROM: " + tg.get_DTG(), area, -0.5 * csFactor, ptCenter, ptCenter, true, "W");
3129                    AddIntegralAreaModifier(tg, "TIME TO: " + tg.get_DTG1(), area, 0.5 * csFactor, ptCenter, ptCenter, true, "W1");
3130                    AddIntegralAreaModifier(tg, "MIN ALT: " + tg.get_X(), area, 1.5 * csFactor, ptCenter, ptCenter, false, "H");
3131                    AddIntegralAreaModifier(tg, "MAX ALT: " + tg.get_X1(), area, 2.5, ptCenter, ptCenter, false, "H1");
3132                    break;
3133                case TacticalLines.OBSFAREA:
3134                    AddIntegralAreaModifier(tg, label, area, -1.5 * csFactor, ptCenter, ptCenter, false);
3135                    AddIntegralAreaModifier(tg, tg.get_Name(), area, -0.5 * csFactor, ptCenter, ptCenter, false);
3136                    AddIntegralAreaModifier(tg, tg.get_DTG() + WDash, area, 0.5 * csFactor, ptCenter, ptCenter, false, "W");
3137                    AddIntegralAreaModifier(tg, tg.get_DTG1(), area, 1.5 * csFactor, ptCenter, ptCenter, false, "W1");
3138                    break;
3139                case TacticalLines.OBSAREA:
3140                    AddIntegralAreaModifier(tg, tg.get_Name(), area, -1 * csFactor, ptCenter, ptCenter, true);
3141                    AddIntegralAreaModifier(tg, tg.get_DTG() + WDash, area, 0, ptCenter, ptCenter, true, "W");
3142                    AddIntegralAreaModifier(tg, tg.get_DTG1(), area, 1 * csFactor, ptCenter, ptCenter, true, "W1");
3143                    break;
3144                case TacticalLines.ROZ:
3145                case TacticalLines.AARROZ:
3146                case TacticalLines.UAROZ:
3147                case TacticalLines.WEZ:
3148                case TacticalLines.FEZ:
3149                case TacticalLines.JEZ:
3150                case TacticalLines.FAADZ:
3151                case TacticalLines.HIDACZ:
3152                case TacticalLines.MEZ:
3153                case TacticalLines.LOMEZ:
3154                case TacticalLines.HIMEZ:
3155                    AddIntegralAreaModifier(tg, label, area, -2.5, ptCenter, ptCenter, false, "");
3156                    AddIntegralAreaModifier(tg, tg.get_Name(), area, -1.5, ptCenter, ptCenter, false, "T");
3157                    AddIntegralAreaModifier(tg, "MIN ALT: " + tg.get_X(), area, -0.5, ptCenter, ptCenter, false, "H");
3158                    AddIntegralAreaModifier(tg, "MAX ALT: " + tg.get_X1(), area, 0.5, ptCenter, ptCenter, false, "H1");
3159                    AddIntegralAreaModifier(tg, "TIME FROM: " + tg.get_DTG(), area, 1.5, ptCenter, ptCenter, false, "W");
3160                    AddIntegralAreaModifier(tg, "TIME TO: " + tg.get_DTG1(), area, 2.5, ptCenter, ptCenter, false, "W1");
3161                    break;
3162                case TacticalLines.ENCIRCLE:
3163                    if (tg.isHostile()) {
3164                        AddIntegralModifier(tg, tg.get_N(), aboveMiddle, 0, 0, 1, true);
3165                        AddIntegralModifier(tg, tg.get_N(), aboveMiddle, 0, middleSegment, middleSegment + 1, true);
3166                    }
3167                    break;
3168                case TacticalLines.LAA:
3169                    AddIntegralAreaModifier(tg, getImageModifier(tg), areaImage, 0, ptCenter, ptCenter, false);
3170                    AddIntegralAreaModifier(tg, label, area, -1 * csFactor, ptCenter, ptCenter, false);
3171                    break;
3172                case TacticalLines.BOUNDARY:
3173                    if (clipRect != null) {
3174                        AddBoundaryModifiers(tg, g2d, clipRect);
3175                    } else {
3176                        AddBoundaryModifiers(tg, g2d, clipArray);
3177                    }
3178                    break;
3179                case TacticalLines.CFL:
3180                    stringWidth = (int) ((double) metrics.stringWidth(label + TSpace + tg.get_Name()));
3181                    stringWidth2 = (int) ((double) metrics.stringWidth(tg.get_DTG() + WDash + tg.get_DTG1()));
3182                    if (stringWidth2 > stringWidth) {
3183                        stringWidth = stringWidth2;
3184                    }
3185                    pt0 = new POINT2(tg.Pixels.get(middleSegment));
3186                    pt1 = new POINT2(tg.Pixels.get(middleSegment + 1));
3187                    getPixelsMiddleSegment(tg, stringWidth, pt0, pt1);
3188                    AddModifier2(tg, label + TSpace + tg.get_Name(), aboveMiddle, -0.7 * csFactor, pt0, pt1, false);
3189                    addDTG(tg, aboveMiddle, 0.7 * csFactor, 1.7 * csFactor, pt0, pt1, metrics);
3190                    break;
3191                case TacticalLines.FLOT:
3192                    if (tg.get_H().equals("1")) {
3193                        label = "LC";
3194                    } else if (tg.get_H().equals("2")) {
3195                        label = "";
3196                    }
3197                    AddIntegralAreaModifier(tg, label, toEnd, 0, pt0, pt1, false);
3198                    AddIntegralAreaModifier(tg, label, toEnd, 0, ptLast, ptNextToLast, false);
3199
3200                    if (tg.isHostile()) {
3201                        AddIntegralAreaModifier(tg, tg.get_N(), toEnd, -1 * csFactor, pt0, pt1, false);
3202                        AddIntegralAreaModifier(tg, tg.get_N(), toEnd, -1 * csFactor, ptLast, ptNextToLast, false);
3203                    }
3204                    break;
3205                case TacticalLines.LC:
3206                    double shiftFactor = 1d;
3207                    if (shiftLines) {
3208                        shiftFactor = 0.5d;
3209                    }
3210                    if (tg.isHostile()) {
3211                        if (pt0.x < pt1.x) {
3212                            TLineFactor = -shiftFactor;//was -1
3213                        } else {
3214                            TLineFactor = shiftFactor;//was 1
3215                        }
3216                        AddIntegralAreaModifier(tg, tg.get_N(), toEnd, TLineFactor, pt0, pt1, false);
3217                        if (ptNextToLast.x < ptLast.x) {
3218                            TLineFactor = -shiftFactor;//was -1
3219                        } else {
3220                            TLineFactor = shiftFactor;//was 1
3221                        }
3222                        AddIntegralAreaModifier(tg, tg.get_N(), toEnd, TLineFactor, ptLast, ptNextToLast, false);
3223                    }
3224                    AddIntegralAreaModifier(tg, label, toEnd, 0, pt0, pt1, false);
3225                    AddIntegralAreaModifier(tg, label, toEnd, 0, ptLast, ptNextToLast, false);
3226                    break;
3227                case TacticalLines.CATK:
3228                    AddIntegralModifier(tg, label, aboveMiddle, 0, 1, 0, false);
3229                    break;
3230                case TacticalLines.CATKBYFIRE:
3231                    stringWidth = (int) (1.5 * (double) metrics.stringWidth(label));
3232                    pt2 = lineutility.ExtendAlongLineDouble(pt0, pt1, stringWidth);
3233                    AddModifier2(tg, label, aboveMiddle, 0, pt1, pt2, false);
3234                    break;
3235                case TacticalLines.IL:
3236                    AddIntegralModifier(tg, tg.get_Name(), aboveMiddle, 0, 1, 0, false);
3237                    break;
3238                case TacticalLines.RETIRE:
3239                case TacticalLines.PURSUIT:
3240                case TacticalLines.WITHDRAW:
3241                case TacticalLines.DISENGAGE:
3242                case TacticalLines.WDRAWUP:
3243                case TacticalLines.FPOL:
3244                case TacticalLines.RPOL:
3245                case TacticalLines.DEMONSTRATE:
3246                    AddIntegralModifier(tg, label, aboveMiddle, 0, 0, 1, true);
3247                    break;
3248                case TacticalLines.RIP:
3249                case TacticalLines.BOMB:
3250                case TacticalLines.TGMF:
3251                    AddIntegralAreaModifier(tg, label, area, 0, ptCenter, ptCenter, true);
3252                    break;
3253                case TacticalLines.MSDZ:
3254                    AddIntegralAreaModifier(tg, "1", area, 0, pt1, pt1, true);
3255                    AddIntegralAreaModifier(tg, "2", area, 0, pt2, pt2, true);
3256                    AddIntegralAreaModifier(tg, "3", area, 0, pt3, pt3, true);
3257                    break;
3258                case TacticalLines.DELAY:
3259                    AddIntegralModifier(tg, tg.get_DTG(), aboveMiddle, -1 * csFactor, 0, 1, false);
3260                    AddIntegralModifier(tg, label, aboveMiddle, 0, 0, 1, true);
3261                    break;
3262                case TacticalLines.GENERIC_LINE:
3263                    pt0 = tg.Pixels.get(0);
3264                    pt1 = tg.Pixels.get(1);
3265                    pt2 = tg.Pixels.get(tg.Pixels.size() - 1);
3266                    pt3 = tg.Pixels.get(tg.Pixels.size() - 2);
3267                    dist = lineutility.CalcDistanceDouble(pt0, pt1);
3268                    dist2 = lineutility.CalcDistanceDouble(pt2, pt3);
3269                    stringWidth = (int) ((double) metrics.stringWidth(tg.get_H() + " " + tg.get_Name()));
3270                    stringWidth2 = (int) ((double) metrics.stringWidth(tg.get_DTG()));
3271                    if (stringWidth2 > stringWidth) {
3272                        stringWidth = stringWidth2;
3273                    }
3274
3275                    if (tg.Pixels.size() == 2) //one segment
3276                    {
3277                        pt1 = lineutility.ExtendAlongLineDouble(pt0, pt1, stringWidth);
3278                        AddModifier2(tg, tg.get_H() + " " + tg.get_Name(), aboveMiddle, -0.7 * csFactor, pt0, pt1, false);
3279                        AddModifier2(tg, tg.get_DTG() + WDash, aboveMiddle, 0.7 * csFactor, pt0, pt1, false);
3280                        AddModifier2(tg, tg.get_DTG1(), aboveMiddle, 1.7 * csFactor, pt0, pt1, false);
3281                        if (dist > 3.5 * stringWidth)//was 28stringwidth+5
3282                        {
3283                            pt0 = tg.Pixels.get(tg.Pixels.size() - 1);
3284                            pt1 = tg.Pixels.get(tg.Pixels.size() - 2);
3285                            pt1 = lineutility.ExtendAlongLineDouble(pt0, pt1, stringWidth);
3286                            AddModifier2(tg, tg.get_H() + " " + tg.get_Name(), aboveMiddle, -0.7 * csFactor, pt0, pt1, false);
3287                            AddModifier2(tg, tg.get_DTG() + WDash, aboveMiddle, 0.7 * csFactor, pt0, pt1, false);
3288                            AddModifier2(tg, tg.get_DTG1(), aboveMiddle, 1.7 * csFactor, pt0, pt1, false);
3289                        }
3290                    } else //more than one semgent
3291                    {
3292                        double dist3 = lineutility.CalcDistanceDouble(pt0, pt2);
3293                        if (dist > stringWidth + 5 || dist >= dist2 || dist3 > stringWidth + 5) {
3294                            pt1 = lineutility.ExtendAlongLineDouble(pt0, pt1, stringWidth);
3295                            AddModifier2(tg, tg.get_H() + " " + tg.get_Name(), aboveMiddle, -0.7 * csFactor, pt0, pt1, false);
3296                            AddModifier2(tg, tg.get_DTG() + WDash, aboveMiddle, 0.7 * csFactor, pt0, pt1, false);
3297                            AddModifier2(tg, tg.get_DTG1(), aboveMiddle, 1.7 * csFactor, pt0, pt1, false);
3298                        }
3299                        if (dist2 > stringWidth + 5 || dist2 > dist || dist3 > stringWidth + 5) {
3300                            pt0 = tg.Pixels.get(tg.Pixels.size() - 1);
3301                            pt1 = tg.Pixels.get(tg.Pixels.size() - 2);
3302                            pt1 = lineutility.ExtendAlongLineDouble(pt0, pt1, stringWidth);
3303                            AddModifier2(tg, tg.get_H() + " " + tg.get_Name(), aboveMiddle, -0.7 * csFactor, pt0, pt1, false);
3304                            AddModifier2(tg, tg.get_DTG() + WDash, aboveMiddle, 0.7 * csFactor, pt0, pt1, false);
3305                            AddModifier2(tg, tg.get_DTG1(), aboveMiddle, 1.7 * csFactor, pt0, pt1, false);
3306                        }
3307                    }
3308                    break;
3309                default:
3310                    break;
3311            }
3312            scaleModifiers(tg);
3313            tg.Pixels = origPoints;
3314        } catch (Exception exc) {
3315            ErrorLogger.LogException(_className, "AddModifiersGeo",
3316                    new RendererException("Failed inside AddModifiersGeo", exc));
3317        }
3318
3319    }
3320
3321    /**
3322     * RFA, NFA, FFA need these for line spacing
3323     *
3324     * @param tg
3325     * @return
3326     */
3327    private static int getRFALines(TGLight tg) {
3328        int lines = 1;
3329        try {
3330            if (tg.get_Name() != null && !tg.get_Name().isEmpty()) {
3331                lines++;
3332            }
3333            if (tg.get_DTG() != null && !tg.get_DTG().isEmpty()) {
3334                lines++;
3335            } else if (tg.get_DTG1() != null && !tg.get_DTG1().isEmpty()) {
3336                lines++;
3337            }
3338        } catch (Exception exc) {
3339            ErrorLogger.LogException(_className, "AddModifiers",
3340                    new RendererException("Failed inside AddModifiers", exc));
3341        }
3342        return lines;
3343    }
3344
3345    /**
3346     * Added sector range fan modifiers based using the calculated orientation
3347     * indicator points
3348     *
3349     * @param tg
3350     * @param converter
3351     * @return
3352     */
3353    private static void addSectorModifiers(TGLight tg, IPointConversion converter) {
3354        try {
3355            if (tg.get_LineType() == TacticalLines.RANGE_FAN_SECTOR) {
3356                ArrayList<Double> AM = new ArrayList<>();
3357                ArrayList<Double> AN = new ArrayList<>();
3358                //get the number of sectors
3359                String X = tg.get_X();
3360                String[] altitudes = null;
3361                String[] am = tg.get_AM().split(",");
3362                String[] an = tg.get_AN().split(",");
3363                int numSectors = an.length / 2;
3364                //there must be at least one sector
3365                if (numSectors < 1) {
3366                    return;
3367                }
3368                if (!X.isEmpty()) {
3369                    altitudes = X.split(",");
3370                }
3371                try {
3372                    for (String s : am) {
3373                        AM.add(Double.parseDouble(s));
3374                    }
3375                    for (String s : an) {
3376                        AN.add(Double.parseDouble(s));
3377                    }
3378                } catch (NumberFormatException e) {
3379                    return;
3380                }
3381                if (numSectors + 1 > AM.size()) {
3382                    if (Double.parseDouble(am[0]) != 0d) {
3383                        AM.add(0, 0d);
3384                    }
3385                }
3386
3387                int n = tg.Pixels.size();
3388                //pt0 and pt1 are points for the location indicator
3389                POINT2 pt0 = tg.Pixels.get(n - 5);
3390                POINT2 pt1 = tg.Pixels.get(n - 4);
3391                Point2D pt02d = new Point2D.Double(pt0.x, pt0.y);
3392                Point2D pt12d = new Point2D.Double(pt1.x, pt1.y);
3393                pt02d = converter.PixelsToGeo(pt02d);
3394                pt12d = converter.PixelsToGeo(pt12d);
3395                pt0.x = pt02d.getX();
3396                pt0.y = pt02d.getY();
3397                pt1.x = pt12d.getX();
3398                pt1.y = pt12d.getY();
3399                //azimuth of the orientation indicator
3400                double az12 = mdlGeodesic.GetAzimuth(pt0, pt1);
3401
3402                POINT2 pt2 = null;
3403                ArrayList<POINT2> locModifier = new ArrayList();
3404                //diagnostic
3405                POINT2 ptLeft = null, ptRight = null;
3406                ArrayList<POINT2> locAZModifier = new ArrayList();
3407                //end section
3408                Point2D pt22d = null;
3409                double radius = 0;
3410                for (int k = 0; k < numSectors; k++) {
3411                    if (AM.size() < k + 2) {
3412                        break;
3413                    }
3414                    radius = (AM.get(k) + AM.get(k + 1)) / 2;
3415                    pt2 = mdlGeodesic.geodesic_coordinate(pt0, radius, az12);
3416                    //need locModifier in geo pixels
3417                    pt22d = new Point2D.Double(pt2.x, pt2.y);
3418                    pt22d = converter.GeoToPixels(pt22d);
3419                    pt2.x = pt22d.getX();
3420                    pt2.y = pt22d.getY();
3421                    locModifier.add(pt2);
3422                    //diagnostic
3423                    if (tg.get_HideOptionalLabels())
3424                        continue;
3425                    ptLeft = mdlGeodesic.geodesic_coordinate(pt0, radius, AN.get(2 * k));
3426                    //need ptLeft in geo pixels
3427                    pt22d = new Point2D.Double(ptLeft.x, ptLeft.y);
3428                    pt22d = converter.GeoToPixels(pt22d);
3429                    ptLeft.x = pt22d.getX();
3430                    ptLeft.y = pt22d.getY();
3431                    ptRight = mdlGeodesic.geodesic_coordinate(pt0, radius, AN.get(2 * k + 1));
3432                    //need ptRight in geo pixels
3433                    pt22d = new Point2D.Double(ptRight.x, ptRight.y);
3434                    pt22d = converter.GeoToPixels(pt22d);
3435                    ptRight.x = pt22d.getX();
3436                    ptRight.y = pt22d.getY();
3437                    locAZModifier.add(ptLeft);
3438                    locAZModifier.add(ptRight);
3439                    //end section
3440                }
3441                if (altitudes != null) {
3442                    for (int k = 0; k < altitudes.length; k++) {
3443                        if (k >= locModifier.size()) {
3444                            break;
3445                        }
3446                        pt0 = locModifier.get(k);
3447                        AddAreaModifier(tg, "ALT " + altitudes[k], area, 0, pt0, pt0);
3448                    }
3449                }
3450
3451                if (!tg.get_HideOptionalLabels()) {
3452                    for (int k = 0; k < numSectors; k++) {
3453                        pt0 = locModifier.get(k);
3454                        AddAreaModifier(tg, "RG " + removeDecimal(AM.get(k + 1)), area, -1, pt0, pt0);
3455                        ptLeft = locAZModifier.get(2 * k);
3456                        ptRight = locAZModifier.get(2 * k + 1);
3457                        AddAreaModifier(tg, removeDecimal(an[2 * k]), area, 0, ptLeft, ptLeft);
3458                        AddAreaModifier(tg, removeDecimal(an[2 * k + 1]), area, 0, ptRight, ptRight);
3459                    }
3460                }
3461            } else if (tg.get_LineType() == TacticalLines.RADAR_SEARCH) {
3462                // Copies functionality from RANGE_FAN_SECTOR with one sector and different modifiers
3463                String strLeftRightMinMax = tg.get_LRMM();
3464                String[] sector = strLeftRightMinMax.split(",");
3465                double left = Double.parseDouble(sector[0]);
3466                double right = Double.parseDouble(sector[1]);
3467
3468                while (left > 360) {
3469                    left -= 360;
3470                }
3471                while (right > 360) {
3472                    right -= 360;
3473                }
3474                while (left < 0) {
3475                    left += 360;
3476                }
3477                while (right < 0) {
3478                    right += 360;
3479                }
3480
3481                double orientation = 0;
3482                if (left > right) {
3483                    orientation = (left - 360 + right) / 2;
3484                } else {
3485                    orientation = (left + right) / 2;
3486                }
3487
3488                double dist = Double.parseDouble(sector[3]);
3489                double radius = dist * 1.1;
3490
3491                POINT2 pt0 = tg.LatLongs.get(0);
3492                Point2D ptPixels = converter.GeoToPixels(new Point2D.Double(pt0.x, pt0.y));
3493                POINT2 pt0F = new POINT2();
3494                pt0F.x = ptPixels.getX();
3495                pt0F.y = ptPixels.getY();
3496                pt0F.style = pt0.style;
3497
3498                POINT2 pt1 = mdlGeodesic.geodesic_coordinate(pt0, radius, orientation);
3499                ptPixels = converter.GeoToPixels(new Point2D.Double(pt1.x, pt1.y));
3500                POINT2 pt1F = new POINT2();
3501                pt1F.x = ptPixels.getX();
3502                pt1F.y = ptPixels.getY();
3503                pt1F.style = pt1.style;
3504
3505                dist = lineutility.CalcDistanceDouble(pt0F, pt1F);
3506                double base = 10;
3507                if (dist < 100) {
3508                    base = dist / 10;
3509                }
3510                if (base < 5) {
3511                    base = 5;
3512                }
3513                double basex2 = 2 * base;
3514                POINT2 ptTipF = lineutility.ExtendAlongLineDouble(pt0F, pt1F, dist + basex2);  //was 20
3515
3516                pt0 = pt0F;
3517                pt1 = ptTipF;
3518
3519                ArrayList<Double> AM = new ArrayList<>();
3520                String[] am = tg.get_AM().split(",");
3521
3522                for (String s : am) {
3523                    AM.add(Double.parseDouble(s));
3524                }
3525
3526                if (AM.size() < 2) {
3527                    if (Double.parseDouble(am[0]) != 0d) {
3528                        AM.add(0, 0d);
3529                    } else {
3530                        return;
3531                    }
3532                }
3533
3534                Point2D pt02d = new Point2D.Double(pt0.x, pt0.y);
3535                Point2D pt12d = new Point2D.Double(pt1.x, pt1.y);
3536                pt02d = converter.PixelsToGeo(pt02d);
3537                pt12d = converter.PixelsToGeo(pt12d);
3538                pt0.x = pt02d.getX();
3539                pt0.y = pt02d.getY();
3540                pt1.x = pt12d.getX();
3541                pt1.y = pt12d.getY();
3542                double az12 = mdlGeodesic.GetAzimuth(pt0, pt1);
3543
3544                Point2D pt22d = null;
3545
3546                radius = (AM.get(0) + AM.get(1)) / 2;
3547                POINT2 pt2 = mdlGeodesic.geodesic_coordinate(pt0, radius, az12);
3548                pt22d = new Point2D.Double(pt2.x, pt2.y);
3549                pt22d = converter.GeoToPixels(pt22d);
3550                pt2.x = pt22d.getX();
3551                pt2.y = pt22d.getY();
3552                AddAreaModifier(tg, tg.get_Name(), area, -1, pt2, pt2);
3553            }
3554        } catch (Exception exc) {
3555            ErrorLogger.LogException(_className, "addSectorModifiers",
3556                    new RendererException("Failed inside addSectorModifiers", exc));
3557        }
3558    }
3559
3560    /**
3561     * Called by the renderer after tg.Pixels has been filled with the
3562     * calculated points. The modifier path depends on points calculated by
3563     * CELineArray.
3564     *
3565     * @param tg
3566     */
3567    public static void AddModifiers2(TGLight tg, IPointConversion converter) {
3568        try {
3569            if (tg.Pixels == null || tg.Pixels.isEmpty()) {
3570                return;
3571            }
3572            switch (tg.get_LineType()) {
3573                case TacticalLines.BS_RECTANGLE:
3574                case TacticalLines.BBS_RECTANGLE:
3575                case TacticalLines.CONVOY:
3576                case TacticalLines.HCONVOY:
3577                case TacticalLines.BREACH:
3578                case TacticalLines.BYPASS:
3579                case TacticalLines.CANALIZE:
3580                case TacticalLines.PENETRATE:
3581                case TacticalLines.CLEAR:
3582                case TacticalLines.DISRUPT:
3583                case TacticalLines.FIX:
3584                case TacticalLines.ISOLATE:
3585                case TacticalLines.OCCUPY:
3586                case TacticalLines.RETAIN:
3587                case TacticalLines.SECURE:
3588                case TacticalLines.CONTROL:
3589                case TacticalLines.LOCATE:
3590                case TacticalLines.AREA_DEFENSE:
3591                case TacticalLines.CONTAIN:
3592                case TacticalLines.SEIZE:
3593                case TacticalLines.CAPTURE:
3594                case TacticalLines.EVACUATE:
3595                case TacticalLines.TURN:
3596                case TacticalLines.CORDONKNOCK:
3597                case TacticalLines.CORDONSEARCH:
3598                case TacticalLines.DENY:
3599                case TacticalLines.ESCORT:
3600                case TacticalLines.EXFILTRATION:
3601                case TacticalLines.INFILTRATION:
3602                case TacticalLines.FOLLA:
3603                case TacticalLines.FOLSP:
3604                case TacticalLines.ACA_RECTANGULAR:
3605                case TacticalLines.ACA_CIRCULAR:
3606                case TacticalLines.RECTANGULAR:
3607                case TacticalLines.CUED_ACQUISITION:
3608                case TacticalLines.CIRCULAR:
3609                case TacticalLines.BDZ:
3610                case TacticalLines.BBS_POINT:
3611                case TacticalLines.FSA_CIRCULAR:
3612                case TacticalLines.NOTACK:
3613                case TacticalLines.ATI_CIRCULAR:
3614                case TacticalLines.CFFZ_CIRCULAR:
3615                case TacticalLines.SENSOR_CIRCULAR:
3616                case TacticalLines.CENSOR_CIRCULAR:
3617                case TacticalLines.DA_CIRCULAR:
3618                case TacticalLines.CFZ_CIRCULAR:
3619                case TacticalLines.ZOR_CIRCULAR:
3620                case TacticalLines.TBA_CIRCULAR:
3621                case TacticalLines.TVAR_CIRCULAR:
3622                case TacticalLines.FFA_CIRCULAR:
3623                case TacticalLines.NFA_CIRCULAR:
3624                case TacticalLines.RFA_CIRCULAR:
3625                case TacticalLines.KILLBOXBLUE_CIRCULAR:
3626                case TacticalLines.KILLBOXPURPLE_CIRCULAR:
3627                case TacticalLines.BLOCK:
3628                case TacticalLines.FFA_RECTANGULAR:
3629                case TacticalLines.NFA_RECTANGULAR:
3630                case TacticalLines.RFA_RECTANGULAR:
3631                case TacticalLines.KILLBOXBLUE_RECTANGULAR:
3632                case TacticalLines.KILLBOXPURPLE_RECTANGULAR:
3633                case TacticalLines.FSA_RECTANGULAR:
3634                case TacticalLines.SHIP_AOI_RECTANGULAR:
3635                case TacticalLines.DEFENDED_AREA_RECTANGULAR:
3636                case TacticalLines.ATI_RECTANGULAR:
3637                case TacticalLines.CFFZ_RECTANGULAR:
3638                case TacticalLines.SENSOR_RECTANGULAR:
3639                case TacticalLines.CENSOR_RECTANGULAR:
3640                case TacticalLines.DA_RECTANGULAR:
3641                case TacticalLines.CFZ_RECTANGULAR:
3642                case TacticalLines.ZOR_RECTANGULAR:
3643                case TacticalLines.TBA_RECTANGULAR:
3644                case TacticalLines.TVAR_RECTANGULAR:
3645                case TacticalLines.PAA:
3646                case TacticalLines.PAA_RECTANGULAR:
3647                case TacticalLines.RECTANGULAR_TARGET:
3648                case TacticalLines.PAA_CIRCULAR:
3649                case TacticalLines.RANGE_FAN:
3650                case TacticalLines.RANGE_FAN_SECTOR:
3651                case TacticalLines.RADAR_SEARCH:
3652                case TacticalLines.SHIP_AOI_CIRCULAR:
3653                case TacticalLines.MFLANE:
3654                case TacticalLines.ENVELOPMENT:
3655                case TacticalLines.MOBILE_DEFENSE:
3656                    break;
3657                default:
3658                    return;
3659            }
3660            //end section
3661            ArrayList<POINT2> origPoints = lineutility.getDeepCopy(tg.Pixels);
3662            int n = tg.Pixels.size();
3663            if (tg.modifiers == null) {
3664                tg.modifiers = new ArrayList();
3665            }
3666            Font font = tg.get_Font();
3667            POINT2 ptCenter = null;
3668            double csFactor = 1d;//this will be used for text spacing the 3d map (CommandCight)
3669            //String affiliation=tg.get_Affiliation();
3670            int linetype = tg.get_LineType();
3671            POINT2 pt0 = null, pt1 = null, pt2 = null, pt3 = null;
3672            int j = 0, k = 0;
3673            double dist = 0;
3674            String label = GetCenterLabel(tg);
3675            String[] X = null;
3676            int lastIndex = tg.Pixels.size() - 1;
3677            int nextToLastIndex = 0;
3678            if (tg.Pixels.size() > 1) {
3679                nextToLastIndex = tg.Pixels.size() - 2;
3680            }
3681            POINT2 ptLast = new POINT2(tg.Pixels.get(lastIndex));
3682            POINT2 ptNextToLast = null;
3683            if (tg.Pixels.size() > 1) {
3684                ptNextToLast = new POINT2(tg.Pixels.get(nextToLastIndex));
3685            }
3686            String WDash = ""; // Dash between W and W1 if they're not empty
3687            String TSpace = "", TDash = ""; // Space or dash between label and T modifier if T isn't empty
3688            if (tg.get_DTG() != null && tg.get_DTG1() != null && !tg.get_DTG().isEmpty() && !tg.get_DTG1().isEmpty()) {
3689                WDash = " - ";
3690            }
3691            if (tg.get_Name() != null && !tg.get_Name().isEmpty()) {
3692                TSpace = " ";
3693                TDash = " - ";
3694            }
3695
3696            POINT2 ptLeft = null, ptRight = null;
3697            BufferedImage bi = new BufferedImage(8, 8, BufferedImage.TYPE_INT_ARGB);
3698            Graphics2D g2d = bi.createGraphics();
3699            g2d.setFont(tg.get_Font());
3700            FontMetrics metrics = g2d.getFontMetrics();
3701            int stringWidth = 0, rfaLines = 0;
3702            pt0 = new POINT2(tg.Pixels.get(0));
3703            if (tg.Pixels.size() > 1) {
3704                pt1 = new POINT2(tg.Pixels.get(1));
3705            }
3706
3707            POINT2[] pts = null;
3708            // if the client is the 3d map (CS) then we want to shrink the spacing bnetween 
3709            // the lines of text
3710            if (tg.get_Client().equals("cpof3d")) {
3711                csFactor = 0.9d;
3712            }
3713
3714            shiftModifierPath(tg, pt0, pt1, ptLast, ptNextToLast);
3715            switch (linetype) {
3716                case TacticalLines.BS_RECTANGLE:
3717                case TacticalLines.BBS_RECTANGLE:
3718                    pts = new POINT2[4];
3719                    for (j = 0; j < 4; j++) {
3720                        pts[j] = tg.Pixels.get(j);
3721                    }
3722                    ptCenter = lineutility.CalcCenterPointDouble2(pts, 4);
3723                    AddIntegralAreaModifier(tg, tg.get_Name(), area, -0.125 * csFactor, ptCenter, ptCenter, false);
3724                    break;
3725                case TacticalLines.CONVOY:
3726                case TacticalLines.HCONVOY:
3727                    pt2 = lineutility.MidPointDouble(tg.Pixels.get(0), tg.Pixels.get(3), 0);
3728                    pt3 = lineutility.MidPointDouble(tg.Pixels.get(1), tg.Pixels.get(2), 0);
3729                    AddIntegralAreaModifier(tg, tg.get_V(), aboveEndInside, 0, pt2, pt3, false);
3730                    AddIntegralAreaModifier(tg, tg.get_H(), aboveStartInside, 0, pt2, pt3, false);
3731                    addDTG(tg, aboveMiddle, 1.2 * csFactor, 2.2 * csFactor, pt2, pt3, metrics);
3732                    break;
3733                case TacticalLines.BREACH:
3734                case TacticalLines.BYPASS:
3735                case TacticalLines.CANALIZE:
3736                    pt0 = tg.Pixels.get(1);
3737                    pt1 = tg.Pixels.get(2);
3738                    //pt1=lineutility.ExtendAlongLineDouble(pt1, pt0, -10);
3739                    AddIntegralAreaModifier(tg, label, aboveMiddlePerpendicular, -0.125 * csFactor, pt0, pt1, true);
3740                    break;
3741                case TacticalLines.PENETRATE:
3742                case TacticalLines.CLEAR:
3743                    pt0 = tg.Pixels.get(2);
3744                    pt1 = tg.Pixels.get(3);
3745                    //pt1=lineutility.ExtendAlongLineDouble(pt1, pt0, -10);
3746                    AddIntegralAreaModifier(tg, label, aboveMiddle, -0.125 * csFactor, pt0, pt1, true);
3747                    break;
3748                case TacticalLines.DISRUPT:
3749                    pt0 = tg.Pixels.get(4);
3750                    pt1 = tg.Pixels.get(5);
3751                    //pt1=lineutility.ExtendAlongLineDouble(pt1, pt0, -10);
3752                    AddIntegralAreaModifier(tg, label, aboveMiddle, -0.125 * csFactor, pt0, pt1, true);
3753                    break;
3754                case TacticalLines.FIX:
3755                    pt0 = tg.Pixels.get(0);
3756                    pt1 = tg.Pixels.get(1);
3757                    //pt1=lineutility.ExtendAlongLineDouble(pt1, pt0, -10);
3758                    AddIntegralAreaModifier(tg, label, aboveMiddle, -0.125 * csFactor, pt0, pt1, true);
3759                    break;
3760                case TacticalLines.ISOLATE:
3761                case TacticalLines.OCCUPY:
3762                case TacticalLines.RETAIN:
3763                case TacticalLines.SECURE:
3764                case TacticalLines.CONTROL:
3765                case TacticalLines.LOCATE:
3766                case TacticalLines.AREA_DEFENSE:
3767                    pt0 = tg.Pixels.get(13);
3768                    pt1 = tg.Pixels.get(14);
3769                    //pt1=lineutility.ExtendAlongLineDouble(pt1, pt0, -10);
3770                    ptCenter = lineutility.MidPointDouble(pt0, pt1, 0);
3771                    AddIntegralAreaModifier(tg, label, aboveMiddle, -0.125 * csFactor, ptCenter, ptCenter, true);
3772                    break;
3773                case TacticalLines.CONTAIN:
3774                    pt0 = tg.Pixels.get(13);
3775                    pt1 = tg.Pixels.get(14);
3776                    //pt1=lineutility.ExtendAlongLineDouble(pt1, pt0, -10);
3777                    AddIntegralAreaModifier(tg, label, aboveMiddle, -0.125 * csFactor, pt0, pt1, true);
3778
3779                    // Contain always has "ENY" even if friendly (not N modifier)
3780                    for (j = 0; j < n; j++) {
3781                        if (tg.Pixels.get(j).style == 14) {
3782                            pt0 = tg.Pixels.get(j);
3783                            pt1 = tg.Pixels.get(j + 1);
3784                            AddIntegralAreaModifier(tg, "ENY", aboveMiddle, 0, pt0, pt1, true);
3785                            break;
3786                        }
3787                    }
3788                    break;
3789                case TacticalLines.TURN:
3790                    pt0 = tg.Pixels.get(12);
3791                    pt1 = tg.Pixels.get(13);
3792                    ptCenter = lineutility.MidPointDouble(pt0, pt1, 0);
3793                    AddIntegralAreaModifier(tg, label, area, -0.125 * csFactor, ptCenter, ptCenter, true);
3794                    break;
3795                case TacticalLines.SEIZE:
3796                case TacticalLines.CAPTURE:
3797                case TacticalLines.EVACUATE:
3798                    pt0 = tg.Pixels.get(26);
3799                    pt1 = tg.Pixels.get(27);
3800                    //pt1=lineutility.ExtendAlongLineDouble(pt1, pt0, -10);
3801                    ptCenter = lineutility.MidPointDouble(pt0, pt1, 0);
3802                    AddIntegralAreaModifier(tg, label, aboveMiddle, -0.125 * csFactor, ptCenter, ptCenter, true);
3803                    break;
3804                case TacticalLines.DEFENDED_AREA_RECTANGULAR:
3805                    ptLeft = lineutility.MidPointDouble(tg.Pixels.get(0), tg.Pixels.get(1), 0);
3806                    ptRight = lineutility.MidPointDouble(tg.Pixels.get(2), tg.Pixels.get(3), 0);
3807                    AddIntegralAreaModifier(tg, label + TDash + tg.get_Name(), aboveMiddle, 0, ptLeft, ptRight, false);
3808                    break;
3809                case TacticalLines.SHIP_AOI_RECTANGULAR:
3810                    if (tg.Pixels.get(0).x > tg.Pixels.get(3).x) {
3811                        AddIntegralAreaModifier(tg, label, aboveMiddle, csFactor, tg.Pixels.get(0), tg.Pixels.get(3), false);
3812                    } else {
3813                        AddIntegralAreaModifier(tg, label, aboveMiddle, csFactor, tg.Pixels.get(1), tg.Pixels.get(2), false);
3814                    }
3815                    break;
3816                case TacticalLines.NOTACK:
3817                    ptCenter = lineutility.MidPointDouble(tg.Pixels.get(0), tg.Pixels.get(tg.Pixels.size() / 2), 0);
3818                    AddIntegralAreaModifier(tg, label, area, -1, ptCenter, ptCenter, false);
3819                    addDTG(tg, area, csFactor, 2 * csFactor, ptCenter, ptCenter, metrics);
3820                 break;
3821                case TacticalLines.SHIP_AOI_CIRCULAR:
3822                    // Moved from AddModifiersGeo()
3823                    // AddModifiersGeo() called before getGeoEllipse(). Unable to use getMBR with single anchor point
3824
3825                    // Get variables from AddModifiersGeo
3826                    POINT2 lr = new POINT2(tg.Pixels.get(0));
3827                    POINT2 ll = new POINT2(tg.Pixels.get(0));
3828                    POINT2 ul = new POINT2(tg.Pixels.get(0));
3829                    POINT2 ur = new POINT2(tg.Pixels.get(0));
3830                    GetMBR(tg, ul, ur, lr, ll);
3831
3832                    AddIntegralAreaModifier(tg, label, aboveMiddle, csFactor, ll, lr, false);
3833                    break;
3834                case TacticalLines.MFLANE:
3835                    //pt0=tg.Pixels.get(7);
3836                    //pt1=tg.Pixels.get(5);
3837                    pt0 = tg.Pixels.get(4);
3838                    pt1 = tg.Pixels.get(2);
3839                    if (tg.Pixels.get(0).y < tg.Pixels.get(1).y) {
3840                        addDTG(tg, aboveMiddle, 0.5 * csFactor, 1.5 * csFactor, pt0, pt1, metrics);
3841                    } else {
3842                        addDTG(tg, aboveMiddle, -0.5 * csFactor, -1.5 * csFactor, pt0, pt1, metrics);
3843                    }
3844                    break;
3845                case TacticalLines.CORDONKNOCK:
3846                case TacticalLines.CORDONSEARCH:
3847                case TacticalLines.DENY:
3848                    pt0 = tg.Pixels.get(13);
3849                    pt1 = tg.Pixels.get(0);
3850                    stringWidth = metrics.stringWidth(label);
3851                    if (pt0.x < pt1.x) {
3852                        stringWidth = -stringWidth;
3853                    }
3854                    pt1 = lineutility.ExtendAlongLineDouble2(pt0, pt1, 0.75 * stringWidth);
3855                    ptCenter = lineutility.MidPointDouble(pt0, pt1, 0);
3856                    AddIntegralAreaModifier(tg, label, aboveMiddle, 0, ptCenter, ptCenter, true);
3857                    break;
3858                case TacticalLines.ESCORT:
3859                    if(tg.Pixels.size() == 6) {
3860                        if (tg.Pixels.get(2).x == tg.Pixels.get(3).x &&
3861                                tg.Pixels.get(2).y == tg.Pixels.get(3).y) {
3862                            //No Room for E labels
3863                            break;//?
3864                        }
3865                        AddIntegralAreaModifier(tg, label, toEnd, 0, tg.Pixels.get(2), tg.Pixels.get(1), true);
3866                        AddIntegralAreaModifier(tg, label, toEnd, 0, tg.Pixels.get(3), tg.Pixels.get(4), true);
3867                    }
3868                    break;
3869                case TacticalLines.EXFILTRATION:
3870                case TacticalLines.INFILTRATION:
3871                    AddIntegralAreaModifier(tg, label, aboveMiddle, 0, pt0, pt1 , true);
3872                    break;
3873                case TacticalLines.FOLLA:
3874                    pt0 = tg.Pixels.get(0);
3875                    pt1 = lineutility.MidPointDouble(tg.Pixels.get(5), tg.Pixels.get(6), 0);
3876                    pt1 = lineutility.ExtendAlongLineDouble(pt1, pt0, -10);
3877                    AddIntegralAreaModifier(tg, tg.get_Name(), aboveMiddle, 0, pt0, pt1, true);
3878                    break;
3879                case TacticalLines.FOLSP:
3880                    pt0 = tg.Pixels.get(3);
3881                    pt1 = tg.Pixels.get(6);
3882                    pt1 = lineutility.ExtendAlongLineDouble(pt1, pt0, -10);
3883                    AddIntegralAreaModifier(tg, tg.get_Name(), aboveMiddle, 0, pt0, pt1, true);
3884                    break;
3885                case TacticalLines.ACA_RECTANGULAR:
3886                    ptLeft = lineutility.MidPointDouble(tg.Pixels.get(0), tg.Pixels.get(1), 0);
3887                    ptRight = lineutility.MidPointDouble(tg.Pixels.get(2), tg.Pixels.get(3), 0);
3888                    AddModifier2(tg, label + TSpace + tg.get_Name(), aboveMiddle, -3 * csFactor, ptLeft, ptRight, false);
3889                    AddModifier2(tg, tg.get_T1(), aboveMiddle, -2 * csFactor, ptLeft, ptRight, false, "T1");
3890                    AddModifier2(tg, "MIN ALT: " + tg.get_X(), aboveMiddle, -1 * csFactor, ptLeft, ptRight, false, "H");
3891                    AddModifier2(tg, "MAX ALT: " + tg.get_X1(), aboveMiddle, 0, ptLeft, ptRight, false, "H1");
3892                    AddModifier2(tg, "GRID " + tg.get_Location(), aboveMiddle, 1 * csFactor, ptLeft, ptRight, false, "H2");
3893                    AddModifier2(tg, "EFF " + tg.get_DTG() + WDash, aboveMiddle, 2 * csFactor, ptLeft, ptRight, false, "W");
3894                    AddModifier2(tg, tg.get_DTG1(), aboveMiddle, 3 * csFactor, ptLeft, ptRight, false, "W1");
3895                    break;
3896                case TacticalLines.ACA_CIRCULAR:
3897                    ptCenter = lineutility.CalcCenterPointDouble2(tg.Pixels.toArray(), tg.Pixels.size());
3898                    AddIntegralAreaModifier(tg, label + TSpace + tg.get_Name(), area, -3 * csFactor, ptCenter, ptCenter, false);
3899                    AddModifier2(tg, tg.get_T1(), area, -2 * csFactor, ptCenter, ptCenter, false, "T1");
3900                    AddIntegralAreaModifier(tg, "MIN ALT: " + tg.get_X(), area, -1 * csFactor, ptCenter, ptCenter, false, "H");
3901                    AddIntegralAreaModifier(tg, "MAX ALT: " + tg.get_X1(), area, 0, ptCenter, ptCenter, false, "H1");
3902                    AddIntegralAreaModifier(tg, "GRID " + tg.get_Location(), area, 1 * csFactor, ptCenter, ptCenter, false, "H2");
3903                    AddIntegralAreaModifier(tg, "EFF " + tg.get_DTG() + WDash, area, 2 * csFactor, ptCenter, ptCenter, false, "W");
3904                    AddIntegralAreaModifier(tg, tg.get_DTG1(), area, 3 * csFactor, ptCenter, ptCenter, false, "W1");
3905                    break;
3906                case TacticalLines.FSA_CIRCULAR:
3907                case TacticalLines.ATI_CIRCULAR:
3908                case TacticalLines.CFFZ_CIRCULAR:
3909                case TacticalLines.SENSOR_CIRCULAR:
3910                case TacticalLines.CENSOR_CIRCULAR:
3911                case TacticalLines.DA_CIRCULAR:
3912                case TacticalLines.CFZ_CIRCULAR:
3913                case TacticalLines.ZOR_CIRCULAR:
3914                case TacticalLines.TBA_CIRCULAR:
3915                case TacticalLines.TVAR_CIRCULAR:
3916                case TacticalLines.KILLBOXBLUE_CIRCULAR:
3917                case TacticalLines.KILLBOXPURPLE_CIRCULAR:
3918                    ptCenter = lineutility.MidPointDouble(tg.Pixels.get(0), tg.Pixels.get(tg.Pixels.size() / 2), 0);
3919                    AddIntegralAreaModifier(tg, label, area, -0.5 * csFactor, ptCenter, ptCenter, false);
3920                    AddIntegralAreaModifier(tg, tg.get_Name(), area, 0.5 * csFactor, ptCenter, ptCenter, false);
3921                    AddOffsetModifier(tg, tg.get_DTG() + WDash, toEnd, -1 * csFactor, tg.Pixels.size() / 2, 0, 4, "left");
3922                    AddOffsetModifier(tg, tg.get_DTG1(), toEnd, 0, tg.Pixels.size() / 2, 0, 4, "left");
3923                    break;
3924                case TacticalLines.FFA_CIRCULAR:
3925                case TacticalLines.NFA_CIRCULAR:
3926                case TacticalLines.RFA_CIRCULAR:
3927                    rfaLines = getRFALines(tg);
3928                    ptCenter = lineutility.MidPointDouble(tg.Pixels.get(0), tg.Pixels.get(51), 0);
3929                    switch (rfaLines) {
3930                        case 3: //2 valid modifiers and a label
3931                            AddIntegralAreaModifier(tg, label, area, -1 * csFactor, ptCenter, ptCenter, true);
3932                            AddIntegralAreaModifier(tg, tg.get_Name(), area, 0, ptCenter, ptCenter, true);
3933                            addDTG(tg, area, 1 * csFactor, 2 * csFactor, ptCenter, ptCenter, metrics);
3934                            break;
3935                        case 2: //one valid modifier and a label
3936                            AddIntegralAreaModifier(tg, label, area, -0.5 * csFactor, ptCenter, ptCenter, true);
3937                            if (tg.get_Name() != null && !tg.get_Name().isEmpty()) {
3938                                AddIntegralAreaModifier(tg, tg.get_Name(), area, 0.5 * csFactor, ptCenter, ptCenter, true);
3939                            } else {
3940                                addDTG(tg, area, 0.5 * csFactor, 1.5 * csFactor, ptCenter, ptCenter, metrics);
3941                            }
3942                            break;
3943                        default:    //one label only
3944                            AddIntegralAreaModifier(tg, label, area, 0, ptCenter, ptCenter, true);
3945                            break;
3946                    }
3947                    break;
3948                case TacticalLines.BLOCK:
3949                    //for (j = 0; j < tg.Pixels.size(); j++) 
3950                    for (j = 0; j < n; j++) {
3951                        if (tg.Pixels.get(j).style == 14) {
3952                            AddIntegralModifier(tg, label, aboveMiddle, 0, j, j + 1);
3953                            break;
3954                        }
3955                    }
3956                    break;
3957                case TacticalLines.FFA_RECTANGULAR:
3958                case TacticalLines.NFA_RECTANGULAR:
3959                case TacticalLines.RFA_RECTANGULAR:
3960                    rfaLines = getRFALines(tg);
3961                    pt0 = lineutility.MidPointDouble(tg.Pixels.get(0), tg.Pixels.get(1), 0);
3962                    pt1 = lineutility.MidPointDouble(tg.Pixels.get(2), tg.Pixels.get(3), 0);
3963                    switch (rfaLines) {
3964                        case 3: //two valid modifiers and one label
3965                            AddModifier2(tg, label, aboveMiddle, -1 * csFactor, pt0, pt1, false);
3966                            AddModifier2(tg, tg.get_Name(), aboveMiddle, 0, pt0, pt1, false);
3967                            addDTG(tg, aboveMiddle, 1 * csFactor, 2 * csFactor, pt0, pt1, metrics);
3968                            break;
3969                        case 2: //one valid modifier and one label
3970                            AddModifier2(tg, label, aboveMiddle, -0.5 * csFactor, pt0, pt1, false);
3971                            if (tg.get_Name() != null && !tg.get_Name().isEmpty()) {
3972                                AddModifier2(tg, tg.get_Name(), aboveMiddle, 0.5 * csFactor, pt0, pt1, false);
3973                            } else {
3974                              addDTG(tg, aboveMiddle, 0.5 * csFactor, 1.5 * csFactor, pt0, pt1, metrics);
3975                            }
3976                            break;
3977                        default:    //one label only
3978                            AddModifier2(tg, label, aboveMiddle, 0, pt0, pt1, false);
3979                            break;
3980                    }
3981                    break;
3982                case TacticalLines.KILLBOXBLUE_RECTANGULAR:
3983                case TacticalLines.KILLBOXPURPLE_RECTANGULAR:
3984                case TacticalLines.FSA_RECTANGULAR:
3985                case TacticalLines.ATI_RECTANGULAR:
3986                case TacticalLines.CFFZ_RECTANGULAR:
3987                case TacticalLines.SENSOR_RECTANGULAR:
3988                case TacticalLines.CENSOR_RECTANGULAR:
3989                case TacticalLines.DA_RECTANGULAR:
3990                case TacticalLines.CFZ_RECTANGULAR:
3991                case TacticalLines.ZOR_RECTANGULAR:
3992                case TacticalLines.TBA_RECTANGULAR:
3993                case TacticalLines.TVAR_RECTANGULAR:
3994                    ptLeft = lineutility.MidPointDouble(tg.Pixels.get(0), tg.Pixels.get(1), 0);
3995                    ptRight = lineutility.MidPointDouble(tg.Pixels.get(2), tg.Pixels.get(3), 0);
3996                    AddModifier2(tg, label, aboveMiddle, -0.5 * csFactor, ptLeft, ptRight, false);
3997                    AddModifier2(tg, tg.get_Name(), aboveMiddle, 0.5 * csFactor, ptLeft, ptRight, false);
3998                    pt0 = tg.Pixels.get(0);
3999                    pt1 = tg.Pixels.get(1);
4000                    pt2 = tg.Pixels.get(2);
4001                    pt3 = tg.Pixels.get(3);
4002                    if (tg.get_Client().equalsIgnoreCase("ge")) {
4003                        pt0.x -= font.getSize() / 2;
4004                        pt2.x -= font.getSize() / 2;
4005                    }
4006                    if (!tg.get_Client().equalsIgnoreCase("ge"))//added 2-27-12
4007                    {
4008                        clsUtility.shiftModifiersLeft(pt0, pt3, 12.5);
4009                        clsUtility.shiftModifiersLeft(pt1, pt2, 12.5);
4010                    }
4011                    if (ptLeft.x == ptRight.x) {
4012                        ptRight.x += 1;
4013                    }
4014                    if (ptLeft.x < ptRight.x) {
4015                        AddModifier(tg, tg.get_DTG() + WDash, toEnd, 0, pt0, pt3);//was 1,2 switched for CPOF
4016                        AddModifier(tg, tg.get_DTG1(), toEnd, 1 * csFactor, pt0, pt3);//was 1,2
4017                    } else {
4018                        AddModifier(tg, tg.get_DTG() + WDash, toEnd, 0, pt2, pt1);//was 3,0 //switched for CPOF
4019                        AddModifier(tg, tg.get_DTG1(), toEnd, 1 * csFactor, pt2, pt1);//was 3,0
4020                    }
4021
4022                    break;
4023                case TacticalLines.PAA_RECTANGULAR:
4024                    AddIntegralModifier(tg, label, aboveMiddlePerpendicular, 0, 0, 1, true);
4025                    AddIntegralModifier(tg, label, aboveMiddle, 0, 1, 2, true);
4026                    AddIntegralModifier(tg, label, aboveMiddlePerpendicular, 0, 2, 3, true);
4027                    AddIntegralModifier(tg, label, aboveMiddle, 0, 3, 0, true);
4028                    rfaLines = getRFALines(tg);
4029                    pt0 = lineutility.MidPointDouble(tg.Pixels.get(0), tg.Pixels.get(1), 0);
4030                    pt1 = lineutility.MidPointDouble(tg.Pixels.get(2), tg.Pixels.get(3), 0);
4031                    switch (rfaLines) {
4032                        case 3: // two valid modifiers
4033                            AddModifier2(tg, tg.get_Name(), aboveMiddle, -0.5, pt0, pt1, false);
4034                            addDTG(tg, aboveMiddle, 0.5 * csFactor, 1.5 * csFactor, pt0, pt1, metrics);
4035                            break;
4036                        case 2: // one valid modifier
4037                            if (tg.get_Name() != null && !tg.get_Name().isEmpty()) {
4038                                AddModifier2(tg, tg.get_Name(), aboveMiddle, 0, pt0, pt1, false);
4039                            } else {
4040                                addDTG(tg, aboveMiddle, 0, csFactor, pt0, pt1, metrics);
4041                            }
4042                            break;
4043                        default:
4044                            break;
4045                    }
4046                    break;
4047                case TacticalLines.PAA_CIRCULAR:
4048                    for (int i = 0; i < 4; i++) {
4049                        AddIntegralModifier(tg, label, area, -0.5 * csFactor, n / 4 * i, n / 4 * i, false);
4050                    }
4051
4052                    rfaLines = getRFALines(tg);
4053                    ptCenter = lineutility.MidPointDouble(tg.Pixels.get(0), tg.Pixels.get((int) (n / 2.0 + 0.5)), 0);
4054                    switch (rfaLines) {
4055                        case 3: // two valid modifiers
4056                            AddIntegralAreaModifier(tg, tg.get_Name(), area, -0.5, ptCenter, ptCenter, false);
4057                            addDTG(tg, area, 0.5 * csFactor, 1.5 * csFactor, ptCenter, ptCenter, metrics);
4058                            break;
4059                        case 2: // one valid modifier
4060                            if (tg.get_Name() != null && !tg.get_Name().isEmpty()) {
4061                                AddIntegralAreaModifier(tg, tg.get_Name(), area, 0, ptCenter, ptCenter, false);
4062                            } else {
4063                               addDTG(tg, area, 0, csFactor, ptCenter, ptCenter, metrics);
4064                            }
4065                            break;
4066                        default:
4067                            break;
4068                    }
4069                    break;
4070                case TacticalLines.RANGE_FAN:
4071                    if (tg.get_X() != null) {
4072                        X = tg.get_X().split(",");
4073                        for (j = 0; j < X.length; j++) {
4074                            if (tg.Pixels.size() > j * 102 + 25) {
4075                                pt0 = tg.Pixels.get(j * 102 + 25);
4076                                AddAreaModifier(tg, "ALT " + X[j], area, 0, pt0, pt0);
4077                            }
4078                        }
4079                    }
4080                    if(!tg.get_HideOptionalLabels())
4081                    {
4082                        String[] am = tg.get_AM().split(",");
4083                        for(j=0;j<am.length;j++)
4084                        {
4085                            if (tg.Pixels.size() > j * 102 + 25) {
4086                                pt0 = tg.Pixels.get(j * 102 + 25);
4087                                //AddAreaModifier(tg, "RG " + am[j], area, -1, pt0, pt0);
4088                                if(j==0)
4089                                    AddAreaModifier(tg, "MIN RG " + removeDecimal(am[j]), 3, -1, pt0, pt0);
4090                                else
4091                                    AddAreaModifier(tg, "MAX RG " + "(" + Integer.toString(j) + ") " + removeDecimal(am[j]), 3, -1, pt0, pt0);
4092                            }                            
4093                        }
4094                    }// end if set range fan text
4095                    break;
4096                case TacticalLines.RANGE_FAN_SECTOR:
4097                case TacticalLines.RADAR_SEARCH:
4098                    addSectorModifiers(tg, converter);
4099                    break;
4100                case TacticalLines.ENVELOPMENT:
4101                    AddIntegralModifier(tg, label, aboveMiddle, 0, 0, 1, true);
4102                    break;
4103                case TacticalLines.MOBILE_DEFENSE:
4104                    AddIntegralModifier(tg, label, area, 0, 16, 16, true);
4105                    break;
4106                default:
4107                    break;
4108            }//end switch
4109            scaleModifiers(tg);
4110            tg.Pixels = origPoints;
4111            g2d.dispose();
4112            g2d = null;
4113        } catch (Exception exc) {
4114            ErrorLogger.LogException(_className, "AddModifiers2",
4115                    new RendererException("Failed inside AddModifiers2", exc));
4116        }
4117    }
4118
4119    /**
4120     * Displays the tg modifiers using a client Graphics2D, this is an option
4121     * provided to clients for displaying modifiers without using shapes
4122     *
4123     * @param tg the tactical graphic
4124     * @param g2d the graphics object for drawing
4125     * @deprecated
4126     */
4127    public static void DisplayModifiers(TGLight tg,
4128            Graphics2D g2d) {
4129        try {
4130            Font font = g2d.getFont();
4131            int j = 0;
4132            Modifier2 modifier = null;
4133            g2d.setBackground(Color.white);
4134            POINT2 pt = null;
4135            double theta = 0;
4136            int stringWidth = 0, stringHeight = 0;
4137            FontMetrics metrics = g2d.getFontMetrics();
4138            String s = "";
4139            int x = 0, y = 0;
4140            POINT2 pt1 = null, pt2 = null;
4141            int quadrant = -1;
4142            int n = tg.Pixels.size();
4143            //for (j = 0; j < tg.modifiers.size(); j++) 
4144            for (j = 0; j < n; j++) {
4145                modifier = (Modifier2) tg.modifiers.get(j);
4146                double lineFactor = modifier.lineFactor;
4147                s = modifier.text;
4148                double x1 = 0, y1 = 0, x2 = 0, y2 = 0;
4149                pt = modifier.textPath[0];
4150                x1 = pt.x;
4151                y1 = pt.y;
4152                pt = modifier.textPath[1];
4153                x2 = pt.x;
4154                y2 = pt.y;
4155                theta = Math.atan2(y2 - y1, x2 - x1);
4156                POINT2 midPt;
4157                if (x1 > x2) {
4158                    theta -= Math.PI;
4159                }
4160                switch (modifier.type) {
4161                    case toEnd: //corresponds to LabelAndTextBeforeLineTG
4162                        g2d.rotate(theta, x1, y1);
4163                        stringWidth = metrics.stringWidth(s);
4164                        stringHeight = font.getSize();
4165                        if (x1 < x2 || (x1 == x2 && y1 > y2)) {
4166                            x = (int) x1 - stringWidth;
4167                            y = (int) y1 - (int) stringHeight / 2 + (int) (lineFactor * stringHeight);
4168                            g2d.setColor(tg.get_FontBackColor());
4169                            g2d.clearRect(x, y, stringWidth, stringHeight);
4170                            y = (int) y1 + (int) stringHeight / 2 + (int) (lineFactor * stringHeight);
4171                            g2d.setColor(tg.get_TextColor());
4172                            g2d.drawString(s, x, y);
4173                        } else {
4174                            x = (int) x1;
4175                            y = (int) y1 - (int) stringHeight / 2 + (int) (lineFactor * stringHeight);
4176                            g2d.setColor(tg.get_FontBackColor());
4177                            g2d.clearRect(x, y, stringWidth, stringHeight);
4178                            y = (int) y1 + (int) stringHeight / 2 + (int) (lineFactor * stringHeight);
4179                            g2d.setColor(tg.get_TextColor());
4180                            g2d.drawString(s, x, y);
4181                        }
4182                        break;
4183                    case aboveMiddle:
4184                        midPt = new POINT2((x1 + x2) / 2, (y1 + y2) / 2);
4185                        g2d.rotate(theta, midPt.x, midPt.y);
4186                        stringWidth = metrics.stringWidth(s);
4187                        stringHeight = font.getSize();
4188                        x = (int) midPt.x - stringWidth / 2;
4189                        y = (int) midPt.y - (int) stringHeight / 2 + (int) (lineFactor * stringHeight);
4190                        g2d.setColor(tg.get_FontBackColor());
4191                        g2d.clearRect(x, y, stringWidth, stringHeight);
4192                        y = (int) midPt.y + (int) (stringHeight / 2) + (int) (lineFactor * stringHeight);
4193                        g2d.setColor(tg.get_TextColor());
4194                        g2d.drawString(s, x, y);
4195                        break;
4196                    case area:
4197                        g2d.rotate(0, x1, y1);
4198                        stringWidth = metrics.stringWidth(s);
4199                        stringHeight = font.getSize();
4200
4201                        x = (int) x1 - stringWidth / 2;
4202                        y = (int) y1 - (int) stringHeight / 2 + (int) (lineFactor * stringHeight);
4203                        g2d.setColor(tg.get_FontBackColor());
4204                        g2d.clearRect(x, y, stringWidth, stringHeight);
4205                        y = (int) y1 + (int) (stringHeight / 2) + (int) (lineFactor * stringHeight);
4206                        g2d.setColor(tg.get_TextColor());
4207                        g2d.drawString(s, x, y);
4208                        break;
4209                    case screen:    //for SCREEN, GUARD, COVER
4210                        if (tg.Pixels.size() >= 14) {
4211                            pt1 = tg.Pixels.get(3);
4212                            pt2 = tg.Pixels.get(10);
4213                            quadrant = lineutility.GetQuadrantDouble(pt1, pt2);
4214                            theta = Math.atan2(pt2.y - pt1.y, pt2.x - pt1.x);
4215                            switch (quadrant) {
4216                                case 1:
4217                                    theta += Math.PI / 2;
4218                                    break;
4219                                case 2:
4220                                    theta -= Math.PI / 2;
4221                                    break;
4222                                case 3:
4223                                    theta -= Math.PI / 2;
4224                                    break;
4225                                case 4:
4226                                    theta += Math.PI / 2;
4227                                    break;
4228                                default:
4229                                    break;
4230                            }
4231
4232                            g2d.rotate(theta, x1, y1);
4233                            stringWidth = metrics.stringWidth(s);
4234                            stringHeight = font.getSize();
4235
4236                            x = (int) x1 - stringWidth / 2;
4237                            y = (int) y1 - (int) stringHeight / 2 + (int) (lineFactor * stringHeight);
4238                            g2d.setColor(tg.get_FontBackColor());
4239                            g2d.clearRect(x, y, stringWidth, stringHeight);
4240                            y = (int) y1 + (int) (stringHeight / 2) + (int) (lineFactor * stringHeight);
4241                            g2d.setColor(tg.get_TextColor());
4242                            g2d.drawString(s, x, y);
4243                        } else {
4244                            stringWidth = metrics.stringWidth(s);
4245                            stringHeight = font.getSize();
4246                            x = (int) tg.Pixels.get(0).x;//(int) x1 - stringWidth / 2;
4247                            y = (int) tg.Pixels.get(0).y;//(int) y1 - (int) stringHeight / 2 + (int) (lineFactor * stringHeight);
4248                            g2d.setColor(tg.get_FontBackColor());
4249                            g2d.clearRect(x, y, stringWidth, stringHeight);
4250                            y = (int) y + (int) (stringHeight / 2) + (int) (lineFactor * stringHeight);
4251                            g2d.setColor(tg.get_TextColor());
4252                            g2d.drawString(s, x, y);
4253                        }
4254                        break;
4255                    default:
4256                        break;
4257                }   //end switch
4258            }   //end for
4259        } catch (Exception exc) {
4260            ErrorLogger.LogException(_className, "DisplayModifiers",
4261                    new RendererException("Failed inside DisplayModifiers", exc));
4262        }
4263    }//end function
4264
4265    /**
4266     * Returns a Shape object for the text background for labels and modifiers
4267     *
4268     * @param tg the tactical graphic object
4269     * @param pt0 1st point of segment
4270     * @param pt1 last point of segment
4271     * @param stringWidth string width
4272     * @param stringHeight string height
4273     * @param lineFactor number of text lines above or below the segment
4274     * @param isTextFlipped true if text is flipped
4275     * @return the modifier shape
4276     */
4277    public static Shape2 BuildModifierShape(
4278            TGLight tg,
4279            POINT2 pt0,
4280            POINT2 pt1,
4281            int stringWidth,
4282            int stringHeight,
4283            double lineFactor,
4284            boolean isTextFlipped) {
4285        Shape2 modifierFill = null;
4286        try {
4287
4288            POINT2 ptTemp0 = new POINT2(pt0), ptTemp1 = new POINT2(pt1);
4289
4290            if (isTextFlipped) {
4291                lineFactor += 1;
4292            }
4293
4294            if (lineFactor < 0) //extend pt0,pt1 above the line
4295            {
4296                ptTemp0 = lineutility.ExtendDirectedLine(pt0, pt1, pt0, 2, -lineFactor * stringHeight);
4297                ptTemp1 = lineutility.ExtendDirectedLine(pt0, pt1, pt1, 2, -lineFactor * stringHeight);
4298            }
4299            if (lineFactor > 0) //extend pt0,pt1 below the line
4300            {
4301                ptTemp0 = lineutility.ExtendDirectedLine(pt0, pt1, pt0, 3, lineFactor * stringHeight);
4302                ptTemp1 = lineutility.ExtendDirectedLine(pt0, pt1, pt1, 3, lineFactor * stringHeight);
4303            }
4304            if (ptTemp0.y == ptTemp1.y) {
4305                ptTemp0.y += 1;
4306            }
4307
4308            POINT2 pt3 = null, pt4 = null, pt5 = null, pt6 = null, pt7 = null;
4309            pt3 = lineutility.ExtendAlongLineDouble(ptTemp0, ptTemp1, -stringWidth);
4310            pt4 = lineutility.ExtendDirectedLine(ptTemp1, ptTemp0, pt3, 0, stringHeight / 2);
4311            pt5 = lineutility.ExtendDirectedLine(ptTemp1, ptTemp0, pt3, 1, stringHeight / 2);
4312            pt6 = lineutility.ExtendDirectedLine(ptTemp1, ptTemp0, ptTemp0, 1, stringHeight / 2);
4313            pt7 = lineutility.ExtendDirectedLine(ptTemp1, ptTemp0, ptTemp0, 0, stringHeight / 2);
4314            modifierFill = new Shape2(Shape2.SHAPE_TYPE_MODIFIER_FILL);
4315
4316            modifierFill.moveTo(pt4);
4317            modifierFill.lineTo(pt5);
4318            modifierFill.lineTo(pt6);
4319            modifierFill.lineTo(pt7);
4320            modifierFill.lineTo(pt4);
4321        } catch (Exception exc) {
4322            ErrorLogger.LogException(_className, "BuildModifierShape",
4323                    new RendererException("Failed inside BuildModifierShape", exc));
4324        }
4325        return modifierFill;
4326    }
4327
4328    /**
4329     * For BOUNDARY and other line types which require breaks for the integral
4330     * text. Currently only boundary uses this
4331     *
4332     * @param tg
4333     * @param g2d the graphics object for drawing
4334     * @param shapes the shape array
4335     */
4336    public static void GetIntegralTextShapes(TGLight tg,
4337            Graphics2D g2d,
4338            ArrayList<Shape2> shapes) {
4339        try {
4340            if (tg.Pixels == null || shapes == null) {
4341                return;
4342            }
4343
4344            HashMap<Integer, Color> hmap = clsUtility.getMSRSegmentColors(tg);
4345            Color color = null;
4346
4347            Shape2 shape = null;
4348            Shape2 segShape = null;//diangostic 1-22-13
4349            g2d.setFont(tg.get_Font());
4350            int j = 0;
4351            String affiliation = null;
4352            FontMetrics metrics = g2d.getFontMetrics();
4353            String echelonSymbol = null;
4354            int stringWidthEchelonSymbol = 0;
4355            //boolean lineTooShort = false;
4356            POINT2 ptEchelonStart = null, ptEchelonEnd = null, midpt,
4357                    ptENY0Start = null, ptENY0End = null, ptENY1Start, ptENY1End, pt0 = null, pt1 = null;
4358            double dist = 0;
4359            BasicStroke stroke = null;
4360            switch (tg.get_LineType()) {
4361                case TacticalLines.BOUNDARY:
4362                    echelonSymbol = tg.get_EchelonSymbol();
4363                    //shapes = new ArrayList();
4364                    shape = new Shape2(Shape2.SHAPE_TYPE_POLYLINE);
4365                    shape.setLineColor(tg.get_LineColor());
4366                    shape.set_Style(tg.get_LineStyle());
4367                    stroke = clsUtility.getLineStroke(tg.get_LineThickness(), shape.get_Style(), tg.get_lineCap(), BasicStroke.JOIN_ROUND);
4368                    shape.setStroke(stroke);
4369                    if (echelonSymbol != null && !echelonSymbol.isEmpty()) {
4370                        stringWidthEchelonSymbol = metrics.stringWidth(echelonSymbol);
4371                    }
4372                    //diagnostic
4373                    if (hmap == null || hmap.isEmpty()) {
4374                        shape.moveTo(tg.Pixels.get(0));
4375                        for (j = 1; j < tg.Pixels.size(); j++) {
4376                            shape.lineTo(tg.Pixels.get(j));
4377                        }
4378                        shapes.add(shape);
4379                        break;
4380                    }
4381                    //end section
4382                    int n = tg.Pixels.size();
4383                    //for (j = 0; j < tg.Pixels.size() - 1; j++) 
4384                    for (j = 0; j < n - 1; j++) {
4385                        segShape = null;
4386                        if (hmap != null) {
4387                            if (hmap.containsKey(j)) {
4388                                color = (Color) hmap.get(j);
4389                                segShape = new Shape2(Shape2.SHAPE_TYPE_POLYLINE);
4390                                segShape.setLineColor(color);
4391                                segShape.set_Style(tg.get_LineStyle());
4392                                segShape.setStroke(stroke);
4393                            }
4394                        }
4395
4396                        pt0 = tg.Pixels.get(j);
4397                        pt1 = tg.Pixels.get(j + 1);
4398                        //lineTooShort = GetBoundarySegmentTooShort(tg, g2d, j);
4399                        if (segShape != null) {
4400                            segShape.moveTo(pt0);
4401                        } else {
4402                            shape.moveTo(pt0);
4403                        }
4404
4405                        //uncoment comment to remove line breaks for GE
4406                        //if (lineTooShort || tg.get_Client().equals("ge")) 
4407                        if (tg.get_Client().equals("ge") || GetBoundarySegmentTooShort(tg, g2d, j) == true) {
4408                            if (segShape != null) {
4409                                segShape.lineTo(pt1);
4410                                shapes.add(segShape);
4411                                continue;
4412                            } else {
4413                                shape.lineTo(pt1);
4414                                continue;
4415                            }
4416                        }
4417
4418                        midpt = lineutility.MidPointDouble(pt0, pt1, 0);
4419                        if (segShape != null) {
4420                            segShape.moveTo(pt0);
4421                        } else {
4422                            shape.moveTo(pt0);
4423                        }
4424
4425                        if (stringWidthEchelonSymbol > 0) {
4426                            midpt = lineutility.MidPointDouble(pt0, pt1, 0);
4427                            dist = lineutility.CalcDistanceDouble(pt0, midpt) - stringWidthEchelonSymbol / 1.5;
4428                            ptEchelonStart = lineutility.ExtendAlongLineDouble(pt0, pt1, dist);
4429                            dist = lineutility.CalcDistanceDouble(pt0, midpt) + stringWidthEchelonSymbol / 1.5;
4430                            ptEchelonEnd = lineutility.ExtendAlongLineDouble(pt0, pt1, dist);
4431                            if (segShape != null) {
4432                                segShape.lineTo(ptEchelonStart);
4433                                segShape.moveTo(ptEchelonEnd);
4434                            } else {
4435                                shape.lineTo(ptEchelonStart);
4436                                shape.moveTo(ptEchelonEnd);
4437                            }
4438                        }
4439                        if (segShape != null) {
4440                            segShape.lineTo(pt1);
4441                        } else {
4442                            shape.lineTo(pt1);
4443                        }
4444                        if (segShape != null) {
4445                            shapes.add(segShape);
4446                        }
4447                    }//end for
4448                    shapes.add(shape);
4449                    break;
4450                default:
4451                    break;
4452            }
4453        } catch (Exception exc) {
4454            ErrorLogger.LogException(_className, "GetIntegralTextShapes",
4455                    new RendererException("Failed inside GetIntegralTextShapes", exc));
4456        }
4457    }
4458
4459    /**
4460     * Displays the modifiers to a Graphics2D from a BufferedImage
4461     *
4462     * @param tg the tactical graphic
4463     * @param g2d the Graphic for drawing
4464     * @param shapes the shape array
4465     * @param isTextFlipped true if text is flipped
4466     * @param converter to convert between geographic and pixel coordinates
4467     */
4468    public static void DisplayModifiers2(TGLight tg,
4469            Graphics2D g2d,
4470            ArrayList<Shape2> shapes,
4471            boolean isTextFlipped,
4472            IPointConversion converter) {
4473        try {
4474            if (shapes == null) {
4475                return;
4476            }
4477
4478            if (tg.modifiers == null || tg.modifiers.isEmpty()) {
4479                return;
4480            }
4481            Font font = null;
4482            int j = 0;
4483            Modifier2 modifier = null;
4484            Color fontBackColor = tg.get_FontBackColor();
4485            double theta = 0;
4486            double stringWidth = 0, stringHeight = 0;
4487            String s = "";
4488            Bitmap image = null;
4489            int x = 0, y = 0;
4490            POINT2 pt0 = null, pt1 = null, pt2 = null, pt3 = null;
4491            int quadrant = -1;
4492            Shape2 shape2 = null;
4493            long lineType = tg.get_LineType();
4494            font = tg.get_Font();    //might have to change this
4495            if (font == null) {
4496                font = g2d.getFont();
4497            }
4498            if (font.getSize() == 0) {
4499                return;
4500            }
4501            g2d.setFont(font);
4502            FontMetrics metrics = g2d.getFontMetrics();
4503            //we need a background color
4504            if (fontBackColor != null) {
4505                g2d.setBackground(fontBackColor);
4506            } else {
4507                g2d.setBackground(Color.white);
4508            }
4509
4510            Point2D anchor = null;
4511            Point2D anchorOffset = null;
4512
4513            int direction = -1;
4514            Point glyphPosition = null;
4515            for (j = 0; j < tg.modifiers.size(); j++) {
4516                modifier = (Modifier2) tg.modifiers.get(j);
4517
4518                double lineFactor = modifier.lineFactor;
4519
4520                if (isTextFlipped) {
4521                    lineFactor = -lineFactor;
4522                }
4523
4524                s = modifier.text;
4525                if (s == null || s.equals("")) {
4526
4527                    image = modifier.image;
4528                    if (image == null) {
4529                        continue;
4530                    }
4531                }
4532                stringWidth = s != null ? (double) metrics.stringWidth(s) + 1 : image.getWidth() + 1;
4533                stringHeight = s != null ? (double) font.getSize() : image.getHeight();
4534
4535                double x1 = 0, y1 = 0, x2 = 0, y2 = 0, dist = 0;
4536                pt0 = modifier.textPath[0];
4537                x1 = Math.round(pt0.x);
4538                y1 = Math.round(pt0.y);
4539                pt1 = modifier.textPath[1];
4540                x2 = Math.round(pt1.x);
4541                y2 = Math.round(pt1.y);
4542                theta = Math.atan2(y2 - y1, x2 - x1);
4543                POINT2 midPt;
4544                if (x1 > x2) {
4545                    theta -= Math.PI;
4546                }
4547                pt0 = new POINT2(x1, y1);
4548                pt1 = new POINT2(x2, y2);
4549                midPt = new POINT2((x1 + x2) / 2, (y1 + y2) / 2);
4550                Point2D modifierPosition = null;  //use this if using justify
4551                int justify = ShapeInfo.justify_left;
4552                switch (modifier.type) {
4553                    case aboveEnd: // On line
4554                    case toEnd: // Next to line
4555                        if (x1 == x2) {
4556                            x2 += 1;
4557                        }
4558
4559                        if (lineFactor >= 0) {
4560                            direction = 2;
4561                        } else {
4562                            direction = 3;
4563                        }
4564
4565                        if (lineType == TacticalLines.LC || tg.get_Client().equalsIgnoreCase("ge")) {
4566                            direction = lineutility.reverseDirection(direction);
4567                        }
4568
4569                        if ((modifier.type == toEnd && x1 < x2) || (modifier.type == aboveEnd && x2 < x1)) {
4570                            justify = ShapeInfo.justify_right;
4571                        } else {
4572                            justify = ShapeInfo.justify_left;
4573                        }
4574
4575                        //3rd point value is location to start perpendicular line from
4576                        pt3 = lineutility.ExtendDirectedLine(pt1, pt0, pt0, direction, lineFactor * stringHeight);
4577                        //pt3 is the end point of the perpendicularline
4578
4579                        glyphPosition = new Point((int) pt3.x, (int) pt3.y);
4580                        modifierPosition = new Point2D.Double(pt3.x, pt3.y);
4581
4582                        anchor = new Point2D.Double(pt0.x, pt0.y);
4583                        anchorOffset = new Point2D.Double(pt3.x - pt0.x, pt3.y - pt0.y);
4584
4585                        break;
4586                    case aboveStartInside:
4587                        //returns pt3 which is based on the specified distance from pt0 along the line of pt0 to pt1.
4588                        pt3 = lineutility.ExtendAlongLineDouble(pt0, pt1, stringWidth);
4589
4590                        glyphPosition = new Point((int) pt3.x, (int) pt3.y);
4591                        modifierPosition = new Point2D.Double((int) pt3.x, pt3.y);
4592
4593                        anchor = new Point2D.Double(pt0.x, pt0.y);
4594                        anchorOffset = new Point2D.Double(pt3.x - pt0.x, pt3.y - pt0.y);
4595                        break;
4596                    case aboveEndInside:
4597                        //returns pt3 which is based on the specified distance from pt0 along the line of pt1 to pt0.
4598                        pt3 = lineutility.ExtendAlongLineDouble(pt1, pt0, stringWidth);
4599
4600                        glyphPosition = new Point((int) pt3.x, (int) pt3.y);
4601                        modifierPosition = new Point2D.Double((int) pt3.x, pt3.y);
4602
4603                        anchor = new Point2D.Double(pt1.x, pt1.y);
4604                        anchorOffset = new Point2D.Double(pt3.x - pt1.x, pt3.y - pt1.y);
4605                        break;
4606                    case aboveMiddle:
4607                    case aboveMiddlePerpendicular:
4608                        pt2 = midPt;
4609                        anchor = new Point2D.Double(midPt.x,midPt.y);
4610
4611                        if (tg.get_Client().equals("2D")) {
4612                            lineFactor += 0.5;
4613                        }
4614
4615                        if (lineFactor >= 0) {
4616                            pt3 = lineutility.ExtendDirectedLine(pt0, pt2, pt2, 3, Math.abs((lineFactor) * stringHeight));
4617                            midPt = lineutility.ExtendDirectedLine(pt0, midPt, midPt, 3, Math.abs((lineFactor) * stringHeight));
4618                        } else {
4619                            pt3 = lineutility.ExtendDirectedLine(pt0, pt2, pt2, 2, Math.abs((lineFactor) * stringHeight));
4620                            midPt = lineutility.ExtendDirectedLine(pt0, midPt, midPt, 2, Math.abs((lineFactor) * stringHeight));
4621                        }
4622                        //pt3=lineutility.ExtendDirectedLine(pt0, pt2, pt2, 2, lineFactor*stringHeight);
4623                        if (x1 == x2 && y1 > y2) {
4624                            pt3 = lineutility.ExtendDirectedLine(pt0, pt2, pt2, 1, Math.abs((lineFactor) * stringHeight));
4625                            midPt = lineutility.ExtendDirectedLine(pt0, midPt, midPt, 1, Math.abs((lineFactor) * stringHeight));
4626                        }
4627                        if (x1 == x2 && y1 < y2) {
4628                            pt3 = lineutility.ExtendDirectedLine(pt0, pt2, pt2, 0, Math.abs((lineFactor) * stringHeight));
4629                            midPt = lineutility.ExtendDirectedLine(pt0, midPt, midPt, 0, Math.abs((lineFactor) * stringHeight));
4630                        }
4631
4632                        glyphPosition = new Point((int) pt3.x, (int) pt3.y);
4633                        justify = ShapeInfo.justify_center;
4634                        modifierPosition = new Point2D.Double(midPt.x, midPt.y);
4635
4636                        //anchor = new Point2D.Double(midPt.x, midPt.y);
4637                        anchorOffset = new Point2D.Double(midPt.x - anchor.getX(), midPt.y - anchor.getY());
4638
4639                        if(modifier.type == aboveMiddlePerpendicular) {
4640                            // Need to negate the original rotation
4641                            if (x1 > x2) {
4642                                theta += Math.PI;
4643                            }
4644                            // Adjust the label rotation based on the y values
4645                            if (y1 > y2) {
4646                                theta += Math.PI;
4647                            }
4648                            // Rotate by 90 degrees. This is how we rotate the label perpendicular to the line
4649                            theta -= Math.PI / 2;
4650                        }
4651                        break;
4652                    case area:
4653                        theta = 0;
4654
4655                        //y = (int) y1 + (int) (stringHeight / 2) + (int) (1.25 * lineFactor * stringHeight);
4656                        y = (int) y1 + (int) (stringHeight / 2) + (int) (lineFactor * stringHeight);
4657                        x = image != null ? (int) (x1 - stringWidth / 3) : (int) x1;
4658
4659                        glyphPosition = new Point(x, y);
4660                        justify = ShapeInfo.justify_center;
4661                        modifierPosition = new Point2D.Double(x, y);
4662
4663                        anchor = new Point2D.Double(x1, y1);
4664                        anchorOffset = new Point2D.Double(x - x1, y - y1);
4665                        break;
4666                    case areaImage:
4667                        glyphPosition = new Point((int)x1, (int)y1);
4668                        justify = ShapeInfo.justify_center;
4669                        modifierPosition = new Point2D.Double((int)x1, (int)y1);
4670
4671                        anchor = new Point2D.Double(x1, y1);
4672                        anchorOffset = new Point2D.Double(0, 0);
4673                        break;
4674                    case screen:    //for SCREEN, GUARD, COVER, not currently used
4675                        if (tg.Pixels.size() >= 14) {
4676                            pt1 = tg.Pixels.get(3);
4677                            pt2 = tg.Pixels.get(10);
4678                            quadrant = lineutility.GetQuadrantDouble(pt1, pt2);
4679                            theta = Math.atan2(pt2.y - pt1.y, pt2.x - pt1.x);
4680                            if (Math.abs(theta) < Math.PI / 8) {
4681                                if (theta < 0) {
4682                                    theta -= Math.PI / 2;
4683                                } else {
4684                                    theta += Math.PI / 2;
4685                                }
4686                            }
4687                            switch (quadrant) {
4688                                case 1:
4689                                    theta += Math.PI / 2;
4690                                    break;
4691                                case 2:
4692                                    theta -= Math.PI / 2;
4693                                    break;
4694                                case 3:
4695                                    theta -= Math.PI / 2;
4696                                    break;
4697                                case 4:
4698                                    theta += Math.PI / 2;
4699                                    break;
4700                                default:
4701                                    break;
4702                            }
4703
4704                            x = (int) x1 - (int) stringWidth / 2;
4705                            y = (int) y1 - (int) stringHeight / 2 + (int) (lineFactor * stringHeight);
4706                            y = (int) y1 + (int) (stringHeight / 2) + (int) (lineFactor * stringHeight);
4707                            anchor = new Point2D.Double(x1, y1);
4708                        } else {
4709                            theta = 0;
4710                            x = (int) tg.Pixels.get(0).x;
4711                            y = (int) tg.Pixels.get(0).y;
4712                            anchor = new Point2D.Double(x, y);
4713                            x = (int) x - (int) stringWidth / 2;
4714                            y = (int) y - (int) stringHeight / 2 + (int) (lineFactor * stringHeight);
4715                            y = (int) y + (int) (stringHeight / 2) + (int) (lineFactor * stringHeight);
4716                        }
4717
4718                        glyphPosition = new Point(x, y);
4719                        //glyphPosition=new Point2D.Double(x,y);
4720                        //anchor = new Point2D.Double(x1, y1);
4721                        anchorOffset = new Point2D.Double(x - anchor.getX(), y - anchor.getY());
4722                        break;
4723                    default:
4724                        break;
4725                }   //end switch
4726
4727                shape2 = new Shape2(Shape2.SHAPE_TYPE_MODIFIER_FILL);
4728
4729                shape2.setStroke(new BasicStroke(0, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 3));
4730
4731                if (tg.get_TextColor() != null) {
4732                    shape2.setFillColor(tg.get_TextColor());
4733                } else if (tg.get_LineColor() != null) {
4734                    shape2.setFillColor(tg.get_LineColor());
4735                }
4736                if (tg.get_LineColor() != null) {
4737                    shape2.setLineColor(tg.get_LineColor());
4738                }
4739                //only GE uses the converter, generic uses the affine transform and draws at 0,0
4740                if (converter != null) {
4741                    shape2.setGlyphPosition(glyphPosition);
4742                } else {
4743                    shape2.setGlyphPosition(new Point2D.Double(0, 0));
4744                }
4745                //shape2.setGlyphPosition(new Point(0,0));
4746                //added two settings for use by GE
4747                if(s != null && !s.equals("")) {
4748                    shape2.setModifierString(s);
4749                    TextLayout tl = new TextLayout(s, font, g2d.getFontMetrics().getFontRenderContext());
4750                    shape2.setTextLayout(tl);
4751                    shape2.setTextJustify(justify);
4752                } else if (image != null) {
4753                    shape2.setModifierImage(image);
4754                }
4755                //shape2.setModifierStringPosition(glyphPosition);//M. Deutch 7-6-11
4756                shape2.setModifierAngle(theta * 180 / Math.PI);
4757                shape2.setModifierPosition(modifierPosition);
4758                shape2.setModifierAnchor(anchor);
4759                shape2.setModifierAnchorOffset(anchorOffset);
4760
4761                if (shape2 != null) {
4762                    shapes.add(shape2);
4763                }
4764
4765            }   //end for
4766        } //end try
4767        catch (Exception exc) {
4768            ErrorLogger.LogException(_className, "DisplayModifiers2",
4769                    exc);
4770        }
4771    }//end function
4772
4773    /**
4774     * Builds a shape object to wrap text
4775     *
4776     * @param g2d the Graphic object for drawing
4777     * @param str text to wrap
4778     * @param font the draw font
4779     * @param tx the drawing transform, text rotation and translation
4780     * @return
4781     */
4782    public static Shape getTextShape(Graphics2D g2d,
4783                                     String str,
4784                                     Font font,
4785                                     AffineTransform tx) {
4786        TextLayout tl = null;
4787        FontRenderContext frc = null;
4788        try {
4789            frc = g2d.getFontRenderContext();
4790            tl = new TextLayout(str, font, frc);
4791        } catch (Exception exc) {
4792            ErrorLogger.LogException(_className, "getTextShape",
4793                    new RendererException("Failed inside getTextShape", exc));
4794        }
4795        return tl.getOutline(tx);
4796    }
4797
4798    /**
4799     * Creates text outline as a shape
4800     *
4801     * @param originalText the original text
4802     * @return text shape
4803     */
4804    public static Shape2 createTextOutline(Shape2 originalText) {
4805        Shape2 siOutline = null;
4806        try {
4807            Shape outline = originalText.getShape();
4808
4809            siOutline = new Shape2(Shape2.SHAPE_TYPE_MODIFIER_FILL);
4810            siOutline.setShape(outline);
4811
4812            if (originalText.getFillColor().getRed() == 255
4813                    && originalText.getFillColor().getGreen() == 255
4814                    && originalText.getFillColor().getBlue() == 255) {
4815                siOutline.setLineColor(Color.BLACK);
4816            } else {
4817                siOutline.setLineColor(Color.WHITE);
4818            }
4819
4820            int width = RendererSettings.getInstance().getTextOutlineWidth();
4821
4822            siOutline.setStroke(new BasicStroke(width, BasicStroke.CAP_ROUND,
4823                    BasicStroke.JOIN_ROUND, 3));
4824
4825        } catch (Exception exc) {
4826            ErrorLogger.LogException(_className, "createTextOutline",
4827                    new RendererException("Failed inside createTextOutline", exc));
4828        }
4829        return siOutline;
4830    }
4831
4832    /**
4833     * Channels don't return points in tg.Pixels. For Channels modifiers we only
4834     * need to collect the points, don't need internal arrays, and can calculate
4835     * on which segments the modifiers lie.
4836     *
4837     * @param shape
4838     * @return
4839     */
4840    private static ArrayList<POINT2> getShapePoints(Shape shape) {
4841        try {
4842            ArrayList<Point2D> ptsPoly = new ArrayList();
4843            Point2D ptPoly = null;
4844            double[] coords = new double[6];
4845            int zeros = 0;
4846            for (PathIterator i = shape.getPathIterator(null); !i.isDone(); i.next()) {
4847                int type = i.currentSegment(coords);
4848                if (type == 0 && zeros == 2) {
4849                    break;
4850                }
4851                switch (type) {
4852                    case PathIterator.SEG_MOVETO:
4853                        ptPoly = new Point2D.Double(coords[0], coords[1]);
4854                        ptsPoly.add(ptPoly);
4855                        zeros++;
4856                        break;
4857                    case PathIterator.SEG_LINETO:
4858                        ptPoly = new Point2D.Double(coords[0], coords[1]);
4859                        ptsPoly.add(ptPoly);
4860                        break;
4861                    case PathIterator.SEG_QUADTO: //quadTo was never used
4862                        break;
4863                    case PathIterator.SEG_CUBICTO:  //curveTo was used for some METOC's
4864                        break;
4865                    case PathIterator.SEG_CLOSE:    //closePath was never used
4866                        break;
4867                }
4868            }
4869            if (ptsPoly.size() > 0) {
4870                ArrayList<POINT2> pts = null;
4871                pts = new ArrayList();
4872                for (int j = 0; j < ptsPoly.size(); j++) {
4873                    Point2D pt2d = ptsPoly.get(j);
4874                    POINT2 pt = new POINT2(pt2d.getX(), pt2d.getY());
4875                    pts.add(pt);
4876                }
4877                return pts;
4878            }
4879        } catch (Exception exc) {
4880            ErrorLogger.LogException(_className, "getshapePoints",
4881                    new RendererException("Failed inside getShapePoints", exc));
4882        }
4883        return null;
4884    }
4885
4886    private static Bitmap getImageModifier(TGLight tg) {
4887        String symbolID = tg.get_SymbolId();
4888        ImageInfo symbol = null;
4889        Map<String,String> mods = new HashMap<>();
4890        Map<String,String> sa = new HashMap<>();
4891        sa.put(MilStdAttributes.PixelSize, String.valueOf(tg.get_IconSize()));
4892        int contaminationCode = EntityCode.getSymbolForContaminationArea(SymbolID.getEntityCode(symbolID));
4893        int modifier1Code = SymbolID.getModifier1(symbolID);
4894        int lineType = GetLinetypeFromString(symbolID);
4895        if (contaminationCode > 0) {
4896            sa.put(MilStdAttributes.OutlineSymbol, "true");
4897            sa.put(MilStdAttributes.FillColor, RendererUtilities.colorToHexString(tg.get_FillColor(), true));
4898            sa.put(MilStdAttributes.LineColor, RendererUtilities.colorToHexString(tg.get_LineColor(), true));
4899            String contaminationSP = SymbolID.setEntityCode(symbolID, contaminationCode);
4900            contaminationSP = SymbolID.setHQTFD(contaminationSP, 0); // Remove dummy modifier if necessary
4901            symbol = SinglePointRenderer.getInstance().RenderSP(contaminationSP, mods, sa);
4902        } else if (lineType == TacticalLines.DEPICT || lineType == TacticalLines.MINED || lineType == TacticalLines.FENCED || lineType == TacticalLines.MINE_LINE) {
4903            if (modifier1Code < 13 || modifier1Code > 50) {
4904                // Invalid mine type
4905                modifier1Code = 13;//unspecified mine (default value if not specified as per MilStd 2525)
4906                symbolID = SymbolID.setModifier1(symbolID, modifier1Code);
4907            }
4908            if (tg.get_KeepUnitRation()) {
4909                sa.put(MilStdAttributes.PixelSize, String.valueOf((int) (tg.get_IconSize() * 1.5)));
4910            }
4911            sa.put(MilStdAttributes.OutlineSymbol, "true");
4912            symbol = SinglePointRenderer.getInstance().RenderModifier(symbolID, sa);
4913        } else if (lineType == TacticalLines.LAA && modifier1Code > 0) {
4914            sa.put(MilStdAttributes.OutlineSymbol, "true");
4915            sa.put(MilStdAttributes.FillColor, RendererUtilities.colorToHexString(tg.get_FillColor(), true));
4916            sa.put(MilStdAttributes.LineColor, RendererUtilities.colorToHexString(tg.get_LineColor(), true));
4917            if (tg.get_KeepUnitRation()) {
4918                sa.put(MilStdAttributes.PixelSize, String.valueOf((int) (tg.get_IconSize() * 1.5)));
4919            }
4920            symbol = SinglePointRenderer.getInstance().RenderModifier(symbolID, sa);
4921        }
4922        else if (lineType == TacticalLines.DECISION_LINE) {
4923
4924            sa.put(MilStdAttributes.PixelSize, String.valueOf((int) (tg.get_IconSize() * 1.5)));
4925            sa.put(MilStdAttributes.KeepUnitRatio, String.valueOf((tg.get_KeepUnitRation())));
4926            sa.put(MilStdAttributes.FillColor, RendererUtilities.colorToHexString(tg.get_FillColor(), true));
4927            sa.put(MilStdAttributes.LineColor, RendererUtilities.colorToHexString(tg.get_LineColor(), true));
4928            sa.put(MilStdAttributes.OutlineSymbol, "false");
4929            mods.put(Modifiers.T_UNIQUE_DESIGNATION_1, (tg.get_Name()));
4930
4931            String decisionPoint = SymbolID.setEntityCode(symbolID, EntityCode.EntityCode_Decision_Point);
4932            symbol = SinglePointRenderer.getInstance().RenderSP(decisionPoint, mods, sa);
4933        }
4934        else if (lineType == TacticalLines.ANCHORAGE_LINE || lineType == TacticalLines.ANCHORAGE_AREA) {
4935            sa.put(MilStdAttributes.OutlineSymbol, "false");
4936            String anchorPoint = SymbolID.setEntityCode(symbolID, EntityCode.EntityCode_AnchoragePoint);
4937            symbol = SinglePointRenderer.getInstance().RenderSP(anchorPoint, mods, sa);
4938        }
4939
4940        if (symbol != null)
4941            return symbol.getImage();
4942        else
4943            return null;
4944    }
4945
4946    private static String removeDecimal(double doubleVal) {
4947        return String.valueOf(Math.round(doubleVal));
4948    }
4949
4950    private static String removeDecimal(String strDoubleVal) {
4951        if (strDoubleVal.indexOf(" ") > 0) // String contains unit
4952            return removeDecimal(Double.parseDouble(strDoubleVal.substring(0, strDoubleVal.indexOf(" ")))) + strDoubleVal.substring(strDoubleVal.indexOf(" "));
4953        else
4954            return removeDecimal(Double.parseDouble(strDoubleVal));
4955    }
4956}