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