Formula for triangulation (3 references + distances) - c#

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`

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.

How can I see distance between two pins in xamarin forms and get the distance as a string?

I have two pins on the map with long and latitude and I wish to see the distance between them.
This is what I have so far.
var myPin = new Pin ();
myPin.Label = "pin1";
myPin.Address = "test1";
myPin.Position = new Position(37.797513, -122.402068);
myPin.Label = "pin2";
myPin.Address = "test2";
myPin.Position = new Position(37.7, -122.3);
mymap.Pins.Add(myPin);
So two different pins on my map. How can I see the distance between these two in km? My goal is to make a label with the distance (km) as the text.
(I have a customer renderer base ready incase the only way to solve the distancefunction is via a renderer).
if u have two pins you have their longitude and latitude values , so can calculate the distance between em using below code (taken from geodatasource.com)
private double distance(double lat1, double lon1, double lat2, double lon2, char unit) {
double theta = lon1 - lon2;
double dist = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) + Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * Math.Cos(deg2rad(theta));
dist = Math.Acos(dist);
dist = rad2deg(dist);
dist = dist * 60 * 1.1515;
if (unit == 'K') {
dist = dist * 1.609344;
} else if (unit == 'N') {
dist = dist * 0.8684;
}
return (dist);
}
private double deg2rad(double deg) {
return (deg * Math.PI / 180.0);
}
private double rad2deg(double rad) {
return (rad / Math.PI * 180.0);
}
so basically you just need one starting reference of lat/long value from where you will take reference for further pin to show this distance as a label
There is one built into the Location class
public static Void DistanceBetween (Double startLatitude, Double startLongitude, Double endLatitude, Double endLongitude, Single[] results)
See this option also using the CoreLocation class
Calculate distance between two positions

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 ;

Calculating temporary coordinate if distance exceeds 100

I have a problem with coding a function that will do the following:
Function will take 2 sets of coordinates (x,y,z). First set is starting point and second one is end point.
Now first i will have to determine distance between those two points. If distance will be greater than lets say 100 then i will have to calculate a temporary point. I will then calculate distance between first set of coordinates and this temporary point. Please check illustration below i am sure things will be much more understandable.
Function that calculates new point between points A,B:
x = (x1+x2/2)
y = (y1+y2/2)
z = (z1+z2/2)
Function that calculates distance is:
public float DistanceTo(float x, float y, float z, float x2, float y2, float z2)
{
float a = x - x2;
float b = y - y2;
float c = z - z2;
return Math.Sqrt(a * a + b * b + c * c);
}
Link to illustration:
Perhaps my approach will be CPU heavy and perhaps slow (?) but currently i am out of ideas how to approach the problem.
Basically i need a function that will go from A to B in increments if (distance < 100).
Thank you for reading and thanks for any solution posted!
PS please dont make fun of my paint skills :)
Compute the distance d from (xb,yb,zb) (begin) to (xe,ye,ze) (end). Compute the number of parts N=(int)((d-1)/100)+1. Compute
xk = xb + (k*(xe-xb))/N
yk = yb + (k*(ye-yb))/N
zk = zb + (k*(ze-zb))/N
for k=1,...,N-1 to get equally spaced points on the segment with a distance not surpassing 100.
You can do it recursively
create a Point struct that represent a point in R3, with 2 utility methods to calculate the distance and midpoint.
struct Point
{
public double x;
public double y;
public double z;
public double Distance(Point b)
{
return Math.Sqrt(Math.Pow(b.x - this.x, 2) +
Math.Pow(b.y - this.y, 2) +
Math.Pow(b.z - this.z, 2));
}
public Point MidPoint(Point b)
{
return new Point()
{
x = (this.x + b.x) / 2,
y = (this.y + b.y) / 2,
z = (this.z + b.z) / 2
};
}
}
and write a simple recursive function that will calculate the distance and call itself recursively until the distance between point a and the temp point is less than maxSegmentLength which is 100 in your case:
public static Point GetPoint(Point a, Point b, double maxSegmentLength)
{
var distance = a.Distance(b);
if (distance < maxSegmentLength)
return b;
else
return GetPoint(a, a.MidPoint(b),maxSegmentLength);
}
Or more efficiently with vectors:
struct Vector
{
public double Vx;
public double Vy;
public double Vz;
public double R;
public Vector(Point a,Point b)
{
R = a.Distance(b);
Vx = (b.x - a.x)/R;
Vy = (b.y - a.y)/R;
Vz = (b.z - a.z)/R;
}
}
public static Point GetPoint(Point a, Point b,double maxSegmentLength)
{
var Vab = new Vector(a, b);
var dAC = Vab.R;
while (dAC > maxSegmentLength) { dAC /= 2; } //or replace this line and the one above it with var dAC=Math.Pow(0.5,(int)(-(Math.Log(maxSegmentLength / Vab.R) / Math.Log(2))) + 1)*Vab.R;
return new Point() {
x = a.x + Vab.Vx * dAC ,
y = a.y + Vab.Vy * dAC ,
z = a.z + Vab.Vz * dAC
};
}
If the point is always at a midpoint then its distance is always half of the original
public double Calc(Point A, Point B)
{
double d = Distance(A,B);
while(d>100)
{
d/=2;
}
return d;
}

calculate Point by point, angle and distance on a map

I have a mission to calculate point on a Map. I have the start point, the angle and the distance from the point. How can I do it ? I search a lot I found something but it doesn't work good - I mean it it doesn't calculate the correct point. Thank's all.
My try :
public Point MesPoint(double x1, double x2, double y1, double y2, double distance, double x) // X is the angle
{
double xEndP, yEndP;
var angularDistance = distance / c_EarthRadiusInKilometers; // angular distance in radians
var lat = ToRadian(y2);
var lon = ToRadian(x2);
var angel = ToRadian(x);
double latRadians = Math.Asin((Math.Sin(lat) * Math.Cos(angularDistance)) + (Math.Cos(lat) * Math.Sin(angularDistance) * Math.Cos(angel)));
double lngRadians = Math.Atan2(
Math.Sin(angel) * Math.Sin(angularDistance) * Math.Cos(lat),
Math.Cos(angularDistance) - (Math.Sin(lat) * Math.Sin(latRadians)));
double lon1 = (lon + lngRadians + Math.PI) % (2 * Math.PI) - Math.PI; // normalise to -180..+180º
yEndP = ToDegrees(latRadians);
xEndP = ToDegrees(lon1);
return (new Point(xEndP, yEndP));
}

Categories