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.
Related
In my web application, I have coordinate bounds that I'd like to modify to simulate "zooming in" on google maps. It seems that zooming back and forth with google maps simply doubles or halves each side of the bounding box. So my function to do this on the server looks like this:
private static decimal[] ZoomIn(decimal latMax, decimal lngMin, decimal latMin, decimal lngMax)
{
decimal lngAdjustment = (lngMax - lngMin) * .25m;
decimal latAdjustment = (latMax - latMin) * .25m;
return new[]
{
// North
latMax - latAdjustment,
// West
lngMin + lngAdjustment,
// South
latMin + latAdjustment,
// East
lngMax - lngAdjustment
};
}
The problem with this approach is the latAdjustment that I'm doing. When compared to an actual zoom using the google maps control, this ends up being fairly accurate when zoomed in to city level. However, it is less accurate the further the view is zoomed out. I assume this is due to the Mercator projection of the earth that google maps uses. Is anyone aware of a better formula or method to use to simulate a "zoom"?
Update:
My issue has more to do with not knowing the correct formula than google maps. Let me illustrate using some sample numbers.
Take Chicago, centered at 41.8563226156679,-87.7339862646484
And a bounding box surrounding that point:
West: -87.984955197753800
East: -87.483017331542900
South: 41.546931599561100
North: 42.164224124684300
By observing the behavior of google maps, this bounding box zoomed in one level will be:
- West: -87.859470731201100
- East: -87.608501798095600
- South: 41.701813184067600
- North: 42.010459667660800
(center is kept the same, there is no variance due to mouse movement, etc. I just used the manual zoom button, not the mouse)
Using my formula above, longitude will values will come out correct. Example:
west = west + (west - east) * .25
-87.984955197753800 + ((-87.483017331542900 - -87.984955197753800) * .25) = -87.859470731201075
However, the same formula will not work when dealing with latitude. It is near the correct values, but off by just enough that the map shifts noticeably. This effect is worse with larger bounding boxes and/or when the latitude is further from the equator. I assume this is due to the mercator projection of the earth. Trig class was a long time ago for me, and at this point I'm unable to find a suitable formula for zoom latitude for this situation.
Judging by the fact that your testing method uses the mouse, it seems to me that your testing method is the problem. Since the map zooms in differently based on the centering of the mouse, not the center of the screen, the edge bounds vary, but not the difference between them. This seems to coincide with the details you have given.
Intuitively, there is nothing wrong with your formula -- just how you tested it.
I'm trying to rotate a point around the origin but i'm not sure what exactly i'm doing wrong, i'm using the built in System.Windows.Media.Media3D Namespace in PresentationCore:
var id = Matrix3D.Identity;
id.Rotate(new Quaternion(new Vector3D(1,0,0),90)); // Rotate around the X axis 90 degrees
var pt = new Point3D(0,0,10);
var p2 = id.Transform(pt); // Expect point to be rotated around the X axis 90 degree
Expected value of p2 is
x:0;
y:10;
z:0;
Actual value is
x:0;
y:-10;
z:2,22044604925031E-15
I'm sure i'm making a really basic error but i can't spot it.
(This answer assumes you are using and is using european notation of comma (,) instead of point (.))
You are getting the correct answer. 2,22044604925031 * 10^-15 is such a small number it is practically zero, but with round off error.
It is equal to about: 0,0000000000000022, close enough to 0 for most practical purposes.
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
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.
So here is the basic problem. I am currently working on a GPS system in C# in Unity 3D (the person that has given us the assignment is making us use this program, so I can't do it in anything else).
Now I've run in to a small problem, basically we are able to request (what we think are decimal) coordinates from an android phone, but now we are trying to convert those coordinates to X, Y, Z coordinates. Preferebly X and Z, because we do not actually need height. However everything we have been finding on the internet so far has been for a conversion to a sphere map where as we just have a basic flat digital map.
If anyone knows how to convert the coordinates we have to the basic X and Z coordinates (so our longitude and latitude) it'd be amazing.
To quickly note I am not sure if the sort of coordinates we have are actual decimal coordinates so this is what they look like:
Latitude: 53.228888 Longitude: 6.5403559
these coordinates should end up on "Wegalaan 3, Groningen, The Netherlands" if you would look them up on a map.
Thanks already!
EDIT: (this is also in the comments)
Sorry if it might be confusing. Honestly I only half understand how all this works, anyways to clear some things up. I am currently working in Unity with a simple 2D map I got from the internet of the city I live in (Groningen, The Netherlands) and I am trying to basically take GPS coordinates I get from my android phone and then show them on that map with a red dot, however to do this I need to be able to move the red dot to the right coordinates on the map. What I am trying to do is convert the GPS coords (lon and lat) to X and Z (Unity3D flat coordinates, may also just be X and Y) so that if I align the map right I get a small GPS system for just my city. If you are curious as to why I am doing this it is simply because a friend of mine and me are trying to build a game using our city and this GPS system as a basis
EDIT2:
except that I'll be honest I have no idea how cartesian coordinates work, but they seem to be what I am looking for yes :P Coordinates on a flat plane and with X,Y coords I mean basically just coordinates I could use in Unity3D on a flat 2D plane which is what I am working in.
EDIT3:
Thanks for the answers, to start. This is not a duplicate, secondly my friend and I already found the stackoverflow topic you sent me, but it seems to not be working for us (maybe we did something wrong). Basically the north and south distance between different places we tested with that formula have worked, however the east west distance between them was way bigger than it should have been. We think it might be because that formula was meant for a spherical earth, but maybe we did something wrong. If someone could explain further that'd be amazing!
EDIT4:
We are sure it can't be our map that is wrong in any way, because we have aligned it with multiple locations. We got the coordinates for these locations and then used this website: http://www.gpscoordinaten.nl/converteer-rd-coordinaten.php to convert it to XY coordinates and then used these XY coordinates to check if our map would align properly. It did, so we are sure there is some problem with the maths we are using and not with our actual map.
EDIT5: Removed many, many grammatical errors. It's way too hot over here to be writing properly right now, so I am very very sorry if any of this makes no sense. just let me know and I'll edit to try and explain what we are trying to do.
EDIT6: Found my own asnwer, it is down in between all the other answers if you wanna see what I did to fix my problem
By now I have found the answer to my own question (actually found it a little while ago already, but totally forgot to post it here)
Basically I made a little formula of my own that multiplied the coordinates with a set number (depending on wether or not it is the x or y axis) that is the difference between two set coordinate points. These two points are the outer points of my map.
Basically by doing this I can get quite accurate measurements I haven't even had a meter difference to my actual position yet.
I know this sounds a bit vague and I don't entirely know how to explain it, but for anyone interested here is the code I use:
void RetrieveGPSData()
{
currentGPSPosition = Input.location.lastData;
System.DateTime dateTime = new System.DateTime(1970, 1, 1, 0, 0, 0, 0);
dateTime = dateTime.AddSeconds(currentGPSPosition.timestamp);
float z = latToZ (Input.location.lastData.latitude);
float x = lonToX (Input.location.lastData.longitude);
this.transform.position = new Vector3 (x, 0f, z);
gpsString = ("Last Location: " + Input.location.lastData.latitude.ToString () + " " + Input.location.lastData.longitude.ToString () + " " + Input.location.lastData.altitude.ToString () + " " + Input.location.lastData.horizontalAccuracy.ToString () + " " + dateTime.ToShortDateString() +" "+ dateTime.ToShortTimeString());
}
float latToZ (double lat){
lat = (lat - 53.178469) / 0.00001 * 0.12179047095976932582726898256213;
double z = lat;
return (float)z;
}
float lonToX (double lon){
lon = (lon - 6.503091) / 0.000001 * 0.00728553580298947812081345114627;
double x = lon;
return (float)x;
}
Now for anyone wondering why I took the 53.something and the 6.something off the lon and lat it is because the coordinate of my 0 X and 0 Z point in Unity which corresponds to the bottom left corner of my map, which is one of the two points I talked about that I use for this calculation.
I hope this helps anyone else who might ever be stuck on something similar and if you have any questions feel free to ask them.
-LAKster
Does the map have mercator projection? Is it a world map?
If so, the top of the map is usually around latitude 85, latitude 0 at the center vertically.
longitude 0 is at greenwich (usually center horizontally), 180/-180 is at the antimeridian/date line, at the left and right edges of the map.
When the latitude is -180, x would be 0, when it's 180, x == width of map.
This link should tell you what you need