using System;using System.Drawing;
using System.Windows.Forms;
namespace GNSSView
{
// Code by Aleksandr Dikarev, dikarev-aleksandr@yandex.ru
public struct GeoCoordinate2D
{
public double Latitude;
public double Longitude;
}
public partial class GeoPlot : UserControl
{
#region Properties
int maxPoints = 10;
FixedSizeLIFO<GeoCoordinate2D> points;
Pen pointPen = new Pen(Brushes.Blue, 2.0f);
Pen gridPen = new Pen(Brushes.Black, 1.0f);
#endregion
#region Constructor
public GeoPlot()
{
InitializeComponent();
}
#endregion
#region Methods
public void Init(int trajectoryLength)
{
maxPoints = trajectoryLength;
points = new FixedSizeLIFO<GeoCoordinate2D>(maxPoints);
}
public void AddPoint(GeoCoordinate2D newPoint)
{
points.Add(newPoint);
}
public static void GetCurveLengths(out double byMeridian, out double byParallel, double lat1, double lon1, double lat2, double lon2)
{
double majAxis = 6378137.0;
double invFlt = 298.257223563;
double flt = 1 / invFlt;
double minAxis = majAxis * (1 - flt);
double ellE2 = 1 - minAxis * minAxis / majAxis / majAxis;
double avrLatitude = (lat2 + lat1) / 2.0;
double W = Math.Sqrt(1 - ellE2 * Math.Sin(avrLatitude * Math.PI / 180) * Math.Sin(avrLatitude * Math.PI / 180));
double ecrM = majAxis * (1 - ellE2) / W / W / W;
double ecrN = majAxis / W;
byMeridian = ecrM * (lat2 - lat1) * Math.PI / 180.0;
byParallel = ecrN * Math.Cos(avrLatitude * Math.PI / 180) * (lon2 - lon1) * Math.PI / 180.0;
}
private static double GetDistance2DM(double lat1, double lon1, double lat2, double lon2)
{
double xl, yl;
GetCurveLengths(out xl, out yl, lat1, lon1, lat2, lon2);
return Math.Sqrt(xl * xl + yl * yl);
}
#endregion
#region Handlers
private void GeoPlot_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
if ((points != null) && (!e.ClipRectangle.IsEmpty))
{
var items = points.ToArray();
if (items.Length > 1)
{
double meanLat = items[0].Latitude;
double meanLon = items[0].Longitude;
double farestLat = 0.0;
double farestLon = 0.0;
for (int i = 0; i < items.Length; i++)
{
if (Math.Abs(items[i].Latitude - meanLat) > farestLat)
farestLat = Math.Abs(items[i].Latitude - meanLat);
if (Math.Abs(items[i].Longitude - meanLon) > farestLon)
farestLon = Math.Abs(items[i].Longitude - meanLon);
}
double farestDist = Math.Max(farestLat, farestLon);
if (farestDist < double.Epsilon)
farestDist = 0.000001;
double xScale = e.Graphics.ClipBounds.Width / (farestDist * 2.0f);
double yScale = e.Graphics.ClipBounds.Height / (farestDist * 2.0f);
float scale = (float)Math.Min(xScale, yScale);
e.Graphics.TranslateTransform(e.ClipRectangle.Width / 2.0f, e.ClipRectangle.Height / 2.0f);
float fDist = Math.Abs((float)farestDist * 0.75f);
double fDistM = GetDistance2DM(meanLat, meanLon, meanLat + fDist, meanLon + fDist);
float fDistScaled = (float)(fDist * scale);
e.Graphics.DrawLine(gridPen, -fDistScaled, -4, -fDistScaled, 4);
e.Graphics.DrawLine(gridPen, fDistScaled, -4, fDistScaled, 4);
e.Graphics.DrawLine(gridPen, -4, -fDistScaled, 4, -fDistScaled);
e.Graphics.DrawLine(gridPen, -4, fDistScaled, 4, fDistScaled);
var fDistMLbl = fDistM.ToString("0.0 m");
var fDistMLblSize = e.Graphics.MeasureString(fDistMLbl, this.Font);
e.Graphics.DrawString(fDistMLbl, this.Font, Brushes.Black,
-fDistScaled - fDistMLblSize.Width / 2, -fDistMLblSize.Height - 2);
e.Graphics.DrawString(fDistMLbl, this.Font, Brushes.Black,
fDistScaled - fDistMLblSize.Width / 2, -fDistMLblSize.Height - 2);
e.Graphics.DrawString(fDistMLbl, this.Font, Brushes.Black,
-fDistMLblSize.Width, -fDistScaled - fDistMLblSize.Height / 2);
e.Graphics.DrawString(fDistMLbl, this.Font, Brushes.Black,
-fDistMLblSize.Width, fDistScaled - fDistMLblSize.Height / 2);
float left = -e.ClipRectangle.Width / 2.0f;
float right = e.ClipRectangle.Width / 2.0f;
float top = -e.ClipRectangle.Height / 2.0f;
float bottom = e.ClipRectangle.Height / 2.0f;
e.Graphics.DrawLine(gridPen, left, 0.0f, right, 0.0f);
e.Graphics.DrawLine(gridPen, 0.0f, top, 0.0f, bottom);
PointF[] pointsToDraw = new PointF[items.Length];
for (int i = 0; i < items.Length; i++)
{
float x = (float)(items[i].Longitude - meanLon) * scale;
float y = (float)(items[i].Latitude - meanLat) * scale;
pointsToDraw[i] = new PointF(x, y);
}
e.Graphics.DrawLines(pointPen, pointsToDraw);
var latLabel = StrUtils.AngleToString(meanLat);
var latLabelSize = e.Graphics.MeasureString(latLabel, this.Font);
var lonLabel = StrUtils.AngleToString(meanLon);
var lonLabelSize = e.Graphics.MeasureString(lonLabel, this.Font);
e.Graphics.DrawString(latLabel, this.Font, Brushes.Black, right - lonLabelSize.Width, 2.0f);
e.Graphics.DrawString(lonLabel, this.Font, Brushes.Black, 5.0f, top + 2.0f);
}
}
}
private void GeoPlot_Resize(object sender, EventArgs e)
{
Invalidate();
}
#endregion
}
}