/// <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); }
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); } }