How can I get the distance between two Location in C#?
It also would be very nice to get the direction between two Locations if I have the compass value of the device.
is there any api for this?
It depends.
What do you mean by Location?
Case 1: When location is geographic point (Latitude, Longitude)
You need to go through spherical geometry. In fact you should make some calculation on a sphere (or Ellipsoid or other Spheroids). But the best way to avoid doing such complicated calculation is to use Microsoft.SqlServer.Types.dll (v.10 or v.11). If you have SQL Server 2012 (or 2008) installed on your system, you can find it somewhere like this (otherwise you may download it from the web):
"C:\Program Files\Microsoft SQL Server\110\Shared\Microsoft.SqlServer.Types.dll"
Then using this dll you can declare two SqlGeography type and call the STDistance() method and everything will be done correctly. (Remember there are lost of issue here, I'm not going to complicate it more than this). Here is the code:
SqlGeography p1 =
SqlGeography.STPointFromText(new System.Data.SqlTypes.SqlChars("POINT( lat1, long1)"), 4326); // SRID of WGS84: 4326
SqlGeography p2 =
SqlGeography.STPointFromText(new System.Data.SqlTypes.SqlChars("POINT( lat2, long2)"), 4326); // SRID of WGS84: 4326
double distance = p1.STDistance(p2).Value;
Case 2: When location is a simple local 2D point (x, y) on a plane
In this case you can use the famous formula to calculate the distance:
double distance = Math.Sqrt(dx*dx + dy*dy); //dx and dy are the difference of the x and y of the two points
Related
As the title suggests, I am trying to generate a coordinate based on another coordinate that is within an x mile (or whichever unit is most convenient) radius of the inputted one.
As an example:
I am given a geographic coordinate (lat, lon) of 39.083056, -94.820200.
I want to be returned another set of coordinates that is within a x
miles radius of that coordinate, such as 39.110998, -94.799668.
The x mile radius isn't as important as the fact that the returned
coordinates are within that x mile radius.
I have searched and searched, but I must be searching the wrong thing because all the posts that I have been able to find seem like they get very close to what I am trying to do but aren't quite hitting the nail on the head.
I'm sorry you're being downvoted to oblivion. I understand it can be frustrating trying to search for something without knowing what exactly to search for.
You may be interested in Orthodromic Lines/Distances: wiki. If this answer doesn't fulfil your needs, at least you have a new term to google and hopefully will lead you to one that does suit.
You could try using the Geo library. Its documentation is on the sparse side, but it does contain a method that could be useful to you: CalculateOrthodromicLine(startPoint, heading, distance)
A pseudocode would be something as simple as this:
var startPoint = new Coordinate(lat, long);
var heading = Random between 0 and 360 degrees
var distance = Random between 0 and X metres
var endPoint = //<-- et voila!
GeoContext.Current.GeodeticCalculator
.CalculateOrthodromicLine(startPoint, heading, distance)
.Coordinate2;
Edit: As mentioned in the wiki, the Earth is not a perfect sphere, but a spheroid instead. The library's GeoContext.Current by default uses its Spheroid calculations, so you should be okay.
Good luck!
I'm using Mike Gavaghan's Geodesy library to calculate:
The new Latitude & Longitude from a starting Location, Bearing and Distance ( Vincenty direct formula, CalculateEndingGlobalCoordinates)
However, I am seeing some results I did not expect.
When using the Direct formula, calculating a new point Due East (90 degrees), I expected the Latitude to NOT change, However the following code returns unexpected results:
GeodeticCalculator geoCalc = new GeodeticCalculator();
Ellipsoid reference = Ellipsoid.WGS84;
Angle startBearing = new Angle(90);
double metersDistance = 50000;
GlobalCoordinates dest = geoCalc.CalculateEndingGlobalCoordinates(
reference,
new GlobalCoordinates(
new Angle(50.0d),
new Angle(0.0d)
),
startBearing,
metersDistance
);
I expected the Latitude (50.0) to remain the same, but it returns "49.7909857".
This may well be correct, but to my knowledge, regardless of Latitude, if you travel due east, you should remain on the same Latitude?
At a latitude of 0.0, the Latitude does indeed remain the same.
Is this a bug in the Library, or a lack of understanding on my part?
The latitude is supposed to change! 90° is just your initial bearing. In order to maintain a straight path (the definition of a geodesic), the path must bend away from the circle of latitude (unless it's the equator). To help understand this, imagine a latitude so close to 90° that it's a circle of radius 1m about the north pole.
I can use the following SQL to calculate the distance between a fixed location and the location against the venues in the database.
SELECT Location.STDistance(geography::Point(51, -2, 4326)) * 0.00062137119 FROM Venues
Please note the distance returned is in miles and the Location field is a geography type.
I was wondering what is the equivalent of this in .NET which would return the same values. This method would have the following signature:
public static double Distance(location1Latitude, location1Longitude, location2Latitude, location2Longitude) {
return ...;
}
I know I could call the database method in .NET but I don't wish to do this. I'm hoping there is a formula to calculate the distance. Thanks
I believe you can simply add Microsoft.SqlServer.Types.dll as a reference and then use the SqlGeometry type like any other .NET type, including calling the STDistance method.
You would need to compute the Geographical distance to compute the distance manually. There are many different techniques and formulas to do this, each with different underlying assumptions (ie: a spherical earth, ellipsoidal earth, etc).
A common option is the haversine formula, with a C# implementation available here.
this is very well explained here.
Shortly: with EF5 (to be more specific, with .net 4.5) Microsoft included the type DbGeography. Let say you already have a bunch of lat/long, you can then create a DbGeography object easily using an helper like:
public static DbGeography CreatePoint(double latitude, double longitude)
{
var text = string.Format(CultureInfo.InvariantCulture.NumberFormat,
"POINT({0} {1})", longitude, latitude);
// 4326 is most common coordinate system used by GPS/Maps
return DbGeography.PointFromText(text, 4326);
}
Once you got a two or more points (DbGeography) you got everything to calculate the Distance between them:
var distance = point1.Distance(point2)
How can i store a rectangle - consisting of 2 points NorthEast and SouthWest each point is a coordinate of lattitude and longitude
And add a circle consisting of a center ( lat-lng ) and a radius (int/float value)
what is the best way to store and later on query if a lat-lng is within the bounds of a any circle or rectangle ?
also , can i store an array of those ? say 10 rectangles and 5 circles in a single record ?
Can i use Nhibernate to ease the pain?
Sorry if this seems noobish , i have never done anything with spatial data and i don't even have clue from where to start.
Any samples and pointers are helpful !
Thanks in advance.
Here's how I would approach this problem using TSQL.
For a rectangle, the simplest method is to extrapolate the extra 2 points by using the relevant coordinates from the original points. e.g.
NorthEast (lat1, lon1) NorthWest* (lat1, lon2)
SouthEast* (lat2, lon1) SouthWest (lat2, lon2)
*New point
That doesn't give you a true rectangle (in a mathematical sense) but it's a common method in GIS (it's how geohashes are formed) what you get is a rough rectangle with varying size based on the distance from the equator. If you need an extact rectangle of a certain height/width you should look into using the Haversine formula to calculate the remaining 2 points, that will take into account bearing, and great circle distance.
http://www.movable-type.co.uk/scripts/latlong.html
To store the rectangle, I'd create a SQL table with a GEOGRAPHY type column, this will allow you assign additional attributes (e.g. name) along with a spatial index that will make future queries much faster.
CREATE TABLE dbo.geographies
(
NAME VARCHAR(50)
,GEOG GEOGRAPHY
)
INSERT INTO dbo.geographies (NAME, GEOG)
VALUES ('Rectangle', geography::STPolyFromText('POLYGON((lon1 lat1, lon2 lat1, lon2 lat2, lon1 lat2, lon1 lat1))', 4326))
Note that both the first point and the last point are the same, this is required to 'close' the polygon, and the final number denotes the SRID, or coordinate system, in this case WGS84. You can reference this page: http://msdn.microsoft.com/en-us/library/bb933971
As to the circle, it's simple to store a point and then use the radius to apply a buffer around the point:
INSERT INTO dbo.geographies (NAME, GEOG)
VALUES ('Circle with Radius', geography::STPointFromText('POINT(lon lat)', 4326).STBuffer([radius]))
Note that the buffer takes its input in meters so you may need to apply a conversion, more notes on this page: http://msdn.microsoft.com/en-us/library/bb933979
Now the fun part, it's quite easy to check for intersection on a point using the STIntersects
method.
http://msdn.microsoft.com/en-us/library/bb933962.aspx
DECLARE #point GEOGRAPHY = geography::STPointFromText('POINT(lon lat)', 4326)
SELECT * FROM dbo.geographies
WHERE #point.STIntersects(GEOG) = 1
The code sample takes a point and returns a list of all the geographies that the point is found within. It's important the the SRIDs of the new point and the geographies in the table match, otherwise you'll get zero matches (and probably pound you head against a wall for a while until you realize your mistake, at least, that's what I do).
As to integrating this with C#, I'm not sure how much help I can be, but it shouldn't be too much of a challenge to return the SQLGeography type
http://msdn.microsoft.com/en-us/library/microsoft.sqlserver.types.sqlgeography.aspx
Hopefully this at least points you in the right direction.
I have a current position: Latitude and Longitude values in degrees (Point A), and the same for the final position (Point B).
I need to calculate the course (also in degrees) between the two points and than with given speed (in km/s) and timespan (in seconds) to calculate the new position.
Example (Pseudo code):
PointA.Lat = x.xxxx;
PointA.Lng = x.xxxx;
PointB.Lat = x.xxxx;
PointB.Lng = x.xxxx;
Speed = 3;
TimeSpan = 0.1;
Course = GetCourse(PointA, PointB);
NewPoint = CalculatePoint(PointA, Course, Speed, TimeSpan);
I thought of using the GeoCoordinate class, but I'm not sure how ad I have to implement myself all the calculations. (I don't have a GPS - this is only a simulation and those are fake points).
Can someone help me with the math or with some package that can do it free and can easly be intagrated to my code?
BTW I'm using C#.
Thanks.
I'd have made this a comment but I don't have the required rep.
What you're looking for is a geodesy library that gives you the “geodetic inverse” and “geodetic direct” calculations. I don't know of any myself, but try searching for “c# geodesy library”
The former gives the bearing and distance between two geographical coordinates, the latter gives a new coordinate at a given bearing and distance from the first.
So for your problem:
Use the inverse to get the bearing between PointA and PointB
Calculate a destination distance from the time and speed,
Plug the bearing and distance into the direct to get the desired destination NewCoord.
Coding these calculations from 1st principles will be quite substantial and require the parameters of (presumably) the WGS84 ellipsoid. This, however, is the starting point.
Hope this helps.