Xamarin - How to calculate distance in realtime via GPS - c#

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

Related

Draw polygon from unordered points

So, I know that there are similar questions and I searched a lot before typing my code and asking this question.
In my case, the user clicks on a place on the screen to add a point. When the user finishes adding points, makes a right click to say that the points are ok and draw the polygon.
A the poins are irregularly placed, I must calculate the center point and the angle of each point to order the point list.
And then, when I move a point, I recalculate the angles with new positions and redraw the polygon.
It works but, when I move a point beyond two others beyond them, sometimes it doesn't draw the plygon. I couldn't find what is wrong.
here is my code and two images to explain the problem :
public class CustomPoint3D
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
public int Angle { get; set; }
public CustomPoint3D()
{
}
public CustomPoint3D(double x, double y, double z)
{
this.X = x;
this.Y = y;
this.Z = z;
}
}
private void AddZoneSurface(List<CustomPoint3D> customPoints, string guid)
{
//Calculates angles and orders / sorts the list of points
List<Point2D> points = From3DTo2D(customPoints);
//Draws a polygon in Eyeshot but it can be any tool to create a polygon.
var polygon = devDept.Eyeshot.Entities.Region.CreatePolygon(points.ToArray());
polygon.ColorMethod = colorMethodType.byEntity;
polygon.EntityData = "tool-surface-" + guid;
polygon.Color = System.Drawing.Color.FromArgb(80, 0, 0, 0);
sceneLeft.Entities.Add(polygon);
sceneLeft.Invalidate();
}
private List<Point2D> From3DTo2D(List<CustomPoint3D> points)
{
List<Point2D> retVal = new List<Point2D>();
var minX = points.Min(ro => ro.X);
var maxX = points.Max(ro => ro.X);
var minY = points.Min(ro => ro.Y);
var maxY = points.Max(ro => ro.Y);
var center = new CustomPoint3D()
{
X = minX + (maxX - minX) / 2,
Y = minY + (maxY - minY) / 2
};
// precalculate the angles of each point to avoid multiple calculations on sort
for (var i = 0; i < points.Count; i++)
{
points[i].Angle = (int)(Math.Acos((points[i].X - center.X) / lineDistance(center, points[i])));
if (points[i].Y > center.Y)
{
points[i].Angle = (int)(Math.PI + Math.PI - points[i].Angle);
}
}
//points.Sort((a, b) => a.Angle - b.Angle);
points = points.OrderBy(ro => ro.Angle).ToList();
foreach (var item in points)
{
retVal.Add(new Point2D() { X = item.X, Y = item.Y });
}
return retVal;
}
double lineDistance(CustomPoint3D point1, CustomPoint3D point2)
{
double xs = 0;
double ys = 0;
xs = point2.X - point1.X;
xs = xs * xs;
ys = point2.Y - point1.Y;
ys = ys * ys;
return Math.Sqrt(xs + ys);
}
On the first images, I move the point from its initial position to the indicated position, it doesn't draw the polygon.
You should read the Wikipedia page on convex hull algorithms and pick an algorithm that you feel comfortable implementing that also meets your O(n) complexity requirements.
If convex hull isn't what you're after then you'll need to be a bit more specific as to how you want the points to define the shape. One (probably sub-optimal) solution would be to calculate the convex hull, find the center, pick a point as your "start" point and then order the remaining points by angle from the start point.
So if someone needs a sample which works, I found the problem.
I should have declared the angle property of th CustomPoint3D object like this
As the property was integer, an angle 0,3 or 0,99 was giving 0 as angle.
public class CustomPoint3D
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
public double Angle { get; set; }
public CustomPoint3D()
{
}
public CustomPoint3D(double x, double y, double z)
{
this.X = x;
this.Y = y;
this.Z = z;
}
}
and calculate this values as double
private List<Point2D> From3DTo2D(List<CustomPoint3D> points)
{
List<Point2D> retVal = new List<Point2D>();
var minX = points.Min(ro => ro.X);
var maxX = points.Max(ro => ro.X);
var minY = points.Min(ro => ro.Y);
var maxY = points.Max(ro => ro.Y);
var center = new CustomPoint3D()
{
X = minX + (maxX - minX) / 2,
Y = minY + (maxY - minY) / 2
};
// precalculate the angles of each point to avoid multiple calculations on sort
for (var i = 0; i < points.Count; i++)
{
points[i].Angle = Math.Acos((points[i].X - center.X) / lineDistance(center, points[i]));
if (points[i].Y > center.Y)
{
points[i].Angle = Math.PI + Math.PI - points[i].Angle;
}
}
//points.Sort((a, b) => a.Angle - b.Angle);
points = points.OrderBy(ro => ro.Angle).ToList();
foreach (var item in points)
{
retVal.Add(new Point2D() { X = item.X, Y = item.Y });
}
return retVal;
}
And

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.

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 to calculate map bounds without javascript

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));
}
}

Implementing Geofence - C#

I need to implement Geofence in C#. Geofence area can be round, rectangle, polygon etc. Does anyone have Geofence implementation in C#?
I found Geo Fencing - point inside/outside polygon. But, it supports polygon only.
I have tested various implementations and this example worked properly for me:
Example
public static bool PolyContainsPoint(List<Point> points, Point p) {
bool inside = false;
// An imaginary closing segment is implied,
// so begin testing with that.
Point v1 = points[points.Count - 1];
foreach (Point v0 in points)
{
double d1 = (p.Y - v0.Y) * (v1.X - v0.X);
double d2 = (p.X - v0.X) * (v1.Y - v0.Y);
if (p.Y < v1.Y)
{
// V1 below ray
if (v0.Y <= p.Y)
{
// V0 on or above ray
// Perform intersection test
if (d1 > d2)
{
inside = !inside; // Toggle state
}
}
}
else if (p.Y < v0.Y)
{
// V1 is on or above ray, V0 is below ray
// Perform intersection test
if (d1 < d2)
{
inside = !inside; // Toggle state
}
}
v1 = v0; //Store previous endpoint as next startpoint
}
return inside;
}
Refer to my Implementation:
Polygon
Circle
Adding both C# implementation here
It worked for me!
//Location will hold the latitude and longitude.
public class Location
{
public double lat { get; set; }
public double lng { get; set; }
public Location(double lat, double lng)
{
this.lat = lat;
this.lng = lng;
}
}
//Implementation for the Polygon.
bool IsPointInPolygon(List<Location> poly, Location point)
{
int i, j;
bool c = false;
for (i = 0, j = poly.Count - 1; i < poly.Count; j = i++)
{
if ((((poly[i].lat <= point.lat) && (point.lat < poly[j].lat))
|| ((poly[j].lat <= point.lat) && (point.lat < poly[i].lat)))
&& (point.lng < (poly[j].lng - poly[i].lng) * (point.lat - poly[i].lat)
/ (poly[j].lat - poly[i].lat) + poly[i].lng))
{
c = !c;
}
}
return c;
}
//Geofencing for the Circle.
//GetDistance will return total Kilometers
//p1 is the Center lat,long and p2 is the current location lat,long
//radius in meters
public bool IsPointInCircle(Location p1,Location p2,double radius)
{
return GetDistance(p1,p2)>radius*0.001?false:true;
}
public double GetDistance(Location pos1, Location pos2)
{
double e = pos1.lat * (Math.PI / 180);
double f = pos1.lng * (Math.PI / 180);
double g = pos2.lat * (Math.PI / 180);
double h = pos2.lng * (Math.PI / 180);
double i =
(Math.Cos(e) * Math.Cos(g) * Math.Cos(f) * Math.Cos(h)
+ Math.Cos(e) * Math.Sin(f) * Math.Cos(g) * Math.Sin(h)
+ Math.Sin(e) * Math.Sin(g));
double j = Math.Acos(i);
return (6371 * j);
}

Categories