I have some lines that are described by geographic coordinates (x1,y1)
to (x2,y2) in UTM coordinate. What I'm trying to do is draw these
lines onto a windows form to visualize what they look like. I can
draw lines onto the form using the code below. my question is how do
I convert my UTM coordinates to a form that can be drawn on the
screen?
You need to convert the UTM coordinates to a latitude/longitude
coordinate system and scale it to fit whatever your drawing. Here's a
small example using an example I created a while ago for a related
project:
class MainForm : Form
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
MainForm()
{
ClientSize = new Size(450, 300);
}
protected override void OnResize(EventArgs e)
{
Invalidate();
base.OnResize(e);
}
PointF UTMtoPointF(double x, double y, double f1)
{
double[] output = new double[2];
UTMConversions.UTMXYToLatLon(x, y, f1, false, ref output);
return new PointF((float)output[1], -(float)output[0]);
}
protected override void OnPaint(PaintEventArgs e)
{
List<PointF> points = new List<PointF>();
foreach (UTMCoords utm in UTMCoords.GetExample())
{
points.Add(UTMtoPointF(utm.Northing, utm.Easting,
utm.Zone));
}
PointF max = new PointF(float.MinValue, float.MinValue);
PointF min = new PointF(float.MaxValue, float.MaxValue);
foreach (PointF cur in points)
{
max.X = Math.Max(max.X, cur.X);
max.Y = Math.Max(max.Y, cur.Y);
min.X = Math.Min(min.X, cur.X);
min.Y = Math.Min(min.Y, cur.Y);
}
float temp = (max.X - min.X) * 0.05f;
min.X -= temp;
max.X += temp;
temp = (max.Y - min.Y) * 0.05f;
min.Y -= temp;
max.Y += temp;
List<PointF> output = new List<PointF>();
foreach (PointF cur in points)
{
output.Add(new PointF(
(cur.X - min.X) / (max.X - min.X) * ClientSize.Width,
(cur.Y - min.Y) / (max.Y - min.Y) *
ClientSize.Height));
}
e.Graphics.DrawPolygon(Pens.Black, output.ToArray());
base.OnPaint(e);
}
}
class UTMCoords
{
public double Northing;
public double Easting;
public double Zone;
public static IEnumerable<UTMCoords> GetExample()
{
yield return new UTMCoords(398835.00, 5355174.23, 10);
yield return new UTMCoords(490002.21, 5347785.39, 10);
yield return new UTMCoords(503008.13, 5412417.89, 10);
yield return new UTMCoords(320173.51, 5408878.96, 15);
yield return new UTMCoords(500865.42, 5373721.38, 15);
yield return new UTMCoords(625180.27, 5329608.40, 15);
yield return new UTMCoords(374391.94, 5310006.98, 16);
yield return new UTMCoords(485978.82, 5302106.62, 16);
yield return new UTMCoords(660245.76, 5178393.16, 16);
yield return new UTMCoords(333068.16, 5063639.65, 17);
yield return new UTMCoords(412472.80, 4861109.26, 17);
yield return new UTMCoords(359727.69, 4698202.27, 17);
yield return new UTMCoords(285227.76, 4627613.26, 17);
yield return new UTMCoords(431193.91, 4610145.49, 17);
yield return new UTMCoords(511580.62, 4689595.67, 17);
yield return new UTMCoords(656341.12, 4691331.56, 17);
yield return new UTMCoords(683192.02, 4770921.90, 17);
yield return new UTMCoords(652790.78, 4848200.80, 17);
yield return new UTMCoords(325147.14, 4834620.75, 18);
yield return new UTMCoords(474475.13, 4951399.02, 18);
yield return new UTMCoords(641090.13, 4973681.42, 18);
yield return new UTMCoords(313315.03, 4981765.95, 19);
yield return new UTMCoords(405614.00, 5123203.36, 19);
yield return new UTMCoords(473913.72, 5249490.78, 19);
yield return new UTMCoords(587147.13, 5216921.57, 19);
yield return new UTMCoords(603304.17, 5048602.61, 19);
yield return new UTMCoords(653944.01, 4939287.50, 19);
yield return new UTMCoords(514541.47, 4881616.83, 19);
yield return new UTMCoords(372073.36, 4791028.22, 19);
yield return new UTMCoords(355871.30, 4698280.78, 19);
yield return new UTMCoords(383133.47, 4596162.82, 19);
yield return new UTMCoords(701299.33, 4568712.98, 18);
yield return new UTMCoords(651100.68, 4501141.06, 18);
yield return new UTMCoords(592832.85, 4403321.12, 18);
yield return new UTMCoords(517836.41, 4281898.07, 18);
yield return new UTMCoords(448215.38, 4151581.71, 18);
yield return new UTMCoords(407868.30, 4011530.01, 18);
yield return new UTMCoords(438587.95, 3884554.80, 18);
yield return new UTMCoords(251319.48, 3775310.89, 18);
yield return new UTMCoords(595804.98, 3593289.89, 17);
yield return new UTMCoords(479857.86, 3427139.65, 17);
yield return new UTMCoords(445537.75, 3275888.61, 17);
yield return new UTMCoords(548361.30, 3105273.76, 17);
yield return new UTMCoords(663236.14, 2907027.53, 17);
yield return new UTMCoords(585359.05, 2730547.74, 17);
yield return new UTMCoords(408244.51, 2836302.72, 17);
yield return new UTMCoords(313857.94, 3020366.11, 17);
yield return new UTMCoords(342472.60, 3208900.79, 17);
yield return new UTMCoords(788042.60, 3287927.71, 16);
yield return new UTMCoords(626611.27, 3267998.76, 16);
yield return new UTMCoords(549582.41, 3351810.65, 16);
yield return new UTMCoords(338034.52, 3336060.52, 16);
yield return new UTMCoords(731624.71, 3244200.20, 15);
yield return new UTMCoords(586427.62, 3250658.13, 15);
yield return new UTMCoords(433259.15, 3309772.89, 15);
yield return new UTMCoords(398561.06, 3225293.72, 15);
yield return new UTMCoords(269459.09, 3184531.67, 15);
yield return new UTMCoords(718908.21, 3132943.63, 14);
yield return new UTMCoords(634039.65, 3011034.47, 14);
yield return new UTMCoords(652599.89, 2915625.75, 14);
yield return new UTMCoords(697646.53, 2837455.81, 14);
yield return new UTMCoords(556314.23, 2871158.49, 14);
yield return new UTMCoords(459936.26, 3001714.52, 14);
yield return new UTMCoords(408787.60, 3148406.80, 14);
yield return new UTMCoords(290479.01, 3269236.36, 14);
yield return new UTMCoords(734578.08, 3320499.22, 13);
yield return new UTMCoords(642580.33, 3217222.41, 13);
yield return new UTMCoords(497180.66, 3343286.02, 13);
yield return new UTMCoords(397061.36, 3485927.85, 13);
yield return new UTMCoords(773818.52, 3530518.63, 12);
yield return new UTMCoords(767206.57, 3463872.68, 12);
yield return new UTMCoords(516135.91, 3485431.48, 12);
yield return new UTMCoords(291604.12, 3528980.60, 12);
yield return new UTMCoords(666566.56, 3610649.16, 11);
yield return new UTMCoords(501649.05, 3609257.86, 11);
yield return new UTMCoords(395507.03, 3707813.39, 11);
yield return new UTMCoords(264866.66, 3710115.28, 11);
yield return new UTMCoords(737302.99, 3839429.05, 10);
yield return new UTMCoords(614450.43, 3996051.78, 10);
yield return new UTMCoords(534469.16, 4205461.88, 10);
yield return new UTMCoords(434956.29, 4304951.80, 10);
yield return new UTMCoords(399933.77, 4537206.66, 10);
yield return new UTMCoords(395675.96, 4747832.39, 10);
yield return new UTMCoords(412469.89, 4931092.01, 10);
yield return new UTMCoords(429039.93, 5156560.10, 10);
yield return new UTMCoords(398835.00, 5355174.23, 10);
}
public UTMCoords(double Northing, double Easting, double Zone)
{
this.Northing = Northing;
this.Easting = Easting;
this.Zone = Zone;
}
}
static class UTMConversions
{
//From:
http://home.hiwaay.net/~taylorc/toolbox/geography/geoutm.html
const double cPI = 3.14159265358979;
const double cSM_A = 6378137.0;
const double cSM_B = 6356752.314;
const double cUTMScaleFactor = 0.9996;
static double DegToRad(double deg)
{
return (deg / 180.0 * cPI);
}
static double RadToDeg(double rad)
{
return (rad / cPI * 180.0);
}
static double ArcLengthOfMeridian(double phi)
{
double alpha, beta, gamma, delta, epsilon, n;
double result;
n = (cSM_A - cSM_B) / (cSM_A + cSM_B);
alpha = ((cSM_A + cSM_B) / 2.0)
* (1.0 + (Math.Pow(n, 2.0) / 4.0) + (Math.Pow(n, 4.0) /
64.0));
beta = (-3.0 * n / 2.0) + (9.0 * Math.Pow(n, 3.0) / 16.0)
+ (-3.0 * Math.Pow(n, 5.0) / 32.0);
gamma = (15.0 * Math.Pow(n, 2.0) / 16.0)
+ (-15.0 * Math.Pow(n, 4.0) / 32.0);
delta = (-35.0 * Math.Pow(n, 3.0) / 48.0)
+ (105.0 * Math.Pow(n, 5.0) / 256.0);
epsilon = (315.0 * Math.Pow(n, 4.0) / 512.0);
result = alpha
* (phi + (beta * Math.Sin(2.0 * phi))
+ (gamma * Math.Sin(4.0 * phi))
+ (delta * Math.Sin(6.0 * phi))
+ (epsilon * Math.Sin(8.0 * phi)));
return result;
}
static double UTMCentralMeridian(double zone)
{
return DegToRad(-183.0 + (zone * 6.0));
}
static double FootpointLatitude(double y)
{
double y_, alpha_, beta_, gamma_, delta_, epsilon_, n;
double result;
n = (cSM_A - cSM_B) / (cSM_A + cSM_B);
alpha_ = ((cSM_A + cSM_B) / 2.0)
* (1 + (Math.Pow(n, 2.0) / 4) + (Math.Pow(n, 4.0) / 64));
y_ = y / alpha_;
beta_ = (3.0 * n / 2.0) + (-27.0 * Math.Pow(n, 3.0) / 32.0)
+ (269.0 * Math.Pow(n, 5.0) / 512.0);
gamma_ = (21.0 * Math.Pow(n, 2.0) / 16.0)
+ (-55.0 * Math.Pow(n, 4.0) / 32.0);
delta_ = (151.0 * Math.Pow(n, 3.0) / 96.0)
+ (-417.0 * Math.Pow(n, 5.0) / 128.0);
epsilon_ = (1097.0 * Math.Pow(n, 4.0) / 512.0);
result = y_ + (beta_ * Math.Sin(2.0 * y_))
+ (gamma_ * Math.Sin(4.0 * y_))
+ (delta_ * Math.Sin(6.0 * y_))
+ (epsilon_ * Math.Sin(8.0 * y_));
return result;
}
static void MapLatLonToXY(double phi, double lambda, double
lambda0, ref double[] xy)
{
double N, nu2, ep2, t, t2, l;
double l3coef, l4coef, l5coef, l6coef, l7coef, l8coef;
double tmp;
ep2 = (Math.Pow(cSM_A, 2.0) - Math.Pow(cSM_B, 2.0)) /
Math.Pow(cSM_B, 2.0);
nu2 = ep2 * Math.Pow(Math.Cos(phi), 2.0);
N = Math.Pow(cSM_A, 2.0) / (cSM_B * Math.Sqrt(1 + nu2));
t = Math.Tan(phi);
t2 = t * t;
tmp = (t2 * t2 * t2) - Math.Pow(t, 6.0);
l = lambda - lambda0;
l3coef = 1.0 - t2 + nu2;
l4coef = 5.0 - t2 + 9 * nu2 + 4.0 * (nu2 * nu2);
l5coef = 5.0 - 18.0 * t2 + (t2 * t2) + 14.0 * nu2
- 58.0 * t2 * nu2;
l6coef = 61.0 - 58.0 * t2 + (t2 * t2) + 270.0 * nu2
- 330.0 * t2 * nu2;
l7coef = 61.0 - 479.0 * t2 + 179.0 * (t2 * t2) - (t2 * t2 *
t2);
l8coef = 1385.0 - 3111.0 * t2 + 543.0 * (t2 * t2) - (t2 * t2 *
t2);
xy[0] = N * Math.Cos(phi) * l
+ (N / 6.0 * Math.Pow(Math.Cos(phi), 3.0) * l3coef *
Math.Pow(l, 3.0))
+ (N / 120.0 * Math.Pow(Math.Cos(phi), 5.0) * l5coef *
Math.Pow(l, 5.0))
+ (N / 5040.0 * Math.Pow(Math.Cos(phi), 7.0) * l7coef *
Math.Pow(l, 7.0));
xy[1] = ArcLengthOfMeridian(phi)
+ (t / 2.0 * N * Math.Pow(Math.Cos(phi), 2.0) *
Math.Pow(l, 2.0))
+ (t / 24.0 * N * Math.Pow(Math.Cos(phi), 4.0) * l4coef *
Math.Pow(l, 4.0))
+ (t / 720.0 * N * Math.Pow(Math.Cos(phi), 6.0) * l6coef *
Math.Pow(l, 6.0))
+ (t / 40320.0 * N * Math.Pow(Math.Cos(phi), 8.0) * l8coef
* Math.Pow(l, 8.0));
}
static void MapXYToLatLon(double x, double y, double lambda0, ref
double[] philambda)
{
double phif, Nf, Nfpow, nuf2, ep2, tf, tf2, tf4, cf;
double x1frac, x2frac, x3frac, x4frac, x5frac, x6frac, x7frac,
x8frac;
double x2poly, x3poly, x4poly, x5poly, x6poly, x7poly, x8poly;
phif = FootpointLatitude(y);
ep2 = (Math.Pow(cSM_A, 2.0) - Math.Pow(cSM_B, 2.0))
/ Math.Pow(cSM_B, 2.0);
cf = Math.Cos(phif);
nuf2 = ep2 * Math.Pow(cf, 2.0);
Nf = Math.Pow(cSM_A, 2.0) / (cSM_B * Math.Sqrt(1 + nuf2));
Nfpow = Nf;
tf = Math.Tan(phif);
tf2 = tf * tf;
tf4 = tf2 * tf2;
x1frac = 1.0 / (Nfpow * cf);
Nfpow *= Nf;
x2frac = tf / (2.0 * Nfpow);
Nfpow *= Nf;
x3frac = 1.0 / (6.0 * Nfpow * cf);
Nfpow *= Nf;
x4frac = tf / (24.0 * Nfpow);
Nfpow *= Nf;
x5frac = 1.0 / (120.0 * Nfpow * cf);
Nfpow *= Nf;
x6frac = tf / (720.0 * Nfpow);
Nfpow *= Nf;
x7frac = 1.0 / (5040.0 * Nfpow * cf);
Nfpow *= Nf;
x8frac = tf / (40320.0 * Nfpow);
x2poly = -1.0 - nuf2;
x3poly = -1.0 - 2 * tf2 - nuf2;
x4poly = 5.0 + 3.0 * tf2 + 6.0 * nuf2 - 6.0 * tf2 * nuf2
- 3.0 * (nuf2 * nuf2) - 9.0 * tf2 * (nuf2 * nuf2);
x5poly = 5.0 + 28.0 * tf2 + 24.0 * tf4 + 6.0 * nuf2 + 8.0 *
tf2 * nuf2;
x6poly = -61.0 - 90.0 * tf2 - 45.0 * tf4 - 107.0 * nuf2
+ 162.0 * tf2 * nuf2;
x7poly = -61.0 - 662.0 * tf2 - 1320.0 * tf4 - 720.0 * (tf4 *
tf2);
x8poly = 1385.0 + 3633.0 * tf2 + 4095.0 * tf4 + 1575 * (tf4 *
tf2);
philambda[0] = phif + x2frac * x2poly * (x * x)
+ x4frac * x4poly * Math.Pow(x, 4.0)
+ x6frac * x6poly * Math.Pow(x, 6.0)
+ x8frac * x8poly * Math.Pow(x, 8.0);
philambda[1] = lambda0 + x1frac * x
+ x3frac * x3poly * Math.Pow(x, 3.0)
+ x5frac * x5poly * Math.Pow(x, 5.0)
+ x7frac * x7poly * Math.Pow(x, 7.0);
}
static public double LatLonToUTMXY(double lat, double lon, ref
double[] xy)
{
double zone = Math.Floor((lon + 180.0) / 6) + 1;
lat = DegToRad(lat);
lon = DegToRad(lon);
MapLatLonToXY(lat, lon, UTMCentralMeridian(zone), ref xy);
xy[0] = xy[0] * cUTMScaleFactor + 500000.0;
xy[1] = xy[1] * cUTMScaleFactor;
if (xy[1] < 0.0)
{
xy[1] = xy[1] + 10000000.0;
}
return zone;
}
static public void UTMXYToLatLon(double x, double y, double zone,
bool southhemi, ref double[] latlon)
{
double cmeridian;
x -= 500000.0;
x /= cUTMScaleFactor;
if (southhemi)
{
y -= 10000000.0;
}
y /= cUTMScaleFactor;
cmeridian = UTMCentralMeridian(zone);
MapXYToLatLon(x, y, cmeridian, ref latlon);
}
}