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