コード例 #1
0
        /// <summary>
        /// Performs a correction of inverse projection.
        /// Checks that horizontal coordinates of a point are correct,
        /// and in case if not correct, applies iterative algorithm for searching correct values.
        /// </summary>
        /// <param name="p">Point to check</param>
        /// <param name="hor">Horizontal coordinates of the point</param>
        /// <returns>Corrected horizontal coordinates</returns>
        private CrdsHorizontal CorrectInverse(PointF p, CrdsHorizontal hor)
        {
            PointF pLeftEdge  = Project(new CrdsHorizontal(Map.Center.Azimuth - 90, hor.Altitude));
            PointF pRightEdge = Project(new CrdsHorizontal(Map.Center.Azimuth + 90, hor.Altitude));

            PointF pEdge;

            if (p.X < Map.Width / 2.0)
            {
                pEdge = pLeftEdge;
            }
            else
            {
                pEdge = pRightEdge;
            }

            Point origin = new Point((int)(Map.Width / 2.0), (int)(Map.Height / 2.0));

            double edgeToCenter = Map.DistanceBetweenPoints(origin, pEdge);

            double currentToCenter = Map.DistanceBetweenPoints(origin, p);

            bool correctionNeeded = Math.Abs(Map.Center.Altitude) == 90 || currentToCenter > edgeToCenter;

            if (correctionNeeded)
            {
                // projected coordinates of a horizontal grid pole (zenith or nadir point)
                PointF pole = Project(new CrdsHorizontal(0, 90 * (Map.Center.Altitude > 0 ? 1 : -1)));

                double angleWhole = 360 - Map.AngleBetweenVectors(pole, pLeftEdge, pRightEdge);

                double angleLeft = Map.AngleBetweenVectors(pole, p, pLeftEdge);

                double angleRight = Map.AngleBetweenVectors(pole, p, pRightEdge);

                int shiftSign = angleLeft < angleRight ? -1 : 1;

                int poleFix = 1;
                if (Map.Center.Altitude == 90 && pole.Y < p.Y)
                {
                    poleFix = -1;
                }
                else if (Map.Center.Altitude == -90 && pole.Y > p.Y)
                {
                    poleFix = -1;
                }

                double poleAngle = Math.Min(angleLeft, angleRight);

                double azimuthShift = poleAngle / angleWhole * 180;

                PointF pCorrected = new PointF(0, 0);

                double distOriginal  = Map.DistanceBetweenPoints(p, pEdge);
                double distCorrected = 0;

                int iterations = 0;

                do
                {
                    hor = new CrdsHorizontal(Angle.To360(Map.Center.Azimuth + shiftSign * 90 + poleFix * shiftSign * azimuthShift), hor.Altitude);

                    // corrected coordinates of a projected point
                    pCorrected = Project(hor);

                    distCorrected = Map.DistanceBetweenPoints(pCorrected, pEdge);

                    if (distCorrected > 0)
                    {
                        azimuthShift *= distOriginal / distCorrected;
                    }
                    iterations++;
                }while (Map.DistanceBetweenPoints(p, pCorrected) > 2 && iterations < 5);
            }

            return(hor);
        }
コード例 #2
0
        private void DrawGroupOfPoints(IMapContext map, Pen penGrid, PointF[] points, PointF[] refPoints)
        {
            // Do not draw figure containing less than 2 points
            if (points.Length < 2)
            {
                return;
            }

            // Two points can be simply drawn as a line
            if (points.Length == 2)
            {
                map.Graphics.DrawLine(penGrid, points[0], points[1]);
                return;
            }

            // Coordinates of the screen center
            var origin = new PointF(map.Width / 2, map.Height / 2);

            // Small radius is a screen diagonal
            double r = Math.Sqrt(map.Width * map.Width + map.Height * map.Height) / 2;

            // From 3 to 5 points. Probably we can straighten curve to line.
            // Apply some calculations to detect conditions when it's possible.
            if (points.Length > 2 && points.Length < 6)
            {
                // Determine start, middle and end points of the curve
                PointF pStart = points[0];
                PointF pMid   = points[points.Length / 2];
                PointF pEnd   = points[points.Length - 1];

                // Get angle between middle and last points of the curve
                double alpha = map.AngleBetweenVectors(pMid, pStart, pEnd);

                double d1 = map.DistanceBetweenPoints(pStart, origin);
                double d2 = map.DistanceBetweenPoints(pEnd, origin);

                // It's almost a straight line
                if (alpha > 179)
                {
                    // Check the at least one last point of the curve
                    // is far enough from the screen center
                    if (d1 > r * 2 || d2 > r * 2)
                    {
                        map.Graphics.DrawLine(penGrid, refPoints[0], refPoints[1]);
                        return;
                    }
                }

                // If both of last points of the line are far enough from the screen center
                // then assume that the curve is an arc of a big circle.
                // Check the curvature of that circle by comparing its radius with small radius
                if (d1 > r * 2 && d2 > r * 2)
                {
                    var R = FindCircleRadius(points);
                    if (R / r > 60)
                    {
                        map.Graphics.DrawLine(penGrid, refPoints[0], refPoints[1]);
                        return;
                    }
                }
            }

            if (points.All(p => map.DistanceBetweenPoints(p, origin) < r * 60))
            {
                // Draw the curve in regular way
                map.Graphics.DrawCurve(penGrid, points);
            }
        }