I need to convert UTM to DMS. For example: x 6518585.31 y 13343143.32 -> degrees minutes seconds.
People refer to this library esri.arcgis.defensesolutions.dll, but I can't find where to download it.
Try the ArcGIS Runtime SDK for .NET. You can download and use it at no cost for coordinate conversion. Sample code is available, but here's the relevant code for what you need to do. You can use http://spatialreference.org/ref/ to find the WKID for your UTM zone; I'm using 32642, which is the WKID for UTM zone 42N based on WGS84.
var utmSpatialReferenceWkid = 32642;//UTM zone 42N based on WGS84
var pointUtm = new MapPoint(6518585.31, 13343143.32, utmSpatialReferenceWkid);
var pointLonLat = GeometryEngine.Project(pointUtm, SpatialReference.Wgs84);
var longitude = pointLonLat.X;
var latitude = pointLonLat.Y;
The defensesolutions DLL you mentioned is older technology, and you need an ArcGIS Desktop or Engine license to use it, which incurs a cost. Use ArcGIS Runtime instead.
coordinate system "Meters" to "Degrees Minutes Seconds"
ISpatialReferenceFactory srEnv = new SpatialReferenceEnvironmentClass();
var wgsIn = srEnv.CreateESRISpatialReferenceFromPRJFile(#"C:\111.prj");
var wgsOut = srEnv.CreateESRISpatialReferenceFromPRJFile(#"C:\222.prj");
var point = new PointClass();
point.PutCoords(3304534.9530999996, 6859385.3066000007);
point.Project(wgsIn);
var dmsCoord = new DMSCoordinate
{
Precision = esriCoordinatePrecision.esriCPOneMeter,
InputSpatialReference = wgsIn,
OutputSpatialReference = wgsOut,
Point = point
};
var dsd = dmsCoord.String;
dmsCoord.String Returns incorrect coordinates
You can use CoordinateSharp for exactly this.
Example
UniversalTransverseMercator utm = new UniversalTransverseMercator("T", 32, 233434, 234234);
Coordinate c = UniversalTransverseMercator.ConvertUTMtoLatLong(utm);
Console.WriteLine(c); //Outputs DMS formatted coordinate by default.
You can also access individual lat/long properties within the Coordinate object.
Related
I'm working on migrating a .Net framework application to .Net Core and I need to support running on Linux.
The application needs to calculate the intersection of polygons and very long lines on the Earths surface, and so it uses Geography objects as apposed to Geometry to take into account the Earth's elliptical shape.
For this we use Microsoft.SqlServer.Types, which lets us do the following:
// Line from New York to Paris
SqlGeography line = SqlGeography.STGeomFromText(new System.Data.SqlTypes.SqlChars("LINESTRING(40.730610 -73.935242, 48.864716 2.349014)"), 4326);
// Polygon in the Atlantic
SqlGeography polygon = SqlGeography.STGeomFromText(new System.Data.SqlTypes.SqlChars("POLYGON((60 -40, 60 -20, 30 -20, 30 -40, 60 -40))"), 4326);
// Contains the two locations where the line intersects with the polygon
SqlGeography intersection = line.STIntersection(polygon);
The problem is that Microsoft.SqlServer.Types only works on Windows. How can I get the same result in a way that will also compile and run on Linux?
I've looked into NetTopologySuite but it seems to only support geometry calculations
Not sure if you are using EFCore or the NetTopology Suite for handling geography data in your project - but all these are already supported in that package.
Microsoft
Nuget
As you are using the WellKnownText format you can use the Docs from here:
Github Docs
I can't post the source code of my solution but an example of how to use it would be:
public class GeographyHelper
{
private static GeometryFactory _geometryFactory
{
get
{
return NetTopologySuite.NtsGeometryServices.Instance.CreateGeometryFactory(4326);
}
}
public bool TestIntersectsAPolygon(double latitude, double longitude)
{
var wellKnownText = "YOUR POLYGON WKT";
var point = _geometryFactory.CreatePoint(new Coordinate(longitude, latitude));
var rdr = new NetTopologySuite.IO.WKTReader();
var geometry = rdr.Read(wellKnownText);
var polygon = _geometryFactory.CreatePolygon(geometry.Coordinates);
var intersects = polygon.Intersects(point);
return intersects ;
}
}
I'm trying to read a GeoTIFF with one band which stores a value between 0 and 3 ( 255 is no maks ). My Goal is to write a little program which takes in a latitude/longitude and returns the fitting pixel value at the geocoordinate in the geotiff.
I downloaded it from here : https://dataverse.harvard.edu/dataset.xhtml?persistentId=doi:10.7910/DVN/QQHCIK
And if you wanna take a look at it... heres the download link. https://drive.google.com/file/d/104De_YQN1V8tSbj2uhIPO0FfowjnInnX/view?usp=sharing
However, my code does not work. I cant tell you what is wrong, it just outputs the wrong pixel value every damn time. I guess either my geocordinate to pixel transformation is wrong or theres a huge logic mistake.
This was my first try, it prints the wrong value for the geo-coordinate.
Furthermore it crashes with some geocoordinates, a negative longitude makes it crashes because this will make pixelY negative which causes an exception in the raster method.
GdalConfiguration.ConfigureGdal();
var tif = "C:\\Users\\Lars\\Downloads\\pnv_biome.type_biome00k_c_1km_s0..0cm_2000..2017_v0.1.tif";
var lat = 51.0;
var lon = 8.3;
using (var image = Gdal.Open(tif, Access.GA_ReadOnly)) {
var bOneBand = image.GetRasterBand(1);
var width = bOneBand.XSize;
var height = bOneBand.YSize;
// Geocoordinate ( lat, lon ) to pixel in the tiff ?
var geoTransform = new double[6];
image.GetGeoTransform(geoTransform);
Gdal.InvGeoTransform(geoTransform, geoTransform);
var bOne = new int[1];
Gdal.ApplyGeoTransform(geoTransform, lat, lon, out var pixelXF, out var pixelYF);
var pixelX = (int)Math.Floor(pixelXF);
var pixelY = (int)Math.Floor(pixelYF);
// Read pixel
bOneBand.ReadRaster(pixelX, pixelY, 1, 1, bOne, 1, 1,0,0);
Console.WriteLine(bOne[0]); // bOne[0] contains wrong data
}
My second attempt looks like the following... but also outputs the wrong pixel value for the given coordinates. It also crashes with some geocoordinates.
GdalConfiguration.ConfigureGdal();
var tif = "C:\\Users\\Lars\\Downloads\\pnv_biome.type_biome00k_c_1km_s0..0cm_2000..2017_v0.1.tif";
var lat = 24.7377; // 131.5847
var lon = 131.5847;
using (var image = Gdal.Open(tif, Access.GA_ReadOnly)) {
var bOneBand = image.GetRasterBand(1);
var bOne = new int[1];
// Spatial reference to transform latlng to map coordinates... from python code
var point_srs = new SpatialReference("");
var file_srs = new SpatialReference(image.GetProjection());
point_srs.ImportFromEPSG(4326);
point_srs.SetAxisMappingStrategy(AxisMappingStrategy.OAMS_TRADITIONAL_GIS_ORDER);
var mapCoordinates = new double[2]{ lat, lon};
var transform = new CoordinateTransformation(point_srs, file_srs);
transform.TransformPoint(mapCoordinates);
// Map coordinates to pixel coordinates ?
var geoTransform = new double[6];
image.GetGeoTransform(geoTransform);
Gdal.InvGeoTransform(geoTransform, geoTransform);
Gdal.ApplyGeoTransform(geoTransform, mapCoordinates[0], mapCoordinates[1], out var pixelXF, out var pixelYF);
var pixelX = (int)pixelXF;
var pixelY = (int)pixelYF;
bOneBand.ReadRaster(pixelX, pixelY, 1, 1, bOne, 1, 1, 0,0);
Console.WriteLine(bOne[0]); // bOne[0] contains wrong value
}
What is wrong with my code, why does it output the wrong pixel value ?
Any help appreciated !
Perhaps you are using lat/lon where it should be lon/lat? It would be helpful if you printed some values such as mapCoordinates.
Here is how you can do this with R, for comparison:
library(terra)
r = rast("pnv_biome.type_biome00k_c_1km_s0..0cm_2000..2017_v0.1.tif")
xy = cbind(c(8.3, 131.5847), c(51.0, 24.7377))
extract(r, xy)
# pnv_biome.type_biome00k_c_1km_s0..0cm_2000..2017_v0.1
#1 9
#2 NA
And the zero-based row/col numbers
rowColFromCell(r, cellFromXY(r, xy)) - 1
# [,1] [,2]
#[1,] 4364 22596
#[2,] 7515 37390
And you can use describe (a.k.a. GDALinfo) to get some metadata. E.g.
d = describe("pnv_biome.type_biome00k_c_1km_s0..0cm_2000..2017_v0.1.tif")
d[50]
# [1] "Band 1 Block=43200x1 Type=Byte, ColorInterp=Gray"
I am trying to get the miles between to locations using xamarin essentials. I a have the coordinates for the staring point and destination. The Distance variable equals to 2134.13057845059. Do I need to convert this number to miles? It should equal to 30 miles or so.
var location = await Geolocation.GetLastKnownLocationAsync();
var courtLocation = new Location(Convert.ToDouble(item.Latitude), Convert.ToDouble(item.Longitude));
double distance = Location.CalculateDistance(location, courtLocation, DistanceUnits.Miles);
the last parameter of CalculateDistance is the unit for the return type.
you are requesting km
double distance = Location.CalculateDistance(location, courtLocation, DistanceUnits.Kilometers);
if you want to request miles, use
double distance = Location.CalculateDistance(location, courtLocation, DistanceUnits.Miles);
this works for me, if you are still getting a bad result I would double check your inputs and conversions
var loc1 = new Location(33.887749, -84.345818);
var loc2 = new Location(33.807920, -84.046791);
// result is 18.023...
double distance = Location.CalculateDistance(loc1, loc2, DistanceUnits.Miles);
Given the following set of xs and ys:
xs = [8294400, 2073600, 921600, 409920]
ys = [124, 433, 853, 1449]
Fitting this with a power law in Excel yields a good approximation:
Excel found a function of the form a(x^b). How can one determine a and b in C#? I tried using Math.Net numerics but I don't see any method that would work for a function of this form. All the functions in the Linear Regression module just find linear coefficients to functions of various forms but none seem to be able to determine an exponent.
The equation you want looks like this:
y = a*x^b
Take the natural log of both sides:
ln(y) = ln(a*x^b) = ln(a) + b*ln(x)
Now you can use linear regression on the new transformed variables (ln(x), ln(y)) and calculate the two parameters you want: ln(a) and b.
In an exponential system, the best way to do a regression is probably by doing a linear regression on a log scale. To clarify, even though your function isn't linear, taking the natural log of both sides of the equation will result in a more linear system
Non-linear function: y = a x^b
This then becomes ln(y) = ln(a x^b) = ln(a) b ln(x)
In Math.NET Numerics, a good way to code it could be:
var y = y.Select(r => Math.Log(r)).ToArray(); // transform y = ln(z)
double[] w = Fit.LinearCombination(xy, z_hat,
d => 1.0,
d => Math.Log(d[0]),
d => Math.Log(d[1]))
Or if you wanted to have it return a function you could use LinearCombinationFunc()
Sources: http://numerics.mathdotnet.com/Regression.html and http://numerics.mathdotnet.com/api/MathNet.Numerics/Fit.htm
IPoint pPoint = new ESRI.ArcGIS.Geometry.PointClass();
pPoint.PutCoords(-92.96000, 44.9227); //This should be near Minneapolis
mapControl.CenterAt(pPoint); //mapControl is a AxMapControl
When I run this code the point always ends up near Kansas. Can anyone help me convert lat / longs to an PointClass that will work properly?
I'm using VS2010 ArcEngine 10 C#
There is a lot more to this than you have currently given. Both a lat/long point and your map have a specific spatial reference. If they do not match, it is likely your point will plot in an unexpected way.
The point you are showing is a standard Latitude/Longitude point. Which is likely Nad83 (North American), or WGS84 (World). These are Spatial References with a Geographical Coordinate System. You are likely trying to plot the point on a Projected Coordinate System.
You need to make your MapControl's Spatial Reference match the types of points you are trying to plot.
Since I do not know the Spatial Reference of your Map, I can only give you an example of translating a Lat/Lon into what the MapControl's current spatial reference is.
ISpatialReferenceFactory srFactory = new SpatialReferenceEnvironmentClass();
IGeographicCoordinateSystem gcs = srFactory.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984);
ISpatialReference sr1 = gcs;
IPoint point = new PointClass() as IPoint;
point.PutCoords(-92.96000, 44.9227);
IGeometry geometryShape;
geometryShape = point;
geometryShape.SpatialReference = sr1;
geometryShape.Project(mapControl.SpatialReference);
mapControl.DrawShape(geometryShape);
This takes your point and projects it to the MapControls current spatial reference, then plots the point.
Good Luck.
Here is the code to zoom and center on a lat / long, the above poster was helpful but his solution did not work for me.
mapControl.MapScale = mapControl.MapScale / 2; //for zooming
ISpatialReferenceFactory srFactory = new SpatialReferenceEnvironmentClass(); //move up top later
IGeographicCoordinateSystem gcs = srFactory.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984); //World lat / long format
ISpatialReference sr1 = gcs;
IPoint point = new PointClass();
point.SpatialReference = gcs;
point.PutCoords(-92.96000, 44.9227);
point.Project(mapControl.SpatialReference);
mapControl.CenterAt(point);