C# equivalent of computeArea of Google Maps API - c#

Google Maps Api has a google.maps.geometry.spherical.computeArea method.
How can I write its equivalent in C#? (What will be the formula)
I have a set of lat long values for which I need to calculate area (in meters) of the enclosed polygon.
Sample code is highly appreciated.

Sorry for adding an answer to an old question, but if someone else is looking for a quickly answer:
private const double EARTH_RADIUS = 6378137;
public class LatLng
{
public double latitude { get; private set; }
public double longitude { get; private set; }
public LatLng(double latitude, double longitude)
{
this.latitude = latitude;
this.longitude = longitude;
}
}
public static double computeArea(List<LatLng> path)
{
return Math.Abs(computeSignedArea(path));
}
private static double computeSignedArea(List<LatLng> path, double radius = EARTH_RADIUS)
{
int size = path.Count;
if (size < 3) { return 0; }
double total = 0;
LatLng prev = path[size - 1];
double prevTanLat = Math.Tan((Math.PI / 2 - toRadians(prev.latitude)) / 2);
double prevLng = toRadians(prev.longitude);
// For each edge, accumulate the signed area of the triangle formed by the North Pole
// and that edge ("polar triangle").
foreach (LatLng point in path)
{
double tanLat = Math.Tan((Math.PI / 2 - toRadians(point.latitude)) / 2);
double lng = toRadians(point.longitude);
total += polarTriangleArea(tanLat, lng, prevTanLat, prevLng);
prevTanLat = tanLat;
prevLng = lng;
}
return total * (radius * radius);
}
private static double polarTriangleArea(double tan1, double lng1, double tan2, double lng2)
{
double deltaLng = lng1 - lng2;
double t = tan1 * tan2;
return 2 * Math.Atan2(t * Math.Sin(deltaLng), 1 + t * Math.Cos(deltaLng));
}
private static double toRadians(double input)
{
return input * Math.PI / 180;
}
Reference https://github.com/googlemaps

What have you tried yourself?
There are some very similar questions with detailed answers, so it's best to refer to them:
Polygon area calculation using Latitude and Longitude generated from Cartesian space and a world file
Calculating area enclosed by arbitrary polygon on Earth's surface

You can get the formula from Wikipedia.

Related

Polygon area calculation using Latitude and Longitude

I am using a solution I've found in this post:
Polygon area calculation using Latitude and Longitude generated from Cartesian space and a world file
There is something wrong because the values I am getting are not real. For example we know a football field should have around 5,300.00 square meters, right? but the calculation is giving 5,759,154.21.
This is the code:
private static double CalculatePolygonArea(IList<Position> coordinates)
{
double area = 0;
if (coordinates.Count > 2)
{
for (var i = 0; i < coordinates.Count - 1; i++)
{
Position p1 = coordinates[i];
Position p2 = coordinates[i + 1];
area += (ConvertToRadian(p2.Longitude) - ConvertToRadian(p1.Longitude)) * (2 + Math.Sin(ConvertToRadian(p1.Latitude)) + Math.Sin(ConvertToRadian(p2.Latitude)));
}
area = area * 6378137 * 6378137 / 2;
}
return Math.Abs(area);
}
private static double ConvertToRadian(double input)
{
return input * Math.PI / 180;
}
What can be wrong here? Any help?
The area calculation you are using is just plain wrong.... :-/
I use the SphericalUtil.ComputeSignedArea method from Google's Android Maps Utils.
Note: Google's Java code for that is under Apache License Version 2.0, and I converted it to C#.
Looking up that football field up in one of my apps, I get: 4,461, not quite the actual 5,531 but not bad for using Google Map photos...
Here is just the ComputeSignedArea:
public static class SphericalUtil
{
const double EARTH_RADIUS = 6371009;
static double ToRadians(double input)
{
return input / 180.0 * Math.PI;
}
public static double ComputeSignedArea(IList<LatLng> path)
{
return ComputeSignedArea(path, EARTH_RADIUS);
}
static double ComputeSignedArea(IList<LatLng> path, double radius)
{
int size = path.Count;
if (size < 3) { return 0; }
double total = 0;
var prev = path[size - 1];
double prevTanLat = Math.Tan((Math.PI / 2 - ToRadians(prev.Latitude)) / 2);
double prevLng = ToRadians(prev.Longitude);
foreach (var point in path)
{
double tanLat = Math.Tan((Math.PI / 2 - ToRadians(point.Latitude)) / 2);
double lng = ToRadians(point.Longitude);
total += PolarTriangleArea(tanLat, lng, prevTanLat, prevLng);
prevTanLat = tanLat;
prevLng = lng;
}
return total * (radius * radius);
}
static double PolarTriangleArea(double tan1, double lng1, double tan2, double lng2)
{
double deltaLng = lng1 - lng2;
double t = tan1 * tan2;
return 2 * Math.Atan2(t * Math.Sin(deltaLng), 1 + t * Math.Cos(deltaLng));
}
}

Determine the zoom level to cover all marker about lat/lng

I know, what I ask exist with Google Map, but I'm working with Xamarin.Forms.Map so.. I have to make it by my own.
However, I know how to get the center of my point, the POI (Point of Interest), but I don't know how to determine the zoom of the camera..
I searched on the web and from this post, I got redirected to the algorythm of Haversine.
However, I tried the code given but it doesn't work.. I know how to find the POI, the 2 farest point, but I can't determine the zoom..
Any idea please? :/
Note: There is the code if you want to know something about what I tried
#region Camera focus method
private static void OnCustomPinsPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
CustomMap customMap = ((CustomMap)bindable);
if (customMap.CameraFocusParameter == CameraFocusReference.OnPins)
{
List<Position> PositionPins = new List<Position>();
bool onlyOnePointPresent;
foreach (CustomPin pin in (newValue as List<CustomPin>))
{
PositionPins.Add(pin.Position);
}
Position CentralPosition = GetCentralPosition(PositionPins);
if (PositionPins.Count > 1)
{
Position[] FarestPoints = GetTwoFarestPointsOfCenterPointReference(PositionPins, CentralPosition);
customMap.CameraFocus = GetPositionAndZoomLevelForCameraAboutPositions(FarestPoints);
onlyOnePointPresent = false;
}
else
{
customMap.CameraFocus = new CameraFocusData() { Position = CentralPosition };
onlyOnePointPresent = true;
}
customMap.MoveToRegion(MapSpan.FromCenterAndRadius(customMap.CameraFocus.Position,
(!onlyOnePointPresent) ? (customMap.CameraFocus.Distance) : (new Distance(5))));
}
}
public static Position GetCentralPosition(List<Position> positions)
{
if (positions.Count == 1)
{
foreach (Position pos in positions)
{
return (pos);
}
}
double lat = 0;
double lng = 0;
foreach (var pos in positions)
{
lat += pos.Latitude;
lng += pos.Longitude;
}
var total = positions.Count;
lat = lat / total;
lng = lng / total;
return new Position(lat, lng);
}
public class DataCalc
{
public Position Pos { get; set; }
public double Distance { get; set; }
}
public static Position[] GetTwoFarestPointsOfCenterPointReference(List<Position> farestPosition, Position centerPosition)
{
Position[] FarestPos = new Position[2];
List<DataCalc> dataCalc = new List<DataCalc>();
Debug.WriteLine("So the center is on [{0}]/[{1}]", centerPosition.Latitude, centerPosition.Longitude);
foreach (Position pos in farestPosition)
{
dataCalc.Add(new DataCalc()
{
Pos = pos,
Distance = Math.Sqrt(Math.Pow(pos.Latitude - centerPosition.Latitude, 2) + Math.Pow(pos.Longitude - centerPosition.Longitude, 2))
});
}
DataCalc First = new DataCalc() { Distance = 0 };
foreach (DataCalc dc in dataCalc)
{
if (dc.Distance > First.Distance)
{
First = dc;
}
}
Debug.WriteLine("The farest one is on [{0}]/[{1}]", First.Pos.Latitude, First.Pos.Longitude);
DataCalc Second = new DataCalc() { Distance = 0 };
foreach (DataCalc dc in dataCalc)
{
if (dc.Distance > Second.Distance
&& (dc.Pos.Latitude != First.Pos.Latitude && dc.Pos.Longitude != First.Pos.Longitude))
{
Second = dc;
}
}
Debug.WriteLine("the second is on [{0}]/[{1}]", Second.Pos.Latitude, Second.Pos.Longitude);
FarestPos[0] = First.Pos;
FarestPos[1] = Second.Pos;
return (FarestPos);
}
public class CameraFocusData
{
public Position Position { get; set; }
public Distance Distance { get; set; }
}
//HAVERSINE
public static CameraFocusData GetPositionAndZoomLevelForCameraAboutPositions(Position[] FarestPoints)
{
double earthRadius = 6371000; //metros
Position pos1 = FarestPoints[0];
Position pos2 = FarestPoints[1];
double latitud1Radianes = pos1.Latitude * (Math.PI / 180.0);
double latitud2Radianes = pos2.Latitude * (Math.PI / 180.0);
double longitud1Radianes = pos2.Longitude * (Math.PI / 180.0);
double longitud2Radianes = pos2.Longitude * (Math.PI / 180.0);
double deltaLatitud = (pos2.Latitude - pos1.Latitude) * (Math.PI / 180.0);
double deltaLongitud = (pos2.Longitude - pos1.Longitude) * (Math.PI / 180.0);
double sum1 = Math.Sin(deltaLatitud / 2) * Math.Sin(deltaLatitud / 2);
double sum2 = Math.Cos(latitud1Radianes) * Math.Cos(latitud2Radianes) * Math.Sin(deltaLongitud / 2) * Math.Sin(deltaLongitud / 2);
var a = sum1 + sum2;
var c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
var distance = earthRadius * c;
/* lt is deltaLatitud
* lng is deltaLongitud*/
var Bx = Math.Cos(latitud2Radianes) * Math.Cos(deltaLongitud);
var By = Math.Cos(latitud2Radianes) * Math.Sin(deltaLongitud);
var lt = Math.Atan2(Math.Sin(latitud1Radianes) + Math.Sin(latitud2Radianes),
Math.Sqrt((Math.Cos(latitud1Radianes) + Bx) * (Math.Cos(latitud2Radianes) + Bx) + By * By));//Latitud del punto medio
var lng = longitud1Radianes + Math.Atan2(By, Math.Cos(longitud1Radianes) + Bx);//Longitud del punto medio
Debug.WriteLine("the final pos of the camera is on [{0}]/[{1}]", lt, lng);
return (new CameraFocusData() { Position = new Position(lt, lng), Distance = new Distance(distance + 0.2) });
}
#endregion
I then found the solution, there is the code for it, it has been wrote to be put into your custom map.
Here, private static void OnCustomPinsPropertyChanged(BindableObject bindable, object oldValue, object newValue) is a method which is called by my List<CustomPins> but you can use a different method.
public static readonly BindableProperty CustomPinsProperty =
BindableProperty.Create(nameof(CustomPins), typeof(IList<CustomPin>), typeof(CustomMap), null,
propertyChanged: OnCustomPinsPropertyChanged);
Also, you can add the lat/long of the user, I didn't do it because of my needs which are without the pos of the user :).
Finaly, you can add a multiplicator for the zoom, I mean, you could say, hmm, the zoom is to far for me, then ok, do like me and multiplicate the double distance value by something as 0.7 or 0.6 :)
#region Camera focus definition
public class CameraFocusData
{
public Position Position { get; set; }
public Distance Distance { get; set; }
}
private static void OnCustomPinsPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
CustomMap customMap = ((CustomMap)bindable);
if (customMap.CameraFocusParameter == CameraFocusReference.OnPins)
{
List<double> latitudes = new List<double>();
List<double> longitudes = new List<double>();
foreach (CustomPin pin in (newValue as List<CustomPin>))
{
latitudes.Add(pin.Position.Latitude);
longitudes.Add(pin.Position.Longitude);
}
double lowestLat = latitudes.Min();
double highestLat = latitudes.Max();
double lowestLong = longitudes.Min();
double highestLong = longitudes.Max();
double finalLat = (lowestLat + highestLat) / 2;
double finalLong = (lowestLong + highestLong) / 2;
double distance = DistanceCalculation.GeoCodeCalc.CalcDistance(lowestLat, lowestLong, highestLat, highestLong, DistanceCalculation.GeoCodeCalcMeasurement.Kilometers);
customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(finalLat, finalLong), Distance.FromKilometers(distance * 0.7)));
}
}
private class DistanceCalculation
{
public static class GeoCodeCalc
{
public const double EarthRadiusInMiles = 3956.0;
public const double EarthRadiusInKilometers = 6367.0;
public static double ToRadian(double val) { return val * (Math.PI / 180); }
public static double DiffRadian(double val1, double val2) { return ToRadian(val2) - ToRadian(val1); }
public static double CalcDistance(double lat1, double lng1, double lat2, double lng2)
{
return CalcDistance(lat1, lng1, lat2, lng2, GeoCodeCalcMeasurement.Miles);
}
public static double CalcDistance(double lat1, double lng1, double lat2, double lng2, GeoCodeCalcMeasurement m)
{
double radius = GeoCodeCalc.EarthRadiusInMiles;
if (m == GeoCodeCalcMeasurement.Kilometers) { radius = GeoCodeCalc.EarthRadiusInKilometers; }
return radius * 2 * Math.Asin(Math.Min(1, Math.Sqrt((Math.Pow(Math.Sin((DiffRadian(lat1, lat2)) / 2.0), 2.0) + Math.Cos(ToRadian(lat1)) * Math.Cos(ToRadian(lat2)) * Math.Pow(Math.Sin((DiffRadian(lng1, lng2)) / 2.0), 2.0)))));
}
}
public enum GeoCodeCalcMeasurement : int
{
Miles = 0,
Kilometers = 1
}
}
#endregion
Have fun !
UPDATE of DEC 2018
I worked on a solution which I hosted a long time ago on my repo, with the other POCs https://github.com/Emixam23/XamarinByEmixam23/tree/master/Detailed%20Part/Controls/Map/MapPinsProject

Maximum clockwise angles from 3 nearest points

Help me, because I'm rly tired of this...
I need to count angles between current point and the closest 3 points (look at an image below) - I need to sort the angles in descending order (to get the point with the largest angle - if it doesn't fit expectations, I have to get another one).
I tried to do something, but it doesn't work...
private static Vertex[] SortByAngle(IEnumerable<Vertex> vs, Vertex current, Vertex previous)
{
if (current.CompareTo(previous) == 0)
{
previous.X = previous.X - 1.0; // this is a trick to handle the first point
}
var vertices = new Dictionary<Vertex, double>();
foreach (var v in vs)
{
double priorAngle = Angle(previous, current);
double nextAngle = Angle(current, v);
double angleInBetween = 180.0 - (priorAngle + nextAngle);
vertices.Add((Vertex) v.Clone(), angleInBetween);
}
// here the angles are incorrect, because I want to sort them in desc order, but it's a real mess when I do OrderByDescending - something is wrong with my code:S
vertices = vertices.OrderBy(v => v.Value).ToDictionary(k => k.Key, v => v.Value);
return vertices.Select(v => new Vertex(v.Key.X, v.Key.Y)).ToArray();
}
private static double Angle(Vertex v1, Vertex v2, double offsetInDegrees = 0.0)
{
return (RadianToDegree(Math.Atan2(-v2.Y + v1.Y, -v2.X + v1.X)) + offsetInDegrees);
}
public static double RadianToDegree(double radian)
{
var degree = radian * (180.0 / Math.PI);
if (degree < 0)
degree = 360 + degree;
return degree;
}
vs is my set of 3 nearest points
current and previous are obvious:)
i didn't tested it, but i restyled a little, avoiding dictionaries. I think your mistake is in: double angleInBetween = 180.0 - (priorAngle + nextAngle); should be: double angleInBetween = (180.0 - priorAngle) + nextAngle;
public struct Vertex
{
public double X { get; set; }
public double Y { get; set; }
}
private static double CalcDistance(Vertex v1, Vertex v2)
{
double dX = (v2.X - v1.X);
double dY = (v2.Y - v1.Y);
return Math.Sqrt((dX * dX) + (dY * dY));
}
private static Vertex[] SortByAngle(IEnumerable<Vertex> vs, Vertex current, Vertex previous)
{
var verticesOnDistance = from vertex in vs
where !vertex.Equals(current)
let distance = CalcDistance(current, vertex)
orderby distance
select vertex;
double priorAngle = Angle(previous, current);
var verticeAngles = from vertex in verticesOnDistance.Take(3)
let nextAngle = Angle(current, vertex)
let angleInBetween = (180.0 - priorAngle) + nextAngle
orderby angleInBetween descending
select vertex;
return verticeAngles.ToArray();
}
private static double Angle(Vertex v1, Vertex v2, double offsetInDegrees = 0.0)
{
return (RadianToDegree(Math.Atan2(-v2.Y + v1.Y, -v2.X + v1.X)) + offsetInDegrees);
}
public static double RadianToDegree(double radian)
{
var degree = radian * (180.0 / Math.PI);
if (degree < 0)
degree = 360 + degree;
return degree;
}
I'm running a little out of time here. I'll be on later... I'm not sure this is correct, but maybe shine another light on it...
Good luck

Calculate Current Speed in .NET - With GPS

I would like to know what's the best way to calculate the current speed with GPS.
I've an external GPS receiver which is connected via USB to my car-notebook. It gives me just the following information:
- Longitude
- Latitude
- Altitude
My try is to get two location-infos with timestamps.
Then I am finding the difference in time (timestamp2 - timestamp1) and calculating the speed (distance/time).
Are there any other possibilites oder maybe any libraries available?
To calculate the distance, you will need the Haversine Formula.
You will find many implementations of it around the web, here is one I use in C#:
private static double ArcInMeters(double lat0, double lon0, double lat1, double lon1)
{
double earthRadius = 6372797.560856; // m
return earthRadius * ArcInRadians(lat0, lon0, lat1, lon1);
}
private static double ArcInRadians(double lat0, double lon0, double lat1, double lon1)
{
double latitudeArc = DegToRad(lat0 - lat1);
double longitudeArc = DegToRad(lon0 - lon1);
double latitudeH = Math.Sin(latitudeArc * 0.5);
latitudeH *= latitudeH;
double lontitudeH = Math.Sin(longitudeArc * 0.5);
lontitudeH *= lontitudeH;
double tmp = Math.Cos(DegToRad(lat0)) * Math.Cos(DegToRad(lat1));
return 2.0 * Math.Asin(Math.Sqrt(latitudeH + tmp * lontitudeH));
}
private static double DegToRad(double x)
{
return x * Math.PI / 180;
}

Adding distance to a GPS coordinate

I'm trying to generate some points at random distances away from a fixed point using GPS.
How can I add distance in meters to a GPS coordinate?
I've looked at UTM to GPS conversion but is there a simpler method to achieve this?
I'm working on Android platform just in case.
Cheers,
fgs
P0(lat0,lon0) : initial position (unit : degrees)
dx,dy : random offsets from your initial position in meters
You can use an approximation to compute the position of the randomized position:
lat = lat0 + (180/pi)*(dy/6378137)
lon = lon0 + (180/pi)*(dx/6378137)/cos(lat0)
This is quite precise as long as the random distance offset is below 10-100 km
Edit: of course in Java Math.cos() expects radians so do use Math.cos(Math.PI/180.0*lat0) if lat0 is in degrees as assumed above.
To take a square I'm using this:
private double[] getBoundingBox(final double pLatitude, final double pLongitude, final int pDistanceInMeters) {
final double[] boundingBox = new double[4];
final double latRadian = Math.toRadians(pLatitude);
final double degLatKm = 110.574235;
final double degLongKm = 110.572833 * Math.cos(latRadian);
final double deltaLat = pDistanceInMeters / 1000.0 / degLatKm;
final double deltaLong = pDistanceInMeters / 1000.0 / degLongKm;
final double minLat = pLatitude - deltaLat;
final double minLong = pLongitude - deltaLong;
final double maxLat = pLatitude + deltaLat;
final double maxLong = pLongitude + deltaLong;
boundingBox[0] = minLat;
boundingBox[1] = minLong;
boundingBox[2] = maxLat;
boundingBox[3] = maxLong;
return boundingBox;
}
This returns an array with 4 coordinates, with them you can make a square with your original point in center.
A detailed outline is given at http://www.movable-type.co.uk/scripts/latlong.html.
If you, somewhere, need to interconvert longitude/latitude to UTM coordinates (the ones used in GPS) you may want to have a look at http://www.uwgb.edu/dutchs/UsefulData/UTMFormulas.htm
If you want to go east or north or west or south you can use this:
#SuppressLint("DefaultLocale")
public static double go_mock_loc(double xx_lat,double xx_long,double xx_dinstance,String Direction)
{
// double xx_lat= 45.815005;
// double xx_long= 15.978501;
// int xx_dinstance=500;
int equator_circumference=6371000;
int polar_circumference=6356800;
double m_per_deg_long = 360 / polar_circumference;
double rad_lat=(xx_lat* (Math.PI) / 180);
double m_per_deg_lat = 360 / ( Math.cos(rad_lat) * equator_circumference);
double deg_diff_long = xx_dinstance * m_per_deg_long;
double deg_diff_lat = xx_dinstance * m_per_deg_lat;
double xx_north_lat = xx_lat + deg_diff_long;
//double xx_north_long= xx_long;
double xx_south_lat = xx_lat - deg_diff_long;
//double xx_south_long= xx_long;
//double xx_east_lat = xx_lat;
double xx_east_long= xx_long + deg_diff_lat;
//double xx_west_lat = xx_lat;
double xx_west_long= xx_long - deg_diff_lat;
if (Direction.toUpperCase().contains("NORTH")) {
return xx_north_lat;
} else if (Direction.toUpperCase().contains("SOUTH"))
{
return xx_south_lat;
} else if (Direction.toUpperCase().contains("EAST"))
{
return xx_east_long;
} else if (Direction.toUpperCase().contains("WEST"))
{
return xx_west_long;
}
else
return 0;
}
I found that solution of #Bogdan Khrystov is very well.
So here is C# version of his solution.
public enum GeoDirection
{
NORTH = 1, SOUTH = 2, EAST = 3, WEST = 4
}
public static Tuple<double, double> AddDistanceInMeters(double latitude, double longitude, int distanceInMeters, GeoDirection direction)
{
var equatorCircumference = 6371000;
var polarCircumference = 6356800;
var mPerDegLong = 360 / (double)polarCircumference;
var radLat = latitude * Math.PI / 180;
var mPerDegLat = 360 / (Math.Cos(radLat) * equatorCircumference);
var degDiffLong = distanceInMeters * mPerDegLong;
var degDiffLat = distanceInMeters * mPerDegLat;
var xxNorthLat = latitude + degDiffLong;
var xxSouthLat = latitude - degDiffLong;
var xxEastLong = longitude + degDiffLat;
var xxWestLong = longitude - degDiffLat;
switch (direction)
{
case GeoDirection.NORTH:
return new Tuple<double, double>(xxNorthLat, longitude);
case GeoDirection.SOUTH:
return new Tuple<double, double>(xxSouthLat, longitude);
case GeoDirection.EAST:
return new Tuple<double, double>(latitude, xxEastLong);
case GeoDirection.WEST:
return new Tuple<double, double>(latitude, xxWestLong);
default:
return null;
}
}
rewrite #Ersin Gülbahar answer in Kotlin:
object LocationUtil {
enum class Direction {
NORTH, SOUTH, EAST, WEST
}
fun addDistanceInMeters(
latitude: Double,
longitude: Double,
distanceInMeters: Int,
direction: Direction
): Pair<Double, Double> {
val equatorCircumference = 6371000
val polarCircumference = 6356800
val mPerDegLong = (360 / polarCircumference.toDouble())
val radLat = latitude * Math.PI / 180
val mPerDegLat = 360 / (Math.cos(radLat) * equatorCircumference)
val degDiffLong = distanceInMeters * mPerDegLong
val degDiffLat = distanceInMeters * mPerDegLat
val xxNorthLat = latitude + degDiffLong
val xxSouthLat = latitude - degDiffLong
val xxEastLong = longitude + degDiffLat
val xxWestLong = longitude - degDiffLat
return when (direction) {
Direction.NORTH -> Pair(xxNorthLat, longitude)
Direction.SOUTH -> Pair(xxSouthLat, longitude)
Direction.EAST -> Pair(latitude, xxEastLong)
Direction.WEST -> Pair(latitude, xxWestLong)
}
}
}
This code splits the line between two coordinates in n segments. Replace the delta calculation by your fixed distance
#Override
public void split(Coordinates p1, Coordinates p2, int segments) {
double φ1 = Math.toRadians(p1.getLat());
double λ1 = Math.toRadians(p1.getLon());
double φ2 = Math.toRadians(p2.getLat());
double λ2 = Math.toRadians(p2.getLon());
double xDelta = (φ2 - φ1) / segments;
double yDelta = (λ2 - λ1) / segments;
for (int i = 0; i < segments; i++){
double x = φ1 + i * xDelta;
double y = λ1 + i * yDelta;
double xc = Math.toDegrees(x);
double yc = Math.toDegrees(y);
System.out.println(xc+","+yc);
}
}
Combining answers from #Ersin Gülbahar and #Stéphane above, I came up with this solution in Flutter/Dart:
import 'dart:math' as math;
enum Direction { north, south, east, west }
double moveCoordinate(
double latitude, double longitude, double distanceToMoveInMeters, Direction directionToMove) {
const earthEquatorRadius = 6378137;
final latitudeOffset = (180 / math.pi) * (distanceToMoveInMeters / earthEquatorRadius);
final longitudeOffset = (180 / math.pi) *
(distanceToMoveInMeters / earthEquatorRadius) /
math.cos(math.pi / 180 * latitude);
switch (directionToMove) {
case Direction.north:
return latitude + latitudeOffset;
case Direction.south:
return latitude - latitudeOffset;
case Direction.east:
return longitude + longitudeOffset;
case Direction.west:
return longitude - longitudeOffset;
}
return 0;
}
This works, tested. The code is C# but you can easily change it to another language
private PointLatLng NewPositionBasedOnDistanceAngle(PointLatLng org, double distance, double bearing)
{
double rad = bearing * Math.PI / 180; //to radians
double lat1 = org.Lat * Math.PI / 180; //to radians
double lng1 = org.Lng * Math.PI / 180; //to radians
double lat = Math.Asin(Math.Sin(lat1) * Math.Cos(distance / 6378137) + Math.Cos(lat1) * Math.Sin(distance / 6378137) * Math.Cos(rad));
double lng = lng1 + Math.Atan2(Math.Sin(rad) * Math.Sin(distance / 6378137) * Math.Cos(lat1), Math.Cos(distance / 6378137) - Math.Sin(lat1) * Math.Sin(lat));
return new PointLatLng(lat * 180 / Math.PI, lng * 180 / Math.PI); // to degrees
}

Categories

Resources