I searched but I could not find a complete answer.
In C# if at all possible.
I need the shortest distance between a WGS point and a WGS point defined line segment on a sphere (Earth exactly).
float DistanceInKilometres(PointF LineStartA, PointF LineEndB, PointF ThePoint)
EDIT: Perhaps an illustration would help
Please note that this is an ideal example. 'The point' could be anywhere on the surface of the sphere, the segment start-end, too. Obviously, I'm not looking for the distance through the sphere. Math isn't my stronger side, so I don't understand normalize or to cartesian. Maybe I should also note that path AB, is the shortest possible, and Distance?, is the shortest possible too.
You can use the spherical law of cosines:
http://en.wikipedia.org/wiki/Spherical_law_of_cosines
http://mathworld.wolfram.com/SphericalSegment.html
http://mathworld.wolfram.com/SphericalTrigonometry.html
You will have to use the earth's radius for calculations:
EARTH_RADIUS_KM = 6371;
Here, from my contributions to OsmMercator.java, from openstreetmap.org:
/**
* Gets the distance using Spherical law of cosines.
*
* #param la1 the Latitude in degrees
* #param lo1 the Longitude in degrees
* #param la2 the Latitude from 2nd coordinate in degrees
* #param lo2 the Longitude from 2nd coordinate in degrees
* #return the distance
*/
public static double getDistance(double la1, double lo1, double la2, double lo2) {
double aStartLat = Math.toRadians(la1);
double aStartLong = Math.toRadians(lo1);
double aEndLat =Math.toRadians(la2);
double aEndLong = Math.toRadians(lo2);
double distance = Math.acos(Math.sin(aStartLat) * Math.sin(aEndLat)
+ Math.cos(aStartLat) * Math.cos(aEndLat)
* Math.cos(aEndLong - aStartLong));
return (EARTH_RADIUS_KM * distance);
}
All you need to do is find the closest point with dot product and use that with the distance equation.
Here's the closest point example:
double[] nearestPointSegment (double[] a, double[] b, double[] c)
{
double[] t= nearestPointGreatCircle(a,b,c);
if (onSegment(a,b,t))
return t;
return (distance(a,c) < distance(b,c)) ? a : c;
}
How to calculate distance from a point to a line segment, on a sphere?
http://en.wikipedia.org/wiki/Great-circle_distance
Keep in mind the units haven't been explicitly declared. When dealing with points in space there're are a variety of ways to determine position. The main thing is you have to nail down your units to a consistent type.
When working with position on the earth, I mainly use lat/long coordinates and vectors for magnitude/direction. There're are several known types to use for vectors and earth's position. Among them are the following:
Earth-centered earth-fixed (ECEF) coordinate system
North-East-Down (NED)
Geodetic coordinate system
For your example, I might consider sticking to Geodetic.
Now, bringing this together, you might have some pseudo code which looks like this:
Where a Vector is made up of Geodetic coordinates:
class Vector {
double x=0.0; //latitude
double y=0.0; //longitude
double h=0.0; //height
...
}
public Vector closestPoint(Vector lineStartA, Vector lineEndB, final Vector thePoint ) {
Vector w = thePoint.subtract(lineStartA);
double proj = w.dot(lineEndB);
// endpoint 0 is closest point
if ( proj <= 0.0f )
return lineStartA;
else
{
//Vector square
double vsq = lineEndB.dot(lineEndB);
// endpoint 1 is closest point
if ( proj >= vsq )
return lineStartA.add(lineEndB);
else
return lineStartA.add(lineEndB.multiply(proj/vsq));
}
}
double DistanceInKilometres(Vector lineStartA, Vector lineEndB, Vector thePoint) {
Vector cp=closestPoint(lineStartA, lineEndB, thePoint);
return getDistance(cp.x, cp.y, thePoint.x, thePoint.y);
}
If your point lies within a corridor that is defined by the end points of your line segment, and perpendicular to the line, then this answer should do.
If your point lies outside that corridor then compute the distance from your point to each end of the line segment and take the smaller.
Related
I want to make a bot that will walk along points from two coordinates (X and Y), I have the coordinates of the character, his rotation angle (1-180 / (- 1) - (-180)), and the required point where he is should get there. How do I know if the angle of rotation is necessary for the person to look directly at the point?
I have been sitting with this for a long time, and my head refuses to think at all, I tried to solve this by creating an angle between the radius vector, but nothing came of it.
public static double GetRotation(Point Destination)
{
double cos = Destination.Y / Math.Sqrt(Destination.X * Destination.X + Destination.Y * Destination.Y);
double angle = Math.Acos(cos);
return angle;
}
With regard to this problem, I would suggest generally using tan rather than cos due to the fact to get the angle between two point (X and y), the difference in the points provide the opposite and adjacent sides of the triangle for the calculation, rather than adjacent and hypotenuse.
If the player is at position X,Y, and the new position to walk to is X2,Y2, the equation to calculate the relative angle between them should be tan-1((Y2-Y)/(X2-X)) with regards to the X plane.
I think the below implementation should work for your example (though you may need to subtract the current player angle the player is facing to get the difference):
public static double GetRotation(Point source, Point Destination)
{
double tan = (Destination.Y - source.Y) / (Destination.X -source.X);
double angle = Math.Atan(tan) * (180/Math.PI) // Converts to degrees from radians
return angle;
}
Apologies for the formatting, am currently on mobile.
dx = Destination.X - Person.X;
dy = Destination.Y - Person.Y;
directionangle = Math.Atan2(dy, dx); // in radians!
degrees = directionangle * 180 / Math.PI;
I have a piece of code that returns the angle between two vectors in the range of [0,360]. For this I used this question: Direct way of computing clockwise angle between 2 vectors. Now I need to create a function that takes a vector and an angle as input and returns a vector, that has the specified angle with the inputvector. The length of this vector doesn't matter. For this, I need to know how to reverse the effect of Atan2. The rest is pretty simple math.
internal virtual double AngleWith(Vector2 direction, Vector2 location)
{
Vector2 normDir = Vector2.Normalize(direction);
Vector2 normLoc = Vector2.Normalize(location);
double dot = (normDir.X * normLoc.X) + (normDir.Y * normLoc.Y);
double det = (normDir.X * normLoc.Y) - (normDir.Y * normLoc.X);
return Math.Atan2(-det, -dot) * (180 / Math.PI) + 180;
}
Any help is appreciated.
I don't know what you need this for, but arguably there is merit in transforming your vectors from the x,y-coordinate system to the polar coordinate system, in which points in a plane are given by their distance from the origin and the angle to a reference vector (for instance the x-axis in the explanation below), or
To convert from (x, y) to (r, t) with r being the distance between (x,y) and (0,0) and t being the angle in radians between the x-axis and the line connecting (0, 0) and (x, y), you use this:
(r, t) = (sqrt(x^x+y^y), atan(y/x))
The result can be stored in Vector2, just like with x and y. You just have to remember that the values inside don't signify x and y.
If you want the difference in angle, you can just subtract t2 and t1 of your polar coordinates (in radians, still need to convert to degrees).
If you need to add a certain angle in degrees, just add or subtract it to the t value of your polar coordinate.
To convert back to x and y, use
(x, y) = (r cos(t), r sin(t))
The typical way to do this is with a rotation matrix.
RotatedX = x * sin ϴ - y * sin ϴ
RotatedY = x * sin ϴ + y * cos ϴ
Or use System.Numerics.Matrix3x2.CreateRotation(angle) and use it to transform your vector. Note that 'Clockwise' may depend on what coordinate conventions are used. So you might need to adjust the formula depending on your convention.
The problem I want to solve is:
Calculate the intersection of the ball and the circle with the following information.
Known information about the circle:
1. The coordinates of the center A are known, and the center A is on the spherical surface.
2. The radius ra of the circle A is known.
3. Know the coordinates of a point B on the circle
Known information about the ball:
1. The coordinates of the spherical center B of the known ball.
2. The radius of the known ball rb.
Picture is as follows
Icon
With the above information, I hope to calculate the coordinates of the intersection point.
Then put the algorithm into C# so that the associated points on the plane can be placed on the sphere and the distance between these points does not change.
If the above method works, I can place many points equidistant from A on the sphere, and after placement, the distance between these points and A is unchanged.
I tried before:
1. Solve the problem with simultaneous equations, but unfortunately the final result is not available.
2. Try to get the result by the intersection of two circles, but the circle and the circle are both in a plane relationship, only the coordinates of x, y can be obtained, and the coordinates of z cannot be obtained.
I successfully put some points on the sphere through the following code, but the distance between the points and the points has changed, and the more the number of points, the more obvious this change, I don't want their distance to change, so I came up with it. Determine the position of these points by intersecting the circle with the ball。
The parameter (List atoms ) stores some points on the plane, and (double r) is the radius of the ball. By this method, the point on the plane will be "sticked" to the sphere.
/// <summary>
/// Stick the atom to the sphere
/// </summary>
private void BendAtom(List <Atom> atoms,double r)
{
double L = 2d * Math.PI * r;
double w = L;// * 2d;
double h = L / 2d;
for (int i = 0; i < atoms.Count; i++)
{
atoms[i].Point.x = (float)((360 / w) * atoms[i].Point.x - 180);
atoms[i].Point.y = (float)((180 / h) * atoms[i].Point.y - 90);
}
for (int i = 0; i < atoms.Count; i++)
{
double lat = atoms[i].Point.x;
double lng = atoms[i].Point.y;
double phi = ((90d - lat) * Math.PI) / 180d;
double theta = ((180 - lng) * Math.PI) / 180d;
double x = r * Math.Sin(phi) * Math.Cos(theta);
double y = r * Math.Cos(phi);
double z = r * Math.Sin(phi) * Math.Sin(theta);
atoms[i].Point.x = (float)x;
atoms[i].Point.y = (float)y;
atoms[i].Point.z = (float)z;
}
}
I hope that after the point is "posted" on the ball, the distance of the points does not change, but as a result, they change, and the more the number of points, the greater the change.
My math level is limited. If you have a better way to solve this problem, thank you very much and thank you for your help.
The result of the above code
I am looking to generate some 3D trajectory data for an aircraft simulation.
The idea is that the aircraft takes off at some location x and continues to ascend at some average ascent velocity a_v and angle a_theta until it reaches a maximum altitude m_a. The aircraft would then continue at its m_a until it reaches a certain distance d_d from its destination, at which point it will begin its descent at some angle d_theta with an average descent velocity of d_v. Finally, the aircraft lands at destination y.
I would like the function to return a list of 3D points.
I am looking to implement this in either Python (preferred) or C#.
For illustration purposes:
Does anyone know how I can achieve this? Is there perhaps some open source project which does this? I have been looking for a while now, but have not found anything.
I recommend you to solve the problem in 2 independent steps so that the airplane does not pass through the ground :
Calculate the path on the surface of a sphere.
Interpolate the height along this path.
For 1. you can use the spherical interpolation techniques on Quaternions.
Quaternion slerp(Quaternion v0, Quaternion v1, double t) {
// Only unit quaternions are valid rotations.
// Normalize to avoid undefined behavior.
v0.normalize();
v1.normalize();
// Compute the cosine of the angle between the two vectors.
double dot = dot_product(v0, v1);
const double DOT_THRESHOLD = 0.9995;
if (fabs(dot) > DOT_THRESHOLD) {
// If the inputs are too close for comfort, linearly interpolate
// and normalize the result.
Quaternion result = v0 + t*(v1 – v0);
result.normalize();
return result;
}
// If the dot product is negative, the quaternions
// have opposite handed-ness and slerp won't take
// the shorter path. Fix by reversing one quaternion.
if (dot < 0.0f) {
v1 = -v1;
dot = -dot;
}
Clamp(dot, -1, 1); // Robustness: Stay within domain of acos()
double theta_0 = acos(dot); // theta_0 = angle between input vectors
double theta = theta_0*t; // theta = angle between v0 and result
Quaternion v2 = v1 – v0*dot;
v2.normalize(); // { v0, v2 } is now an orthonormal basis
return v0*cos(theta) + v2*sin(theta);
}
You didn't write any code, so I won't write any either. Python with math package is more than enough to solve this problem.
Required steps:
The plane should fly on a great circle. This means you only need one distance to describe X and Y.
You could place the origin at X and specify Y with a latitude.
Calculate the tangent of the Earth at X, and rotate by a_theta. Find the point where it reaches m_a altitude.
Calculate the tangent of the Earth at Y, and rotate by d_theta. Find the point where it reaches m_a altitude.
Draw an arc between the two previous points, with a radius of EarthRadius + m_a
Every coordinate is known in the 2D of the great circle, you just need to rotate them back to 3D coordinates.
For a list of 3D points, you don't need either a_v, d_v or d_d.
I am working on a Windows Phone 8 app and I am doing a location based search. I am using this example to find my current location which is working fine. I also have a list of latitude and longitude co-ordinates. What I want to do is find out from this list of latitude and longitude co-ordinates, which is the closest to my current location. I may also possibly modify this to find out the nearest 5 or 10 or something like that.
It sounds like it should be simple to find out but I don't know how to do it.
How do I find out which co-ordinates are closest to another?
Any help would be appreciated.
Thanks!
The actual distance requires a geodesic function:
http://en.wikipedia.org/wiki/Great-circle_distance
It is quite costly, so you want to filter first with another function that helps you trimming down the candidates and ordering them later on in your code.
In this prior pass you can use the euclidean distance:
http://en.wikipedia.org/wiki/Euclidean_distance
This two-pass approach greatly reduces computation costs (by factors of 10,000 if need be) and is described in Programming Pearls (chapter 8):
http://www.cs.bell-labs.com/cm/cs/pearls/
Since your distances are probably very short (e.g., < 25km) you can use a distance approximation vs. the Haversine formula. I would suggest using Pythagoras Theorem on an Equirectangular projection, which will correct for the curvature along the longitude lines. Below is a C# implementation:
// Convert Degress to Radians
//
private static double Deg2Rad( double deg )
{
return deg * Math.PI / 180;
}
// Get Distance between two lat/lng points using the PythagorsTheorm (a*a = (b*b + c*c))
// on an equirectangular projection
//
private double PythagorasEquirectangular( Geoposition coord1, Geoposition coord2 )
{
double lat1 = Deg2Rad( coord1.Coordinate.Latitude );
double lat2 = Deg2Rad( coord2.Coordinate.Latitude );
double lon1 = Deg2Rad( coord1.Coordinate.Longitude );
double lon2 = Deg2Rad( coord2.Coordinate.Longitude );
double R = 6371; // km
double x = (lon2-lon1) * Math.Cos((lat1+lat2)/2);
double y = (lat2-lat1);
double d= Math.Sqrt(x*x + y*y) * R;
return d;
}
// Find the closest point to your position
//
private Geoposition NearestPoint( List<Geoposition> points, Geoposition position )
{
double min_dist = 999999;
Geoposition closest = null;
// Calculate distance of each point in the list from your position
foreach ( Geoposition point in points )
{
double dist = PythagorasEquirectangular( position, point );
// keep track of which point is the current closest.
if ( dist < min_dist )
{
min_dist = dist;
closest = point;
}
}
// return the closest point
return closest;
}
The radius of the earth at equator = 6,371 km. The equator is divided into 360 degrees of longitude, so each degree at the equator represents approximately 111.32 km. Moving away from the equator towards a pole this distance decreases to zero at the pole.To calculate the distance at different latitudes multiply it by the cosine of the latitude
3 decimal places,0.001 degrees aproximates to
111.32 meters at equator
96.41meters at 30 degrees N/S
78.71 meters at 45 degrees N/S
55.66 meters at 60 degrees N/S
28.82 meters at 75 degrees N/S
For for small distances (100 meters) Pythagoras’ theorem can be used on an equirectangular projection to calculate distance. This is less complicated than Haversine or Spherical Law of Cosines but still allows for the convergence towards poles.
var R = 6371; // km
lat/lng in radians
In pseudo code as I don't know C#
var x = (lng2-lng1) * cos((lat1+lat2)/2);
var y = (lat2-lat1);
var d = sqrt(x*x + y*y) * R;