I have a list of coordinates which will be considered as a center point of the map.
I need to calculate bounds of the map at zoom level 16 using only C# (no javascript no map object).
Is this possible?
Please advise.
Here is something I wanted. I have not written this class personal and found in somewhere here and I don't remember so the credit goes X person! Provided Latitude and Longitude and a radius in KM gives a bounding box. Somewhat what GMap gives on viewport Bounds.
public class GlobalMercator
{
public class MapPoint
{
public double Longitude { get; set; } // In Degrees
public double Latitude { get; set; } // In Degrees
}
public class BoundingBox
{
public MapPoint MinPoint { get; set; }
public MapPoint MaxPoint { get; set; }
}
// Semi-axes of WGS-84 geoidal reference
private const double WGS84_a = 6378137.0; // Major semiaxis [m]
private const double WGS84_b = 6356752.3; // Minor semiaxis [m]
// 'halfSideInKm' is the half length of the bounding box you want in kilometers.
public static BoundingBox GetBoundingBox(MapPoint point, double halfSideInKm)
{
// Bounding box surrounding the point at given coordinates,
// assuming local approximation of Earth surface as a sphere
// of radius given by WGS84
var lat = Deg2rad(point.Latitude);
var lon = Deg2rad(point.Longitude);
var halfSide = 1000 * halfSideInKm;
// Radius of Earth at given latitude
var radius = WGS84EarthRadius(lat);
// Radius of the parallel at given latitude
var pradius = radius * Math.Cos(lat);
var latMin = lat - halfSide / radius;
var latMax = lat + halfSide / radius;
var lonMin = lon - halfSide / pradius;
var lonMax = lon + halfSide / pradius;
return new BoundingBox
{
MinPoint = new MapPoint { Latitude = Rad2deg(latMin), Longitude = Rad2deg(lonMin) },
MaxPoint = new MapPoint { Latitude = Rad2deg(latMax), Longitude = Rad2deg(lonMax) }
};
}
// degrees to radians
private static double Deg2rad(double degrees)
{
return Math.PI * degrees / 180.0;
}
// radians to degrees
private static double Rad2deg(double radians)
{
return 180.0 * radians / Math.PI;
}
// Earth radius at a given latitude, according to the WGS-84 ellipsoid [m]
private static double WGS84EarthRadius(double lat)
{
// http://en.wikipedia.org/wiki/Earth_radius
var An = WGS84_a * WGS84_a * Math.Cos(lat);
var Bn = WGS84_b * WGS84_b * Math.Sin(lat);
var Ad = WGS84_a * Math.Cos(lat);
var Bd = WGS84_b * Math.Sin(lat);
return Math.Sqrt((An * An + Bn * Bn) / (Ad * Ad + Bd * Bd));
}
}
Related
I have two points making a line, I want to see if a point is ruffly on the line. To do this I need to create a bounding box/ a rectangle which has a width D outwards/ perpendicular to the line. I was following this website for guidance but seem to have implemented it wrongly. Any help would be appreciated.
private static bool IsInside(GPS Point1, GPS Point2)
{
GPS VectorV = new GPS()
{
Longitude = Point1.Longitude - Point2.Longitude,
Latitude = Point1.Latitude - Point2.Latitude
};
GPS VectorW = new GPS()
{
Longitude = -1 / VectorV.Longitude,
Latitude = -1 / VectorV.Latitude
};
double W = Math.Sqrt(Convert.ToDouble(VectorW.Latitude * VectorW.Latitude) + Convert.ToDouble(VectorW.Longitude * VectorW.Longitude));
GPS NewVector = new GPS()
{
Longitude = Convert.ToDecimal(Convert.ToDouble(VectorW.Longitude) / W),
Latitude = Convert.ToDecimal(Convert.ToDouble(VectorW.Latitude) / W),
};
decimal D = 5;
GPS DisplacmentVector = new GPS()
{
Longitude = (D / 2) * NewVector.Longitude,
Latitude = (D / 2) * NewVector.Latitude
};
GPS BPoint1 = new GPS() { Longitude = Point1.Longitude + DisplacmentVector.Longitude, Latitude = Point1.Latitude + DisplacmentVector.Latitude };
GPS BPoint2 = new GPS() { Longitude = Point1.Longitude - DisplacmentVector.Longitude, Latitude = Point1.Latitude - DisplacmentVector.Latitude };
GPS BPoint3 = new GPS() { Longitude = Point2.Longitude + DisplacmentVector.Longitude, Latitude = Point2.Latitude + DisplacmentVector.Latitude };
GPS BPoint4 = new GPS() { Longitude = Point2.Longitude - DisplacmentVector.Longitude, Latitude = Point2.Latitude - DisplacmentVector.Latitude };
}
public partial class GPS
{
public decimal Longitude { get; set; }
public decimal Latitude { get; set; }
public GPS() { }
public GPS(decimal longitude, decimal latitude) {
Longitude = longitude;
Latitude = latitude;
}
}
When you have a vector v= A to B = {xb-xa, yb-ya} = {vx, vy} there are two directions for its perpendicular: one heading right of A->B, the orther heading left of A->B.
One perpendicular vector is w1= {-vy, vx} (towards left), the other is w2= {vy, -vx} (towards right). Note than w1 = -w2.
To get the four corners you may use w1 or w2 or both. It's a matter of the used signs and the order of resultant points.
Let's use w1. Your definition is wrong. Use this instead:
GPS VectorW = new GPS()
{
Longitude = - VectorV.Latitude,
Latitude = VectorV.Longitude
};
You are overcomplicating things. There are 3 cases for the line:
Line parallel with x axis (y coordinate of both points are equal), easy to calculate
Line parallel with y axis (x coordinate of both points are equal), easy to calculate
for the rest you need dx and dy:
cos(θ) = dx / (D / 2) => dx = cos(θ) * (D / 2)
sin(θ) = dy / (D / 2) => dy = sin(θ) * (D / 2)
θ = 90 - φ
tan(φ) = a / b => φ = atan(a / b)
Thats it.
In the end I decided to go for a different approach and instead found the distance away from the line the point was. It follows the same logic that it must be X distance away from the line.
For guidance I followed/ used this code.
How can i calculate distance in real time(the distance must increment if there is a movement) via GPS ?
I have an App that shows the travelling speed, and it is accurate. I just need to show the distance that was traveled by the user.
How can i archive this ? Please see my code below :
public void OnLocationChanged(Location location)
{
try
{
currentLocation = location;
if (currentLocation == null)
{
//"Make sure the GPS is on.";
}
else
{
gpsLatitude = currentLocation.Latitude.ToString();
gpsLongitude = currentLocation.Longitude.ToString();
if (currentLocation.Speed != 0)
{
kmh = (int)((currentLocation.Speed * 3600) / 1000);
//mph = (int)(currentLocation.Speed * 2.2369);
}
}
}
catch (Exception ex)
{
LogException(ex);
}
}
Assuming you are storing the LatLng points as the user travels, the following methods can provide what you need.
There is a ComputeDistanceBetween that returns the meters between to LatLng points and a ComputeLength that returns the total meters between a sequential list of LatLng points.
This is based on SphericalUtil methods from Google's Android Maps Utils and is one of best implementations that I've seen in the public domain.
Note: Google's Java code for that is under Apache License Version 2.0, and I converted it to C#.
Example:
var latlng1 = new LatLng(47.61472695767613, -122.33327865600586);
var latlng2 = new LatLng(47.60269078742121, -122.30581283569336);
var latlng3 = new LatLng(47.608593486245546, -122.3001480102539);
var latlngList = new List<LatLng> { latlng1, latlng2, latlng3 };
var km1 = Meters.ComputeDistanceBetween(latlng1, latlng2);
var km2 = Meters.ComputeDistanceBetween(latlng2, latlng3);
var kmTotal = Meters.ComputeLength(latlngList);
Implementation:
public static class Meters
{
const double EARTH_RADIUS = 6371009;
static double ToRadians(double input)
{
return input / 180.0 * Math.PI;
}
static double DistanceRadians(double lat1, double lng1, double lat2, double lng2)
{
double Hav(double x)
{
double sinHalf = Math.Sin(x * 0.5);
return sinHalf * sinHalf;
}
double ArcHav(double x)
{
return 2 * Math.Asin(Math.Sqrt(x));
}
double HavDistance(double lat1b, double lat2b, double dLng)
{
return Hav(lat1b - lat2b) + Hav(dLng) * Math.Cos(lat1b) * Math.Cos(lat2b);
}
return ArcHav(HavDistance(lat1, lat2, lng1 - lng2));
}
public static double ComputeDistanceBetween(LatLng from, LatLng to)
{
double ComputeAngleBetween(LatLng From, LatLng To)
{
return DistanceRadians(ToRadians(from.Latitude), ToRadians(from.Longitude),
ToRadians(to.Latitude), ToRadians(to.Longitude));
}
return ComputeAngleBetween(from, to) * EARTH_RADIUS;
}
public static double ComputeLength(List<LatLng> path)
{
if (path.Count < 2)
return 0;
double length = 0;
LatLng prev = path[0];
double prevLat = ToRadians(prev.Latitude);
double prevLng = ToRadians(prev.Longitude);
foreach (LatLng point in path)
{
double lat = ToRadians(point.Latitude);
double lng = ToRadians(point.Longitude);
length += DistanceRadians(prevLat, prevLng, lat, lng);
prevLat = lat;
prevLng = lng;
}
return length * EARTH_RADIUS;
}
}
FYI: If you need an area in square meters, see my answer here, also based on Google's Android Maps Utils code
Polygon area calculation using Latitude and Longitude
I have been reading through stackoverflow and this site (http://www.movable-type.co.uk/scripts/latlong.html) about how to do this, but I cant get my code to give a correct answer. It is giving a coordinate that isnt in the correct direction. I have been working on this all day and seem to have hit a wall. This is my function:
public static void destination()
{
double heading = 335.9;
double startLatitude = 41.8369;
double startLongitude = 87.6847;
//Convert to Radians
startLatitude = startLatitude * Math.PI / 180;
startLongitude = startLongitude * Math.PI / 180;
heading = heading * Math.PI / 180;
int distanceKilometers = 100;
double angularDistance = distanceKilometers / 6371e3;
double endLat = Math.Asin((Math.Sin(startLatitude) * Math.Cos(angularDistance)) +
(Math.Cos(startLatitude) * Math.Sin(angularDistance) * Math.Cos(heading)));
double endLong = startLongitude + (Math.Atan2((Math.Sin(heading) * Math.Sin(angularDistance) * Math.Cos(startLatitude)),
Math.Cos((angularDistance) - (Math.Sin(startLatitude) * Math.Sin(endLat)))));
endLong = (endLong + 3 * Math.PI) % (2 * Math.PI) - Math.PI;
Console.WriteLine("endLatitude: " + (endLat * 180 / Math.PI) + " endLongitude: " + (endLong * 180 / Math.PI));
}
I use the below function.
float provide you a 3 meters precision. If you need more, use double.
internal class SxMath
{
internal const float PI = (float)Math.PI;
internal const float x2PI = PI * 2;
internal const float PIDiv2 = PI/2;
internal const float RadPerSec = (float)(PI / 648000F);
internal const float SecPerRad = (float)(648000F / PI);
internal const float RadPerDeg = PI / 180;
internal const float RadPerMin = PI / 10800;
internal const float DegPerRad = 180 / PI;
internal const float MinParRad = (float)(10800.0/PI);
internal const float RadPerMeter = RadPerMin * (1F/1852F) /* Meter_To_NMs */ ;
internal static float RealMod(float val,float modval)
{ // Example : RealMod(3,2*PI)=3 , RealMod(2*PI+3,2*PI)=3 , RealMod(-3,2*PI)=2*PI-3
float result = (float)Math.IEEERemainder(val,modval);
if (result<0) result = result + modval;
return result;
}
} // SxMath
internal struct SxGeoPt
{
internal float lat ; // in radians, N positive
internal float lon ; // in radians, W positive
} // SxGeoPt
internal static SxGeoPt GEO_CoorPointInAzim(SxGeoPt p1,float az,float raddist)
// This procedure provides coordinates of the point p2 located
// - at a distance raddist of a point p1
// - in the direction of azimuth az
// input p1 <SxGeoPt> coordinates of reference point
// raddist <float> distance in radian between p1 and p2
// az <float> azimut of p2 from p1,
// (az=0, if p1 and p2 on same longitude and P2 north of P1)
// (az=90, if p1 is on equator and p2 on equtor at East of P1)
// output p2 <SxGeoPt> coordinates of resulting point
{
SxGeoPt result;
if (p1.lat>SxMath.PIDiv2-SxMath.RadPerMin)
{ if (az<=SxMath.PI) result.lon=az; else result.lon=az-SxMath.PI; result.lat=SxMath.PIDiv2-raddist; }
else if (p1.lat<-SxMath.PIDiv2+SxMath.RadPerMin)
{ if (az<=SxMath.PI) result.lon=-az; else result.lon=-az+SxMath.PI; result.lat=-SxMath.PIDiv2+raddist; }
else
{
result.lat = (float)Math.Asin((Math.Sin(p1.lat)*Math.Cos(raddist)) +
(Math.Cos(p1.lat)*Math.Sin(raddist)*Math.Cos(az)));
float dlon = (float)Math.Atan2( Math.Sin(az)*Math.Sin(raddist)*Math.Cos(p1.lat),
Math.Cos(raddist)-Math.Sin(p1.lat)*Math.Sin(result.lat));
result.lon = SxMath.RealMod(p1.lon-dlon+SxMath.PI,SxMath.x2PI)-SxMath.PI;
}
return result;
}
As I extracted code from different classes, I hope that nothing is missing.
To get the input parameter DistInRad from Kilometers:
float raddist = distanceKilometers * 1000f * SxMath.RadPerMeter ;
I am trying to implement a function that will give me the GEO location (Lat,Long) given 3 GEO reference points and radius away from each point.
The signature for the function I'm looking for is:
public static GeoLocation Triangle(GeoLocation pos1, double r1, GeoLocation pos2,
double r2, GeoLocation pos3, double r3)
As example, 3 friends meet up somewhere secret. Each one can only tell me where he/she lives (GeoLocation = lat,long) and how far they are meeting from their house (r = radius). Given 3 such reference points (from all 3 friends), I should have sufficient information to calculate this secret meeting point as a GeoLocation.
This problem is very similar to the mobile / towers problem where you triangulate a mobile by measuring individual signal strengths from a few towers.
I have tried to find formulas online for quite some time now, which is why I'm posting my question here on Stack Overflow.
I will appreciate it if you could help me fill in the formula (Triangle method) - Thanks.
Code I have so far:
public class GeoLocation
{
private double _latitude;
private double _longitude;
public GeoLocation(double latitude, double longitude)
{
this._latitude = latitude;
this._longitude = longitude;
}
//Tested and working!
public double DistanceToKm(GeoLocation loc)
{
double lat1, lon1, lat2, lon2;
lat1 = this._latitude;
lon1 = this._longitude;
lat2 = loc._latitude;
lon2 = loc._longitude;
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2 - lat1); // deg2rad below
var dLon = deg2rad(lon2 - lon1);
var a =
Math.Sin(dLat / 2) * Math.Sin(dLat / 2) +
Math.Cos(deg2rad(lat1))*Math.Cos( deg2rad(lat2))*
Math.Sin(dLon / 2) * Math.Sin(dLon / 2)
;
var c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
var d = R*c; // Distance in km
return d;
}
}
Code which I think is not needed, but for what it's worth:
public static Coords ToCoord(GeoLocation pos)
{
var x = Math.Cos(pos._longitude) * Math.Cos(pos._latitude);
var y = Math.Sin( pos._longitude) * Math.Cos(pos._latitude);
var z = Math.Sin(pos._latitude);
return new Coords(x,y,z);
}
class Coords
{
public double x;
public double y;
public double z;
public Coords(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}
}
Seems this is the solution after all.
https://gis.stackexchange.com/questions/66/trilateration-using-3-latitude-and-longitude-points-and-3-distances
... far more complicated than school geometry #DrKoch
Here is the Python solution:
yC = earthR *(math.cos(math.radians(LatC)) * math.sin(math.radians(LonC)))
zC = earthR *(math.sin(math.radians(LatC)))
P1 = array([xA, yA, zA])
P2 = array([xB, yB, zB])
P3 = array([xC, yC, zC])
#from wikipedia
#transform to get circle 1 at origin
#transform to get circle 2 on x axis
ex = (P2 - P1)/(numpy.linalg.norm(P2 - P1))
i = dot(ex, P3 - P1)
ey = (P3 - P1 - i*ex)/(numpy.linalg.norm(P3 - P1 - i*ex))
ez = numpy.cross(ex,ey)
d = numpy.linalg.norm(P2 - P1)
j = dot(ey, P3 - P1)
#from wikipedia
#plug and chug using above values
x = (pow(DistA,2) - pow(DistB,2) + pow(d,2))/(2*d)
y = ((pow(DistA,2) - pow(DistC,2) + pow(i,2) + pow(j,2))/(2*j)) - ((i/j)*x)
# only one case shown here
z = sqrt(pow(DistA,2) - pow(x,2) - pow(y,2))
#triPt is an array with ECEF x,y,z of trilateration point
triPt = P1 + x*ex + y*ey + z*ez
#convert back to lat/long from ECEF
#convert to degrees
lat = math.degrees(math.asin(triPt[2] / earthR))
lon = math.degrees(math.atan2(triPt[1],triPt[0]))
print lat, lon`
I have been able to draw an ellipse on my map using latitude and longitude values around a given center point. Although I see a shape on the map, I get an ellipse instead of a circle and I don't think it matches the distance specified. I intend to use this to display objects within that circle (this will be done later on once I can get the circle displaying properly, which is the reason why i need a circle not an ellipse as it should be perfectly round).
I am using a Bing Maps API. I wish to draw the circle in a given miles (distance) from the center which has been passed in through the parameter, the other variable in the parameter called miles is just holding a double value of 1D. I think the problem is to do with the way my maths is being calculated. Has anyone got a clue on how I can refine this code to calculate my miles better.
private void drawPoly(SearchLocation center, Double miles)
{
//amount of vertex
double vertexCount = 100D;
//used by the api to carried out searches
List<SearchLocation> vertices = new List<SearchLocation>();
double v = 0;
double radians = Math.PI / 180D;
double radiansPerDegree = Math.PI / 180D;
double degreePerVertex = 360D / vertexCount;
double radiansPerVertex = degreePerVertex * radiansPerDegree;
var centerOfMap = center;
const double degLatMiles = 68.68637156368D;
double degLonMiles = Math.Cos(center.Latitude.Value) * (68.68637156368D);
double milesLat = (miles * degLatMiles) / 3600;
double milesLon = (miles * degLonMiles) / 3600;
for (v = 0; v < vertexCount; v++)
{
radians = v * radiansPerVertex;
//adds the miles from the center point and draws a circle
double centrLat = center.Latitude.Value + (milesLat * Math.Sin(radians));
double centrLon = center.Longitude.Value + (milesLon * Math.Cos(radians));
vertices.Add(new SearchLocation() { Latitude = centrLat, Longitude = centrLon });
}
Ok, I've misundestood your question. This should work :
/// <summary>
/// Calculates the end-point from a given source at a given range (meters) and bearing (degrees).
/// This methods uses simple geometry equations to calculate the end-point.
/// </summary>
/// <param name="source">Point of origin</param>
/// <param name="range">Range in meters</param>
/// <param name="bearing">Bearing in degrees</param>
/// <returns>End-point from the source given the desired range and bearing.</returns>
public static PointLatLng CalculateDerivedPosition(PointLatLng source, double range, double bearing)
{
double latA = source.Lat * DEGREES_TO_RADIANS;
double lonA = source.Lng * DEGREES_TO_RADIANS;
double angularDistance = range / EARTH_RADIUS_M;
double trueCourse = bearing * DEGREES_TO_RADIANS;
double lat = Math.Asin(
Math.Sin(latA) * Math.Cos(angularDistance) +
Math.Cos(latA) * Math.Sin(angularDistance) * Math.Cos(trueCourse));
double dlon = Math.Atan2(
Math.Sin(trueCourse) * Math.Sin(angularDistance) * Math.Cos(latA),
Math.Cos(angularDistance) - Math.Sin(latA) * Math.Sin(lat));
double lon = ((lonA + dlon + Math.PI) % (Math.PI * 2)) - Math.PI;
return new PointLatLng(
lat / DEGREES_TO_RADIANS,
lon / DEGREES_TO_RADIANS);
}
Juste take your center as source :
for (int i = 0; i < 360; i++)
{
vertices.Add(CalculateDerivedPosition(center, circleRadius, i));
}
To prevent elipses on sertain latitudes I use the following code:
// Function to draw circle on map:
private void DrawCircle(BasicGeoposition CenterPosition, int Radius)
{
Color FillColor = Colors.Purple;
Color StrokeColor = Colors.Red;
FillColor.A = 80;
StrokeColor.A = 80;
Circle = new MapPolygon
{
StrokeThickness = 2,
FillColor = FillColor,
StrokeColor = StrokeColor,
Path = new Geopath(Functions.CalculateCircle(CenterPosition, Radius))
};
mpBingMaps.MapElements.Add(Circle);
}
// Constants and helper functions:
const double earthRadius = 6371000D;
const double Circumference = 2D * Math.PI * earthRadius;
public static List<BasicGeoposition> CalculateCircle(BasicGeoposition Position, double Radius)
{
List<BasicGeoposition> GeoPositions = new List<BasicGeoposition>();
for (int i = 0; i <= 360; i++)
{
double Bearing = ToRad(i);
double CircumferenceLatitudeCorrected = 2D * Math.PI * Math.Cos(ToRad(Position.Latitude)) * earthRadius;
double lat1 = Circumference / 360D * Position.Latitude;
double lon1 = CircumferenceLatitudeCorrected / 360D * Position.Longitude;
double lat2 = lat1 + Math.Sin(Bearing) * Radius;
double lon2 = lon1 + Math.Cos(Bearing) * Radius;
BasicGeoposition NewBasicPosition = new BasicGeoposition();
NewBasicPosition.Latitude = lat2 / (Circumference / 360D);
NewBasicPosition.Longitude = lon2 / (CircumferenceLatitudeCorrected / 360D);
GeoPositions.Add(NewBasicPosition);
}
return GeoPositions;
}
private static double ToRad(double degrees)
{
return degrees * (Math.PI / 180D);
}
This code is usefull for small radius of less than a few miles.