001/*
002 * To change this template, choose Tools | Templates
003 * and open the template in the editor.
004 */
005package armyc2.c2sd.JavaLineArray;
006
007/**
008 * A class to provide the utility functions required for calculating the line
009 * points.
010 *
011 * @author Michael Deutch
012 */
013import java.util.ArrayList;
014import armyc2.c2sd.renderer.utilities.ErrorLogger;
015import armyc2.c2sd.renderer.utilities.RendererException;
016import armyc2.c2sd.renderer.utilities.RendererSettings;
017import java.io.*;
018import armyc2.c2sd.graphics2d.*;
019import armyc2.c2sd.renderer.utilities.IPointConversion;
020import armyc2.c2sd.JavaTacticalRenderer.mdlGeodesic;
021public final class lineutility {
022
023    private static final String _className = "lineutility";
024    public static final int extend_left = 0;
025    public static final int extend_right = 1;
026    public static final int extend_above = 2;
027    public static final int extend_below = 3;
028
029    /**
030     * Resizes the array to the length speicifed, called by the Channels class.
031     *
032     * @param pLinePoints the array to resize
033     * @param length the length to which to resize the array.
034     * @return the resized array
035     */
036    protected static POINT2[] ResizeArray(POINT2[] pLinePoints, int length) {
037        POINT2[] array = new POINT2[length];
038        try {
039            if (pLinePoints.length <= length) {
040                return pLinePoints;
041            }
042
043            int j = 0;
044            for (j = 0; j < length; j++) {
045                array[j] = new POINT2(pLinePoints[j]);
046            }
047        } catch (Exception exc) {
048            ErrorLogger.LogException(_className, "ResizeArray",
049                    new RendererException("Failed inside ResizeArray", exc));
050        }
051        return array;
052    }
053
054    /**
055     * post-segments a line segment into 50 pixel intervals
056     *
057     * @param pt0
058     * @param pt1
059     * @param shape
060     */
061    protected static void SegmentLineShape(POINT2 pt0, POINT2 pt1, Shape2 shape) {
062        try {
063            if (pt0 == null || pt1 == null) {
064                return;
065            }
066
067            int j = 0, n = 0;
068            double dist = CalcDistanceDouble(pt0, pt1);
069            n = (int) (dist / 25d);
070            POINT2 pt = null;
071            shape.lineTo(pt0);
072            for (j = 1; j <= n; j++) {
073                pt = lineutility.ExtendAlongLineDouble(pt0, pt1, 25);
074                shape.lineTo(pt);
075            }
076            shape.lineTo(pt1);
077        } catch (Exception exc) {
078            ErrorLogger.LogException(_className, "SegmentLineShape",
079                    new RendererException("Failed inside SegmentLineShape", exc));
080        }
081    }
082
083    /**
084     * Calculates the middle segment for the Direction of Attack Aviation symbol
085     *
086     * @param pLinePoints the point array
087     * @param vblSaveCounter the size of the point array
088     * @return the middle segment
089     */
090    public static int GetDirAtkAirMiddleSegment(POINT2[] pLinePoints,
091            int vblSaveCounter) {
092        int middleSegment = -1;
093        try {
094            double d = 0;
095            int k = 0;
096            for (k = vblSaveCounter - 1; k > 0; k--) {
097                d += lineutility.CalcDistanceDouble(pLinePoints[k], pLinePoints[k - 1]);
098                if (d > 60) {
099                    break;
100                }
101            }
102            if (d > 60) {
103                middleSegment = k;
104            } else {
105                if (vblSaveCounter <= 3) {
106                    middleSegment = 1;
107                } else {
108                    middleSegment = 2;
109                }
110            }
111        } catch (Exception exc) {
112            ErrorLogger.LogException(_className, "GetDirAtkAirMiddleSegment",
113                    new RendererException("Failed inside GetDirAtkAirMiddleSegment", exc));
114        }
115        return middleSegment;
116    }
117
118    /**
119     * Computes the angle in radians between two points
120     *
121     * @param pt0 the first point
122     * @param pt1 the last point
123     *
124     * @return the angle in radians
125     */
126    protected static double CalcSegmentAngleDouble(POINT2 pt0,
127            POINT2 pt1) {
128        double dAngle = 0;
129        try {
130            //declarations
131            int nTemp = 0;
132            ref<double[]> m = new ref();
133            //end declarations
134
135            nTemp = CalcTrueSlopeDouble(pt0, pt1, m);
136            if (nTemp == 0) {
137                dAngle = Math.PI / 2;
138            } else {
139                dAngle = Math.atan(m.value[0]);
140            }
141
142        } catch (Exception exc) {
143            ErrorLogger.LogException(_className, "CalcSegmentAngleDouble",
144                    new RendererException("Failed inside CalcSegmentAngleDouble", exc));
145        }
146        return dAngle;
147    }
148
149    /**
150     * POINT2 in previous applications has been a struct that did not require
151     * initialization.
152     *
153     * @param pts array of points to instantiate.
154     */
155    protected static void InitializePOINT2Array(POINT2[] pts) {
156        //int j=0;
157        if (pts == null || pts.length == 0) {
158            return;
159        }
160        int n=pts.length;
161        //for (int j = 0; j < pts.length; j++) 
162        for (int j = 0; j < n; j++) 
163        {
164            pts[j] = new POINT2();
165        }
166    }
167
168    /**
169     * Calculates the center point of an area using the first vblCounter points
170     * in the array.
171     *
172     * @param pLinePoints the client points
173     * @param vblCounter the number of points in the array to use
174     *
175     * @return the center point
176     */
177    protected static POINT2 CalcCenterPointDouble(POINT2[] pLinePoints,
178            int vblCounter) {
179        POINT2 CenterLinePoint = new POINT2(pLinePoints[0]);
180        try {
181            //declarations
182            int j = 0;
183            double dMinX = pLinePoints[0].x,
184                    dMinY = pLinePoints[0].y,
185                    dMaxX = pLinePoints[0].x,
186                    dMaxY = pLinePoints[0].y;
187
188            //end declarations
189            dMinX = pLinePoints[0].x;
190            dMinY = pLinePoints[0].y;
191            dMaxX = pLinePoints[0].x;
192            dMaxY = pLinePoints[0].y;
193
194            for (j = 0; j < vblCounter; j++) {
195                if (pLinePoints[j].x < dMinX) {
196                    dMinX = pLinePoints[j].x;
197                }
198
199                if (pLinePoints[j].y < dMinY) {
200                    dMinY = pLinePoints[j].y;
201                }
202
203                if (pLinePoints[j].x > dMaxX) {
204                    dMaxX = pLinePoints[j].x;
205                }
206
207                if (pLinePoints[j].y > dMaxY) {
208                    dMaxY = pLinePoints[j].y;
209                }
210
211            }   //end for
212
213            CenterLinePoint.x = (dMinX + dMaxX) / 2;
214            CenterLinePoint.y = (dMinY + dMaxY) / 2;
215        } catch (Error exc) {
216            ErrorLogger.LogException(_className, "CalcCenterPointDouble",
217                    new RendererException("Failed inside CalcCenterPointDouble", exc));
218        }
219        return CenterLinePoint;
220    }
221
222    /**
223     * Called by renderer Modifier2 class after ArrayList.ToArray was called,
224     * which produces an array of objects.
225     *
226     * @param pLinePoints
227     * @param vblCounter
228     * @return
229     */
230    public static POINT2 CalcCenterPointDouble2(Object[] pLinePoints,
231            int vblCounter) {
232        POINT2 pt0 = (POINT2) pLinePoints[0];
233        POINT2 CenterLinePoint = new POINT2();
234        try {
235            //declarations
236            int j = 0;
237            double dMinX = pt0.x,
238                    dMinY = pt0.y,
239                    dMaxX = pt0.x,
240                    dMaxY = pt0.y;
241
242            //end declarations
243            dMinX = pt0.x;
244            dMinY = pt0.y;
245            dMaxX = pt0.x;
246            dMaxY = pt0.y;
247
248            POINT2 pt;
249
250            for (j = 0; j < vblCounter; j++) {
251                pt = (POINT2) pLinePoints[j];
252                if (pt.x < dMinX) {
253                    dMinX = pt.x;
254                }
255
256                if (pt.y < dMinY) {
257                    dMinY = pt.y;
258                }
259
260                if (pt.x > dMaxX) {
261                    dMaxX = pt.x;
262                }
263
264                if (pt.y > dMaxY) {
265                    dMaxY = pt.y;
266                }
267
268            }   //end for
269
270            CenterLinePoint.x = (dMinX + dMaxX) / 2;
271            CenterLinePoint.y = (dMinY + dMaxY) / 2;
272        } catch (Error exc) {
273            ErrorLogger.LogException(_className, "CalcCenterPointDouble2",
274                    new RendererException("Failed inside CalcCenterPointDouble2", exc));
275        }
276        return CenterLinePoint;
277    }
278
279    /**
280     * Calculates the distance in pixels between two points
281     *
282     * @param p1 the first point
283     * @param p2 the last point
284     *
285     * @return the distance between p1 and p2 in pixels
286     */
287    public static double CalcDistanceDouble(POINT2 p1,
288            POINT2 p2) {
289        double returnValue = 0;
290        try {
291            returnValue = Math.sqrt((p1.x - p2.x)
292                    * (p1.x - p2.x)
293                    + (p1.y - p2.y)
294                    * (p1.y - p2.y));
295
296            //sanity check
297            //return x or y distance if returnValue is 0 or infinity
298            double xdist = Math.abs(p1.x - p2.x);
299            double ydist = Math.abs(p1.y - p2.y);
300            double max = xdist;
301            if (ydist > xdist) {
302                max = ydist;
303            }
304
305            if (returnValue == 0 || Double.isInfinite(returnValue)) {
306                if (max > 0) {
307                    returnValue = max;
308                }
309            }
310        } catch (Exception exc) {
311            ErrorLogger.LogException(_className, "CalcDistanceDouble",
312                    new RendererException("Failed inside CalcDistanceDouble", exc));
313        }
314        return returnValue;
315    }
316
317    /**
318     * Computes the slope of a line
319     *
320     * @param firstLinePoint the first line point
321     * @param lastLinePoint the last line point
322     * @param slope OUT - object with member to hold the slope of the line
323     *
324     * @return 1 if successful, else return 0
325     */
326    protected static int CalcTrueSlopeDouble(POINT2 firstLinePoint,
327            POINT2 lastLinePoint,
328            ref<double[]> slope)//ref is a double
329    {
330        int result = 1;
331        try {
332            if (slope.value == null) {
333                slope.value = new double[1];
334            }
335
336            double deltaX = 0, deltaY = 0;
337            deltaX = firstLinePoint.x - lastLinePoint.x;
338            //if (deltaX == 0) 
339            if (Math.abs(deltaX) < 1) 
340            {
341                //deltaX = 1;
342                if(deltaX>=0)
343                    deltaX=1;
344                else
345                    deltaX=-1;
346                result = 1;
347            }
348            deltaY = firstLinePoint.y - lastLinePoint.y;
349
350            slope.value[0] = deltaY / deltaX;   //cannot blow up
351        } catch (Error exc) {
352            ErrorLogger.LogException(_className, "CalcTrueSlopeDouble",
353                    new RendererException("Failed inside CalcTrueSlopeDouble", exc));
354        }
355        return result;
356    }
357
358    public static void WriteFile(String str) {
359        try {
360            BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("Test.txt"));
361            bufferedWriter.write(str);
362            bufferedWriter.close();
363            bufferedWriter = null;
364        } catch (Exception exc) {
365            ErrorLogger.LogException(_className, "WriteFile",
366                    new RendererException("Failed inside WriteFile", exc));
367        }
368    }
369
370    /**
371     * reverses the first vblCounter points
372     *
373     * @param pLowerLinePoints OUT - points to reverse
374     * @param vblCounter
375     */
376    protected static void ReversePointsDouble2(POINT2[] pLowerLinePoints,
377            int vblCounter) {
378        try {
379            POINT2[] pResultPoints = new POINT2[vblCounter];
380            int k = 0;
381            for (k = 0; k < vblCounter; k++) {
382                pResultPoints[k] = new POINT2(pLowerLinePoints[vblCounter - k - 1]);
383            }
384            for (k = 0; k < vblCounter; k++) {
385                pLowerLinePoints[k] = new POINT2(pResultPoints[k]);
386            }
387            pResultPoints = null;
388        } catch (Exception exc) {
389            ErrorLogger.LogException(_className, "ReversePointsDouble2",
390                    new RendererException("Failed inside ReversePointsDouble2", exc));
391        }
392    }
393
394    public static boolean CalcTrueSlopeDoubleForRoutes(POINT2 firstLinePoint,
395            POINT2 lastLinePoint,
396            ref<double[]> slope) {
397        try {
398            double deltaX = 0, deltaY = 0;
399            deltaX = (double) (firstLinePoint.x) - (double) (lastLinePoint.x);
400            if (Math.abs(deltaX) < 2) //was 2,infinite slope
401            {
402                return (false);
403            }
404
405            deltaY = (double) (firstLinePoint.y) - (double) (lastLinePoint.y);
406            if (slope.value == null) {
407                slope.value = new double[1];
408            }
409
410            slope.value[0] = deltaY / deltaX;
411        } catch (Exception exc) {
412            ErrorLogger.LogException(_className, "CalcTrueSlopeDoubleForRoutes",
413                    new RendererException("Failed inside CalcTrueSlopeDoubleForRoutes", exc));
414        }
415        return true;
416    }
417
418    /**
419     * Computes the slope of a line
420     *
421     * @param firstLinePoint the first line point
422     * @param lastLinePoint the last line point
423     * @param slope OUT - object with member to hold the slope of the line
424     *
425     * @return true if successful
426     */
427    public static boolean CalcTrueSlopeDouble2(POINT2 firstLinePoint,
428            POINT2 lastLinePoint,
429            ref<double[]> slope) {
430        Boolean result = true;
431        try {
432            double deltaX = 0, deltaY = 0;
433            deltaX = (double) (firstLinePoint.x) - (double) (lastLinePoint.x);
434            //if (deltaX == 0)
435            if (Math.abs(deltaX) < 1) 
436            {
437                //deltaX = 1;
438                if(deltaX>=0)
439                    deltaX=1;
440                else
441                    deltaX=-1;
442                result = false;
443            }
444
445            deltaY = (double) (firstLinePoint.y) - (double) (lastLinePoint.y);
446            if (slope.value == null) {
447                slope.value = new double[1];
448            }
449
450            slope.value[0] = deltaY / deltaX;
451        } catch (Exception exc) {
452            ErrorLogger.LogException(_className, "CalcTrueSlopeDouble2",
453                    new RendererException("Failed inside CalcTrueSlopeDouble2", exc));
454        }
455        return result;
456    }
457
458    /**
459     * Calculates the slopes and y intercepts in pixels for the line from pt1 to
460     * pt2 and a parallel line a vertical distance from the line
461     *
462     * @param nDistance the distance in pixels
463     * @param linePoint1 first point on the line
464     * @param linePoint2 last point on the line
465     * @param pdResult OUT - array to hold m, b for both lines
466     *
467     * @return 1 if the lines are not vertical, else return 0
468     */
469    protected static int CalcTrueLinesDouble(long nDistance,
470            POINT2 linePoint1,
471            POINT2 linePoint2,
472            ref<double[]> pdResult) //for vertical line e.g. if line equation is x=7
473    {
474        try {
475            //declarations
476            int nTemp = 0;
477            double b = 0;
478            double delta = 0;
479            ref<double[]> m = new ref();
480            //end declarations
481            nTemp = CalcTrueSlopeDouble(linePoint1, linePoint2, m);
482            pdResult.value = new double[6];
483            //Fill the result array with the line parameters
484            if (nTemp == 0) //vertical lines
485            {
486                pdResult.value[3] = linePoint1.x + (double) nDistance;  //the lower line eqn, e.g. x=7
487                pdResult.value[5] = linePoint1.x - (double) nDistance;  //the upper line eqn,
488                return 0;
489            } else {
490                b = linePoint2.y - m.value[0] * linePoint2.x;
491                delta = Math.sqrt(m.value[0] * m.value[0] * ((double) (nDistance) * (double) (nDistance))
492                        + ((double) (nDistance) * (double) (nDistance)));
493                pdResult.value[0] = m.value[0];    //original line eq'n: y = mx + b
494                pdResult.value[1] = b;
495                pdResult.value[2] = m.value[0];    //lower line eq'n: y = mx + (b+dDistance)
496                pdResult.value[3] = b + delta;
497                pdResult.value[4] = m.value[0];    //upper line eq'n: y = mx + (b-dDistance)
498                pdResult.value[5] = b - delta;
499            }
500        } catch (Exception exc) {
501            ErrorLogger.LogException(_className, "CalcTrueLinesDouble",
502                    new RendererException("Failed inside CalcTrueLinesDouble", exc));
503        }
504        return 1;
505    }
506
507    /**
508     * Calculates the intersection of two lines.
509     *
510     * @param m1 slope of first line
511     * @param b1 Y intercept of first line
512     * @param m2 slope of second line
513     * @param b2 Y intercept of second line
514     * @param bolVertical1 0 if first line is vertical, else 1
515     * @param bolVertical2 0 if second line is vertical, else 1
516     * @param X1 X intercept if first line is vertical
517     * @param X2 X intercept if 2nd line is vertical.
518     *
519     * @return intersection point
520     */
521    public static POINT2 CalcTrueIntersectDouble2(double m1,
522            double b1,
523            double m2,
524            double b2,
525            int bolVertical1,
526            int bolVertical2,
527            double X1, //x intercept if line1 is vertical
528            double X2) {
529        POINT2 ptIntersect = new POINT2();
530        try {
531            //declarations
532            double x = 0, y = 0;
533            //end declarations
534
535            //initialize ptIntersect
536            ptIntersect.x = X1;
537            ptIntersect.y = X2;
538            if (bolVertical1 == 0 && bolVertical2 == 0) //both lines vertical
539            {
540                return ptIntersect;
541            }
542            //the following 3 if blocks are the only ways to get an intersection
543            if (bolVertical1 == 0 && bolVertical2 == 1) //line1 vertical, line2 not
544            {
545                ptIntersect.x = X1;
546                ptIntersect.y = m2 * X1 + b2;
547                return ptIntersect;
548            }
549            if (bolVertical1 == 1 && bolVertical2 == 0) //line2 vertical, line1 not
550            {
551                ptIntersect.x = X2;
552                ptIntersect.y = m1 * X2 + b1;
553                return ptIntersect;
554            }
555            //if either of the lines is vertical function has already returned
556            //so both m1 and m2 should be valid
557            if (m1 != m2) {
558                x = (b2 - b1) / (m1 - m2);      //cannot blow up
559                y = (m1 * x + b1);
560                ptIntersect.x = x;
561                ptIntersect.y = y;
562                return ptIntersect;
563            }
564        } catch (Exception exc) {
565            ErrorLogger.LogException(_className, "CalcTrueIntersectDouble2",
566                    new RendererException("Failed inside CalcTrueIntersectDouble2", exc));
567        }
568        return ptIntersect;
569    }
570
571    /**
572     * Calculates an offset point for channel types which require arrows.
573     *
574     * @param startLinePoint the first point
575     * @param endLinePoint the last point
576     * @param nOffset the offset in pixels
577     *
578     * @return the offset point
579     */
580    protected static POINT2 GetOffsetPointDouble(POINT2 startLinePoint,
581            POINT2 endLinePoint,
582            long nOffset) {
583        POINT2 tempLinePoint = new POINT2(startLinePoint);
584        try {
585            //declarations
586            double dx = endLinePoint.x - startLinePoint.x,
587                    dy = endLinePoint.y - startLinePoint.y,
588                    dOffset = (double) nOffset,
589                    dHypotenuse = 0,
590                    dAngle = 0;
591
592            //end declarations
593            if (dx == 0) {
594                if (dy > 0) {
595                    tempLinePoint.x = endLinePoint.x;
596                    tempLinePoint.y = endLinePoint.y + dOffset;
597                } else {
598                    tempLinePoint.x = endLinePoint.x;
599                    tempLinePoint.y = endLinePoint.y - dOffset;
600                }
601                return tempLinePoint;
602            }
603            if (dy == 0) {
604                if (dx > 0) {
605                    tempLinePoint.x = endLinePoint.x + dOffset;
606                    tempLinePoint.y = endLinePoint.y;
607                } else {
608                    tempLinePoint.x = endLinePoint.x - dOffset;
609                    tempLinePoint.y = endLinePoint.y;
610                }
611                return tempLinePoint;
612            }
613
614            if (dy == 0) {
615                dAngle = 0;
616            } else {
617                dAngle = Math.atan(dx / dy) + Math.PI / 2;//1.570795;
618            }
619            dHypotenuse = (double) nOffset;
620            if (endLinePoint.x > startLinePoint.x) {
621                tempLinePoint.x = endLinePoint.x + dHypotenuse * Math.abs(Math.cos(dAngle));
622            } else {
623                tempLinePoint.x = endLinePoint.x - dHypotenuse * Math.abs(Math.cos(dAngle));
624            }
625            if (endLinePoint.y > startLinePoint.y) {
626                tempLinePoint.y = endLinePoint.y + dHypotenuse * Math.abs(Math.sin(dAngle));
627            } else {
628                tempLinePoint.y = endLinePoint.y - dHypotenuse * Math.abs(Math.sin(dAngle));
629            }
630
631        } catch (Exception exc) {
632            ErrorLogger.LogException(_className, "GetOffsetPointDouble",
633                    new RendererException("Failed inside GetOffsetPointDouble", exc));
634        }
635        return (tempLinePoint);
636    }
637
638    /**
639     * Computes the arc points for FEBA Assumes pResultLinePoints has been
640     * allocated.
641     *
642     * @param dRadius the arc radius in pixels
643     * @param pLinePoints the client points, each one is a center for a computed
644     * arc (cricle)
645     * @param vblCounter number of client points to use
646     * @param pResultLinePoints OUT - the arc points to return
647     */
648    protected static POINT2[] GetArcFEBADouble(double dRadius,
649            POINT2[] pLinePoints,
650            int vblCounter,
651            POINT2[] pResultLinePoints) {
652        try {
653            //declarations
654            double dStartAngle = 0,
655                    dEndAngle = 2 * Math.PI,
656                    dIncrement = (dEndAngle - dStartAngle) / 25.0;
657
658            int i = 0, j = 0, nArcCounter = 0;
659            double x = 0, y = 0;
660            POINT2 CenterLinePoint = new POINT2(pLinePoints[0]);
661            POINT2[] pArcLinePoints = new POINT2[26];
662            //end declarations
663            InitializePOINT2Array(pArcLinePoints);
664
665            for (i = 0; i < vblCounter; i++) //stuff the pArcLinePoints collector
666            {
667                CenterLinePoint = new POINT2(pLinePoints[i]);
668                CalcCircleDouble(CenterLinePoint, dRadius, 26, pArcLinePoints, 0);
669                for (j = 0; j < 26; j++) {
670                    pResultLinePoints[nArcCounter] = new POINT2(pArcLinePoints[j]);
671                    nArcCounter++;
672                }
673
674                pResultLinePoints[nArcCounter - 1].style = 5;
675            }   //end for
676
677            pResultLinePoints[26 * vblCounter - 1].style = 5;
678            pArcLinePoints = null;
679        } catch (Exception exc) {
680            ErrorLogger.LogException(_className, "GetArcFEBADouble",
681                    new RendererException("Failed inside GetArcFEBADouble", exc));
682        }
683        return pResultLinePoints;
684    }
685
686    /**
687     * Used for DMAF
688     *
689     * @param pLinePoints the client points
690     * @return ArrayList of X points
691     */
692    protected static ArrayList LineOfXPoints(POINT2[] pLinePoints) {
693        ArrayList xPoints = new ArrayList();
694        try {
695            int j = 0, k = 0;
696            double dist = 0;
697            int iterations = 0;
698            POINT2 frontPt = null, backPt = null;
699            POINT2 extendFrontAbove = null, extendFrontBelow = null;
700            POINT2 extendBackAbove = null, extendBackBelow = null;
701            POINT2 xPoint1 = null, xPoint2 = null;
702            int n=pLinePoints.length;
703            //for (j = 0; j < pLinePoints.length - 1; j++) 
704            for (j = 0; j < n - 1; j++) 
705            {
706                dist = CalcDistanceDouble(pLinePoints[j], pLinePoints[j + 1]);
707                iterations = (int) ((dist - 5.0) / 20.0);
708                if (dist - iterations * 20 > 10) {
709                    iterations += 1;
710                }
711
712                for (k = 0; k < iterations; k++) {
713                    frontPt = ExtendAlongLineDouble(pLinePoints[j], pLinePoints[j + 1], k * 20 - 5);
714                    backPt = ExtendAlongLineDouble(pLinePoints[j], pLinePoints[j + 1], k * 20 + 5);
715                    extendFrontAbove = ExtendDirectedLine(pLinePoints[j], pLinePoints[j + 1], frontPt, 2, 5);
716                    extendFrontBelow = ExtendDirectedLine(pLinePoints[j], pLinePoints[j + 1], frontPt, 3, 5);
717                    extendBackAbove = ExtendDirectedLine(pLinePoints[j], pLinePoints[j + 1], backPt, 2, 5);
718                    extendBackBelow = ExtendDirectedLine(pLinePoints[j], pLinePoints[j + 1], backPt, 3, 5);
719                    xPoints.add(extendFrontAbove);
720                    extendBackBelow.style = 5;
721                    xPoints.add(extendBackBelow);
722                    xPoints.add(extendBackAbove);
723                    extendFrontBelow.style = 5;
724                    xPoints.add(extendFrontBelow);
725                }
726            }
727        } catch (Exception exc) {
728            ErrorLogger.LogException(_className, "LineOfXPoints",
729                    new RendererException("Failed inside LineOfXPoints", exc));
730        }
731        return xPoints;
732    }
733
734    /**
735     * Computes the "X" points for FEBA Assumes pResultLinePoints has been
736     * allocated.
737     *
738     * @param pLinePoints the client points
739     * @param dSize size in pixels to use for X
740     * @param vblCounter number of client points to use
741     * @param pResultLinePoints OUT - the points to return
742     */
743    protected static void GetXFEBADouble(POINT2[] pLinePoints,
744            double dSize,
745            long vblCounter,
746            POINT2[] pResultLinePoints
747    ) {
748        try {
749            //declarations
750            int j = 0, nXcounter = 0;
751
752            POINT2 upperLeftLinePoint = new POINT2(pLinePoints[0]),
753                    lowerLeftLinePoint = new POINT2(pLinePoints[0]),
754                    upperRightLinePoint = new POINT2(pLinePoints[0]),
755                    lowerRightLinePoint = new POINT2(pLinePoints[0]);
756            //end declarations
757
758            for (j = 0; j < vblCounter; j++) {
759                upperRightLinePoint.x = pLinePoints[j].x + dSize;
760                upperRightLinePoint.y = pLinePoints[j].y + dSize;
761                lowerRightLinePoint.x = pLinePoints[j].x + dSize;
762                lowerRightLinePoint.y = pLinePoints[j].y - dSize;
763                upperLeftLinePoint.x = pLinePoints[j].x - dSize;
764                upperLeftLinePoint.y = pLinePoints[j].y + dSize;
765                lowerLeftLinePoint.x = pLinePoints[j].x - dSize;
766                lowerLeftLinePoint.y = pLinePoints[j].y - dSize;
767                pResultLinePoints[nXcounter] = new POINT2(lowerLeftLinePoint);
768
769                nXcounter++;
770                pResultLinePoints[nXcounter] = new POINT2(upperRightLinePoint);
771                pResultLinePoints[nXcounter].style = 5;
772
773                nXcounter++;
774                pResultLinePoints[nXcounter] = new POINT2(upperLeftLinePoint);
775
776                nXcounter++;
777                pResultLinePoints[nXcounter] = new POINT2(lowerRightLinePoint);
778                pResultLinePoints[nXcounter].style = 5;
779
780                nXcounter++;
781            }   //end for
782        } catch (Exception exc) {
783            ErrorLogger.LogException(_className, "GetXFEBADouble",
784                    new RendererException("Failed inside GetXFEBADouble", exc));
785        }
786    }
787
788    /**
789     * Reorders points for HOLD, BRDGHD
790     *
791     * @param pLinePoints OUT - client points also reordered points
792     */
793    protected static void ReorderPoints(POINT2[] pLinePoints) {
794        try {
795            //int n = 3;//pLinePoints.length;
796            int n = pLinePoints.length;
797            POINT2 pt = new POINT2();
798            POINT2 pt1 = new POINT2(pLinePoints[1]);
799            //reorder the points
800            for (int j = 1; j < n - 1; j++) {
801                pt = new POINT2(pLinePoints[j + 1]);
802                pLinePoints[j] = new POINT2(pt);
803            }
804            pLinePoints[n - 1] = new POINT2(pt1);
805        } catch (Exception exc) {
806            ErrorLogger.LogException(_className, "ReorderPoints",
807                    new RendererException("Failed inside ReorderPoints", exc));
808        }
809    }
810
811    /**
812     * Computes the distance in pixels of pt3 to the line from pt1 to pt2.
813     *
814     * @param pt1 first line point
815     * @param pt2 last line point
816     * @param pt3 point distance to compute
817     * @return distance to pt3
818     */
819    public static double CalcDistanceToLineDouble(POINT2 pt1,
820            POINT2 pt2,
821            POINT2 pt3) {
822        double dResult = 0;
823        try {
824            //declarations
825            double m1 = 1, b = 0, b1 = 0;
826            POINT2 ptIntersect = new POINT2(pt1);
827            int bolVertical = 0;
828            ref<double[]> m = new ref();
829            //end declarations
830
831            bolVertical = CalcTrueSlopeDouble(pt1, pt2, m);
832
833            //get line y intercepts
834            if (bolVertical != 0 && m.value[0] != 0) {
835                m1 = -1 / m.value[0];
836                b = pt1.y - m.value[0] * pt1.x;
837                b1 = pt3.y - m1 * pt3.x;
838                ptIntersect = CalcTrueIntersectDouble2(m.value[0], b, m1, b1, 1, 1, ptIntersect.x, ptIntersect.y);
839            }
840            if (bolVertical != 0 && m.value[0] == 0) //horizontal line
841            {
842                ptIntersect.y = pt1.y;
843                ptIntersect.x = pt3.x;
844            }
845            if (bolVertical == 0) //vertical line
846            {
847                ptIntersect.y = pt3.y;
848                ptIntersect.x = pt1.x;
849            }
850
851            dResult = CalcDistanceDouble(pt3, ptIntersect);
852        } catch (Exception exc) {
853            //System.out.println(e.getMessage());
854            ErrorLogger.LogException(_className, "CaclDistanceToLineDouble",
855                    new RendererException("Failed inside CalcDistanceToLineDouble", exc));
856        }
857        return dResult;
858    }
859
860    /**
861     * Calculates a point along a line. Returns the past point if the distance
862     * is 0.
863     *
864     * @param pt1 first line point
865     * @param pt2 last line point
866     * @param dist extension distance in pixels from the beginning of the line
867     *
868     * @return the extension point
869     */
870    public static POINT2 ExtendLineDouble(POINT2 pt1,
871            POINT2 pt2,
872            double dist) {
873        POINT2 pt3 = new POINT2();
874        try {
875            double dOriginalDistance = CalcDistanceDouble(pt1, pt2);
876            if (dOriginalDistance == 0 || dist == 0) {
877                return pt2;
878            }
879
880            pt3.x = (dOriginalDistance + dist) / dOriginalDistance * (pt2.x - pt1.x) + pt1.x;
881            pt3.y = (dOriginalDistance + dist) / dOriginalDistance * (pt2.y - pt1.y) + pt1.y;
882        } catch (Exception exc) {
883            //System.out.println(e.getMessage());
884            ErrorLogger.LogException(_className, "ExtendLineDouble",
885                    new RendererException("Failed inside ExtendLineDouble", exc));
886        }
887        return pt3;
888    }
889
890    /**
891     * Extends a point along a line. If dist is 0 returns last point.
892     *
893     * @param pt1 first point on the line
894     * @param pt2 last point on the line
895     * @param dist the distance in pixels from pt1
896     *
897     * @return the extended point
898     */
899    public static POINT2 ExtendAlongLineDouble(POINT2 pt1, POINT2 pt2, double dist) {
900        POINT2 pt3 = new POINT2();
901        try {
902            double dOriginalDistance = CalcDistanceDouble(pt1, pt2);
903            if (dOriginalDistance == 0 || dist == 0) {
904                return pt2;
905            }
906
907            pt3.x = ((dist / dOriginalDistance) * (pt2.x - pt1.x) + pt1.x);
908            pt3.y = ((dist / dOriginalDistance) * (pt2.y - pt1.y) + pt1.y);
909        } catch (Exception exc) {
910            //System.out.println(e.getMessage());
911            ErrorLogger.LogException(_className, "ExtendAlongLineDouble",
912                    new RendererException("Failed inside ExtendAlongLineDouble", exc));
913        }
914        return pt3;
915    }
916
917    public static POINT2 ExtendAlongLineDouble2(POINT2 pt1, POINT2 pt2, double dist) {
918        POINT2 pt3 = new POINT2();
919        try {
920            double dOriginalDistance = CalcDistanceDouble(pt1, pt2);
921            if (dOriginalDistance == 0 || dist == 0) {
922                return pt1;
923            }
924
925            pt3.x = (dist / dOriginalDistance * (pt2.x - pt1.x) + pt1.x);
926            pt3.y = (dist / dOriginalDistance * (pt2.y - pt1.y) + pt1.y);
927        } catch (Exception exc) {
928            //System.out.println(e.getMessage());
929            ErrorLogger.LogException(_className, "ExtendAlongLineDouble2",
930                    new RendererException("Failed inside ExtendAlongLineDouble2", exc));
931        }
932        return pt3;
933    }
934
935    public static POINT2 ExtendAlongLineDouble(POINT2 pt1, POINT2 pt2, double dist, int styl) {
936        POINT2 pt3 = new POINT2();
937        try {
938            double dOriginalDistance = CalcDistanceDouble(pt1, pt2);
939            if (dOriginalDistance == 0 || dist == 0) {
940                return pt2;
941            }
942
943            pt3.x = (dist / dOriginalDistance * (pt2.x - pt1.x) + pt1.x);
944            pt3.y = (dist / dOriginalDistance * (pt2.y - pt1.y) + pt1.y);
945            pt3.style = styl;
946        } catch (Exception exc) {
947            //System.out.println(e.getMessage());
948            ErrorLogger.LogException(_className, "ExtendAlongLineDouble",
949                    new RendererException("Failed inside ExtendAlongLineDouble", exc));
950        }
951        return pt3;
952    }
953
954    /**
955     * Extends a point above a line
956     *
957     * @param pt1 first line point
958     * @param pt2 last line point
959     * @param pt3 point at which to extend
960     * @param d distance in pixels to extend above the line
961     * @param X OUT - extended point x value
962     * @param Y OUT - extended point y value
963     * @param direction direction to extend the line
964     *
965     * @return 1 if successful, else return 0
966     */
967    protected static int ExtendLineAbove(POINT2 pt1,
968            POINT2 pt2,
969            POINT2 pt3,
970            double d,
971            ref<double[]> X,
972            ref<double[]> Y,
973            int direction) {
974        try {
975            ref<double[]> m = new ref();
976            double dx = 0, dy = 0;
977            int bolVertical = 0;
978
979            X.value = new double[1];
980            Y.value = new double[1];
981
982            bolVertical = CalcTrueSlopeDouble(pt1, pt2, m);
983            if (bolVertical == 0) {
984                return 0;       //cannot extend above a vertical line
985            }
986            if (m.value[0] == 0) {
987                X.value[0] = pt3.x;
988                if (direction == 0) //extend above the line
989                {
990                    Y.value[0] = pt3.y - Math.abs(d);
991                } else //extend below the line
992                {
993                    Y.value[0] = pt3.y + Math.abs(d);
994                }
995                return 1;
996            }
997            //the line is neither vertical nor horizontal
998            //else function would already have returned
999            if (direction == 0) //extend above the line
1000            {
1001                dy = -Math.abs(d / (m.value[0] * Math.sqrt(1 + 1 / (m.value[0] * m.value[0]))));
1002            } else //extend below the line
1003            {
1004                dy = Math.abs(d / (m.value[0] * Math.sqrt(1 + 1 / (m.value[0] * m.value[0]))));
1005            }
1006
1007            dx = -m.value[0] * dy;
1008            X.value[0] = pt3.x + dx;
1009            Y.value[0] = pt3.y + dy;
1010        } catch (Exception exc) {
1011            //System.out.println(e.getMessage());
1012            ErrorLogger.LogException(_className, "ExtendLineAbove",
1013                    new RendererException("Failed inside ExtendLineAbove", exc));
1014        }
1015        return 1;
1016    }
1017
1018    /**
1019     * Extends a point to the left of a line
1020     *
1021     * @param pt1 first line point
1022     * @param pt2 last line point
1023     * @param pt3 point at which to extend
1024     * @param d distance in pixels to extend above the line
1025     * @param X OUT - extended point x value
1026     * @param Y OUT - extended point y value
1027     * @param direction direction to extend the line
1028     *
1029     * @return 1 if successful, else return 0
1030     */
1031    protected static int ExtendLineLeft(POINT2 pt1,
1032            POINT2 pt2,
1033            POINT2 pt3,
1034            double d,
1035            ref<double[]> X,
1036            ref<double[]> Y,
1037            int direction) {
1038        try {
1039            ref<double[]> m = new ref();
1040            double dx = 0, dy = 0;
1041            int bolVertical = 0;
1042
1043            X.value = new double[1];
1044            Y.value = new double[1];
1045
1046            bolVertical = CalcTrueSlopeDouble(pt1, pt2, m);
1047            if (bolVertical != 0 && m.value[0] == 0) {
1048                return 0;       //cannot left of horiz line
1049            }
1050            if (bolVertical == 0) //vertical line
1051            {
1052                Y.value[0] = pt3.y;
1053                if (direction == 0) //extend left of the line
1054                {
1055                    X.value[0] = pt3.x - Math.abs(d);
1056                } else //extend right of the line
1057                {
1058                    X.value[0] = pt3.x + Math.abs(d);
1059                }
1060
1061                return 1;
1062            }
1063            //the line is neither vertical nor horizontal
1064            //else function would already have returned
1065            if (direction == 0) //extend left of the line
1066            {
1067                dx = -Math.abs(d / Math.sqrt(1 + 1 / (m.value[0] * m.value[0])));
1068            } else //extend right of the line
1069            {
1070                dx = Math.abs(d / Math.sqrt(1 + 1 / (m.value[0] * m.value[0])));
1071            }
1072
1073            dy = -(1 / m.value[0]) * dx;
1074
1075            X.value[0] = pt3.x + dx;
1076            Y.value[0] = pt3.y + dy;
1077        } catch (Exception exc) {
1078            //System.out.println(e.getMessage());
1079            ErrorLogger.LogException(_className, "ExtendLineLeft",
1080                    new RendererException("Failed inside ExtendLineLeft", exc));
1081        }
1082        return 1;
1083    }
1084
1085    /**
1086     * Calculates the direction of a point relative to a line
1087     *
1088     * @param pt0 first point fo the line
1089     * @param pt1 last point of the line
1090     * @param pt2 relative point
1091     * @deprecated
1092     * @return 0 if left, 1 if right, 2 if above, 3 if below
1093     */
1094    protected static int CalcDirectionFromLine(POINT2 pt0,
1095            POINT2 pt1,
1096            POINT2 pt2) {
1097        int result = -1;
1098        try {
1099            double m2 = 0, b1 = 0, b2 = 0;
1100            ref<double[]> m1 = new ref();
1101            POINT2 ptIntersect = new POINT2();
1102            //int direction=-1;
1103            //handle vertical line
1104            if (pt0.x == pt1.x) {
1105                if (pt2.x < pt0.x) {
1106                    return 0;
1107                } else {
1108                    return 1;
1109                }
1110            }
1111            //handle horizontal line so that we do not have slope = 0.
1112            if (pt0.y == pt1.y) {
1113                if (pt2.y < pt0.y) {
1114                    return 2;
1115                } else {
1116                    return 3;
1117                }
1118            }
1119            CalcTrueSlopeDouble(pt0, pt1, m1);
1120            m2 = -1 / m1.value[0];      //slope for the perpendicular line from the line to pt2
1121            //b=mx-y line equation for line
1122            b1 = pt0.y - m1.value[0] * pt0.x;
1123            //b=mx-y line equation for perpendicular line which contains pt2
1124            b2 = pt2.y - m2 * pt2.x;
1125            ptIntersect = CalcTrueIntersectDouble2(m1.value[0], b1, m2, b2, 1, 1, 0, 0);
1126            //compare the intersection point with pt2 to get the direction,
1127            //i.e. the direction from the line is the same as the direction
1128            //from the interseciton point.
1129            if (m1.value[0] > 1) //line is steep, use left/right
1130            {
1131                if (pt2.x < ptIntersect.x) {
1132                    return 0;
1133                } else {
1134                    return 1;
1135                }
1136            } else //line is not steep, use above/below
1137            {
1138                if (pt2.y < ptIntersect.y) {
1139                    return 2;
1140                } else {
1141                    return 3;
1142                }
1143            }
1144            //should not reach this point
1145            //return direction;
1146        } catch (Exception e) {
1147            System.out.println(e.getMessage());
1148        }
1149        return result;
1150    }
1151
1152    /**
1153     * Returns a point extended perpendicularly from a line at a given direction
1154     *
1155     * @param pt1 first line point
1156     * @param pt2 last line point
1157     * @param pt0 on line from which to extend
1158     * @param direction the direction to extend: above, below, left, right
1159     * @param d the length to extend in pixels
1160     *
1161     */
1162    public static POINT2 ExtendDirectedLine(POINT2 pt1,
1163            POINT2 pt2,
1164            POINT2 pt0,
1165            int direction,
1166            double d) {
1167        POINT2 ptResult = new POINT2();
1168        try {
1169            ref<double[]> X = new ref(), Y = new ref();
1170            ptResult = new POINT2(pt0);
1171            switch (direction) {
1172                case 0: //extend left
1173                    ExtendLineLeft(pt1, pt2, pt0, d, X, Y, 0);
1174                    break;
1175                case 1: //extend right
1176                    ExtendLineLeft(pt1, pt2, pt0, d, X, Y, 1);
1177                    break;
1178                case 2: //extend above
1179                    ExtendLineAbove(pt1, pt2, pt0, d, X, Y, 0);
1180                    break;
1181                case 3: //extend below
1182                    ExtendLineAbove(pt1, pt2, pt0, d, X, Y, 1);
1183                    break;
1184                default:
1185                    break;
1186            }
1187            ptResult.x = X.value[0];
1188            ptResult.y = Y.value[0];
1189        } catch (Exception exc) {
1190            //System.out.println(e.getMessage());
1191            ErrorLogger.LogException(_className, "ExtendDirectedLine",
1192                    new RendererException("Failed inside ExtendDirectedLine", exc));
1193        }
1194        return ptResult;
1195    }
1196
1197    /**
1198     * @deprecated Returns a point extended perpendicularly from a line at a
1199     * given direction same as original function except it accounts for vertical
1200     * lines and negative d values
1201     *
1202     * @param pt1 first line point
1203     * @param pt2 last line point
1204     * @param pt0 on line from which to extend
1205     * @param direction the direction to extend: above, below, left, right
1206     * @param d the length to extend in pixels
1207     *
1208     */
1209    public static POINT2 ExtendDirectedLineText(POINT2 pt1,
1210            POINT2 pt2,
1211            POINT2 pt0,
1212            int direction,
1213            double d) {
1214        POINT2 ptResult = new POINT2();
1215        try {
1216            ref<double[]> X = new ref(), Y = new ref();
1217            ptResult = new POINT2(pt0);
1218            if (d < 0) {
1219                switch (direction) {
1220                    case 0:
1221                        direction = extend_right;
1222                        break;
1223                    case 1:
1224                        direction = extend_left;
1225                        break;
1226                    case 2:
1227                        direction = extend_below;
1228                        break;
1229                    case 3:
1230                        direction = extend_above;
1231                        break;
1232                    default:
1233                        break;
1234                }
1235                d = Math.abs(d);
1236            }
1237            if (pt1.y == pt2.y)//horizontal segment
1238            {
1239                switch (direction) {
1240                    case 0://left means above
1241                        direction = extend_above;
1242                    case 1://right means below
1243                        direction = extend_below;
1244                    default:
1245                        break;
1246                }
1247            }
1248            if (pt1.x == pt2.x)//vertical segment
1249            {
1250                switch (direction) {
1251                    case 2://above means left
1252                        direction = extend_left;
1253                    case 3://below means right
1254                        direction = extend_right;
1255                    default:
1256                        break;
1257                }
1258            }
1259            switch (direction) {
1260                case 0: //extend left
1261                    ExtendLineLeft(pt1, pt2, pt0, d, X, Y, 0);
1262                    break;
1263                case 1: //extend right
1264                    ExtendLineLeft(pt1, pt2, pt0, d, X, Y, 1);
1265                    break;
1266                case 2: //extend above
1267                    ExtendLineAbove(pt1, pt2, pt0, d, X, Y, 0);
1268                    break;
1269                case 3: //extend below
1270                    ExtendLineAbove(pt1, pt2, pt0, d, X, Y, 1);
1271                    break;
1272                default:
1273                    break;
1274            }
1275            ptResult.x = X.value[0];
1276            ptResult.y = Y.value[0];
1277        } catch (Exception exc) {
1278            //System.out.println(e.getMessage());
1279            ErrorLogger.LogException(_className, "ExtendDirectedLine",
1280                    new RendererException("Failed inside ExtendDirectedLine", exc));
1281        }
1282        return ptResult;
1283    }
1284
1285    /**
1286     * Returns a point extended perpendicularly from a line at a given direction
1287     *
1288     * @param pt1 first line point
1289     * @param pt2 last line point
1290     * @param pt0 on line from which to extend
1291     * @param direction the direction to extend: above, below, left, right
1292     * @param d the length to extend in pixels
1293     * @param style the style to assign the return point
1294     *
1295     */
1296    public static POINT2 ExtendDirectedLine(POINT2 pt1,
1297            POINT2 pt2,
1298            POINT2 pt0,
1299            int direction,
1300            double d,
1301            int style) {
1302        POINT2 ptResult = new POINT2(pt0);
1303        try {
1304            ref<double[]> X = new ref(), Y = new ref();
1305            //int bolResult=0;
1306            //handle parallel, perpendicular cases
1307            if (pt1.x == pt2.x) {
1308                if (direction == 2) {
1309                    direction = 0;
1310                }
1311                if (direction == 3) {
1312                    direction = 1;
1313                }
1314            }
1315            if (pt1.y == pt2.y) {
1316                if (direction == 0) {
1317                    direction = 2;
1318                }
1319                if (direction == 1) {
1320                    direction = 3;
1321                }
1322            }
1323            switch (direction) {
1324                case 0: //extend left
1325                    ExtendLineLeft(pt1, pt2, pt0, d, X, Y, 0);
1326                    break;
1327                case 1: //extend right
1328                    ExtendLineLeft(pt1, pt2, pt0, d, X, Y, 1);
1329                    break;
1330                case 2: //extend above
1331                    ExtendLineAbove(pt1, pt2, pt0, d, X, Y, 0);
1332                    break;
1333                case 3: //extend below
1334                    ExtendLineAbove(pt1, pt2, pt0, d, X, Y, 1);
1335                    break;
1336            }
1337            ptResult.x = X.value[0];
1338            ptResult.y = Y.value[0];
1339            ptResult.style = style;
1340        } catch (Exception exc) {
1341            ErrorLogger.LogException(_className, "ExtendDirectedLine",
1342                    new RendererException("Failed inside ExtendDirectedLine", exc));
1343        }
1344        return ptResult;
1345    }
1346
1347    /**
1348     * Calculates a point along a line
1349     *
1350     * @param pt1 first line point
1351     * @param pt2 last line point
1352     * @param dist extension distance in pixels from the beginning of the line
1353     * @param styl the line style to assign the point
1354     *
1355     * @return the extension point
1356     */
1357    protected static POINT2 ExtendLine2Double(POINT2 pt1,
1358            POINT2 pt2,
1359            double dist,
1360            int styl) {
1361        POINT2 pt3 = new POINT2();
1362        try {
1363            double dOriginalDistance = CalcDistanceDouble(pt1, pt2);
1364
1365            pt3.x = pt2.x;
1366            pt3.y = pt2.y;
1367            if (dOriginalDistance > 0) {
1368                pt3.x = ((dOriginalDistance + dist) / dOriginalDistance * (pt2.x - pt1.x) + pt1.x);
1369                pt3.y = ((dOriginalDistance + dist) / dOriginalDistance * (pt2.y - pt1.y) + pt1.y);
1370                pt3.style = styl;
1371            }
1372        } catch (Exception exc) {
1373            ErrorLogger.LogException(_className, "ExtendLine2Double",
1374                    new RendererException("Failed inside ExtendLine2Double", exc));
1375        }
1376        return pt3;
1377    }
1378
1379    /**
1380     * Extends a point at an angle from a line.
1381     *
1382     * @param pt0 the first line point
1383     * @param pt1 the second line point
1384     * @param pt2 point on line from which to extend
1385     * @param alpha angle of extension in degrees
1386     * @param d the distance in pixels to extend
1387     *
1388     * @return the extension point
1389     */
1390    public static POINT2 ExtendAngledLine(POINT2 pt0,
1391            POINT2 pt1,
1392            POINT2 pt2,
1393            double alpha,
1394            double d) {
1395        POINT2 pt = new POINT2();
1396        try {
1397            //first get the angle psi between pt0 and pt1
1398            double psi = Math.atan((pt1.y - pt0.y) / (pt1.x - pt0.x));
1399            //convert alpha to radians
1400            double alpha1 = Math.PI * alpha / 180;
1401
1402            //theta is the angle of extension from the x axis
1403            double theta = psi + alpha1;
1404            //dx is the x extension from pt2
1405            double dx = d * Math.cos(theta);
1406            //dy is the y extension form pt2
1407            double dy = d * Math.sin(theta);
1408            pt.x = pt2.x + dx;
1409            pt.y = pt2.y + dy;
1410        } catch (Exception exc) {
1411            ErrorLogger.LogException(_className, "ExtendAngledLine",
1412                    new RendererException("Failed inside ExtendAngledLine", exc));
1413        }
1414        return pt;
1415    }
1416
1417    /**
1418     * Returns an integer indicating the quadrant for the direction of the line
1419     * from pt1 to pt2
1420     *
1421     * @param pt1 first line point
1422     * @param pt2 second line point
1423     *
1424     * @return the quadrant
1425     */
1426    public static int GetQuadrantDouble(POINT2 pt1,
1427            POINT2 pt2) {
1428        int nQuadrant = 1;
1429        try {
1430            if (pt2.x >= pt1.x && pt2.y <= pt1.y) {
1431                nQuadrant = 1;
1432            }
1433            if (pt2.x >= pt1.x && pt2.y >= pt1.y) {
1434                nQuadrant = 2;
1435            }
1436            if (pt2.x <= pt1.x && pt2.y >= pt1.y) {
1437                nQuadrant = 3;
1438            }
1439            if (pt2.x <= pt1.x && pt2.y <= pt1.y) {
1440                nQuadrant = 4;
1441            }
1442
1443        } catch (Exception exc) {
1444            ErrorLogger.LogException(_className, "GetQuadrantDouble",
1445                    new RendererException("Failed inside GetQuadrantDouble", exc));
1446        }
1447        return nQuadrant;
1448    }
1449
1450    public static int GetQuadrantDouble(double x1, double y1,
1451            double x2, double y2) {
1452        int nQuadrant = 1;
1453        try {
1454//            if(pt2.x>=pt1.x && pt2.y<=pt1.y)
1455//                    nQuadrant=1;
1456//            if(pt2.x>=pt1.x && pt2.y>=pt1.y)
1457//                    nQuadrant=2;
1458//            if(pt2.x<=pt1.x && pt2.y>=pt1.y)
1459//                    nQuadrant=3;
1460//            if(pt2.x<=pt1.x && pt2.y<=pt1.y)
1461//                    nQuadrant=4;
1462
1463            if (x2 >= x1 && y2 <= y1) {
1464                nQuadrant = 1;
1465            }
1466            if (x2 >= x1 && y2 >= y1) {
1467                nQuadrant = 2;
1468            }
1469            if (x2 <= x1 && y2 >= y1) {
1470                nQuadrant = 3;
1471            }
1472            if (x2 <= x1 && y2 <= y1) {
1473                nQuadrant = 4;
1474            }
1475        } catch (Exception exc) {
1476            ErrorLogger.LogException(_className, "GetQuadrantDouble",
1477                    new RendererException("Failed inside GetQuadrantDouble", exc));
1478        }
1479        return nQuadrant;
1480    }
1481
1482    /**
1483     * Returns the smallest x and y pixel values from an array of points
1484     *
1485     * @param ptsSeize array of points from which to find minimum vaules
1486     * @param vblCounter the number of points to test in the array
1487     * @param x OUT - an object with a member to hold the xminimum
1488     * @param y OUT - an object with a member to hold the y minimum value
1489     *
1490     */
1491    protected static void GetPixelsMin(POINT2[] ptsSeize,
1492            int vblCounter,
1493            ref<double[]> x,
1494            ref<double[]> y) {
1495        try {
1496            double xmin = Double.POSITIVE_INFINITY;
1497            double ymin = Double.POSITIVE_INFINITY;
1498            int j = 0;
1499
1500            for (j = 0; j < vblCounter; j++) {
1501                if (ptsSeize[j].x < xmin) {
1502                    xmin = ptsSeize[j].x;
1503                }
1504                if (ptsSeize[j].y < ymin) {
1505                    ymin = ptsSeize[j].y;
1506                }
1507            }
1508            x.value = new double[1];
1509            y.value = new double[1];
1510            x.value[0] = xmin;
1511            y.value[0] = ymin;
1512        } catch (Exception exc) {
1513            ErrorLogger.LogException(_className, "GetPixelsMin",
1514                    new RendererException("Failed inside GetPixelsMin", exc));
1515        }
1516    }
1517
1518    /**
1519     * Returns center point for a clockwise arc to connect pts 1 and 2. Also
1520     * returns an extended point on the line between pt1 and the new center
1521     * Caller passes a POINT1 array of size 2 for ptsSeize, passes pt1 and pt2
1522     * in ptsSeize Returns the radius of the 90 degree arc between C (arc
1523     * center) and pt1
1524     *
1525     * @param ptsSeize OUT - two point array also used for the returned two
1526     * points
1527     *
1528     * @return the radius
1529     */
1530    protected static double CalcClockwiseCenterDouble(POINT2[] ptsSeize) {
1531        double dRadius = 0;
1532        try {
1533            //declarations
1534            POINT2 pt1 = new POINT2(ptsSeize[0]);
1535            POINT2 pt2 = new POINT2(ptsSeize[1]);
1536            POINT2 C = new POINT2(pt1), midPt = new POINT2(pt1);        //the center to calculate
1537            POINT2 E = new POINT2(pt1); //the extended point to calculate
1538            POINT2 ptYIntercept = new POINT2(pt1);
1539            int nQuadrant = 1;
1540            double b = 0, b1 = 0, b2 = 0, dLength = 0;
1541            ref<double[]> m = new ref();
1542            int bolVertical = 0;
1543            ref<double[]> offsetX = new ref(), offsetY = new ref();
1544            POINT2[] ptsTemp = new POINT2[2];
1545            //end declarations
1546
1547            //must offset the points if necessary because there will be calculations
1548            //extending from the Y Intercept
1549            ptsTemp[0] = new POINT2(pt1);
1550            ptsTemp[1] = new POINT2(pt2);
1551            GetPixelsMin(ptsTemp, 2, offsetX, offsetY);
1552            if (offsetX.value[0] < 0) {
1553                offsetX.value[0] = offsetX.value[0] - 100;
1554            } else {
1555                offsetX.value[0] = 0;
1556            }
1557            //end section
1558
1559            midPt.x = (pt1.x + pt2.x) / 2;
1560            midPt.y = (pt1.y + pt2.y) / 2;
1561            dLength = CalcDistanceDouble(pt1, pt2);
1562            dRadius = dLength / Math.sqrt(2);
1563            nQuadrant = GetQuadrantDouble(pt1, pt2);
1564
1565            bolVertical = CalcTrueSlopeDouble(pt1, pt2, m);
1566            if (bolVertical != 0 && m.value[0] != 0) //line not vertical or horizontal
1567            {
1568                b = pt1.y - m.value[0] * pt1.x;
1569                //y intercept of line perpendicular to midPt of pt,p2
1570                b1 = midPt.y + (1 / m.value[0]) * midPt.x;
1571                //we want to shift the Y axis to the left by offsetX
1572                //so we get the new Y intercept at x=offsetX
1573                b2 = (-1 / m.value[0]) * offsetX.value[0] + b1;
1574                ptYIntercept.x = offsetX.value[0];
1575                ptYIntercept.y = b2;
1576                switch (nQuadrant) {
1577                    case 1:
1578                    case 4:
1579                        C = ExtendLineDouble(ptYIntercept, midPt, dLength / 2);
1580                        break;
1581                    case 2:
1582                    case 3:
1583                        C = ExtendLineDouble(ptYIntercept, midPt, -dLength / 2);
1584                        break;
1585                    default:
1586                        break;
1587                }
1588            }
1589            if (bolVertical != 0 && m.value[0] == 0) //horizontal line
1590            {
1591                C.x = midPt.x;
1592                if (pt1.x < pt2.x) {
1593                    C.y = midPt.y + dLength / 2;
1594                } else {
1595                    C.y = midPt.y - dLength / 2;
1596                }
1597            }
1598            if (bolVertical == 0) //vertical line
1599            {
1600                ptYIntercept.x = offsetX.value[0];
1601                ptYIntercept.y = midPt.y;
1602                switch (nQuadrant) {
1603                    case 1:
1604                    case 4:
1605                        C = ExtendLineDouble(ptYIntercept, midPt, dLength / 2);
1606                        break;
1607                    case 2:
1608                    case 3:
1609                        C = ExtendLineDouble(ptYIntercept, midPt, -dLength / 2);
1610                        break;
1611                    default:
1612                        break;
1613                }
1614            }
1615
1616            E = ExtendLineDouble(C, pt1, 50);
1617            ptsSeize[0] = new POINT2(C);
1618            ptsSeize[1] = new POINT2(E);
1619
1620            ptsTemp = null;
1621        } catch (Exception exc) {
1622            ErrorLogger.LogException(_className, "CalcClockwiseCenterDouble",
1623                    new RendererException("Failed inside CalcClockwiseCenterDouble", exc));
1624        }
1625        return dRadius;
1626    }
1627
1628    /**
1629     * Computes the points for an arrowhead based on a line segment
1630     *
1631     * @param startLinePoint segment start point
1632     * @param endLinePoint segment end point
1633     * @param nBiSector bisecotr in pixels
1634     * @param nBase base size in pixels
1635     * @param pResultLinePoints OUT - the arrowhead points
1636     * @param styl the line style to assign the last aroowhead point
1637     */
1638    protected static void GetArrowHead4Double(POINT2 startLinePoint,
1639            POINT2 endLinePoint,
1640            int nBiSector,
1641            int nBase,
1642            POINT2[] pResultLinePoints,
1643            int styl) {
1644        try {
1645            //declarations
1646            int j = 0;
1647            double dy = (double) (endLinePoint.y - startLinePoint.y),
1648                    dx = (double) (endLinePoint.x - startLinePoint.x),
1649                    dSign = 1.0,
1650                    AHBY = 0,
1651                    AHBX = 0,
1652                    AHBLY = 0,
1653                    AHBLX = 0,
1654                    AHBRY = 0,
1655                    AHBRX = 0,
1656                    dAngle = 0,
1657                    dHypotenuse = 0;
1658
1659            POINT2 tempLinePoint = new POINT2(startLinePoint);
1660            //end declarations
1661
1662            if (dy == 0) {
1663                if (dx > 0) {
1664                    dAngle = Math.PI;
1665                } else {
1666                    dAngle = 0;
1667                }
1668            } else {
1669                dAngle = Math.atan(dx / dy) + Math.PI / 2;
1670            }
1671
1672            tempLinePoint.style = 0;//PS_SOLID;
1673
1674            if (dx <= 0.0 && dy <= 0.0) {
1675                dSign = -1.0;
1676            }
1677            if (dx >= 0.0 && dy <= 0.0) {
1678                dSign = -1.0;
1679            }
1680            if (dx <= 0.0 && dy >= 0.0) {
1681                dSign = 1.0;
1682            }
1683            if (dx >= 0.0 && dy >= 0.0) {
1684                dSign = 1.0;
1685            }
1686
1687            dHypotenuse = dSign * (double) nBiSector;
1688
1689            //Find x, y for Arrow Head nBase startLinePoint POINT1
1690            AHBX = (double) endLinePoint.x + dHypotenuse * Math.cos(dAngle);
1691            AHBY = (double) endLinePoint.y - dHypotenuse * Math.sin(dAngle);
1692
1693            //Half of the arrow head's length will be 10 units
1694            dHypotenuse = dSign * (double) (nBase / 2.0);
1695
1696            //Find x, y of Arrow Head nBase Left side end POINT1
1697            AHBLX = AHBX - dHypotenuse * Math.sin(dAngle);
1698            AHBLY = AHBY - dHypotenuse * Math.cos(dAngle);
1699
1700            //Find x, y of Arrow Head nBase Right side end POINT1
1701            AHBRX = AHBX + dHypotenuse * Math.sin(dAngle);
1702            AHBRY = AHBY + dHypotenuse * Math.cos(dAngle);
1703
1704            //replacement, just trying to return the POINT1s
1705            tempLinePoint.x = (int) AHBLX;
1706            tempLinePoint.y = (int) AHBLY;
1707            pResultLinePoints[0] = new POINT2(tempLinePoint);
1708            pResultLinePoints[1] = new POINT2(endLinePoint);
1709            tempLinePoint.x = (int) AHBRX;
1710            tempLinePoint.y = (int) AHBRY;
1711            pResultLinePoints[2] = new POINT2(tempLinePoint);
1712            switch (styl) {
1713                case 0:
1714                    for (j = 0; j < 2; j++) {
1715                        pResultLinePoints[j].style = 0;
1716                    }
1717                    pResultLinePoints[2].style = 5;
1718                    break;
1719                case 9:
1720                    for (j = 0; j < 2; j++) {
1721                        pResultLinePoints[j].style = 9;
1722                    }
1723                    pResultLinePoints[2].style = 10;
1724                    break;
1725                case 18:
1726                    for (j = 0; j < 2; j++) {
1727                        pResultLinePoints[j].style = 18;
1728                    }
1729                    pResultLinePoints[2].style = 5;
1730                    break;
1731                default:
1732                    for (j = 0; j < 2; j++) {
1733                        pResultLinePoints[j].style = styl;
1734                    }
1735                    pResultLinePoints[2].style = 5;
1736                    break;
1737            }
1738        } catch (Exception exc) {
1739            ErrorLogger.LogException(_className, "GetArrowhead4Double",
1740                    new RendererException("Failed inside GetArrowhead4Double", exc));
1741        }
1742    }
1743
1744    /**
1745     * Returns the midpoint between two points.
1746     *
1747     * @param pt0 the first point
1748     * @param pt1 the second point
1749     * @param styl the style to assign the mid point
1750     *
1751     * @return the mid point
1752     */
1753    public static POINT2 MidPointDouble(POINT2 pt0,
1754            POINT2 pt1,
1755            int styl) {
1756        POINT2 ptResult = new POINT2(pt0);
1757        try {
1758            ptResult.x = (pt0.x + pt1.x) / 2;
1759            ptResult.y = (pt0.y + pt1.y) / 2;
1760            ptResult.style = styl;
1761        } catch (Exception exc) {
1762            ErrorLogger.LogException(_className, "MidPointDouble",
1763                    new RendererException("Failed inside MidPointDouble", exc));
1764        }
1765        return ptResult;
1766    }
1767
1768    /**
1769     * Rotates an the first vblCounter points in the array about its first point
1770     *
1771     * @param pLinePoints OUT - the points to rotate
1772     * @param vblCounter the number of points to rotate
1773     * @param lAngle the angle in degrees to rotate
1774     *
1775     * @return pLinePoints
1776     */
1777    protected static POINT2[] RotateGeometryDoubleOrigin(POINT2[] pLinePoints,
1778            int vblCounter,
1779            int lAngle) {
1780        try {
1781            //declarations
1782            int j = 0;
1783            double dRotate = 0,
1784                    dTheta = 0,
1785                    dGamma = 0,
1786                    x = 0,
1787                    y = 0;
1788            //end declarations
1789
1790            if (lAngle != 0) {
1791                POINT2 pdCenter = new POINT2();
1792                dRotate = (double) lAngle * Math.PI / 180d;
1793                //pdCenter = CalcCenterPointDouble(pLinePoints,vblCounter);
1794                pdCenter = new POINT2(pLinePoints[0]);
1795
1796                for (j = 0; j < vblCounter; j++) {
1797                    dGamma = Math.PI + Math.atan((pLinePoints[j].y - pdCenter.y)
1798                            / (pLinePoints[j].x - pdCenter.x));
1799
1800                    if (pLinePoints[j].x >= pdCenter.x) {
1801                        dGamma = dGamma + Math.PI;
1802                    }
1803
1804                    dTheta = dRotate + dGamma;
1805                    y = CalcDistanceDouble(pLinePoints[j], pdCenter) * Math.sin(dTheta);
1806                    x = CalcDistanceDouble(pLinePoints[j], pdCenter) * Math.cos(dTheta);
1807                    pLinePoints[j].y = pdCenter.y + y;
1808                    pLinePoints[j].x = pdCenter.x + x;
1809                }       //end for
1810
1811                return pLinePoints;
1812            }   //end if
1813        } catch (Exception exc) {
1814            ErrorLogger.LogException(_className, "RotateGeometryDoubleOrigin",
1815                    new RendererException("Failed inside RotateGeometryDoubleOrigin", exc));
1816        }
1817        return pLinePoints;
1818    }  // end function
1819
1820    /**
1821     * Returns a point a distance d pixels perpendicular to the pt0-pt1 line and
1822     * going toward pt2
1823     *
1824     * @param pt0 the first line point
1825     * @param pt1 the second line point
1826     * @param pt2 the relative line point
1827     * @param d the distance in pixels
1828     * @param styl the linestyle to assign the computed point
1829     *
1830     * @return the extended point
1831     */
1832    public static POINT2 ExtendTrueLinePerpDouble(POINT2 pt0,
1833            POINT2 pt1,
1834            POINT2 pt2,
1835            double d,
1836            int styl) {
1837        POINT2 ptResult = new POINT2(pt0);
1838        try {
1839            POINT2 ptYIntercept = new POINT2(pt0);
1840            ref<double[]> m = new ref();
1841            double b = 0, b1 = 0;       //b is the normal Y intercept (at 0)
1842            int nTemp = 0;                      //b1 is the y intercept at offsetX
1843
1844            //must obtain x minimum to get the y-intercept to the left of
1845            //the left-most point
1846            ref<double[]> offsetX = new ref(), offsetY = new ref();
1847            POINT2[] pts = new POINT2[3];
1848            pts[0] = new POINT2(pt0);
1849            pts[1] = new POINT2(pt1);
1850            pts[2] = new POINT2(pt2);
1851            GetPixelsMin(pts, 3, offsetX, offsetY);
1852
1853            if (offsetX.value[0] <= 0) //was < 0
1854            {
1855                offsetX.value[0] = offsetX.value[0] - 100;
1856            } else {
1857                offsetX.value[0] = 0;
1858            }
1859            //end section
1860
1861            nTemp = CalcTrueSlopeDouble(pt0, pt1, m);
1862            switch (nTemp) {
1863                case 0: //vertical line
1864                    if (pt0.y < pt1.y) {
1865                        ptResult.x = pt2.x - d;
1866                        ptResult.y = pt2.y;
1867                    } else {
1868                        ptResult.x = pt2.x + d;
1869                        ptResult.y = pt2.y;
1870                    }
1871                    break;
1872                default:        //non-vertical line
1873                    if (m.value[0] == 0) {
1874                        ptResult.x = pt2.x;
1875                        ptResult.y = pt2.y + d;
1876                    } else {
1877                        b = (double) pt2.y + (1 / m.value[0]) * (double) pt2.x;
1878                        //we need the y-intercept at the -offset
1879                        b1 = (-1 / m.value[0]) * offsetX.value[0] + b;
1880                        ptYIntercept.x = offsetX.value[0];
1881                        ptYIntercept.y = b1;
1882                        ptResult = ExtendLineDouble(ptYIntercept, pt2, d);
1883                    }
1884                    break;
1885            }
1886            ptResult.style = styl;
1887            pts = null;
1888        } catch (Exception exc) {
1889            ErrorLogger.LogException(_className, "ExtendTrueLinePerpDouble",
1890                    new RendererException("Failed inside ExtendTrueLinePerpDouble", exc));
1891        }
1892        return ptResult;
1893    }
1894
1895    /**
1896     * Calculates the intersection of 2 lines pelative to a point. if one of the
1897     * lines is vertical use a distance dWidth above or below the line. pass
1898     * bolVertical1 = 1, or bolVertical2 = 1 if either line segment is vertical,
1899     * else pass 0. return the unique intersection in X,Y pointers. p2 is the
1900     * point that connects the 2 line segments to which the intersecting lines
1901     * are related, i.e. the intersecting lines are a distance dWidth pixels
1902     * above or below p2. uses dWidth and lOrient for cases in which at least
1903     * one of the lines is vertical. for normal lines this function assumes the
1904     * caller has passed the m, b for the appropriate upper or lower lines to
1905     * get the desired intgercept. this function is used for calculating the
1906     * upper and lower channel lines for channel types. For lOrient: see
1907     * comments in Channels.ConnectTrueDouble2
1908     *
1909     * @param m1 slope of the first line
1910     * @param b1 intercept of the first line
1911     * @param m2 slope of the second line
1912     * @param b2 y intercept of the second line
1913     * @param p2 point that connects the 2 line segments to which the
1914     * intersecting lines are related
1915     * @param bolVerticalSlope1 1 if first segment is vertical, else 0
1916     * @param bolVerticalSlope2 1 if second line segment is vertical, else 0
1917     * @param dWidth the distance of the intersecting lines from p2 in pixels
1918     * @param lOrient the orientation of the intersecting lines relative to the
1919     * segments connecting p2
1920     * @param X OUT - object holds the x value of the intersection point
1921     * @param Y OUT - object holds the y value of the intersection point
1922     */
1923    protected static int CalcTrueIntersectDouble(double m1,
1924            double b1,
1925            double m2,
1926            double b2,
1927            POINT2 p2, //can use for vertical lines
1928            int bolVerticalSlope1,
1929            int bolVerticalSlope2,
1930            double dWidth, //use for vertical lines, use + for upper line, - for lower line
1931            int lOrient,
1932            ref<double[]> X, //intersection x value
1933            ref<double[]> Y) //intersection y value
1934    {
1935
1936        try {
1937            //case both lines are vertical
1938            double dWidth2 = Math.abs(dWidth);
1939            double b = 0;
1940            double dx = 0, dy = 0, m = 0;
1941            X.value = new double[1];
1942            Y.value = new double[1];
1943
1944            //cannot get out of having to do this
1945            //the problem is caused by inexact slopes which are created by
1946            //clsLineUtility.DisplayIntersectPixels. This occurs when setting
1947            //pt2 or pt3 with X or Y on the boundary +/-maxPixels
1948            //if you try to walk out until you get exactly the same slope
1949            //it can be thousands of pixels, so you have to accept an arbitrary
1950            //and, unfortuantely, inexact slope
1951            if (m1 != m2 && Math.abs(m1 - m2) <= Double.MIN_VALUE) {
1952                m1 = m2;
1953            }
1954            if (b1 != b2 && Math.abs(b1 - b2) <= Double.MIN_VALUE) {
1955                b1 = b2;
1956            }
1957
1958            //M. Deutch 10-24-11
1959            if (b1 == b2 && m1 + b1 == m2 + b2) {
1960                m1 = m2;
1961            }
1962
1963            if (bolVerticalSlope1 == 0 && bolVerticalSlope2 == 0) //both lines vertical
1964            {
1965                switch (lOrient) {
1966                    case 0:
1967                        X.value[0] = p2.x - dWidth2;
1968                        Y.value[0] = p2.y;
1969                        break;
1970                    case 3:
1971                        X.value[0] = p2.x + dWidth2;
1972                        Y.value[0] = p2.y;
1973                        break;
1974                    default:    //can never occur
1975                        X.value[0] = p2.x;
1976                        Y.value[0] = p2.y;
1977                        break;
1978                }
1979                return 1;
1980            }
1981            if (bolVerticalSlope1 == 0 && bolVerticalSlope2 != 0) //line1 vertical, line2 is not
1982            {   //there is a unique intersection
1983                switch (lOrient) {
1984                    case 0:     //Line1 above segment1
1985                    case 1:
1986                        X.value[0] = p2.x - dWidth2;
1987                        Y.value[0] = m2 * X.value[0] + b2;
1988                        break;
1989                    case 2:     //Line1 below segment1
1990                    case 3:
1991                        X.value[0] = p2.x + dWidth2;
1992                        Y.value[0] = m2 * X.value[0] + b2;
1993                        break;
1994                    default:    //can not occur
1995                        X.value[0] = p2.x;
1996                        Y.value[0] = p2.y;
1997                        break;
1998                }
1999                return 1;
2000            }
2001            if (bolVerticalSlope2 == 0 && bolVerticalSlope1 != 0) //line2 vertical, line1 is not
2002            {   //there is a unique intersection
2003                switch (lOrient) {
2004                    case 0:     //Line1 above segment2
2005                    case 2:
2006                        X.value[0] = p2.x - dWidth2;
2007                        Y.value[0] = m1 * (X.value[0]) + b1;
2008                        break;
2009                    case 1:     //Line1 below segment2
2010                    case 3:
2011                        X.value[0] = p2.x + dWidth2;
2012                        Y.value[0] = m1 * (X.value[0]) + b1;
2013                        break;
2014                    default:    //can not occur
2015                        X.value[0] = p2.x;
2016                        Y.value[0] = p2.y;
2017                        break;
2018                }
2019                return 1;
2020            }//end if
2021
2022            //must deal with this case separately because normal lines use m1-m2 as a denominator
2023            //but we've handled all the vertical cases above so can assume it's not vertical
2024            //if the b's are different then one is an upper line, the other is a lower, no intersection
2025            //m and b will be used to build the perpendicular line thru p2 which we will use to
2026            //build the intersection, so must assume slopes are not 0, handle separately
2027            if (m1 == m2 && m1 != 0) {
2028                if (b1 == b2) //then the intercept is the point joining the 2 segments
2029                {
2030                    //build the perpendicular line
2031                    m = -1 / m1;
2032                    b = p2.y - m * p2.x;
2033                    X.value[0] = (b2 - b) / (m - m2);   //intersect the lines (cannot blow up, m = m2 not possible)
2034                    Y.value[0] = (m1 * (X.value[0]) + b1);
2035                    return 1;
2036                } else //can not occur
2037                {
2038                    X.value[0] = p2.x;
2039                    Y.value[0] = p2.y;
2040                    return 1;
2041                }
2042            }
2043            //slope is zero
2044            if (m1 == m2 && m1 == 0) {
2045                switch (lOrient) {
2046                    case 0:     //Line1 above the line
2047                    case 1:     //should never happen
2048                        X.value[0] = p2.x;
2049                        Y.value[0] = p2.y - dWidth2;
2050                        break;
2051                    case 3:     //Line1 below the line
2052                    case 2:     //should never happen
2053                        X.value[0] = p2.x;
2054                        Y.value[0] = p2.y + dWidth2;
2055                        break;
2056                    default:    //can not occur
2057                        X.value[0] = p2.x;
2058                        Y.value[0] = p2.y;
2059                        break;
2060                }
2061                return 1;
2062            }
2063
2064            if (m1 == m2 && b1 == b2 && bolVerticalSlope1 != 0 && bolVerticalSlope2 != 0) {
2065                switch (lOrient) {
2066                    case 0:     //Line1 is above the line
2067                        if (m1 < 0) {
2068                            dy = m1 * dWidth / Math.sqrt(1 + m1 * m1);  //dy is negative
2069                            dx = dy / m1;       //dx is negative
2070                            X.value[0] = p2.x + dx;
2071                            Y.value[0] = p2.y + dy;
2072                        }
2073                        if (m1 > 0) //slope is positive
2074                        {
2075                            dy = -m1 * dWidth / Math.sqrt(1 + m1 * m1); //dy is negative
2076                            dx = -dy / m1;      //dx is positive
2077                            X.value[0] = p2.x + dx;
2078                            Y.value[0] = p2.y + dy;
2079                        }
2080                        break;
2081                    case 3:     //Line1 is below the line
2082                        if (m1 <= 0) {
2083                            dy = -m1 * dWidth / Math.sqrt(1 + m1 * m1); //dy is positive
2084                            dx = dy / m1;       //dx is positive
2085                            X.value[0] = p2.x + dx;
2086                            Y.value[0] = p2.y + dy;
2087                        } else {
2088                            dy = m1 * dWidth / Math.sqrt(1 + m1 * m1);  //dy is positive
2089                            dx = -dy / m1;      //dx is negative
2090                            X.value[0] = p2.x + dx;
2091                            Y.value[0] = p2.y + dy;
2092                        }
2093                        break;
2094                    default:
2095                        X.value[0] = p2.x;
2096                        Y.value[0] = p2.y;
2097                        break;
2098                }
2099                return 1;
2100            }//end if
2101
2102            //a normal line. no vertical or identical slopes
2103            //if m1=m2 function will not reach this point
2104            X.value[0] = (b2 - b1) / (m1 - m2); //intersect the lines
2105            Y.value[0] = (m1 * (X.value[0]) + b1);
2106            return 1;
2107        }//end try
2108        catch (Exception exc) {
2109            X.value[0] = p2.x;
2110            Y.value[0] = p2.y;
2111            ErrorLogger.LogException(_className, "CalcTrueIntersectDouble",
2112                    new RendererException("Failed inside ExtendTrueIntersectDouble", exc));
2113        }
2114        return 1;
2115    }
2116
2117    /**
2118     * Returns the distance in pixels from x1,y1 to x2,y2
2119     *
2120     * @param x1 first point x location in pixels
2121     * @param y1 first point y location in pixels
2122     * @param x2 second point x location in pixels
2123     * @param y2 second point y location in pixels
2124     *
2125     * @return the distance
2126     */
2127    protected static double CalcDistance2(long x1,
2128            long y1,
2129            long x2,
2130            long y2) {
2131        double dResult = 0;
2132        try {
2133            dResult = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
2134
2135            //sanity check
2136            //return x or y distance if return value is 0 or infinity
2137            double xdist = Math.abs(x1 - x2);
2138            double ydist = Math.abs(y1 - y2);
2139            double max = xdist;
2140            if (ydist > xdist) {
2141                max = ydist;
2142            }
2143            if (dResult == 0 || Double.isInfinite(dResult)) {
2144                if (max > 0) {
2145                    dResult = max;
2146                }
2147            }
2148        } catch (Exception exc) {
2149            ErrorLogger.LogException(_className, "CalcDistance2",
2150                    new RendererException("Failed inside CalcDistance2", exc));
2151        }
2152        return dResult;
2153    }
2154    /**
2155     * gets the middle line for Rev B air corridors AC, LLTR, MRR, UAV
2156     * Middle line is handled separately now because the line may have been segmented
2157     * @param pLinePoints
2158     * @return 
2159     */
2160    protected static POINT2[] GetSAAFRMiddleLine(POINT2[] pLinePoints) {
2161        POINT2[] pts = null;
2162        try {
2163            int j = 0, count = 0;
2164            for (j = 0; j < pLinePoints.length-1; j++) {
2165                if (pLinePoints[j].style > 0) {
2166                    count++;
2167                }
2168            }
2169            pts = new POINT2[count*2];
2170            count=0;
2171            double dMRR=0;
2172            POINT2 firstSegPt=null,lastSegPt=null,pt0=null,pt1=null;
2173            for (j = 0; j < pLinePoints.length; j++) {
2174                if(pLinePoints[j].style>=0 || j==pLinePoints.length-1)
2175                {
2176                    if(lastSegPt != null)
2177                    {
2178                        firstSegPt=new POINT2(lastSegPt);
2179                        lastSegPt=new POINT2(pLinePoints[j]);
2180                        dMRR=firstSegPt.style;
2181                        pt0 = ExtendLine2Double(lastSegPt, firstSegPt, -dMRR, 0);
2182                        pt1 = ExtendLine2Double(firstSegPt, lastSegPt, -dMRR, 5);                        
2183                        pts[count++]=pt0;
2184                        pts[count++]=pt1;
2185                    }
2186                    else
2187                    {
2188                        lastSegPt=new POINT2(pLinePoints[j]);
2189                    }
2190                }
2191            }            
2192        } catch (Exception exc) {
2193            ErrorLogger.LogException(_className, "GetSAAFRMiddleLine",
2194                    new RendererException("Failed inside GetSAAFRMiddleLine", exc));
2195        }
2196        return pts;
2197    }
2198    /**
2199     * Computes the points for a SAAFR segment
2200     *
2201     * @param pLinePoints OUT - the client points also used for the returned
2202     * points
2203     * @param lineType the line type
2204     * @param dMRR the symbol width
2205     */
2206    protected static void GetSAAFRSegment(POINT2[] pLinePoints,
2207            int lineType,
2208            double dMRR,
2209            int rev) {
2210        try {
2211            POINT2 pt0 = new POINT2();
2212            POINT2 pt1 = new POINT2();
2213            POINT2 pt2 = new POINT2();
2214            POINT2 pt3 = new POINT2();
2215            POINT2 pt4 = new POINT2();
2216            POINT2 pt5 = new POINT2();
2217            ref<double[]> m = new ref();
2218            int bolVertical = CalcTrueSlopeDouble(pLinePoints[0], pLinePoints[1], m);
2219            //shortened line
2220            //pt1=ExtendLine2Double(pLinePoints[0],pLinePoints[1],-dMRR/2,5);
2221            //pt0=ExtendLine2Double(pLinePoints[1],pLinePoints[0],-dMRR/2,0);
2222            pt1 = ExtendLine2Double(pLinePoints[0], pLinePoints[1], -dMRR, 5);
2223            pt0 = ExtendLine2Double(pLinePoints[1], pLinePoints[0], -dMRR, 0);
2224            if (bolVertical != 0 && m.value[0] < 1) {
2225                //upper line
2226                pt2 = ExtendDirectedLine(pLinePoints[0], pLinePoints[1], pLinePoints[0], 2, dMRR);
2227                pt2.style = 0;
2228                pt3 = ExtendDirectedLine(pLinePoints[0], pLinePoints[1], pLinePoints[1], 2, dMRR);
2229                pt3.style = 5;
2230                //lower line
2231                pt4 = ExtendDirectedLine(pLinePoints[0], pLinePoints[1], pLinePoints[0], 3, dMRR);
2232                pt4.style = 0;
2233                pt5 = ExtendDirectedLine(pLinePoints[0], pLinePoints[1], pLinePoints[1], 3, dMRR);
2234                pt5.style = 5;
2235            } //if( (bolVertical!=0 && m>1) || bolVertical==0)
2236            else {
2237                //left line
2238                pt2 = ExtendDirectedLine(pLinePoints[0], pLinePoints[1], pLinePoints[0], 0, dMRR);
2239                pt2.style = 0;
2240                pt3 = ExtendDirectedLine(pLinePoints[0], pLinePoints[1], pLinePoints[1], 0, dMRR);
2241                pt3.style = 5;
2242                //right line
2243                pt4 = ExtendDirectedLine(pLinePoints[0], pLinePoints[1], pLinePoints[0], 1, dMRR);
2244                pt4.style = 0;
2245                pt5 = ExtendDirectedLine(pLinePoints[0], pLinePoints[1], pLinePoints[1], 1, dMRR);
2246                pt5.style = 5;
2247            }
2248            //load the line points
2249            pLinePoints[0] = new POINT2(pt0);
2250            pLinePoints[1] = new POINT2(pt1);
2251            pLinePoints[2] = new POINT2(pt2);
2252            pLinePoints[3] = new POINT2(pt3);
2253            pLinePoints[4] = new POINT2(pt4);
2254            pLinePoints[5] = new POINT2(pt5);
2255            pLinePoints[5].style = 5;
2256//            if (lineType == TacticalLines.SAAFR) {
2257//                pLinePoints[0].style = 5;
2258//            }
2259//            if (rev == RendererSettings.Symbology_2525C) {
2260//                pLinePoints[0].style = 5;
2261//            }
2262            pLinePoints[0].style = 5;
2263        } catch (Exception exc) {
2264            ErrorLogger.LogException(_className, "GetSAAFRSegment",
2265                    new RendererException("Failed inside GetSAAFRSegment", exc));
2266        }
2267    }
2268    /**
2269     * Called by arraysupport for SAAFR and AC fill shapes
2270     * @param pLinePoints
2271     * @param lineType
2272     * @param dMRR
2273     * @param rev 
2274     */
2275    protected static void GetSAAFRFillSegment(POINT2[] pLinePoints,
2276            double dMRR) {
2277        try {
2278            POINT2 pt2 = new POINT2();
2279            POINT2 pt3 = new POINT2();
2280            POINT2 pt4 = new POINT2();
2281            POINT2 pt5 = new POINT2();
2282            ref<double[]> m = new ref();
2283            int bolVertical = CalcTrueSlopeDouble(pLinePoints[0], pLinePoints[1], m);
2284            if (bolVertical != 0 && m.value[0] < 1) {
2285                //upper line
2286                pt2 = ExtendDirectedLine(pLinePoints[0], pLinePoints[1], pLinePoints[0], 2, dMRR);
2287                pt3 = ExtendDirectedLine(pLinePoints[0], pLinePoints[1], pLinePoints[1], 2, dMRR);
2288                //lower line
2289                pt4 = ExtendDirectedLine(pLinePoints[0], pLinePoints[1], pLinePoints[0], 3, dMRR);
2290                pt5 = ExtendDirectedLine(pLinePoints[0], pLinePoints[1], pLinePoints[1], 3, dMRR);
2291            } //if( (bolVertical!=0 && m>1) || bolVertical==0)
2292            else {
2293                //left line
2294                pt2 = ExtendDirectedLine(pLinePoints[0], pLinePoints[1], pLinePoints[0], 0, dMRR);
2295                pt3 = ExtendDirectedLine(pLinePoints[0], pLinePoints[1], pLinePoints[1], 0, dMRR);
2296                //right line
2297                pt4 = ExtendDirectedLine(pLinePoints[0], pLinePoints[1], pLinePoints[0], 1, dMRR);
2298                pt5 = ExtendDirectedLine(pLinePoints[0], pLinePoints[1], pLinePoints[1], 1, dMRR);
2299            }
2300            //load the line points
2301            pLinePoints[0] = new POINT2(pt2);
2302            pLinePoints[1] = new POINT2(pt3);
2303            pLinePoints[2] = new POINT2(pt5);
2304            pLinePoints[3] = new POINT2(pt4);
2305        } catch (Exception exc) {
2306            ErrorLogger.LogException(_className, "GetSAAFRFillSegment",
2307                    new RendererException("Failed inside GetSAAFRFillSegment", exc));
2308        }
2309        //return;
2310    }
2311    /**
2312     * Computes an arc.
2313     *
2314     * @param pResultlinePoints OUT - contains center and start point and holds
2315     * the result arc points
2316     * @param vblCounter the number of client points
2317     * @param dRadius the arc radius in pixels
2318     * @param linetype the linetype determines start andgle and end angle for
2319     * the arc
2320     *
2321     */
2322    protected static POINT2[] ArcArrayDouble(POINT2[] pResultLinePoints,
2323            int vblCounter,
2324            double dRadius,
2325            int linetype,
2326            IPointConversion converter) {
2327        try {
2328            //declarations
2329            double startangle = 0, //start of pArcLinePoints
2330                    endangle = 0, //end of the pArcLinePoints
2331                    increment = 0,
2332                    //m = 0,
2333                    length = 0, //length of a to e
2334                    M = 0;
2335
2336            int j, numarcpts = 0, bolVertical = 0;
2337            ref<double[]> m = new ref();
2338            //C is the center of the pArcLinePoints derived from a and e
2339            POINT2 C = new POINT2(pResultLinePoints[0]),
2340                    a = new POINT2(pResultLinePoints[1]),
2341                    e = new POINT2(pResultLinePoints[0]);
2342
2343            POINT2[] pArcLinePoints = null;
2344            //end declarations
2345
2346            bolVertical = CalcTrueSlopeDouble(a, e, m);
2347            if (bolVertical != 0) {
2348                M = Math.atan(m.value[0]);
2349            } else {
2350                if (a.y < e.y) {
2351                    M = -Math.PI / 2;
2352                } else {
2353                    M = Math.PI / 2;
2354                }
2355            }
2356            if(converter != null)
2357            {
2358                Point2D pt02d=new Point2D.Double(pResultLinePoints[0].x,pResultLinePoints[0].y);
2359                Point2D pt12d=new Point2D.Double(pResultLinePoints[1].x,pResultLinePoints[1].y);
2360                //boolean reverseM=false;
2361                pt02d=converter.PixelsToGeo(pt02d);
2362                pt12d=converter.PixelsToGeo(pt12d);
2363                //M=mdlGeodesic.GetAzimuth(pt02d,pt12d);
2364                M=mdlGeodesic.GetAzimuth(new POINT2(pt02d.getX(),pt02d.getY()),new POINT2(pt12d.getX(),pt12d.getY()  )  );
2365                M*=(Math.PI/180);
2366                if(M<0)
2367                    M+=Math.PI;
2368            }
2369            length = CalcDistanceDouble(a, e);
2370            if(converter != null)
2371            {
2372                Point2D pt02d=new Point2D.Double(pResultLinePoints[0].x,pResultLinePoints[0].y);
2373                Point2D pt12d=new Point2D.Double(pResultLinePoints[1].x,pResultLinePoints[1].y);
2374                pt02d=converter.PixelsToGeo(pt02d);
2375                pt12d=converter.PixelsToGeo(pt12d);
2376                //length=mdlGeodesic.geodesic_distance(pt02d,pt12d,null,null);
2377                length=mdlGeodesic.geodesic_distance(new POINT2(pt02d.getX(),pt02d.getY()),new POINT2(pt12d.getX(),pt12d.getY()),null,null);
2378            }
2379            switch (linetype) {
2380                case TacticalLines.CLUSTER:
2381                    startangle = M - 90 * Math.PI / 180.0;
2382                    endangle = startangle + 2 * 90 * Math.PI / 180.0;
2383                    break;
2384                case TacticalLines.TRIP:
2385                    startangle = M - 45 * Math.PI / 180.0;
2386                    endangle = startangle + 2 * 45 * Math.PI / 180.0;
2387                    break;
2388                case TacticalLines.ISOLATE:
2389                case TacticalLines.CORDONKNOCK:
2390                case TacticalLines.CORDONSEARCH:
2391                    startangle = M;
2392                    endangle = startangle + 330 * Math.PI / 180;
2393                    break;
2394                case TacticalLines.TURN:
2395                    startangle = M;
2396                    endangle = startangle + 90 * Math.PI / 180;
2397                    break;
2398                case TacticalLines.OCCUPY:
2399                case TacticalLines.RETAIN:
2400                case TacticalLines.SECURE:
2401                    startangle = M;
2402                    //if(CELineArrayGlobals.Change1==false)
2403                    endangle = startangle + 338 * Math.PI / 180;
2404                    //else
2405                    //  endangle=startangle+330*pi/180;
2406                    break;
2407                default:
2408                    startangle = 0;
2409                    endangle = 2 * Math.PI;
2410                    break;
2411            }
2412
2413            if (a.x < e.x) {
2414                switch (linetype) {
2415                    case TacticalLines.ISOLATE:
2416                    case TacticalLines.CORDONKNOCK:
2417                    case TacticalLines.CORDONSEARCH:
2418                        startangle = M - Math.PI;
2419                        endangle = startangle + 330 * Math.PI / 180;
2420                        break;
2421                    case TacticalLines.OCCUPY:
2422                    case TacticalLines.RETAIN:
2423                    case TacticalLines.SECURE:
2424                        startangle = M - Math.PI;
2425                        //if(CELineArrayGlobals.Change1==false)
2426                        endangle = startangle + 338 * Math.PI / 180;
2427                        //else
2428                        //      endangle=startangle+330*pi/180;
2429                        break;
2430                    case TacticalLines.TURN:
2431                        startangle = M - Math.PI;
2432                        endangle = startangle + 90 * Math.PI / 180;
2433                        break;
2434                    case TacticalLines.CLUSTER:
2435                        startangle = M - Math.PI + 90 * Math.PI / 180.0;
2436                        endangle = startangle - 2 * 90 * Math.PI / 180.0;
2437                        break;
2438                    case TacticalLines.TRIP:
2439                        startangle = M - Math.PI + 45 * Math.PI / 180.0;
2440                        endangle = startangle - 2 * 45 * Math.PI / 180.0;
2441                        break;
2442                    default:
2443                        break;
2444                }
2445            }
2446
2447            numarcpts = 26;
2448            pArcLinePoints = new POINT2[numarcpts];
2449            InitializePOINT2Array(pArcLinePoints);
2450            increment = (endangle - startangle) / (numarcpts - 1);
2451            if(dRadius != 0 && length != 0)
2452            {
2453                C.x = (int) ((double) e.x - (dRadius / length)
2454                        * ((double) a.x - (double) e.x));
2455                C.y = (int) ((double) e.y - (dRadius / length)
2456                        * ((double) a.y - (double) e.y));
2457            }
2458            else
2459            {
2460                C.x=e.x;
2461                C.y=e.y;
2462            }
2463            if (converter != null)
2464            {
2465                Point2D C2d=new Point2D.Double(pResultLinePoints[0].x,pResultLinePoints[0].y);
2466                C2d=converter.PixelsToGeo(C2d);    
2467                double az=0;
2468                Point2D ptGeo2d=null;
2469                POINT2 ptGeo=null;
2470                POINT2 ptPixels=null;
2471                for (j = 0; j < numarcpts; j++) {
2472                    az=startangle*180/Math.PI+j*increment*180/Math.PI;
2473                    //ptGeo=mdlGeodesic.geodesic_coordinate(C2d,length,az);
2474                    ptGeo=mdlGeodesic.geodesic_coordinate(new POINT2(C2d.getX(),C2d.getY()),length,az);
2475                    ptGeo2d=new Point2D.Double(ptGeo.x,ptGeo.y);
2476                    ptGeo2d=converter.GeoToPixels(ptGeo2d);
2477                    ptPixels=new POINT2(ptGeo2d.getX(),ptGeo2d.getY());
2478                    pArcLinePoints[j].x = ptPixels.x;
2479                    pArcLinePoints[j].y = ptPixels.y;                            
2480                }
2481            }
2482            else
2483            {
2484                for (j = 0; j < numarcpts; j++) {
2485                    //pArcLinePoints[j]=pResultLinePoints[0];   //initialize
2486                    pArcLinePoints[j].x = (int) (dRadius * Math.cos(startangle + j * increment));
2487                    pArcLinePoints[j].y = (int) (dRadius * Math.sin(startangle + j * increment));
2488                }
2489
2490                for (j = 0; j < numarcpts; j++) {
2491                    pArcLinePoints[j].x += C.x;
2492                    pArcLinePoints[j].y += C.y;
2493                }
2494            }
2495            switch (linetype) {
2496                case TacticalLines.ISOLATE:
2497                case TacticalLines.CORDONKNOCK:
2498                case TacticalLines.CORDONSEARCH:
2499                case TacticalLines.OCCUPY:
2500                case TacticalLines.RETAIN:
2501                case TacticalLines.SECURE:
2502                case TacticalLines.CLUSTER:
2503                case TacticalLines.TURN:
2504                case TacticalLines.TRIP:
2505                    for (j = 0; j < numarcpts; j++) {
2506                        pResultLinePoints[j] = new POINT2(pArcLinePoints[j]);
2507                    }
2508                    break;
2509                default:
2510                    for (j = 0; j < numarcpts; j++) {
2511                        pResultLinePoints[j] = new POINT2(pArcLinePoints[j]);
2512                    }
2513                    break;
2514            }
2515            pArcLinePoints = null;
2516        } catch (Exception exc) {
2517            ErrorLogger.LogException(_className, "ArcArrayDouble",
2518                    new RendererException("Failed inside ArcArrayDouble", exc));
2519        }
2520        return pResultLinePoints;
2521    }
2522    /**
2523     * Gets geodesic circle using the converter
2524     * @param Center in pixels
2525     * @param pt1 a point on the radius in pixels
2526     * @param numpts number of points to return
2527     * @param CirclePoints the result points
2528     * @param converter 
2529     */
2530    protected static void CalcCircleDouble2(POINT2 Center,
2531            POINT2 pt1,
2532            int numpts,
2533            POINT2[] CirclePoints,
2534            IPointConversion converter) {
2535        try {
2536            int j = 0;
2537            double increment = (Math.PI * 2) / (numpts - 1);
2538            Point2D ptCenter2d=new Point2D.Double(Center.x,Center.y);
2539            ptCenter2d=converter.PixelsToGeo(ptCenter2d);
2540            Point2D pt12d=new Point2D.Double(pt1.x,pt1.y);
2541            pt12d=converter.PixelsToGeo(pt12d);
2542            Center=new POINT2(ptCenter2d.getX(),ptCenter2d.getY());
2543            pt1=new POINT2(pt12d.getX(),pt12d.getY());
2544            double dist=mdlGeodesic.geodesic_distance(Center, pt1, null, null);
2545            
2546            //double dSegmentAngle = 2 * Math.PI / numpts;
2547            double az=0;
2548            double startangle=0,endAngle=Math.PI*2;
2549            POINT2 ptGeo=null,ptPixels=null;
2550            Point2D ptGeo2d=null;           
2551            for (j = 0; j < numpts - 1; j++) {
2552                az=startangle*180/Math.PI+j*increment*180/Math.PI;
2553                //ptGeo=mdlGeodesic.geodesic_coordinate(C2d,length,az);
2554                ptGeo=mdlGeodesic.geodesic_coordinate(Center,dist,az);
2555                ptGeo2d=new Point2D.Double(ptGeo.x,ptGeo.y);
2556                ptGeo2d=converter.GeoToPixels(ptGeo2d);
2557                ptPixels=new POINT2(ptGeo2d.getX(),ptGeo2d.getY());
2558                CirclePoints[j].x = ptPixels.x;
2559                CirclePoints[j].y = ptPixels.y;                            
2560            }
2561            CirclePoints[numpts - 1] = new POINT2(CirclePoints[0]);
2562
2563        } catch (Exception exc) {
2564            ErrorLogger.LogException(_className, "CalcCircleDouble2",
2565                    new RendererException("Failed inside CalcCircleDouble2", exc));
2566        }
2567        return;
2568    }
2569    /**
2570     * Computes the points for a circle. Assumes CirclePoints has been allocated
2571     * with size numpts.
2572     *
2573     * @param Center the cicle center
2574     * @param radius the circle radius in pixels
2575     * @param numpts the number of circle points
2576     * @param CirclePoints - OUT - array of circle points
2577     * @param styl the style to set the last circle point
2578     */
2579    protected static void CalcCircleDouble(POINT2 Center,
2580            double radius,
2581            int numpts,
2582            POINT2[] CirclePoints,
2583            int styl) {
2584        try {
2585            int j = 0;
2586            double dSegmentAngle = 2 * Math.PI / numpts;
2587            double x = 0, y = 0;
2588            for (j = 0; j < numpts - 1; j++) {
2589                x = Center.x + (radius * Math.cos((double) j * dSegmentAngle));
2590                y = Center.y + (radius * Math.sin((double) j * dSegmentAngle));
2591                CirclePoints[j] = new POINT2(x, y);
2592                CirclePoints[j].style = styl;
2593            }
2594            CirclePoints[numpts - 1] = new POINT2(CirclePoints[0]);
2595
2596            switch (styl) {
2597                case 0:
2598                    CirclePoints[numpts - 1].style = 0;
2599                    break;
2600                case 9:
2601                    CirclePoints[numpts - 1].style = 10;
2602                    break;
2603                case 11:
2604                    CirclePoints[numpts - 1].style = 12;
2605                    break;
2606                default:
2607                    CirclePoints[numpts - 1].style = 5;
2608                    break;
2609            }
2610        } catch (Exception exc) {
2611            ErrorLogger.LogException(_className, "CalcCircleDouble",
2612                    new RendererException("Failed inside CalcCircleDouble", exc));
2613        }
2614    }
2615
2616    protected static Shape2 CalcCircleShape(POINT2 Center,
2617            double radius,
2618            int numpts,
2619            POINT2[] CirclePoints,
2620            int styl) {
2621        Shape2 shape;
2622        if (styl == 9) {
2623            shape = new Shape2(Shape2.SHAPE_TYPE_FILL);
2624        } else {
2625            shape = new Shape2(Shape2.SHAPE_TYPE_POLYLINE);
2626        }
2627
2628        shape.set_Style(styl);
2629        try {
2630            int j = 0;
2631            CalcCircleDouble(Center, radius, numpts, CirclePoints, styl);
2632            shape.moveTo(CirclePoints[0]);
2633            for (j = 1; j < numpts; j++) {
2634                shape.lineTo(CirclePoints[j]);
2635            }
2636        } catch (Exception exc) {
2637            ErrorLogger.LogException(_className, "CalcCircleShape",
2638                    new RendererException("Failed inside CalcCircleShape", exc));
2639        }
2640        return shape;
2641    }
2642
2643    private static void GetSquallCurve(POINT2 StartPt,
2644            POINT2 EndPt,
2645            POINT2[] pSquallPts,
2646            int sign,
2647            int amplitude,
2648            int quantity) {
2649        try {
2650            double dist = CalcDistanceDouble(StartPt, EndPt);
2651            POINT2 ptTemp = new POINT2();
2652            int j = 0;
2653                //end declarations
2654
2655            //get points along the horizontal segment between StartPt and EndPt2;
2656            for (j = 0; j < quantity; j++) {
2657                ptTemp = ExtendLineDouble(EndPt, StartPt, -dist * (double) j / (double) quantity);
2658                pSquallPts[j].x = ptTemp.x;
2659                //calculate the sin value along the x axis
2660                pSquallPts[j].y = ptTemp.y + amplitude * sign * Math.sin((double) j * 180 / (double) quantity * Math.PI / 180);
2661            }
2662        } catch (Exception exc) {
2663            ErrorLogger.LogException(_className, "GetSquallShape",
2664                    new RendererException("Failed inside GeSquallShape", exc));
2665        }
2666    }
2667    //caller needs to instantiate sign.value
2668    /**
2669     * Gets the squall curves for a line segment Assumes pSquallPts has been
2670     * allocated the proper number of points.
2671     *
2672     * @param StartPt segment start point
2673     * @param EndPt segment end point
2674     * @param pSquallPts OUT - the squall points
2675     * @param sign OUT - an object with a member to hold the starting curve sign
2676     * for the segment.
2677     * @param amplitude the sin curve amplitutde
2678     * @param quantity the number of points for each sin curve
2679     * @param length the desired length of the curve along the segment for each
2680     * sin curve
2681     *
2682     * @return segment squall points count
2683     */
2684    protected static int GetSquallSegment(POINT2 StartPt,
2685            POINT2 EndPt,
2686            POINT2[] pSquallPts,
2687            ref<int[]> sign,
2688            int amplitude,
2689            int quantity,
2690            int length) {
2691        int counter = 0;
2692        try {
2693            POINT2 StartCurvePt, EndCurvePt;    //use these for the curve points
2694            POINT2[] pSquallPts2 = new POINT2[quantity];
2695            double dist = CalcDistanceDouble(StartPt, EndPt);
2696            int numCurves = (int) (dist / (double) length);
2697            int j = 0, k = 0;
2698            POINT2 EndPt2 = new POINT2();
2699            double angle = Math.atan((StartPt.y - EndPt.y) / (StartPt.x - EndPt.x));
2700            int lAngle = (int) ((180 / Math.PI) * angle);
2701            InitializePOINT2Array(pSquallPts2);
2702            //define EndPt2 to be the point dist from StartPt along the x axis
2703            if (StartPt.x < EndPt.x) {
2704                EndPt2.x = StartPt.x + dist;
2705            } else {
2706                EndPt2.x = StartPt.x - dist;
2707            }
2708
2709            EndPt2.y = StartPt.y;
2710
2711            EndCurvePt = StartPt;
2712            for (j = 0; j < numCurves; j++) {
2713                StartCurvePt = ExtendLineDouble(EndPt2, StartPt, -(double) (j * length));
2714                EndCurvePt = ExtendLineDouble(EndPt2, StartPt, -(double) ((j + 1) * length));
2715
2716                //get the curve points
2717                GetSquallCurve(StartCurvePt, EndCurvePt, pSquallPts2, sign.value[0], amplitude, quantity);
2718
2719                //fill the segment points with the curve points
2720                for (k = 0; k < quantity; k++) {
2721                    //pSquallPts[counter].x=pSquallPts2[k].x;
2722                    //pSquallPts[counter].y=pSquallPts2[k].y;
2723                    pSquallPts[counter] = new POINT2(pSquallPts2[k]);
2724                    counter++;
2725                }
2726                //reverse the sign
2727
2728                sign.value[0] = -sign.value[0];
2729            }
2730            if (numCurves == 0) {
2731                pSquallPts[counter] = new POINT2(StartPt);
2732                counter++;
2733                pSquallPts[counter] = new POINT2(EndPt);
2734                counter++;
2735            }
2736            //the points are along the x axis. Rotate them about the first point as the origin
2737            RotateGeometryDoubleOrigin(pSquallPts, counter, lAngle);
2738            pSquallPts2 = null;
2739        } catch (Exception exc) {
2740            ErrorLogger.LogException(_className, "GetSquallSegment",
2741                    new RendererException("Failed inside GetSquallSegment", exc));
2742        }
2743        return counter;
2744    }
2745
2746    //temporarily using 2000 pixels
2747    private static int PointInBounds(POINT2 pt) {
2748        try {
2749            //double maxPixels=CELineArrayGlobals.MaxPixels2;
2750            double maxPixels = 100000;//was 2000
2751            if (Math.abs(pt.x) <= maxPixels && Math.abs(pt.y) <= maxPixels) {
2752                return 1;
2753            } else {
2754                return 0;
2755            }
2756        } catch (Exception exc) {
2757            ErrorLogger.LogException(_className, "PointInBounds",
2758                    new RendererException("Failed inside PointInBounds", exc));
2759        }
2760        return 1;
2761    }
2762
2763    /**
2764     * @param pt
2765     * @param ul
2766     * @param lr
2767     * @return
2768     */
2769    private static int PointInBounds2(POINT2 pt, POINT2 ul, POINT2 lr) {
2770        try {
2771            double maxX = lr.x, minX = ul.x, maxY = lr.y, minY = ul.y;
2772            if (pt.x <= maxX && pt.x >= minX && pt.y <= maxY && pt.y >= minY) {
2773                return 1;
2774            } else {
2775                return 0;
2776            }
2777        } catch (Exception exc) {
2778            ErrorLogger.LogException(_className, "PointInBounds2",
2779                    new RendererException("Failed inside PointInBounds2", exc));
2780        }
2781        return 1;
2782    }
2783
2784    /**
2785     * Analyzes if line from pt0 to pt 1 intersects a side and returns the
2786     * intersection or null assumes pt0 to pt1 is not vertical. the caller will
2787     * replace pt0 with the intersection point if it is not null
2788     *
2789     * @param pt0
2790     * @param pt1
2791     * @param sidePt0 vertical or horizontal side first point
2792     * @param sidePt1
2793     * @return null if it does not intersect the side
2794     */
2795    private static POINT2 intersectSegment(POINT2 pt0, POINT2 pt1, POINT2 sidePt0, POINT2 sidePt1) {
2796        POINT2 pt = null;
2797        try {
2798            if (pt0.x == pt1.x) {
2799                return null;
2800            }
2801            double m = (pt1.y - pt0.y) / (pt1.x - pt0.x);
2802            double dx = 0, dy = 0, x = 0, y = 0;
2803            POINT2 upper = null, lower = null, left = null, right = null;
2804            Boolean bolVertical = false;
2805            //the side is either vertical or horizontal
2806            if (sidePt0.x == sidePt1.x) //vertical side
2807            {
2808                bolVertical = true;
2809                if (sidePt0.y < sidePt1.y) {
2810                    upper = sidePt0;
2811                    lower = sidePt1;
2812                } else {
2813                    upper = sidePt1;
2814                    lower = sidePt0;
2815                }
2816            } else //horizontal side
2817            {
2818                if (sidePt0.x < sidePt1.x) {
2819                    left = sidePt0;
2820                    right = sidePt1;
2821                } else {
2822                    left = sidePt1;
2823                    right = sidePt0;
2824                }
2825            }
2826            //travel in the direction from pt0 to pt1 to find the pt0 intersect
2827            if (bolVertical) {  //the side to intersect is vertical
2828                dx = upper.x - pt0.x;
2829                dy = m * dx;
2830                x = upper.x;
2831                y = pt0.y + dy;
2832                //the potential intersection point
2833                pt = new POINT2(x, y);
2834
2835                if (pt0.x <= pt.x && pt.x <= pt1.x) //left to right
2836                {
2837                    if (upper.y <= pt.y && pt.y <= lower.y) {
2838                        return pt;
2839                    }
2840                } else if (pt0.x >= pt.x && pt.x >= pt1.x) //right to left
2841                {
2842                    if (upper.y <= pt.y && pt.y <= lower.y) {
2843                        return pt;
2844                    }
2845                }
2846            } else //horizontal side
2847            {
2848                dy = left.y - pt0.y;
2849                dx = dy / m;
2850                x = pt0.x + dx;
2851                y = left.y;
2852                //the potential intersection point
2853                pt = new POINT2(x, y);
2854
2855                if (pt0.y <= pt.y && pt.y <= pt1.y) {
2856                    if (left.x <= pt.x && pt.x <= right.x) {
2857                        return pt;
2858                    }
2859                } else if (pt0.y >= pt.y && pt.y >= pt1.y) {
2860                    if (left.x <= pt.x && pt.x <= right.x) {
2861                        return pt;
2862                    }
2863                }
2864            }
2865        } catch (Exception exc) {
2866            ErrorLogger.LogException(_className, "intersectSegment",
2867                    new RendererException("Failed inside intersectSegment", exc));
2868        }
2869        return null;
2870    }
2871
2872    /**
2873     * side 1 ----- | | side 0 | | side 2 | | ------ side 3 bounds one segment
2874     * for autoshapes that need it: bydif, fordif, fix, mnfldfix if null is
2875     * returned the client should conect the original line points (i.e. no
2876     * jaggies)
2877     *
2878     * @param pt0
2879     * @param pt1
2880     * @param ul
2881     * @param lr
2882     * @return bounded segment or null
2883     */
2884    public static POINT2[] BoundOneSegment(POINT2 pt0, POINT2 pt1, POINT2 ul, POINT2 lr) {
2885        POINT2[] line = new POINT2[2];
2886        try {
2887            if (pt0.y < ul.y && pt1.y < ul.y) {
2888                return null;
2889            }
2890            if (pt0.y > lr.y && pt1.y > lr.y) {
2891                return null;
2892            }
2893            if (pt0.x < ul.x && pt1.x < ul.x) {
2894                return null;
2895            }
2896            if (pt0.x > lr.x && pt1.x > lr.x) {
2897                return null;
2898            }
2899
2900            Boolean bolVertical = false;
2901            InitializePOINT2Array(line);
2902            if (pt0.x == pt1.x) {
2903                bolVertical = true;
2904            }
2905
2906            if (bolVertical) {
2907                line[0] = new POINT2(pt0);
2908                if (line[0].y < ul.y) {
2909                    line[0].y = ul.y;
2910                }
2911                if (line[0].y > lr.y) {
2912                    line[0].y = lr.y;
2913                }
2914
2915                line[1] = new POINT2(pt1);
2916                if (line[1].y < ul.y) {
2917                    line[1].y = ul.y;
2918                }
2919                if (line[1].y > lr.y) {
2920                    line[1].y = lr.y;
2921                }
2922
2923                return line;
2924            }
2925
2926            double dx = 0, dy = 0, x = 0, y = 0;
2927            double m = (pt1.y - pt0.y) / (pt1.x - pt0.x);
2928            Boolean side0Intersect = false,
2929                    side1Intersect = false,
2930                    side2Intersect = false,
2931                    side3Intersect = false;
2932            //travel in the direction from pt0 to pt1 to find pt0 intersect
2933            POINT2 ur = new POINT2(lr.x, ul.y);
2934            POINT2 ll = new POINT2(ul.x, lr.y);
2935
2936            POINT2 pt0Intersect = null;
2937            if (PointInBounds2(pt0, ul, lr) == 1) {
2938                pt0Intersect = pt0;
2939            }
2940            if (pt0Intersect == null) {
2941                pt0Intersect = intersectSegment(pt0, pt1, ll, ul);  //interesect side 0
2942                side0Intersect = true;
2943            }
2944            if (pt0Intersect == null) {
2945                pt0Intersect = intersectSegment(pt0, pt1, ul, ur);  //interesect side 1
2946                side1Intersect = true;
2947            }
2948            if (pt0Intersect == null) {
2949                pt0Intersect = intersectSegment(pt0, pt1, ur, lr);  //interesect side 2
2950                side2Intersect = true;
2951            }
2952            if (pt0Intersect == null) {
2953                pt0Intersect = intersectSegment(pt0, pt1, ll, lr);  //interesect side 3
2954                side3Intersect = true;
2955            }
2956
2957            //travel in the direction from pt1 to pt0 to find pt1 intersect
2958            POINT2 pt1Intersect = null;
2959            if (PointInBounds2(pt1, ul, lr) == 1) {
2960                pt1Intersect = pt1;
2961            }
2962            if (pt1Intersect == null && side0Intersect == false) {
2963                pt1Intersect = intersectSegment(pt1, pt0, ll, ul);  //interesect side 0
2964            }
2965            if (pt1Intersect == null && side1Intersect == false) {
2966                pt1Intersect = intersectSegment(pt1, pt0, ul, ur);  //interesect side 1
2967            }
2968            if (pt1Intersect == null && side2Intersect == false) {
2969                pt1Intersect = intersectSegment(pt1, pt0, ur, lr);  //interesect side 2
2970            }
2971            if (pt1Intersect == null && side3Intersect == false) {
2972                pt1Intersect = intersectSegment(pt1, pt0, ll, lr);  //interesect side 3
2973            }
2974
2975            if (pt0Intersect != null && pt1Intersect != null) {
2976                line[0] = pt0Intersect;
2977                line[1] = pt1Intersect;
2978                //return line;
2979            } else {
2980                line = null;
2981            }
2982        } catch (Exception exc) {
2983            ErrorLogger.LogException(_className, "BoundOneSegment",
2984                    new RendererException("Failed inside BoundOneSegment", exc));
2985        }
2986        return line;
2987    }
2988
2989    private static int DisplayIntersectPixels(POINT2 pt0,
2990            POINT2 pt1,
2991            ref<double[]> pt2x,
2992            ref<double[]> pt2y,
2993            ref<double[]> pt3x,
2994            ref<double[]> pt3y) //POINT2 ul,
2995    //POINT2 lr)
2996    {
2997        int nResult = -1;
2998        try {
2999            //declarations
3000            double X = 0, Y = 0;
3001            ref<double[]> m = new ref();
3002            //double maxPixels=CELineArrayGlobals.MaxPixels2;
3003            double maxPixels = 2000;
3004            //double maxX=lr.x,minX=ul.x,maxY=lr.y,minY=ul.y;
3005
3006            int bol0Inside = 0, bol1Inside = 0;
3007            int bolVertical = CalcTrueSlopeDouble(pt0, pt1, m);
3008            double b = pt0.y - m.value[0] * pt0.x;      //the y intercept for the segment line
3009            POINT2 pt2, pt3;
3010            //end declarations
3011
3012            pt2x.value = new double[1];
3013            pt2y.value = new double[1];
3014            pt3x.value = new double[1];
3015            pt3y.value = new double[1];
3016            pt2 = new POINT2(pt0);
3017            pt3 = new POINT2(pt1);
3018
3019            //diagnostic
3020            if (pt0.x <= maxPixels && pt0.x >= -maxPixels
3021                    && pt0.y <= maxPixels && pt0.y >= -maxPixels) {
3022                bol0Inside = 1;
3023            }
3024            if (pt1.x <= maxPixels && pt1.x >= -maxPixels
3025                    && pt1.y <= maxPixels && pt1.y >= -maxPixels) {
3026                bol1Inside = 1;
3027            }
3028            //if both points are inside the area then use the whole segment
3029            if (bol0Inside == 1 && bol1Inside == 1) {
3030                return 0;
3031            }
3032            //if at leat one of the points is inside the area then use some of the segment
3033            if (bol0Inside == 1 || bol1Inside == 1) {
3034                nResult = 1;
3035            }
3036
3037            //segment is not vertical
3038            if (bolVertical != 0) {
3039                //analysis for side 0, get the intersection for either point if it exists
3040                //diagnostic
3041                X = -maxPixels;
3042                //X=minX;
3043
3044                Y = m.value[0] * X + b;
3045                if (pt0.x < -maxPixels && -maxPixels < pt1.x) //pt0 is outside the area
3046                {
3047                    if (-maxPixels <= Y && Y <= maxPixels) //intersection is on side 0
3048                    //if(minY<=Y && Y<=maxY)    //intersection is on side 0
3049                    {
3050                        pt2.x = X;
3051                        pt2.y = Y;
3052                        nResult = 1;    //use at least some of the pixels
3053                    }
3054                }
3055                if (pt1.x < -maxPixels && -maxPixels < pt0.x) //pt1 is outside the area
3056                //if(pt1.x<minX && minX<pt0.x)  //pt1 is outside the area
3057                {
3058                    if (-maxPixels <= Y && Y <= maxPixels) //intersection is on side 0
3059                    {
3060                        pt3.x = X;
3061                        pt3.y = Y;
3062                        nResult = 1;    //use at least some of the pixels
3063                    }
3064                }
3065
3066                //analysis for side 1, get the intersection for either point if it exists
3067                Y = -maxPixels;
3068                if (m.value[0] != 0) {
3069                    X = (Y - b) / m.value[0];
3070                    if (pt0.y < -maxPixels && -maxPixels < pt1.y) //pt0 is outside the area
3071                    {
3072                        if (-maxPixels <= X && X <= maxPixels) //intersection is on side 1
3073                        {
3074                            pt2.x = X;
3075                            pt2.y = Y;
3076                            nResult = 1;        //use at least some of the pixels
3077                        }
3078                    }
3079                    if (pt1.y <= -maxPixels && -maxPixels <= pt0.y) //pt1 is outside the area
3080                    {
3081                        if (-maxPixels < X && X < maxPixels) //intersection is on the boundary
3082                        {
3083                            pt3.x = X;
3084                            pt3.y = Y;
3085                            nResult = 1;        //use at least some of the pixels
3086                        }
3087                    }
3088                }
3089                //analysis for side 2, get the intersection for either point if it exists
3090                X = maxPixels;
3091                Y = m.value[0] * X + b;
3092                if (pt0.x < maxPixels && maxPixels < pt1.x) //pt1 is outside the area
3093                {
3094                    if (-maxPixels <= Y && Y <= maxPixels) //intersection is on the boundary
3095                    {
3096                        pt3.x = X;
3097                        pt3.y = Y;
3098                        nResult = 1;    //use at least some of the pixels
3099                    }
3100                }
3101                if (pt1.x < maxPixels && maxPixels < pt0.x) //pt0 is outside the area
3102                {
3103                    if (-maxPixels <= Y && Y <= maxPixels) //intersection is on the boundary
3104                    {
3105                        pt2.x = X;
3106                        pt2.y = Y;
3107                        nResult = 1;    //use at least some of the pixels
3108                    }
3109                }
3110
3111                //analysis for side 3, get the intersection for either point if it exists
3112                Y = maxPixels;
3113                if (m.value[0] != 0) {
3114                    X = (Y - b) / m.value[0];
3115                    if (pt0.y < maxPixels && maxPixels < pt1.y) //pt1 is outside the area
3116                    {
3117                        if (-maxPixels <= X && X <= maxPixels) //intersection is on the boundary
3118                        {
3119                            pt3.x = X;
3120                            pt3.y = Y;
3121                            nResult = 1;        //use at least some of the pixels
3122                        }
3123                    }
3124                    if (pt1.y < maxPixels && maxPixels < pt0.y) //pt0 is outside the area
3125                    {
3126                        if (-maxPixels <= X && X <= maxPixels) //intersection is on the boundary
3127                        {
3128                            pt2.x = X;
3129                            pt2.y = Y;
3130                            nResult = 1;        //use at least some of the pixels
3131                        }
3132                    }
3133                }
3134            }
3135
3136            //segment is vertical
3137            if (bolVertical == 0) {
3138                //analysis for side 1
3139                X = pt0.x;
3140                Y = -maxPixels;
3141                if (-maxPixels < pt0.x && pt0.x < maxPixels) {
3142                    if (pt0.y <= -maxPixels && -maxPixels <= pt1.y) //pt0 outside the area
3143                    {
3144                        pt2.x = X;
3145                        pt2.y = Y;
3146                        nResult = 1;    //use at least some of the pixels
3147                    }
3148                    if (pt1.y <= -maxPixels && -maxPixels <= pt0.y) //pt1 outside the area
3149                    {
3150                        pt3.x = X;
3151                        pt3.y = Y;
3152                        nResult = 1;    //use at least some of the pixels
3153                    }
3154                }
3155
3156                //analysis for side 3
3157                X = pt0.x;
3158                Y = maxPixels;
3159                if (-maxPixels < pt0.x && pt0.x < maxPixels) {
3160                    if (pt0.y <= maxPixels && maxPixels <= pt1.y) //pt1 outside the area
3161                    {
3162                        pt3.x = X;
3163                        pt3.y = Y;
3164                        nResult = 1;    //use at least some of the pixels
3165                    }
3166                    if (pt1.y <= maxPixels && maxPixels <= pt0.y) //pt0 outside the area
3167                    {
3168                        pt2.x = X;
3169                        pt2.y = Y;
3170                        nResult = 1;    //use at least some of the pixels
3171                    }
3172                }
3173            }
3174
3175            pt2x.value[0] = pt2.x;
3176            pt2y.value[0] = pt2.y;
3177            pt3x.value[0] = pt3.x;
3178            pt3y.value[0] = pt3.y;
3179        } catch (Exception exc) {
3180            ErrorLogger.LogException(_className, "DisplayIntersectPixels",
3181                    new RendererException("Failed inside DisplayIntersectPixels", exc));
3182        }
3183        return nResult;
3184    }
3185    /**
3186     * Computes Ditch spikes for the ATDITCH line types. This function uses
3187     * linestyles provided by the caller to skip segments.
3188     *
3189     * @param pLinePoints OUT - the client points also used for the return
3190     * points
3191     * @param nOldCounter the number of client points
3192     * @param bWayIs the parallel line to use (0) for inner or outer spikes
3193     * @param linetype the line type
3194     *
3195     * @return the symbol point count
3196     */
3197    protected static int GetDitchSpikeDouble(POINT2[] pLinePoints,
3198            int nOldCounter,
3199            int bWayIs,
3200            int linetype) {
3201        int nSpikeCounter = 0;
3202        try {
3203            //declarations
3204            int nNumberOfSegments = 0,
3205                    lCircleCounter = 0,
3206                    bolVertical = 0,
3207                    nTemp = 0,
3208                    i,
3209                    j;
3210            double dPrinter = 1.0;
3211            double dIntLocation1x = 0,
3212                    dIntLocation2x = 0,
3213                    dIntLocation1y = 0,
3214                    dIntLocation2y = 0,
3215                    r = 0,
3216                    s = 0,
3217                    use = 0,
3218                    length = 0,
3219                    k = 0,
3220                    bint = 0;
3221            ref<double[]> pdAnswer = new ref();//new double[6];
3222            ref<double[]> m = new ref();
3223
3224            POINT2 UpperLinePoint = new POINT2(pLinePoints[0]),
3225                    Lower1LinePoint = new POINT2(pLinePoints[0]),
3226                    Lower2LinePoint = new POINT2(pLinePoints[0]),
3227                    a = new POINT2(pLinePoints[0]),
3228                    b = new POINT2(pLinePoints[0]);
3229            POINT2[] pCirclePoints = new POINT2[pLinePoints.length];
3230            POINT2 averagePoint = new POINT2();
3231            POINT2 lastAveragePoint = new POINT2();
3232            POINT2[] pTempLinePoints = null;
3233            double minLength = 24;
3234            //end declarations
3235
3236            pTempLinePoints = new POINT2[nOldCounter];
3237            for (j = 0; j < nOldCounter; j++) {
3238                pTempLinePoints[j] = new POINT2(pLinePoints[j]);
3239            }
3240
3241            ArrayList<POINT2> basePoints = new ArrayList();
3242
3243            InitializePOINT2Array(pCirclePoints);
3244            nSpikeCounter = nOldCounter;
3245            for (i = 0; i < nOldCounter - 1; i++) {
3246                if (linetype == TacticalLines.ATDITCHM && i == 0) {
3247                    minLength = 38;
3248                }
3249
3250                nTemp = CalcTrueLinesDouble(15 * (int) dPrinter, pLinePoints[i], pLinePoints[i + 1], pdAnswer);
3251                r = pdAnswer.value[3];
3252                s = pdAnswer.value[5];
3253                length = CalcDistanceDouble(pLinePoints[i], pLinePoints[i + 1]);
3254                bolVertical = CalcTrueSlopeDouble(pLinePoints[i], pLinePoints[i + 1], m);
3255                nNumberOfSegments = (int) ((length - 1) / (12 * dPrinter));
3256
3257                if (length > minLength * dPrinter) {    //minLength was 24
3258                    if (bWayIs != 0) {
3259                        if (pLinePoints[i].x <= pLinePoints[i + 1].x) {
3260                            use = r;
3261                        }
3262                        if (pLinePoints[i].x >= pLinePoints[i + 1].x) {
3263                            use = s;
3264                        }
3265                    } //end if
3266                    else {
3267                        if (pLinePoints[i].x <= pLinePoints[i + 1].x) {
3268                            use = s;
3269                        }
3270                        if (pLinePoints[i].x >= pLinePoints[i + 1].x) {
3271                            use = r;
3272                        }
3273                    }   //end else
3274
3275                    for (j = 1; j <= nNumberOfSegments; j++) {
3276                        k = (double) j;
3277                        a = new POINT2(pLinePoints[i]);
3278                        b = new POINT2(pLinePoints[i + 1]);
3279
3280                        if (j > 1) {
3281                            dIntLocation1x = dIntLocation2x;
3282                        } else {
3283                            dIntLocation1x
3284                                    = (double) pLinePoints[i].x + ((k * 12.0 - 12) * dPrinter / length)
3285                                    * (double) (pLinePoints[i + 1].x - pLinePoints[i].x);
3286                        }
3287
3288                        if (j > 1) //added M. Deutch 2-23-99
3289                        {
3290                            dIntLocation1y = dIntLocation2y;
3291                        } else {
3292                            dIntLocation1y
3293                                    = (double) pLinePoints[i].y + ((k * 12.0 - 6.0) * dPrinter / length)
3294                                    * (double) (pLinePoints[i + 1].y - pLinePoints[i].y);
3295                        }
3296
3297                        dIntLocation2x = (double) pLinePoints[i].x
3298                                + ((k * 12.0 + 6.0) * dPrinter / length)
3299                                * (double) (pLinePoints[i + 1].x
3300                                - pLinePoints[i].x);
3301
3302                        dIntLocation2y = (double) pLinePoints[i].y
3303                                + ((k * 12.0 + 6.0) * dPrinter / length)
3304                                * (double) (pLinePoints[i + 1].y
3305                                - pLinePoints[i].y);
3306
3307                        if (m.value[0] != 0 && bolVertical != 0) {
3308                            bint = (dIntLocation1y + dIntLocation2y) / 2.0
3309                                    + (1 / m.value[0]) * (dIntLocation1x + dIntLocation2x) / 2.0;
3310                            //independent of direction
3311                            UpperLinePoint = CalcTrueIntersectDouble2(m.value[0], use, -1 / m.value[0], bint, 1, 1, pLinePoints[0].x, pLinePoints[0].y);
3312                        }
3313
3314                        if (bolVertical == 0) //vertical segment
3315                        {
3316                            if (dIntLocation1y < dIntLocation2y) {
3317                                UpperLinePoint.y = (int) dIntLocation1y + (int) (length / nNumberOfSegments / 2);
3318                            } else {
3319                                UpperLinePoint.y = (int) dIntLocation1y - (int) (length / nNumberOfSegments / 2);
3320                            }
3321                            if (pLinePoints[i].y < pLinePoints[i + 1].y) {
3322                                UpperLinePoint.x = (int) dIntLocation1x + (int) (length / nNumberOfSegments);
3323                            } else {
3324                                UpperLinePoint.x = (int) dIntLocation1x - (int) (length / nNumberOfSegments);
3325                            }
3326                        }
3327                        if (m.value[0] == 0 && bolVertical != 0) {
3328                            if (dIntLocation1x < dIntLocation2x) {
3329                                UpperLinePoint.x = (int) dIntLocation1x + (int) (length / nNumberOfSegments / 2);
3330                            } else {
3331                                UpperLinePoint.x = (int) dIntLocation1x - (int) (length / nNumberOfSegments / 2);
3332                            }
3333                            if (pLinePoints[i + 1].x < pLinePoints[i].x) {
3334                                UpperLinePoint.y = (int) dIntLocation1y + (int) (length / nNumberOfSegments);
3335                            } else {
3336                                UpperLinePoint.y = (int) dIntLocation1y - (int) (length / nNumberOfSegments);
3337                            }
3338                        }
3339                        //end section
3340
3341                        Lower1LinePoint.x = dIntLocation1x;
3342                        Lower1LinePoint.y = dIntLocation1y;
3343                        Lower2LinePoint.x = dIntLocation2x;
3344                        Lower2LinePoint.y = dIntLocation2y;
3345
3346                        pLinePoints[nSpikeCounter] = new POINT2(Lower1LinePoint);
3347                        if (linetype == TacticalLines.ATDITCHC || linetype == TacticalLines.ATDITCHM) {
3348                            pLinePoints[nSpikeCounter].style = 9;
3349                        }
3350                        if (j % 2 == 1 && linetype == TacticalLines.ATDITCHM)//diagnostic 1-8-13
3351                        {
3352                            pLinePoints[nSpikeCounter].style = 5;
3353                        }
3354
3355                        nSpikeCounter++;
3356
3357                        pLinePoints[nSpikeCounter] = new POINT2(UpperLinePoint);
3358                        if (linetype == (long) TacticalLines.ATDITCHC || linetype == (long) TacticalLines.ATDITCHM) {
3359                            pLinePoints[nSpikeCounter].style = 9;
3360                        }
3361                        if (j % 2 == 1 && linetype == TacticalLines.ATDITCHM)//diagnostic 1-8-13
3362                        {
3363                            pLinePoints[nSpikeCounter].style = 5;
3364                        }
3365
3366                        nSpikeCounter++;
3367
3368                        pLinePoints[nSpikeCounter] = new POINT2(Lower2LinePoint);
3369                        if (linetype == (long) TacticalLines.ATDITCHC || linetype == (long) TacticalLines.ATDITCHM) {
3370                            pLinePoints[nSpikeCounter].style = 10;
3371                        }
3372                        if (j % 2 == 1 && linetype == TacticalLines.ATDITCHM)//diagnostic 1-8-13
3373                        {
3374                            pLinePoints[nSpikeCounter].style = 5;
3375                        }
3376
3377                        nSpikeCounter++;
3378
3379                        if (linetype == TacticalLines.ATDITCHM) {
3380                            if (j % 2 == 0) {
3381                                averagePoint = lineutility.MidPointDouble(Lower1LinePoint, Lower2LinePoint, 0);
3382                                averagePoint = lineutility.MidPointDouble(averagePoint, UpperLinePoint, 0);
3383                            } else if (j == 1) {
3384                                averagePoint = lineutility.ExtendLineDouble(Lower2LinePoint, Lower1LinePoint, 5);
3385                                averagePoint = lineutility.MidPointDouble(averagePoint, UpperLinePoint, 0);
3386                            }
3387                        }
3388                        //end section
3389                        if (j > 1 && j < nNumberOfSegments) {
3390                            basePoints.add(new POINT2(Lower1LinePoint));
3391                            //if(j==nNumberOfSegments-1)
3392                            //  basePoints.get(basePoints.size()-1).style=5;
3393                        } else if (j == 1) {
3394                            basePoints.add(new POINT2(pLinePoints[i]));
3395                        } else if (j == nNumberOfSegments) {
3396                            basePoints.add(new POINT2(pLinePoints[i + 1]));
3397                            basePoints.get(basePoints.size() - 1).style = 5;
3398                        }
3399                        if (linetype == TacticalLines.ATDITCHM && j > 1) {
3400                            if (j % 2 == 0) {
3401                                pCirclePoints[lCircleCounter] = lineutility.MidPointDouble(averagePoint, lastAveragePoint, 20);
3402                                lCircleCounter++;
3403                            }
3404                            //end section
3405                        }
3406                        if (j < nNumberOfSegments && linetype == TacticalLines.ATDITCHM) {
3407                            if (j == 1 || j % 2 == 0) {
3408                                //LastUpperLinePoint = new POINT2(UpperLinePoint);
3409                                lastAveragePoint = new POINT2(averagePoint);
3410                            }
3411                            //end section
3412                        }
3413                    }//end for j<numberOfsegments
3414                } //end if length big enough
3415                else {
3416                    //diagnostic
3417                    pLinePoints[nSpikeCounter].x = pLinePoints[i].x;
3418                    pLinePoints[nSpikeCounter].y = pLinePoints[i].y;
3419                    pLinePoints[nSpikeCounter].style = 0;
3420                    nSpikeCounter++;
3421                    pLinePoints[nSpikeCounter].x = pLinePoints[i + 1].x;
3422                    pLinePoints[nSpikeCounter].y = pLinePoints[i + 1].y;
3423                    pLinePoints[nSpikeCounter].style = 5;
3424                    nSpikeCounter++;
3425                }
3426            }
3427
3428            for (j = 0; j < nOldCounter; j++) //reverse the first nOldCounter points for
3429            {
3430                pLinePoints[j] = new POINT2(pTempLinePoints[nOldCounter - j - 1]); //purpose of drawing
3431                pLinePoints[j].style = 5;
3432            }
3433
3434            if (pLinePoints[nSpikeCounter - 1].style == 0) {
3435                pLinePoints[nSpikeCounter - 1].style = 5;
3436            }
3437            int t=basePoints.size();
3438            //for (j = nSpikeCounter; j < nSpikeCounter + basePoints.size(); j++) 
3439            for (j = nSpikeCounter; j < nSpikeCounter + t; j++) 
3440            {
3441                pLinePoints[j] = new POINT2(basePoints.get(j - nSpikeCounter));
3442                //if(linetype == TacticalLines.ATDITCHM && pLinePoints[j].style != 5)
3443                if (pLinePoints[j].style != 5) {
3444                    pLinePoints[j].style = 0;
3445                }
3446            }
3447            nSpikeCounter += basePoints.size();
3448
3449            if (linetype == (int) TacticalLines.ATDITCHM) {
3450                pLinePoints[nSpikeCounter - 1].style = 5;//was 10
3451                for (j = nSpikeCounter; j < nSpikeCounter + lCircleCounter; j++) {
3452                    pLinePoints[j] = new POINT2(pCirclePoints[j - nSpikeCounter]);
3453                    pLinePoints[j].style = 20;
3454                }
3455                nSpikeCounter += lCircleCounter;
3456            }
3457
3458        } catch (Exception exc) {
3459            ErrorLogger.LogException(_className, "GetDitchSpikeDouble",
3460                    new RendererException("Failed inside GetDitchSpikeDouble", exc));
3461        }
3462        return nSpikeCounter;
3463    }
3464
3465    /**
3466     * Moves pixels if points are identical, used for the channel types
3467     *
3468     * @param pLinePoints OUT - client points also for returned points
3469     */
3470    protected static void MoveChannelPixels(POINT2[] pLinePoints) {
3471        try {
3472            if (pLinePoints == null || pLinePoints.length <= 0) {
3473                return;
3474            }
3475
3476            double[] pixels = new double[pLinePoints.length * 2];
3477            boolean bolNoRepeats;
3478            int j, k = 0;
3479            double x1;
3480            double y1;
3481            double x2;
3482            double y2;
3483            int count = pLinePoints.length;
3484            //stuff pixels
3485            for (j = 0; j < count; j++) {
3486                pixels[k++] = pLinePoints[j].x;
3487                pixels[k++] = pLinePoints[j].y;
3488            }
3489
3490            bolNoRepeats = false;
3491            do {
3492                bolNoRepeats = true;
3493                for (j = 0; j < count - 1; j++) {
3494                    x1 = pixels[2 * j];
3495                    y1 = pixels[2 * j + 1];
3496                    x2 = pixels[2 * j + 2];
3497                    y2 = pixels[2 * j + 3];
3498                    if (x1 == x2 && y1 == y2) //it's the same point
3499                    {
3500                        bolNoRepeats = false;
3501                        pixels[2 * j + 2] = (long) x2 + 1; //move the point
3502                        break;
3503                    }
3504                }
3505            } while (bolNoRepeats == false);
3506            //stuff pLinePoints
3507            k = 0;
3508            for (j = 0; j < count; j++) {
3509                pLinePoints[j].x = pixels[k++];
3510                pLinePoints[j].y = pixels[k++];
3511            }
3512        } catch (Exception exc) {
3513            ErrorLogger.LogException(_className, "MoveChannelPixels",
3514                    new RendererException("Failed inside MoveChannelPixels", exc));
3515        }
3516    }
3517
3518    /**
3519     * Single Concertina cannot have horizontal first segment
3520     *
3521     * @param linetype
3522     * @param pLinePoints
3523     */
3524    protected static void moveSingleCPixels(int linetype, POINT2[] pLinePoints) {
3525        try {
3526            switch (linetype) {
3527                case TacticalLines.SINGLEC:
3528                    break;
3529                default:
3530                    return;
3531            }
3532            if (pLinePoints.length > 1) {
3533                if (pLinePoints[1].y == pLinePoints[0].y) {
3534                    pLinePoints[1].y++;
3535                }
3536            }
3537        } catch (Exception exc) {
3538            ErrorLogger.LogException(_className, "MoveSingleCPixels",
3539                    new RendererException("Failed inside MoveSingleCPixels", exc));
3540        }
3541    }
3542
3543    /**
3544     * Rotates an the first vblCounter points in the array about its first point
3545     *
3546     * @param pLinePoints OUT - the points to rotate
3547     * @param vblCounter the number of points to rotate
3548     * @param lAngle the angle in degrees to rotate
3549     *
3550     * @return pLinePoints
3551     */
3552    protected static void RotateGeometryDouble(POINT2[] pLinePoints,
3553            int vblCounter,
3554            double lAngle) {
3555        try {
3556            int j = 0;
3557            double dRotate = 0,
3558                    dTheta = 0,
3559                    dGamma = 0,
3560                    x = 0,
3561                    y = 0;
3562
3563            if (lAngle != 0) //if the angle is 0 no rotation occurs
3564            {
3565                POINT2 pdCenter;
3566                dRotate = lAngle * Math.PI / 180d;
3567                pdCenter = CalcCenterPointDouble(pLinePoints, vblCounter);
3568
3569                for (j = 0; j < vblCounter; j++) {
3570                    //added if/else to get rid of divide by zero error 5/12/04 M. Deutch
3571                    if (pLinePoints[j].x == pdCenter.x) {
3572                        if ((pLinePoints[j].y > pdCenter.y)) {
3573                            dGamma = Math.PI + Math.PI / 2;
3574                        } else {
3575                            dGamma = Math.PI / 2;
3576                        }
3577                    } else {
3578                        dGamma = Math.PI + Math.atan((pLinePoints[j].y - pdCenter.y)
3579                                / (pLinePoints[j].x - pdCenter.x));
3580                    }
3581
3582                    if ((double) pLinePoints[j].x >= pdCenter.x) {
3583                        dGamma = dGamma + Math.PI;
3584                    }
3585
3586                    dTheta = dRotate + dGamma;
3587                    y = CalcDistanceDouble(pLinePoints[j], pdCenter) * Math.sin(dTheta);
3588                    x = CalcDistanceDouble(pLinePoints[j], pdCenter) * Math.cos(dTheta);
3589                    pLinePoints[j].y = pdCenter.y + y;
3590                    pLinePoints[j].x = pdCenter.x + x;
3591                }       //end for
3592
3593                return;
3594            }   //end if
3595        } catch (Exception exc) {
3596            ErrorLogger.LogException(_className, "RotateGeometryDouble",
3597                    new RendererException("Failed inside RotateGeometryDouble", exc));
3598        }
3599    }  // end
3600
3601    /**
3602     * Returns the point perpendicular to the line (pt0 to pt1) at the midpoint
3603     * the same distance from (and on the same side of) the the line as
3604     * ptRelative.
3605     *
3606     * @param pt0 the first point
3607     * @param pt1 the second point
3608     * @param ptRelative the point to use for computing the return point
3609     *
3610     * @return the point perpendicular to the line at the midpoint
3611     */
3612    protected static POINT2 PointRelativeToLine(POINT2 pt0,
3613            POINT2 pt1,
3614            POINT2 ptRelative) {
3615        POINT2 ptResult = new POINT2(pt0);
3616        try {
3617            int bolVertical = 0;
3618            ref<double[]> m = new ref();
3619            POINT2 midPt = MidPointDouble(pt0, pt1, 0);
3620            double b1 = 0, b2 = 0;
3621            //end declarations
3622
3623            bolVertical = CalcTrueSlopeDouble(pt0, pt1, m);
3624            if (bolVertical == 0) //line is vertical
3625            {
3626                ptResult.x = ptRelative.x;
3627                ptResult.y = midPt.y;
3628            }
3629            if (bolVertical != 0 && m.value[0] == 0) {
3630                ptResult.x = midPt.x;
3631                ptResult.y = ptRelative.y;
3632            }
3633            if (bolVertical != 0 && m.value[0] != 0) {
3634                b1 = midPt.y + (1 / m.value[0]) * midPt.x;      //the line perp to midPt
3635                b2 = ptRelative.y - m.value[0] * ptRelative.x;  //the line  ptRelative with the slope of pt1-pt2
3636                ptResult = CalcTrueIntersectDouble2(-1 / m.value[0], b1, m.value[0], b2, 1, 1, 0, 0);
3637            }
3638        } catch (Exception exc) {
3639            ErrorLogger.LogException(_className, "PointRelativeToLine",
3640                    new RendererException("Failed inside PointRelativeToLine", exc));
3641        }
3642        return ptResult;
3643    }
3644
3645    /**
3646     * shift the control point to match the shift that occurs in
3647     * Channels.GetAXADDouble for CATKBYFIRE. This is because the rotary feature
3648     * arrow tip must align with the anchor point
3649     *
3650     * @param linetype
3651     * @param pLinePoints the anchor points including the control point
3652     * @param minDist the minimum required distance from the front of the rotary
3653     * arrow
3654     */
3655    public static void adjustCATKBYFIREControlPoint(int linetype,
3656            ArrayList<POINT2> pLinePoints,
3657            double dist) {
3658        try {
3659            if (linetype != TacticalLines.CATKBYFIRE) {
3660                return;
3661            }
3662
3663            double dist2 = lineutility.CalcDistanceDouble(pLinePoints.get(0), pLinePoints.get(1));
3664            if (dist2 <= dist) {
3665                return;
3666            }
3667
3668            POINT2 pt = null;
3669            int count = pLinePoints.size();
3670            POINT2 pt0 = new POINT2(pLinePoints.get(0));
3671            POINT2 pt1 = new POINT2(pLinePoints.get(1));
3672            POINT2 controlPt = new POINT2(pLinePoints.get(count - 1));
3673            POINT2 pt4 = PointRelativeToLine(pt0, pt1, pt1, controlPt);
3674            pt = lineutility.ExtendLineDouble(pt4, controlPt, dist);
3675            pLinePoints.set(count - 1, pt);
3676        } catch (Exception exc) {
3677            ErrorLogger.LogException(_className, "adjustCATKBYFIREControlPoint",
3678                    new RendererException("Failed inside adjustCATKBYFIREControlPoint", exc));
3679        }
3680    }
3681
3682    /**
3683     * Returns the point perpendicular to the line (pt0 to pt1) at atPoint the
3684     * same distance from (and on the same side of) the the line as ptRelative.
3685     *
3686     * @param pt0 the first point
3687     * @param pt1 the second point
3688     * @param atPoint the point on the line at which to compute the extended
3689     * point
3690     * @param ptRelative the point to use for computing the return point
3691     *
3692     * @return the point perpendicular to the line at ptRelative
3693     */
3694    public static POINT2 PointRelativeToLine(POINT2 pt0,
3695            POINT2 pt1,
3696            POINT2 atPoint,
3697            POINT2 ptRelative) {
3698        POINT2 ptResult = new POINT2(pt0);
3699        try {
3700            int bolVertical = 0;
3701            ref<double[]> m = new ref();
3702            double b1 = 0, b2 = 0;
3703
3704            bolVertical = CalcTrueSlopeDouble(pt0, pt1, m);
3705            if (bolVertical == 0) //line is vertical
3706            {
3707                ptResult.x = ptRelative.x;
3708                ptResult.y = atPoint.y;
3709            }
3710            if (bolVertical != 0 && m.value[0] == 0) {
3711                ptResult.x = atPoint.x;
3712                ptResult.y = ptRelative.y;
3713            }
3714            if (bolVertical != 0 && m.value[0] != 0) {
3715                b1 = atPoint.y + (1 / m.value[0]) * atPoint.x;  //the line perp to midPt
3716                b2 = ptRelative.y - m.value[0] * ptRelative.x;  //the line  ptRelative with the slope of pt1-pt2
3717                ptResult = CalcTrueIntersectDouble2(-1 / m.value[0], b1, m.value[0], b2, 1, 1, 0, 0);
3718            }
3719        } catch (Exception exc) {
3720            ErrorLogger.LogException(_className, "PointRelativeToLine",
3721                    new RendererException("Failed inside PointRelativeToLine", exc));
3722        }
3723        return ptResult;
3724    }
3725
3726    /**
3727     * Returns in pt2 and pt3 the line segment parallel to segment pt0-pt1 which
3728     * would contain ptRelative. pt2 corresponds to pt0 and pt3 corresponds to
3729     * pt1.
3730     *
3731     * @param pt0 first line point
3732     * @param pt1 second line point
3733     * @param ptRelative relative line point
3734     * @param pt2 OUT - first computed relative line point
3735     * @param pt3 OUT - second computed relative line point
3736     */
3737    public static void LineRelativeToLine(POINT2 pt0,
3738            POINT2 pt1,
3739            POINT2 ptRelative,
3740            POINT2 pt2,
3741            POINT2 pt3) {
3742        try {
3743            int bolVertical = 0;
3744            ref<double[]> m = new ref();
3745            double b1 = 0, b2 = 0;
3746            POINT2 pt2Temp = null;
3747            POINT2 pt3Temp = null;
3748
3749            bolVertical = CalcTrueSlopeDouble(pt0, pt1, m);
3750            if (bolVertical == 0) //line is vertical
3751            {
3752                pt2.x = ptRelative.x;
3753                pt2.y = pt0.y;
3754                pt3.x = ptRelative.x;
3755                pt3.y = pt1.y;
3756            }
3757            if (bolVertical != 0 && m.value[0] == 0) //line is horizontal
3758            {
3759                pt2.x = pt0.x;
3760                pt2.y = ptRelative.y;
3761                pt3.x = pt1.x;
3762                pt3.y = ptRelative.y;
3763            }
3764            if (bolVertical != 0 && m.value[0] != 0) {
3765                b1 = pt0.y + (1 / m.value[0]) * pt0.x;  //the line perp to pt0
3766                b2 = ptRelative.y - m.value[0] * ptRelative.x;  //the line the ptRelative with the slope of pt0-pt1
3767                pt2Temp = CalcTrueIntersectDouble2(-1 / m.value[0], b1, m.value[0], b2, 1, 1, 0, 0);
3768
3769                b1 = pt1.y + (1 / m.value[0]) * pt1.x;  //the line perp to pt1
3770                //b2=ptRelative.y-m*ptRelative.x;       //the line the ptRelative with the slope of pt0-pt1
3771                pt3Temp = CalcTrueIntersectDouble2(-1 / m.value[0], b1, m.value[0], b2, 1, 1, 0, 0);
3772
3773                pt2.x = pt2Temp.x;
3774                pt2.y = pt2Temp.y;
3775                pt3.x = pt3Temp.x;
3776                pt3.y = pt3Temp.y;
3777            }
3778        } catch (Exception exc) {
3779            ErrorLogger.LogException(_className, "LineRelativeToLine",
3780                    new RendererException("Failed inside LineRelativeToLine", exc));
3781        }
3782    }
3783
3784    private static void CalcMBR(POINT2[] pLinePoints,
3785            int numpts,
3786            ref<double[]> ulx,
3787            ref<double[]> uly,
3788            ref<double[]> lrx,
3789            ref<double[]> lry) {
3790        try {
3791            int j = 0;
3792            //initialize the MBR
3793            ulx.value = new double[1];
3794            uly.value = new double[1];
3795            lrx.value = new double[1];
3796            lry.value = new double[1];
3797            ulx.value[0] = Double.MAX_VALUE;//was 99999
3798            uly.value[0] = Double.MAX_VALUE;//was 99999
3799            lrx.value[0] = -Double.MAX_VALUE;//was -99999
3800            lry.value[0] = -Double.MAX_VALUE;//was -99999
3801            for (j = 0; j < numpts; j++) {
3802                if (pLinePoints[j].x > lrx.value[0]) {
3803                    lrx.value[0] = pLinePoints[j].x;
3804                }
3805                if (pLinePoints[j].y > lry.value[0]) {
3806                    lry.value[0] = pLinePoints[j].y;
3807                }
3808                if (pLinePoints[j].x < ulx.value[0]) {
3809                    ulx.value[0] = pLinePoints[j].x;
3810                }
3811                if (pLinePoints[j].y < uly.value[0]) {
3812                    uly.value[0] = pLinePoints[j].y;
3813                }
3814            }
3815        } catch (Exception exc) {
3816            ErrorLogger.LogException(_className, "CalcMBR",
3817                    new RendererException("Failed inside CalcMBR", exc));
3818        }
3819        return;
3820    }
3821
3822    public static void CalcMBRPoints(POINT2[] pLinePoints,
3823            int numpts,
3824            POINT2 ul,
3825            POINT2 lr) {
3826        try {
3827            int j = 0;
3828            ul.x = Double.MAX_VALUE;
3829            ul.y = Double.MAX_VALUE;
3830            lr.x = -Double.MAX_VALUE;
3831            lr.y = -Double.MAX_VALUE;
3832            for (j = 0; j < numpts; j++) {
3833                if (pLinePoints[j].x > lr.x) {
3834                    lr.x = pLinePoints[j].x;
3835                }
3836                if (pLinePoints[j].y > lr.y) {
3837                    lr.y = pLinePoints[j].y;
3838                }
3839                if (pLinePoints[j].x < ul.x) {
3840                    ul.x = pLinePoints[j].x;
3841                }
3842                if (pLinePoints[j].y < ul.y) {
3843                    ul.y = pLinePoints[j].y;
3844                }
3845            }
3846        } catch (Exception exc) {
3847            ErrorLogger.LogException(_className, "CalcMBRPoints",
3848                    new RendererException("Failed inside CalcMBRPoints", exc));
3849        }
3850    }
3851
3852    /**
3853     * Computes the distance in pixels from upper left to lower right of the
3854     * minimum bounding rectangle for the first numpts of pLinePoints
3855     *
3856     * @param pLinePoints the inpupt point array
3857     * @param numpts the number of points to use
3858     *
3859     * @return the distance in pixels
3860     */
3861    protected static double MBRDistance(POINT2[] pLinePoints,
3862            int numpts) {
3863        double result = 0;
3864        try {
3865            ref<double[]> ulx = new ref(), uly = new ref(), lrx = new ref(), lry = new ref();
3866            CalcMBR(pLinePoints, numpts, ulx, uly, lrx, lry);
3867            result = Math.sqrt((lrx.value[0] - ulx.value[0]) * (lrx.value[0] - ulx.value[0]) + (lry.value[0] - uly.value[0]) * (lry.value[0] - uly.value[0]));
3868            //sanity check
3869
3870            //return x or y distance if returnValue is 0 or infinity
3871            double xdist = Math.abs(lrx.value[0] - ulx.value[0]);
3872            double ydist = Math.abs(lry.value[0] - uly.value[0]);
3873            double max = xdist;
3874            if (ydist > xdist) {
3875                max = ydist;
3876            }
3877
3878            if (result == 0 || Double.isInfinite(result)) {
3879                if (max > 0) {
3880                    result = max;
3881                }
3882            }
3883
3884        } catch (Exception exc) {
3885            ErrorLogger.LogException(_className, "MBRDistance",
3886                    new RendererException("Failed inside MBRDistance", exc));
3887        }
3888        return result;
3889    }
3890
3891    /**
3892     * Swaps two points.
3893     *
3894     * @param pt1 OUT - first point
3895     * @param pt2 OUT - second point
3896     *
3897     */
3898    protected static void Reverse2Points(POINT2 pt1, POINT2 pt2) {
3899        try {
3900            POINT2 tempPt = new POINT2();
3901            //store pt1
3902            tempPt.x = pt1.x;
3903            tempPt.y = pt1.y;
3904            pt1.x = pt2.x;
3905            pt1.y = pt2.y;
3906            pt2.x = tempPt.x;
3907            pt2.y = tempPt.y;
3908        } catch (Exception exc) {
3909            ErrorLogger.LogException(_className, "Reverse2Points",
3910                    new RendererException("Failed inside Reverse2Points", exc));
3911        }
3912    }
3913    /**
3914     * Creates a GeneralPath from a Path2D
3915     *
3916     * @param shape
3917     * @return
3918     */
3919    public static Shape createStrokedShape(Shape shape) {
3920        GeneralPath newshape = new GeneralPath(); // Start with an empty shape
3921        try {
3922            // Iterate through the specified shape, perturb its coordinates, and
3923            // use them to build up the new shape.
3924            float[] coords = new float[6];
3925            for (PathIterator i = shape.getPathIterator(null); !i.isDone(); i.next()) {
3926                int type = i.currentSegment(coords);
3927                switch (type) {
3928                    case PathIterator.SEG_MOVETO:
3929                        //perturb(coords, 2);
3930                        newshape.moveTo(coords[0], coords[1]);
3931                        break;
3932                    case PathIterator.SEG_LINETO:
3933                        //perturb(coords, 2);
3934                        newshape.lineTo(coords[0], coords[1]);
3935                        break;
3936                    case PathIterator.SEG_QUADTO:
3937                        //perturb(coords, 4);
3938                        newshape.quadTo(coords[0], coords[1], coords[2], coords[3]);
3939                        break;
3940                    case PathIterator.SEG_CUBICTO:
3941                        //perturb(coords, 6);
3942                        newshape.curveTo(coords[0], coords[1], coords[2], coords[3],
3943                                coords[4], coords[5]);
3944                        break;
3945                    case PathIterator.SEG_CLOSE:
3946                        newshape.closePath();
3947                        break;
3948                }
3949
3950            }
3951        } catch (Exception exc) {
3952            ErrorLogger.LogException(_className, "createStrokedShape",
3953                    new RendererException("Failed inside createStrokedShape", exc));
3954        }
3955        return newshape;
3956    }
3957    //These functions were added to create a minimum bounding polygon
3958    /**
3959     * @deprecated Returns the determinant of the point matrix This determinant
3960     * tells how far p3 is from vector p1p2 and on which side it is
3961     * @param p1
3962     * @param p2
3963     * @param p3
3964     * @return
3965     */
3966    static private int distance(Point p1, Point p2, Point p3) {
3967        try {
3968            int x1 = p1.x;
3969            int x2 = p2.x;
3970            int x3 = p3.x;
3971            int y1 = p1.y;
3972            int y2 = p2.y;
3973            int y3 = p3.y;
3974            return x1 * y2 + x3 * y1 + x2 * y3 - x3 * y2 - x2 * y1 - x1 * y3;
3975        } catch (Exception exc) {
3976            ErrorLogger.LogException(_className, "distance",
3977                    new RendererException("Failed inside distance", exc));
3978        }
3979        return 0;
3980    }
3981
3982    /**
3983     * @deprecated Returns the determinant of the point matrix This determinant
3984     * tells how far p3 is from vector p1p2 and on which side it is
3985     * @param p1
3986     * @param p2
3987     * @param p3
3988     * @return
3989     */
3990    static private double distance2(POINT2 p1, POINT2 p2, POINT2 p3) {
3991        try {
3992            double x1 = p1.x;
3993            double x2 = p2.x;
3994            double x3 = p3.x;
3995            double y1 = p1.y;
3996            double y2 = p2.y;
3997            double y3 = p3.y;
3998            return x1 * y2 + x3 * y1 + x2 * y3 - x3 * y2 - x2 * y1 - x1 * y3;
3999        } catch (Exception exc) {
4000            ErrorLogger.LogException(_className, "distance2",
4001                    new RendererException("Failed inside distance2", exc));
4002        }
4003        return 0;
4004    }
4005
4006    /**
4007     * @deprecated @param points
4008     * @param l
4009     * @param r
4010     * @param path
4011     */
4012    static private void cHull(ArrayList<Point> points, Point l, Point r, ArrayList<Point> path) {
4013
4014        if (points.size() < 3) {
4015            return;
4016        }
4017
4018        int maxDist = 0;
4019        int tmp;
4020        Point p = null;
4021
4022        for (Point pt : points) {
4023            if (pt != l && pt != r) {
4024                tmp = distance(l, r, pt);
4025
4026                if (tmp > maxDist) {
4027                    maxDist = tmp;
4028                    p = pt;
4029                }
4030            }
4031        }
4032
4033        ArrayList<Point> left = new ArrayList<Point>();
4034        ArrayList<Point> right = new ArrayList<Point>();
4035        left.add(l);
4036        right.add(p);
4037
4038        for (Point pt : points) {
4039            if (distance(l, p, pt) > 0) {
4040                left.add(pt);
4041            } else if (distance(p, r, pt) > 0) {
4042                right.add(pt);
4043            }
4044        }
4045
4046        left.add(p);
4047        right.add(r);
4048        cHull(left, l, p, path);
4049        path.add(p);
4050        cHull(right, p, r, path);
4051    }
4052
4053    /**
4054     * @deprecated @param points
4055     * @param l
4056     * @param r
4057     * @param path
4058     */
4059    static private void cHull2(ArrayList<POINT2> points, POINT2 l, POINT2 r, ArrayList<POINT2> path) {
4060
4061        if (points.size() < 3) {
4062            return;
4063        }
4064
4065        double maxDist = 0;
4066        double tmp;
4067        POINT2 p = null;
4068
4069        for (POINT2 pt : points) {
4070            if (pt != l && pt != r) {
4071                tmp = distance2(l, r, pt);
4072
4073                if (tmp > maxDist) {
4074                    maxDist = tmp;
4075                    p = pt;
4076                }
4077            }
4078        }
4079
4080        ArrayList<POINT2> left = new ArrayList<POINT2>();
4081        ArrayList<POINT2> right = new ArrayList<POINT2>();
4082        left.add(l);
4083        right.add(p);
4084
4085        for (POINT2 pt : points) {
4086            if (distance2(l, p, pt) > 0) {
4087                left.add(pt);
4088            } else if (distance2(p, r, pt) > 0) {
4089                right.add(pt);
4090            }
4091        }
4092
4093        left.add(p);
4094        right.add(r);
4095        cHull2(left, l, p, path);
4096        path.add(p);
4097        cHull2(right, p, r, path);
4098    }
4099    //Returns the points of convex hull in the correct order
4100    /**
4101     * @deprecated @param array
4102     * @return
4103     */
4104    static public ArrayList<Point> cHull(ArrayList<Point> array) {
4105        int size = array.size();
4106        if (size < 2) {
4107            return null;
4108        }
4109
4110        Point l = array.get(0);
4111        Point r = array.get(size - 1);
4112        ArrayList<Point> path = new ArrayList<Point>();
4113        path.add(l);
4114        cHull(array, l, r, path);
4115        path.add(r);
4116        cHull(array, r, l, path);
4117        return path;
4118    }
4119
4120    /**
4121     * @deprecated @param array
4122     * @return
4123     */
4124    static public ArrayList<POINT2> cHull2(ArrayList<POINT2> array) {
4125        try {
4126            int size = array.size();
4127            if (size < 2) {
4128                return null;
4129            }
4130
4131            POINT2 l = array.get(0);
4132            POINT2 r = array.get(size - 1);
4133            ArrayList<POINT2> path = new ArrayList<POINT2>();
4134            path.add(l);
4135            cHull2(array, l, r, path);
4136            path.add(r);
4137            cHull2(array, r, l, path);
4138            return path;
4139        } catch (Exception exc) {
4140            ErrorLogger.LogException(_className, "cHull2",
4141                    new RendererException("Failed inside cHull2", exc));
4142        }
4143        return null;
4144    }
4145
4146    public static void getExteriorPoints(POINT2[] pLinePoints,
4147            int vblCounter,
4148            int lineType,
4149            boolean interior
4150    ) {
4151        int j;
4152        int index;
4153        POINT2 pt0, pt1, pt2;
4154        ref<double[]> m01 = new ref(), m12 = new ref();
4155        int direction;
4156        POINT2 intersectPt;
4157        //ref<double[]> m1 = new ref(), m2 = new ref();
4158        ArrayList<POINT2> intersectPoints = new ArrayList();
4159        double b01, b12;        //the y intercepts for the lines corresponding to m1,m2 
4160        double dist = pLinePoints[0].style;
4161        for (j = 0; j < vblCounter; j++) {
4162            if (j == 0 || j == vblCounter - 1) {
4163                pt0 = new POINT2(pLinePoints[vblCounter - 2]);
4164                pt1 = new POINT2(pLinePoints[0]);
4165                pt2 = new POINT2(pLinePoints[1]);
4166            } else {
4167                pt0 = new POINT2(pLinePoints[j - 1]);
4168                pt1 = new POINT2(pLinePoints[j]);
4169                pt2 = new POINT2(pLinePoints[j + 1]);
4170            }
4171            if (pt1.style > 0) {
4172                dist = pt1.style;
4173            }
4174            //the exterior/interior points
4175            POINT2 pt00, pt01, pt10, pt11;
4176
4177            index = j - 1;
4178            if (index < 0) {
4179                index = vblCounter - 1;
4180            }
4181            POINT2[] pts = new POINT2[pLinePoints.length];
4182            int n=pLinePoints.length;
4183            //for (int k = 0; k < pLinePoints.length; k++) 
4184            for (int k = 0; k < n; k++) 
4185            {
4186                pts[k] = pLinePoints[k];
4187            }
4188
4189            direction = arraysupport.GetInsideOutsideDouble2(pt0, pt1, pts, vblCounter, index, lineType);
4190            //reverse the direction if these are interior points
4191            if (interior == true) {
4192                switch (direction) {
4193                    case 0:
4194                        direction = 1;
4195                        break;
4196                    case 1:
4197                        direction = 0;
4198                        break;
4199                    case 2:
4200                        direction = 3;
4201                        break;
4202                    case 3:
4203                        direction = 2;
4204                        break;
4205                    default:
4206                        break;
4207                }
4208            }
4209            //pt00-pt01 will be the interior line inside line pt0-pt1
4210            //pt00 is inside pt0, pt01 is inside pt1
4211            pt00 = lineutility.ExtendDirectedLine(pt0, pt1, pt0, direction, dist);
4212            pt01 = lineutility.ExtendDirectedLine(pt0, pt1, pt1, direction, dist);
4213
4214            //pt10-pt11 will be the interior line inside line pt1-pt2
4215            //pt10 is inside pt1, pt11 is inside pt2
4216            index = j;
4217            if (j == vblCounter - 1) {
4218                index = 0;
4219            }
4220            direction = arraysupport.GetInsideOutsideDouble2(pt1, pt2, (POINT2[]) pts, vblCounter, index, lineType);
4221            //reverse the direction if these are interior points
4222            if (interior == true) {
4223                switch (direction) {
4224                    case 0:
4225                        direction = 1;
4226                        break;
4227                    case 1:
4228                        direction = 0;
4229                        break;
4230                    case 2:
4231                        direction = 3;
4232                        break;
4233                    case 3:
4234                        direction = 2;
4235                        break;
4236                    default:
4237                        break;
4238                }
4239            }
4240            pt10 = lineutility.ExtendDirectedLine(pt1, pt2, pt1, direction, dist);
4241            pt11 = lineutility.ExtendDirectedLine(pt1, pt2, pt2, direction, dist);
4242            //intersectPt=new POINT2(null);
4243            //get the intersection of pt01-p00 and pt10-pt11
4244            //so it it is the interior intersection of pt0-pt1 and pt1-pt2
4245
4246            //first handle the case of vertical lines.
4247            if (pt0.x == pt1.x && pt1.x == pt2.x) {
4248                intersectPt = new POINT2(pt01);
4249                intersectPoints.add(intersectPt);
4250                continue;
4251            }
4252            //it's the same situation if the slopes are identical,
4253            //simply use pt01 or pt10 since they already uniquely define the intesection
4254            lineutility.CalcTrueSlopeDouble2(pt00, pt01, m01);
4255            lineutility.CalcTrueSlopeDouble2(pt10, pt11, m12);
4256            //if(m01.dbl==m12.dbl)                                      
4257            if (m01.value[0] == m12.value[0]) {
4258                intersectPt = new POINT2(pt01);
4259                intersectPoints.add(intersectPt);
4260                continue;
4261            }
4262            //now we are assuming a non-trivial intersection
4263            //calculate the y-intercepts using y=mx+b (use b=y-mx)
4264            b01 = pt01.y - m01.value[0] * pt01.x;
4265            b12 = pt11.y - m12.value[0] * pt11.x;
4266            intersectPt = lineutility.CalcTrueIntersectDouble2(m01.value[0], b01, m12.value[0], b12, 1, 1, 0, 0);
4267            intersectPoints.add(intersectPt);
4268        }//end for
4269        int n=intersectPoints.size();
4270        //for (j = 0; j < intersectPoints.size(); j++) 
4271        for (j = 0; j < n; j++) 
4272        {
4273            pLinePoints[j] = intersectPoints.get(j);
4274        }
4275    }
4276    public static ArrayList<POINT2> getDeepCopy(ArrayList<POINT2>pts)
4277    {
4278        ArrayList<POINT2>deepCopy=null;
4279        try
4280        {
4281            if(pts == null || pts.isEmpty())
4282                return pts;
4283            deepCopy=new ArrayList();
4284            int j=0;
4285            POINT2 pt=null;
4286            for(j=0;j<pts.size();j++)
4287            {                
4288                pt=new POINT2(pts.get(j).x,pts.get(j).y,pts.get(j).style);
4289                deepCopy.add(pt);
4290            }
4291        }
4292        catch (Exception exc) {
4293            ErrorLogger.LogException(_className, "getDeepCopy",
4294                    new RendererException("Failed inside getDeepCopy", exc));
4295        }
4296        return deepCopy;
4297    }
4298
4299}//end lineutility