Calculate the Geo Position at Given Time

Calculate the geo position at given time

working example using GetPointAtDistance from the epoly.js third party library from Mike Williams ported to v3

  var directionDisplay;
var directionsService = new google.maps.DirectionsService();
var map;
var polyline = null;

function createMarker(latlng, label, html) {
// alert("createMarker("+latlng+","+label+","+html+","+color+")");
var contentString = '<b>'+label+'</b><br>'+html;
var marker = new google.maps.Marker({
position: latlng,
map: map,
title: label,
zIndex: Math.round(latlng.lat()*-100000)<<5
});
marker.myname = label;
// gmarkers.push(marker);

google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(contentString);
infowindow.open(map,marker);
});
return marker;
}

function initialize() {
directionsDisplay = new google.maps.DirectionsRenderer({suppressMarkers:true});
var chicago = new google.maps.LatLng(41.850033, -87.6500523);
var myOptions = {
zoom: 6,
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: chicago
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
polyline = new google.maps.Polyline({
path: [],
strokeColor: '#FF0000',
strokeWeight: 3
});
directionsDisplay.setMap(map);
calcRoute();
}

function calcRoute() {

var start = document.getElementById("start").value;
var end = document.getElementById("end").value;
var travelMode = google.maps.DirectionsTravelMode.DRIVING

var request = {
origin: start,
destination: end,
travelMode: travelMode
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
polyline.setPath([]);
var bounds = new google.maps.LatLngBounds();
startLocation = new Object();
endLocation = new Object();
directionsDisplay.setDirections(response);
var route = response.routes[0];
var summaryPanel = document.getElementById("directions_panel");
summaryPanel.innerHTML = "";

// For each route, display summary information.
var path = response.routes[0].overview_path;
var legs = response.routes[0].legs;
for (i=0;i<legs.length;i++) {
if (i == 0) {
startLocation.latlng = legs[i].start_location;
startLocation.address = legs[i].start_address;
// marker = google.maps.Marker({map:map,position: startLocation.latlng});
marker = createMarker(legs[i].start_location,"start",legs[i].start_address,"green");
}
endLocation.latlng = legs[i].end_location;
endLocation.address = legs[i].end_address;
var steps = legs[i].steps;
for (j=0;j<steps.length;j++) {
var nextSegment = steps[j].path;
for (k=0;k<nextSegment.length;k++) {
polyline.getPath().push(nextSegment[k]);
bounds.extend(nextSegment[k]);
}
}
}

polyline.setMap(map);

computeTotalDistance(response);
} else {
alert("directions response "+status);
}
});
}

var totalDist = 0;
var totalTime = 0;
function computeTotalDistance(result) {
totalDist = 0;
totalTime = 0;
var myroute = result.routes[0];
for (i = 0; i < myroute.legs.length; i++) {
totalDist += myroute.legs[i].distance.value;
totalTime += myroute.legs[i].duration.value;
}
totalDist = totalDist / 1000.
document.getElementById("total").innerHTML = "total distance is: "+ totalDist + " km<br>total time is: " + (totalTime / 60).toFixed(2) + " minutes";
document.getElementById("totalTime").value = (totalTime/60.).toFixed(2);
}

function putMarkerOnRoute(time) {
var distance = (time*60/totalTime) * totalDist*1000;
// alert("Time:"+time+" totalTime:"+totalTime+" totalDist:"+totalDist+" dist:"+distance);
if (!marker) {
marker = createMarker(polyline.GetPointAtDistance(distance),"time: "+time,"marker");
} else {
marker.setPosition(polyline.GetPointAtDistance(distance));
marker.setTitle("time:"+time);
}
}

v3_epoly.js

/*********************************************************************\
* *
* epolys.js by Mike Williams *
* updated to API v3 by Larry Ross *
* *
* A Google Maps API Extension *
* *
* Adds various Methods to google.maps.Polygon and google.maps.Polyline *
* *
* .GetPointAtDistance() returns a GLatLng at the specified distance *
* along the path. *
* The distance is specified in metres *
* Reurns null if the path is shorter than that *
* *
* .GetPointsAtDistance() returns an array of GLatLngs at the *
* specified interval along the path. *
* The distance is specified in metres *
* *
***********************************************************************
* *
* This Javascript is provided by Mike Williams *
* Blackpool Community Church Javascript Team *
* http://www.blackpoolchurch.org/ *
* http://econym.org.uk/gmap/ *
* *
* This work is licenced under a Creative Commons Licence *
* http://creativecommons.org/licenses/by/2.0/uk/ *
* *
***********************************************************************
* *
* Version 1.1 6-Jun-2007 *
* Version 1.2 1-Jul-2007 - fix: Bounds was omitting vertex zero *
* add: Bearing *
* Version 1.3 28-Nov-2008 add: GetPointsAtDistance() *
* Version 1.4 12-Jan-2009 fix: GetPointsAtDistance() *
* Version 3.0 11-Aug-2010 update to v3 *
* *
\*********************************************************************/

// === first support methods that don't (yet) exist in v3
google.maps.LatLng.prototype.distanceFrom = function(newLatLng) {
var EarthRadiusMeters = 6378137.0; // meters
var lat1 = this.lat();
var lon1 = this.lng();
var lat2 = newLatLng.lat();
var lon2 = newLatLng.lng();
var dLat = (lat2-lat1) * Math.PI / 180;
var dLon = (lon2-lon1) * Math.PI / 180;
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1 * Math.PI / 180 ) * Math.cos(lat2 * Math.PI / 180 ) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = EarthRadiusMeters * c;
return d;
}

google.maps.LatLng.prototype.latRadians = function() {
return this.lat() * Math.PI/180;
}

google.maps.LatLng.prototype.lngRadians = function() {
return this.lng() * Math.PI/180;
}

// === A method which returns the length of a path in metres ===
google.maps.Polygon.prototype.Distance = function() {
var dist = 0;
for (var i=1; i < this.getPath().getLength(); i++) {
dist += this.getPath().getAt(i).distanceFrom(this.getPath().getAt(i-1));
}
return dist;
}

// === A method which returns a GLatLng of a point a given distance along the path ===
// === Returns null if the path is shorter than the specified distance ===
google.maps.Polygon.prototype.GetPointAtDistance = function(metres) {
// some awkward special cases
if (metres == 0) return this.getPath().getAt(0);
if (metres < 0) return null;
if (this.getPath().getLength() < 2) return null;
var dist=0;
var olddist=0;
for (var i=1; (i < this.getPath().getLength() && dist < metres); i++) {
olddist = dist;
dist += this.getPath().getAt(i).distanceFrom(this.getPath().getAt(i-1));
}
if (dist < metres) {
return null;
}
var p1= this.getPath().getAt(i-2);
var p2= this.getPath().getAt(i-1);
var m = (metres-olddist)/(dist-olddist);
return new google.maps.LatLng( p1.lat() + (p2.lat()-p1.lat())*m, p1.lng() + (p2.lng()-p1.lng())*m);
}

// === A method which returns an array of GLatLngs of points a given interval along the path ===
google.maps.Polygon.prototype.GetPointsAtDistance = function(metres) {
var next = metres;
var points = [];
// some awkward special cases
if (metres <= 0) return points;
var dist=0;
var olddist=0;
for (var i=1; (i < this.getPath().getLength()); i++) {
olddist = dist;
dist += this.getPath().getAt(i).distanceFrom(this.getPath().getAt(i-1));
while (dist > next) {
var p1= this.getPath().getAt(i-1);
var p2= this.getPath().getAt(i);
var m = (next-olddist)/(dist-olddist);
points.push(new google.maps.LatLng( p1.lat() + (p2.lat()-p1.lat())*m, p1.lng() + (p2.lng()-p1.lng())*m));
next += metres;
}
}
return points;
}

// === Copy all the above functions to GPolyline ===
google.maps.Polyline.prototype.Distance = google.maps.Polygon.prototype.Distance;
google.maps.Polyline.prototype.GetPointAtDistance = google.maps.Polygon.prototype.GetPointAtDistance;
google.maps.Polyline.prototype.GetPointsAtDistance = google.maps.Polygon.prototype.GetPointsAtDistance;

How do I calculate and get the next latitude-longitude estimated by time between two points every 10 minutes having the start and end point?

There are multiple ways to calculate this. Some of them are quite complex.

You could use Vincenty's formula, which is often used for bearing and distance calculations.
The formula needs Long/Lat of the starting point, the bearing and a distance.
I doubt, that you want to reimplement this algo, so here you go: Implementing Vincenty's Formula in PHP

Another solution could be to use vectors to calculate the destination points along a great-circle given distance and bearing from start point. This approach might be a bit easier, then to work with spherical trigonometry. http://www.movable-type.co.uk/scripts/latlong-vectors.html and https://stackoverflow.com/a/1739066/1163786

Another one is to calculate the intermediate points on a great-circle.
http://williams.best.vwh.net/avform.htm#Intermediate


Let's use Vincenty here and re-calc your end-point, given a starting-point, bearing and distance:

  • a starting point: Point A lat1=37.78472; lon1=-122.39913;
  • the bearing: approx. 89
  • the distance: 102 km

Result: Latitude: 37°47′42″N 37.79506902, Longitude: 121°14′28″W -121.24119021

That is pretty close your Point B.


Now, you want to determine the future position (lang/lat) by calculating the distance you will travel based on your current speed and your known time interval.
In other words, your next point is 10 minutes from the starting point given speed 122 km/h and 89 bearing.

Calculate new distance: 122 km/h = 2033.33 m/min, so in 10 minutes: 20333.33 m = 20,333 km approx.

You new data for the formula:

  • a starting point, here: Point A lat1=37.78472; lon1=-122.39913;
  • the bearing: approx. 89
  • the distance: 20,333 km

And re-run vincenty with these values to get Lat/Long...


This might be of help:

  • PHP library for geo/nav calculations
  • Google Maps API v3 provides Navigation Helper methods

how to use direction angle and speed to calculate next time's latitude and longitude

First, calculate the distance you will travel based on your current speed and your known time interval ("next time"):

distance = speed * time

Then you can use this formula to calculate your new position (lat2/lon2):

lat2 =asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))
dlon=atan2(sin(tc)*sin(d)*cos(lat1),cos(d)-sin(lat1)*sin(lat2))
lon2=mod( lon1-dlon +pi,2*pi )-pi

For an implementation in Javascript, see the function LatLon.prototype.destinationPoint on this page

Update for those wishing a more fleshed-out implementation of the above, here it is in Javascript:

  /**
* Returns the destination point from a given point, having travelled the given distance
* on the given initial bearing.
*
* @param {number} lat - initial latitude in decimal degrees (eg. 50.123)
* @param {number} lon - initial longitude in decimal degrees (e.g. -4.321)
* @param {number} distance - Distance travelled (metres).
* @param {number} bearing - Initial bearing (in degrees from north).
* @returns {array} destination point as [latitude,longitude] (e.g. [50.123, -4.321])
*
* @example
* var p = destinationPoint(51.4778, -0.0015, 7794, 300.7); // 51.5135°N, 000.0983°W
*/
function destinationPoint(lat, lon, distance, bearing) {
var radius = 6371e3; // (Mean) radius of earth

var toRadians = function(v) { return v * Math.PI / 180; };
var toDegrees = function(v) { return v * 180 / Math.PI; };

// sinφ2 = sinφ1·cosδ + cosφ1·sinδ·cosθ
// tanΔλ = sinθ·sinδ·cosφ1 / cosδ−sinφ1·sinφ2
// see mathforum.org/library/drmath/view/52049.html for derivation

var δ = Number(distance) / radius; // angular distance in radians
var θ = toRadians(Number(bearing));

var φ1 = toRadians(Number(lat));
var λ1 = toRadians(Number(lon));

var sinφ1 = Math.sin(φ1), cosφ1 = Math.cos(φ1);
var sinδ = Math.sin(δ), cosδ = Math.cos(δ);
var sinθ = Math.sin(θ), cosθ = Math.cos(θ);

var sinφ2 = sinφ1*cosδ + cosφ1*sinδ*cosθ;
var φ2 = Math.asin(sinφ2);
var y = sinθ * sinδ * cosφ1;
var x = cosδ - sinφ1 * sinφ2;
var λ2 = λ1 + Math.atan2(y, x);

return [toDegrees(φ2), (toDegrees(λ2)+540)%360-180]; // normalise to −180..+180°
}

How to get a time zone from a location using latitude and longitude coordinates?

Time Zone Location Web Services

  • Google Maps Time Zone API
  • Bing Maps Time Zone API
  • Azure Maps Time Zone API
  • GeoNames Time Zone API
  • TimeZoneDB API
  • AskGeo - commercial (but arguably more accurate than GeoNames)
  • GeoGarage Time Zone API - commercial, focusing on Nautical time zones.

Raw Time Zone Boundary Data

  • Timezone Boundary Builder - builds time zone shapefiles from OpenStreetMaps map data. Includes territorial waters near coastlines.

The following projects have previously been sources of time zone boundary data, but are no longer actively maintained.

  • tz_world - the original shapefile data from Eric Muller
  • whereonearth-timezone - GeoJSON version with WOEDB data merged in

Time Zone Geolocation Offline Implementations

Implementations that use the Timezone Boundary Builder data

  • node-geo-tz - JavaScript library (Node.js only)
  • timespace - JavaScript library
  • tz-lookup-oss - JavaScript library
  • GeoTimeZone - .NET library
  • Geo-Timezone - PHP library
  • timezonefinder - Python library
  • ZoneDetect - C library
  • Timeshape - Java library
  • TimeZoneMap - Java and Android library
  • lutz - R library
  • go-tz - Go library
  • Timezone lookup - Go library
  • docker-timezone-lookup - docker container wrapping node-geo-tz
  • tzf - Go library
  • tzfpy - Python port of tzf library
  • tzf-rs - Rust port of tzf library

Implementations that use the older tz_world data

  • latlong - Go library (Read this post also.)
  • TimeZoneMapper - Java library
  • tzwhere - JavaScript/Node library
  • pytzwhere - Python library
  • timezone_finder - Ruby library
  • LatLongToTimeZone - Java and Swift libraries
  • What Time is it here? - Blog post describing PHP and MongoDB
  • rundel/timezone - R library

Libraries that call one of the web services

  • timezone - Ruby gem that calls GeoNames
  • AskGeo has its own libraries for calling from Java or .Net
  • GeoNames has client libraries for just about everything

Self-hosted web services

  • geo2tz - based on Timezone lookup, available via Docker image

Other Ideas

  • Find the nearest city with an R-Tree
  • Find the nearest city with MySQL

Please update this list if you know of any others

Also, note that the nearest-city approach may not yield the "correct" result, just an approximation.

Conversion To Windows Zones

Most of the methods listed will return an IANA time zone id. If you need to convert to a Windows time zone for use with the TimeZoneInfo class in .NET, use the TimeZoneConverter library.

Don't use zone.tab

The tz database includes a file called zone.tab. This file is primarily used to present a list of time zones for a user to pick from. It includes the latitude and longitude coordinates for the point of reference for each time zone. This allows a map to be created highlighting these points. For example, see the interactive map shown on the moment-timezone home page.

While it may be tempting to use this data to resolve the time zone from a latitude and longitude coordinates, consider that these are points - not boundaries. The best one could do would be to determine the closest point, which in many cases will not be the correct point.

Consider the following example:

                            Time Zone Example Art

The two squares represent different time zones, where the black dot in each square is the reference location, such as what can be found in zone.tab. The blue dot represents the location we are attempting to find a time zone for. Clearly, this location is within the orange zone on the left, but if we just look at closest distance to the reference point, it will resolve to the greenish zone on the right.

How to calculate current position lat/long based on previously kown lat/long

This link GeoTools - How to do Dead Reckoning and course calculations using GeoTools classes answers my question. Given an angle, distance and starting geographic point, GeoTools (java) can be used to do the calculation. Refer to the SO link to see the sample.

Get lat/long given current point, distance and bearing

Needed to convert answers from radians back to degrees. Working code below:

import math

R = 6378.1 #Radius of the Earth
brng = 1.57 #Bearing is 90 degrees converted to radians.
d = 15 #Distance in km

#lat2 52.20444 - the lat result I'm hoping for
#lon2 0.36056 - the long result I'm hoping for.

lat1 = math.radians(52.20472) #Current lat point converted to radians
lon1 = math.radians(0.14056) #Current long point converted to radians

lat2 = math.asin( math.sin(lat1)*math.cos(d/R) +
math.cos(lat1)*math.sin(d/R)*math.cos(brng))

lon2 = lon1 + math.atan2(math.sin(brng)*math.sin(d/R)*math.cos(lat1),
math.cos(d/R)-math.sin(lat1)*math.sin(lat2))

lat2 = math.degrees(lat2)
lon2 = math.degrees(lon2)

print(lat2)
print(lon2)

Calculating position from another GPS position + distance

Once we know the meridional distance in km, and knowing this is 360° of latitude, we can calculate the offset due to moving north or south by x kilometres.

For every degree we move north or south we move (40007.86 / 360) = 111.13 km.

Also we'll include some error checking for locations near the poles..

And I'll add a more general formula for getting a new location given an offset north and east. (Negative for south and west as is the usual convention), this will only be accurate for small displacements.

function getNewLatitude(latitude, distanceKm) {    const meridionalRadiuskm = 40007.86;    latitude = (latitude + distanceKm / (meridionalRadiuskm / 360));    if (latitude > 90) return 180 - latitude;    if (latitude < -90) return -(180 + latitude);    return latitude;}
console.log(getNewLatitude(50, 100));console.log(getNewLatitude(50, -100));
// This function may also be useful, you can use this to get a new location base on a north/south / east/west offset in km. Note that accuracy will start to reduce as the offset increases. function getNewLocation(lat, lon, offsetNorthKm, offsetEastKm) { // The approximate distance in kilometres of one degree at 0,0. const ONE_DEGREE_KM = 111.32;
const deltaLatitude = offsetNorthKm / ONE_DEGREE_KM; const deltaLongitude = offsetEastKm / (ONE_DEGREE_KM * Math.cos(Math.PI * lat / 180));
let result = { lat: lat + deltaLatitude, lon: lon + deltaLongitude } return result;}

Calculate distance between two latitude-longitude points? (Haversine formula)

This link might be helpful to you, as it details the use of the Haversine formula to calculate the distance.

Excerpt:

This script [in Javascript] calculates great-circle distances between the two points –
that is, the shortest distance over the earth’s surface – using the
‘Haversine’ formula.

function getDistanceFromLatLonInKm(lat1,lon1,lat2,lon2) {
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;
}

function deg2rad(deg) {
return deg * (Math.PI/180)
}

Calculating distance between multiple points at the same time of the day

V2, Update (January 17, 2022)

Glad it works for you. If you are willing to avoid for-loops you could consider a dplyr approach. Have a look.

  library(dplyr)

df <- silvia %>%
rowwise() %>%
mutate(distance = geosphere::distGeo(c(lon1, lat1), c(lon2, lat2)))
df

The base R **apply-family would be another option.


V1 (January 16, 2022)

Hopefully this approach does help you. Often it is recommended to not use for-loops. However, I used one, since they are easy to understand.

I made the following assumptions:

  • boat1 is your boat. lat1 and lon1 represent the position of boat1 for any IDdatecode;
  • as I did not fully understand what you mean with "based on a unique time of the day" I assumed looping over each row is sufficient;
  • the function distGeo() is from geosphere package.
# loading your dataframe as "silvia"
silvia <- structure(list(Record = 1:10, IDdatecode = structure(c(1L, 2L, 3L, 3L, 4L, 4L, 5L, 5L, 6L, 6L),
.Label = c("d201805081203","d201805081204", "d201805081205", "d201805081206", "d201805081207", "d201805081208"),
class = "factor"), lon1 = c(12.40203333, 12.4071, 12.41165, 12.41165, 12.41485, 12.41485, 12.41663333,
12.41663333, 12.41841667, 12.41841667), lat1 = c(45.1067, 45.10921667, 45.11218333, 45.11218333, 45.11303333,
45.11303333, 45.11313333, 45.11313333, 45.11348333, 45.11348333), boat1 = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L), .Label = "RB", class = "factor"), lon2 = c(13.02718, 13.02585827, 13.02453654, 13.02173, 13.02321482,
13.02052301, 13.02189309, 13.01931602, 13.02057136, 13.01810904), lat2 = c(44.98946, 44.99031749, 44.99117498, 44.98792,
44.99203246, 44.98868065, 44.99288995, 44.98944129, 44.99374744, 44.99020194), boat2 = structure(c(1L, 1L, 1L, 2L,
1L, 2L, 1L, 2L, 1L, 2L), .Label = c("IMPERO II", "MISTRAL"), class = "factor")), .Names = c("Record", "IDdatecode",
"lon1", "lat1", "boat1", "lon2", "lat2", "boat2"), row.names = c(NA, -10L), class = "data.frame")

# for EACH ROW in "silvia" calculate the distance between c("lon1", "lat1") and c("lon2", "lat2")
for (i in 1:nrow(silvia)){

silvia$distance[i] <- geosphere::distGeo(c(silvia[i, "lon1"], silvia[i,"lat1"]),
c(silvia[i, "lon2"], silvia[i,"lat2"]))

}

# here you see the first 5 entrys of the df "silvia"
# the distances are calculated in metres
# the parameters a and f are set to WGS84 by default.
head(silvia, n=5)
#> Record IDdatecode lon1 lat1 boat1 lon2 lat2 boat2
#> 1 1 d201805081203 12.40203 45.10670 RB 13.02718 44.98946 IMPERO II
#> 2 2 d201805081204 12.40710 45.10922 RB 13.02586 44.99032 IMPERO II
#> 3 3 d201805081205 12.41165 45.11218 RB 13.02454 44.99117 IMPERO II
#> 4 4 d201805081205 12.41165 45.11218 RB 13.02173 44.98792 MISTRAL
#> 5 5 d201805081206 12.41485 45.11303 RB 13.02321 44.99203 IMPERO II
#> distance
#> 1 50943.77
#> 2 50503.93
#> 3 50118.46
#> 4 50005.52
#> 5 49774.51

Note. Created on 2022-01-16 by the reprex package (v2.0.1)



Related Topics



Leave a reply



Submit