Created
August 23, 2014 04:08
-
-
Save rgoldfinger/84d49def17283f864c18 to your computer and use it in GitHub Desktop.
algorithm to sort a trail, where the points are out of order
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var fs = require('fs'); | |
var path = require('path'); | |
var simple = require('simplify-js'); | |
var geolib = require('geolib'); | |
fs.readFile(path.join(__dirname, 'map.geojson'), 'utf8', function(err, data) { | |
// var jsonPoints = data; | |
// console.log(data); | |
var parsedData = JSON.parse(data); | |
var waypoints = parsedData.features; | |
var newWaypoints = []; | |
var tempPoint = {}; | |
for (var i = 0; i < waypoints.length; i++) { | |
tempPoint.lat = '' + waypoints[i]['geometry']['coordinates'][1]; | |
tempPoint.lon = '' + waypoints[i]['geometry']['coordinates'][0]; | |
tempPoint.id = "_id" + i; | |
newWaypoints.push(tempPoint); | |
tempPoint = {}; | |
} | |
var segmentsUnsorted = []; | |
var segmentStart = 0; //initialize to zero for the first segment | |
var tempDistance; | |
var tempSegment = []; | |
for (var j = 1; j < newWaypoints.length - 1; j ++) { | |
tempDistance = geolib.getDistance({ | |
latitude: newWaypoints[j].lat, | |
longitude: newWaypoints[j].lon | |
}, { | |
latitude: newWaypoints[j + 1].lat, | |
longitude: newWaypoints[j + 1].lon | |
}); | |
if (tempDistance > 700) { | |
// console.log("distance is: ", tempDistance, " at index ", j); | |
//we have a segment | |
for (var k = segmentStart; k <= j; k ++) { | |
tempSegment.push(newWaypoints[k]); | |
} | |
segmentsUnsorted.push(tempSegment); | |
tempSegment = []; | |
segmentStart = j + 1; | |
} | |
} | |
//push the first segment's children to results to get us started | |
var results = []; | |
segmentsUnsorted[0].forEach(function(item) { | |
results.push(item); | |
}); | |
// strategy: | |
// iterate through all segments repetedly until no more matches have been made | |
// keep track of segments that are used. | |
// push the closest segment, within bounds, to 'result' segment | |
var usedSegment = {0: true};//we always start by using the first segment | |
var nextSegment; | |
var distances; | |
var shortestIndex; | |
var shortest; | |
var tempShortest = null; | |
var getAllFourDistances = function(segment1, segment2) { | |
var segment1start = segment1[0]; | |
var segment1end = segment1[segment1.length -1]; | |
var segment2start = segment2[0]; | |
var segment2end = segment2[segment2.length -1]; | |
var a = geolib.getDistance({ | |
latitude: segment1start.lat, | |
longitude: segment1start.lon | |
}, { | |
latitude: segment2start.lat, | |
longitude: segment2start.lon | |
}); | |
var b = geolib.getDistance({ | |
latitude: segment1start.lat, | |
longitude: segment1start.lon | |
}, { | |
latitude: segment2end.lat, | |
longitude: segment2end.lon | |
}); | |
var c = geolib.getDistance({ | |
latitude: segment1end.lat, | |
longitude: segment1end.lon | |
}, { | |
latitude: segment2start.lat, | |
longitude: segment2start.lon | |
}); | |
var d = geolib.getDistance({ | |
latitude: segment1end.lat, | |
longitude: segment1end.lon | |
}, { | |
latitude: segment2end.lat, | |
longitude: segment2end.lon | |
}); | |
// start-start, start-end, end-start, end-end | |
return [a, b, c, d]; | |
}; | |
var getIndexOfShortest = function(arr) { | |
var shortest = arr[0]; | |
var index = 0; | |
for (var i = 1; i < arr.length; i ++) { | |
if (shortest > arr[i]) { | |
shortest = arr[i]; | |
index = i; | |
} | |
} | |
return index; | |
}; | |
var getShortest = function(arr) { | |
var shortest = arr[0]; | |
for (var i = 1; i < arr.length; i ++) { | |
if (shortest > arr[i]) { | |
shortest = arr[i]; | |
} | |
} | |
return shortest; | |
}; | |
var matchesThisRun = true; | |
var forwards; | |
var unshift; | |
while (matchesThisRun) { | |
console.log('new run', results.length); | |
matchesThisRun = false; | |
//iterate through all of the segments | |
for (var q = 1; q < segmentsUnsorted.length; q ++) { | |
// skip segments that have been used | |
if (!usedSegment[q]) { | |
//compare all four directions: start-start, start-end, end-start, end-end | |
distances = getAllFourDistances(results, segmentsUnsorted[q]); | |
shortestIndex = getIndexOfShortest(distances); | |
shortest = getShortest(distances); | |
if (! tempShortest || shortest < tempShortest.distance) { | |
// 0: start-start, 1: start-end, 2: end-start, 3: end-end | |
// this is a little complicated, but it determines whether the path is forwards or backwards | |
// and whether it goes at the beginning or end of the results | |
if (shortestIndex === 0 || shortestIndex === 2) { | |
forwards = true; | |
} else { | |
forwards = false; | |
} | |
if (shortestIndex === 0 || shortestIndex === 1) { | |
unshift = true; | |
} else { | |
unshift = false; | |
} | |
tempShortest = { | |
index: q, | |
distance: shortest, | |
forwards: forwards, | |
unshift: unshift | |
}; | |
} | |
if (tempShortest.distance < 4000) { | |
console.log('making match', tempShortest.distance); | |
matchesThisRun = true; | |
nextSegment = segmentsUnsorted[tempShortest.index]; | |
//now that we have the shortest, push it's members to results | |
if (tempShortest.forwards) { | |
if (tempShortest.unshift) { | |
nextSegment.forEach(function(item) { | |
results.unshift(item); | |
}); | |
} else { | |
nextSegment.forEach(function(item) { | |
results.push(item); | |
}); | |
} | |
} else { //segment is reversed | |
if (tempShortest.unshift) { | |
for (var t = nextSegment.length - 1; t > -1; t --) { | |
results.unshift(nextSegment[t]); | |
} | |
} else { | |
for (var t = nextSegment.length - 1; t > -1; t --) { | |
results.push(nextSegment[t]); | |
} | |
} | |
} | |
usedSegment[tempShortest.index] = true; | |
} | |
tempShortest = null; | |
} | |
} | |
} | |
var stringWaypoints = "var trailJSON = '" + JSON.stringify(results) + "'"; | |
fs.writeFile(path.join(__dirname, 'ct_clean.json'), stringWaypoints); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment