2

I have a JSON array that is being populated with lat/long pairs among some other data between periods of 3 minutes.

I want to calculate the distances between each of the elements using a haversine function which takes two pairs of coordinates (start point and end point).

How can I loop through the array in order to calculate the distance between element A and B, then B and C, C -> D, D -> E and so on...

Here is how my JSON looks like:

{
  "data":[
    { 
      "latitude":37.80,
      "longitude":-121.493300,
      "report_date":"2019-07-01 12:00:00"
    },
    {
      "latitude":37.80,
      "longitude":-121.493300,
      "report_date":"2019-07-01 12:03:00"       
    },
    { 
      "latitude":37.80,
      "longitude":-121.493300,
      "report_date":"2019-07-01 12:06:00"   
    }
  ]
}

I haven't tried much other than just trying to start a for loop and manipulating some of the other data that I didn't show in the JSON example (that other data is irrelevant)

I think this is gonna be much more complicated than using a for loop, perhaps there is some other JS feature that could help me accomplish this? I need a way to store that iteration variable and make an exception for the first iteration?

var i = 0 
data.forEach(element => {
    var current_location = {lat: element.latitude, lon:element.longitude}
    i++
});

For every iteration I would like to be able to call my haversine(pair1, pair2) function and get the distance, I could now perform other operations like calculating speed, etc...

Shidersz
  • 16,846
  • 2
  • 23
  • 48
Luis
  • 305
  • 1
  • 14

7 Answers7

2

First, start defining a function that calculate the distance between two pairs of latitude/longitude coordinates, for example, using the one suggested on the next link:

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

Then, you can use a basic for loop (starting at index 1 to ensure having at least two point to compare) to generate your desired result, something like this:

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

function getDistance(pair1, pair2)
{
    const [lat1, lon1] = pair1, [lat2, lon2] = pair2;
    const R = 6371; // Radius of the earth in km.

    var dLat = deg2rad(lat2-lat1);
    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));

    // Return distance in km.
    return R * c;
}

const input = {
  "data": [
    {"latitude":37.80, "longitude":-121.493300, "report_date":"2019-07-01 12:00:00"},
    {"latitude":37.80, "longitude":-121.493300, "report_date":"2019-07-01 12:03:00"},
    {"latitude":37.80, "longitude":-121.493300, "report_date":"2019-07-01 12:06:00"}
  ]
};

// Get the distances:

const data = input.data;

for (let i = 1; i < data.length; i++)
{
    let timestamp1 = data[i-1].report_date;
    let timestamp2 = data[i].report_date;
    let pair1 = [data[i-1].latitude, data[i-1].longitude];
    let pair2 = [data[i].latitude, data[i].longitude];
    console.log(`Distance from ${timestamp1} to ${timestamp2}:`);
    console.log(getDistance(pair1, pair2));
}
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
Shidersz
  • 16,846
  • 2
  • 23
  • 48
1

You can use the index within the forEach function, and use the next point's index with it.

    data.forEach((element, index) => {
      if (index < data.length-1) { // prevent out of bounds errors
        var current_location = { lat: element.latitude, lon: element.longitude };
        var next_location = { lat: data[index + 1].latitude, lon: data[index + 1].longitude };
        haversine(current_location, next_location);
      }
    });
cWerning
  • 583
  • 1
  • 5
  • 15
1

You can use an index based for-loop:

var data = [{
       "latitude": 37.80,
       "longitude": -121.493300,
       "report_date": "2019-07-01 12:00:00"
    }, {
       "latitude": 37.80,
       "longitude": -121.493300,
       "report_date": "2019-07-01 12:03:00"
    }, {
       "latitude": 37.80,
       "longitude": -121.493300,
       "report_date": "2019-07-01 12:06:00"
}];

for (let index = 0; index < data.length - 1; index++) {
    const currentLocation = { lat: data[index].latitude, long: data[index].latitude };
    const nextLocation = { lat: data[index + 1].latitude, long: data[index + 1].latitude };

    haversine(currentLocation , nextLocation);
}
0xA03DA
  • 13
  • 3
1
if(data.length != 0) {    
    for(let i = 1; i<data.length; i++) {
      var currentLatitude = data[i-1].latitude;
      var currentLong = data[i-1].longitude;
      var nextLat= data[i].latitude;
      var nextLong= data[i].longitude;

      var pair1 = {lat: currentLatitude , lon: currentLong };
      var pair2 = {lat: nextLat, lon: nextLong};

      haversine(pair1 , pair2);

    }
}
1

In this case plain for loop looks more convenient.

var path = {
  "data": [{
    "latitude": 37.80,
    "longitude": -121.493301,
    "report_date": "2019-07-01 12:00:00"
  }, {
    "latitude": 37.80,
    "longitude": -121.493302,
    "report_date": "2019-07-01 12:03:00"
  }, {
    "latitude": 37.80,
    "longitude": -121.493303,
    "report_date": "2019-07-01 12:06:00"
  }]
};

for (var i = 1 /*sic*/ , prev, current; prev = path.data[i - 1], current = path.data[i]; ++i) {
  console.log(prev, current);
  //var distance=somefoo(prev,current);
  //do something with distance
}
Alex Kudryashev
  • 9,120
  • 3
  • 27
  • 36
0

You could do a few things.


data.forEach((element, i) => {
   var current_location = {lat: element.latitude, lon:element.longitude}
   if( i <= data.length - 2) {
       var next_location = {lat: data[i + 1], lon: data[i + 1]}
   }
});

And plug those values into your function. If your function returns the distance. The following will give you an array of distances

data.reduce((acc, element, i) => {
   if( i <= data.length - 2) {
       var current_location = {lat: element.latitude, lon:element.longitude}
       var next_location = {lat: data[i + 1], lon: data[i + 1]}
       var distance = haversine(current_location, next_location)
       acc.push(distance)
   }
   return acc
}, []);
Drew D
  • 11
  • 2
0

When iterating over your array, can't you just store the value from the previous iteration in some variable? (And on the first iteration, just continue, since you have no other element to compare with?)

E.g.

var foo = null;
for(var i = 0; i < arr.length; i++) {
    if(i == 0) {
        foo = arr[i];
        continue;   
    }           
    haversine(foo, arr[i]);
    foo = arr[i];
}           
jason120
  • 94
  • 3