9

Background:

I'm working with transport routes and Google provides Route points far apart enough to create 'shapes'. These are the bus/train routes you see in Google Maps.

My Requirement:

Google's points are far enough to create straight lines. However I want a point every, say, 5 metres.

Problem:

So, say I have two points [lat,long]:

[-33.8824219918503,151.206686052582] and [-33.8815434600467,151.206556440037]

Given those two points I can calculate the distance between them. Say it's 1km for the sake of argument.

So we can imagine an imaginary straight line in between those two points.

How do I generate coordinates for that imaginary line for every, say, 5 metres?

andy
  • 8,775
  • 13
  • 77
  • 122

3 Answers3

14

Destination point given distance and bearing from start point applied to your problem:

class Numeric
  def to_rad
    self * Math::PI / 180
  end
  def to_deg
    self * 180 / Math::PI
  end
end

include Math

R = 6371.0

def waypoint(φ1, λ1, θ, d)
  φ2 = asin( sin(φ1) * cos(d/R) + cos(φ1) * sin(d/R) * cos(θ) )
  λ2 = λ1 + atan2( sin(θ) * sin(d/R) * cos(φ1), cos(d/R) - sin(φ1) * sin(φ2) )
  λ2 = (λ2 + 3 * Math::PI) % (2 * Math::PI) - Math::PI # normalise to -180..+180°
  [φ2, λ2]
end

φ1, λ1 = -33.to_rad, -71.6.to_rad   # Valparaíso
φ2, λ2 = 31.4.to_rad, 121.8.to_rad  # Shanghai

d = R * acos( sin(φ1) * sin(φ2) + cos(φ1) * cos(φ2) * cos(λ2 - λ1) )
θ = atan2( sin(λ2 - λ1) * cos(φ2), cos(φ1) * sin(φ2) - sin(φ1) * cos(φ2) * cos(λ2 - λ1) )

waypoints = (0..d).step(2000).map { |d| waypoint(φ1, λ1, θ, d) }

markers = waypoints.map { |φ, λ| "#{φ.to_deg},#{λ.to_deg}" }.join("|")

puts "http://maps.googleapis.com/maps/api/staticmap?size=640x320&sensor=false&markers=#{markers}"

Generates a Google Static Maps link with the waypoints from Valparaíso to Shanghai every 2,000 km:

http://maps.googleapis.com/maps/api/staticmap?size=640x320&sensor=false&markers=-33.0,-71.60000000000002|-32.54414813683714,-93.02142653011552|-28.59922979115139,-113.43958859125276|-21.877555679819015,-131.91586675556778|-13.305784544363858,-148.5297601858932|-3.7370081151180683,-163.94988578467394|6.094273692291354,-179.03345538133888|15.493534924596633,165.33401731030006|23.70233917422386,148.3186618914762|29.83806632244171,129.34766276764626

Community
  • 1
  • 1
Stefan
  • 109,145
  • 14
  • 143
  • 218
  • This is great @stefan. I know it's out of the scope of the question, but would you mind explaining some of the maths and/or pointing me in the right direction? I get the trigonometry part (in theory) but I don't get the unit of distance. It seems it doesn't matter which unit it is? – andy Feb 28 '14 at 00:04
  • Oh, and why does everything have to be converted to radians? – andy Feb 28 '14 at 00:05
  • 1
    Just use the same unit. Traveling 1 km on a 6,000 km sphere is equivalent to traveling 1 mm on a 6,000 mm sphere. The conversion is needed because [`Math`](http://www.ruby-doc.org/core-2.1.1/Math.html)'s trigonometric functions expect radians. – Stefan Feb 28 '14 at 08:11
3

Step 1 - Get the overall distance

Comprehensive answer can be found here: http://www.movable-type.co.uk/scripts/latlong.html

TL;DR:

This uses the ‘haversine’ formula to calculate the great-circle distance between two points – that is, the shortest distance over the earth’s surface – giving an ‘as-the-crow-flies’ distance between the points (ignoring any hills, of course!).

var R = 6371; // km
var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad();
var lat1 = lat1.toRad();
var lat2 = lat2.toRad();

var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
        Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); 
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
var distance = R * c;

Step 2 - Get the percentage travelled.

Now you have the distance for this straight line, you can then work out a percentage of the overall distance for each 5 meters.

Step 3 - Apply the percentage travelled to the difference between the Latitude and Longitude

Find out the difference between the starting latitude and the final latitude. With this number, multiply it by the percentage traveled (as a decimal). This can then be added back to the starting latitude to find the current latitude of this point. Repeat for longitude.

benjaminjosephw
  • 4,369
  • 3
  • 21
  • 40
  • This is javascript but you could do the same thing in Ruby I'm sure. – benjaminjosephw Feb 27 '14 at 11:24
  • thanks @benjaminjosephw. But hold on, this gives me the distance between two points right? But I want to know how to generate points every 5 metres along a line. Get what I mean? – andy Feb 27 '14 at 11:26
  • Sorry, update added. This make sense and seems logical to me but I have to confess that I am not a mathematician. Please check this works first! – benjaminjosephw Feb 27 '14 at 11:48
  • @benjaminjosephw Can you elaborate on the specifics for steps 2 + 3 please? – Alan Jul 26 '15 at 18:40
1

The following solution isn't exactly what you've requested, but may suffice for your purposes...

Check the official docs (https://developers.google.com/maps/documentation/javascript/reference) for the interpolate method. From the docs: 'Returns the LatLng which lies the given fraction of the way between the origin LatLng and the destination LatLng.'

So if you know that your original points are, say, 100m apart, and you specify 0.05 as the fraction, the method will return the lat/lng along that line for every 5m.

Nick Clark
  • 89
  • 3