3

I have two points on a map and I know the distance between them. Now, I need to get a new point between them X meters away from start point. However, i cannot figure out, how to find the new coords.

var nextTrazadoPoint = new Coord {Lat = ....,  Lng=...., Alt=...};
var previousTrazadoPoint = new Coord {Lat = ....,  Lng=...., Alt...};
var fromCoords = new GeoCoordinate(nextTrazadoPoint.Lat, nextTrazadoPoint.Lng, nextTrazadoPoint.Alt);
var toCoords = new GeoCoordinate(previousTrazadoPoint .Lat, previousTrazadoPoint .Lng, previousTrazadoPoint .Alt);
var distance = fromCoords.GetDistanceTo(toCoords); //Let's say 1000 ¿meters?

Now I want to walk 200 meters from previousTrazadoPoint to nextTrazadoPoint

//Vector from previousTrazadoPoint to nextTrazadoPoint
var vectorDireccion = new Vector(
    (double)(nextTrazadoPoint.Latitud - previousTrazadoPoint.Latitud), 
    (double)(nextTrazadoPoint.Longitud - previousTrazadoPoint.Longitud)
    );

//Normalize
vectorDireccion.Normalize();

//meters from previousTrazadoPoint 
var distanciaARecorrer = 200;

//New coords
var vectorDestino = distanciaARecorrer * vectorDireccion;
point.Latitud = (decimal)vectorDestino.X + previousTrazadoPoint.Latitud;
point.Longitud = (decimal)vectorDestino.Y + previousTrazadoPoint.Longitud;

However, when i draw the new point on Gmaps, it is not placed between both. Any ideas?

Rumpelstinsk
  • 3,107
  • 3
  • 30
  • 57

2 Answers2

1

Thanks to @HansKilian and @cletus (Calculate distance between 2 GPS coordinates), I could find the solution

private const double EARTH_RADIUS = 6378.1;
private static double ConvertToRadians(double angle)
{
    return (Math.PI / 180) * angle;
}
private static double ConvertToDegree(double angle)
{
    return angle * (180.0 / Math.PI);
}

private static double CalculateBearing(CoordsDto from, CoordsDto to)
{
    var from_lat_rad = ConvertToRadians(from.Latitud);
    var to_lat_rad = ConvertToRadians(to.Latitud);

    var dif_lng_rad = ConvertToRadians(to.Longitud - from.Longitud);

    double x = Math.Cos(from_lat_rad) * Math.Sin(to_lat_rad) - Math.Sin(from_lat_rad) * Math.Cos(to_lat_rad) * Math.Cos(dif_lng_rad);
    double y = Math.Sin(dif_lng_rad) * Math.Cos(to_lat_rad);

    // Math.Atan2 can return negative value, 0 <= output value < 2*PI expected 
    return (Math.Atan2(y, x) + Math.PI * 2) % (Math.PI * 2);
}

public static CoordsDto GetPointFarAway(CoordsDto from, CoordsDto to, double meterAwayFromStart)
{
    var resp = new CoordsDto();
    var bearing_rad = CalculateBearing(from, to);
    var d = meterAwayFromStart * 0.001; //KM

    var input_lat1_rad = ConvertToRadians(from.Latitud);
    var input_lon1_rad = ConvertToRadians(from.Longitud);

    var newPoint_lat_rad = Math.Asin(
        Math.Sin(input_lat1_rad) * Math.Cos(d / EARTH_RADIUS) + Math.Cos(input_lat1_rad) * Math.Sin(d / EARTH_RADIUS) * Math.Cos(bearing_rad)
    );
    var newPoint_lon_rad = input_lon1_rad + Math.Atan2(
        Math.Sin(bearing_rad) * Math.Sin(d / EARTH_RADIUS) * Math.Cos(input_lat1_rad),
        Math.Cos(d / EARTH_RADIUS) - Math.Sin(input_lat1_rad) * Math.Sin(newPoint_lat_rad)
    );

    resp.Latitud = ConvertToDegree(newPoint_lat_rad);
    resp.Longitud = ConvertToDegree(newPoint_lon_rad);

    return resp;
}
Rumpelstinsk
  • 3,107
  • 3
  • 30
  • 57
0

I can't see anything wrong with your code. You haven't really provided enough information that I can take your code and compile it and see what's wrong, so I tried coding it up from scratch using the Vector2 class. I couldn't use Vector since that isn't available in .NET core and my sandbox project is a .NET core project.

This is what I got

var origin = new Vector2(100.0f, 100.0f);
var destination = new Vector2(0.0f, 400.0f);
var direction = destination - origin;
var movement = Vector2.Normalize(direction) * 200.0f;
var movementdestination = origin + movement;
Console.WriteLine($"X: {movementdestination.X}, Y: {movementdestination.Y}");

It prints

X: 36.75444, Y: 289.7367

which - as far as I can tell - is correct. I hope that helps.

Hans Kilian
  • 18,948
  • 1
  • 26
  • 35
  • You should probably make sure movement isn't larger than direction (thus overshooting target). – Radosław Cybulski Jul 18 '19 at 07:52
  • It's similar of what i'm doing. However i think the problem is on the units. I mean, let's say I want to move the destination 200meters or 200km or 200 milles. `var movement = Vector2.Normalize(direction) * 200.0f;` That line will be the same on all cases. In some point has to be a conversión to ¿degrees? ¿radians? ¿meters? – Rumpelstinsk Jul 18 '19 at 07:53
  • @Rumpelstinsk Yes, that might be an issue. The length of a vector using longitude and latitude isn't really a distance as such. A vector with a length of 10 will be shorter near the poles than if it's close to the equator. – Hans Kilian Jul 18 '19 at 07:59
  • 1
    Maybe this can help: https://stackoverflow.com/questions/365826/calculate-distance-between-2-gps-coordinates (see the .NET answer a few pages down) – Hans Kilian Jul 18 '19 at 08:01
  • 1
    @HansKilian Thanks for the help. That point me on the right direction. I solved it finally. As you said, with coords is a bit more complex, because you have to deal with the curvature of the earth and some converstion from radians to degrees... – Rumpelstinsk Jul 18 '19 at 08:50