Tuesday, February 27, 2018

Parsing UTM coordinates to DBGeography in C#

Leave a Comment

I'm writing a WinForms app in C#. I need to ensure no two Datarows in my Datatable are more than 100 km apart. Each row has a UTM Zone, Easting, and Northing in separate DataColumns. All coordinates use the same datum, but some have different zones (otherwise, I would just use pythag math since UTMs are in metres). So far, I'm using the following code to do this, but it doesn't seem like my DbGeography.PointFromText method is working quite right (see * in the code), as when the code reaches the line of code with the '**' at the start of it, I get an error saying "24201: Latitude values must be between -90 and 90 degrees". I've also tried:

dtTrap.Rows[i]["TrapGeog"] = DbGeography.PointFromText(pointWellKnownText: "POINT M(" + dtTrap.Rows[i][intEastingIndex].ToString() + " " + dtTrap.Rows[i][intNorthingIndex].ToString() + " " + dtTrap.Rows[i][Zone].ToString() + ")", coordinateSystemId: SRID); 

Only to have it complain that "There's no column # 17" (17 is my UTM Zone).

I've found very little documentation for using this stuff... as far as I can tell, my SRIDs are correct (I pulled them from this site). I've done this kind of thing using Lat+Longs before, and it worked wonderfully. I just can't find proper syntax for the UTMs.

using System.Data.Entity.Spatial; ... DataColumn dcGeog = new DataColumn("TrapGeog", typeof(DbGeography)); dtTrap.Columns.Add(dcGeog); byte Zone; Int16 SRID; for (int i = 0; i < dtTrap.Rows.Count; ++i) {     if (dtTrap.Rows[i][intZoneIndex] != null     && dtTrap.Rows[i][intNorthingIndex] != null     && dtTrap.Rows[i][intEastingIndex] != null     && byte.TryParse(dtTrap.Rows[i][intZoneIndex].ToString(), out Zone) == true)     {         if (Zone == 15) { SRID = 26915; }         else if (Zone == 16) { SRID = 26916; }         else if (Zone == 17) { SRID = 26917; }         else { SRID = 26918; }         // shove it in:         try         {             *dtTrap.Rows[i]["TrapGeog"] = DbGeography.PointFromText(pointWellKnownText: "POINT(" + dtTrap.Rows[i][intEastingIndex].ToString() + " " + dtTrap.Rows[i][intNorthingIndex].ToString() + ")", coordinateSystemId: SRID);         }         catch (Exception ex)         {             if (ex.InnerException != null)             {                 **MessageBox.Show(ex.InnerException.Message);             }             else             {                 MessageBox.Show(ex.Message);             }         }      } } for (int i = 0; i < dtTrap.Rows.Count - 1; ++i) {     for (int k = i + 1; k < dtTrap.Rows.Count; ++i)     {         DbGeography iTrap = (DbGeography)dtTrap.Rows[i]["TrapGeog"];         DbGeography kTrap = (DbGeography)dtTrap.Rows[k]["TrapGeog"];         if (iTrap.Distance(kTrap) > 100000)         {             sbErrorsAndWarningsLog.Append(@"Warning:  Line number " + (i + 2).ToString() + " on the Trap spreadsheet has coordinates that are at least 100 km away from row " + (k + 2).ToString() + "'s point.  Please check that these coordinates are correct.").AppendLine();             boolWarningsFound = true;             break;         }     } } 

2 Answers

Answers 1

In my quest to figure this out, I stumbled upon this post on a sister site here. I figure that DbGeography is based on SQL Server's geography data type, and DbGeometry likewise, geometry data type.

Some pertinent tidbits:

The geography datatype, EPSG:4326, is in degrees, which is why your POINT(257306 142708) is failing, as it falls out of the (-180,180), (-90,90) range.

...

The solution ... to use a geometry datatype instead, ie, projected, not geographic.

And so I've changed my code to:

DataColumn dcGeom = new DataColumn("TrapGeom", typeof(DbGeometry)); ... dtTrap.Rows[i]["TrapGeom"] = DbGeometry.PointFromText(pointWellKnownText: stPoint, coordinateSystemId: SRID); 

And it appears to parse just fine. Though, the last part of the post has me worried:

SQL Server insists on there being a SRID, even though you can't actually do anything useful with it, such as convert for one coordinate system to another. It can get really confusing if you accidentally mix geometries with different SRIDs as you will simply get no results (witout warning, but this is an aside).

And so, when I finally do if (Trap1.Distance(Trap2) > 100000) ... then I'm half-expecting it to malfunction when I have two different points in different SRIDs. I'll test and write a comment on what I find.

Answers 2

For better debugging of this error I recommend first checking your input data.

string point = ""; try {     string point = "POINT(" + dtTrap.Rows[i][intEastingIndex].ToString() + " " + dtTrap.Rows[i][intNorthingIndex].ToString() + ")";      dtTrap.Rows[i]["TrapGeog"] = DbGeography.PointFromText(pointWellKnownText: point, coordinateSystemId: SRID); } catch (Exception ex) {     System.Diagnostics.Debug.WriteLine("correct point? " + point);     if (ex.InnerException != null)     {         MessageBox.Show(ex.InnerException.Message + " at " + point);     }     else     {         MessageBox.Show(ex.Message);     } } 

My guess is, there is some comma instead of a point or some spaces inside your string.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment