How to calculate map bounds without javascript - c#

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

Create a bounding box from two points with a customizable width

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.

Xamarin - How to calculate distance in realtime via GPS

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

Calculate future latitude longitude with initial coordinates, heading and distance

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 ;

Formula for triangulation (3 references + distances)

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`

How do I draw a circle on my Bing Map application around a centerpoint with a radius given in miles

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.

Categories