module PathCompare require 'json' # p1 and p2 given as geojson strings def self.compare(p1, p2) p1 = JSON.parse(p1)['coordinates'].first p2 = JSON.parse(p2)['coordinates'].first p1 = even_split(p1, 10) p2 = even_split(p2, 10) point_distances = [] p1.each_with_index do |coord, index| unless p2.size < index + 1 #TODO: Handle different length paths point_distances << Math.sqrt((coord[0] - p2[index][0]) ** 2) + Math.sqrt((coord[1] - p2[index][1]) ** 2) end end return point_distances.sum / point_distances.size end # Splits a linestring in to points split_size apart. (Not quite but it should be close) def self.even_split(coords, split_size) new_coords = [] current_distance = 0 target_distance = split_size last_coord = coords.first coords.each do |coord| if current_distance < target_distance current_distance += distance(coord[0], coord[1], last_coord[0], last_coord[1]) else new_coords << last_coord #TODO: Add a new point at exactly the right spot instead of using last point target_distance += split_size end last_coord = coord end new_coords end RAD_PER_DEG = Math::PI / 180 EARTH_DIAMETER_KM = 6371 def self.distance(lat1, lon1, lat2, lon2) dlon = lon2 - lon1 dlat = lat2 - lat1 a = calc(dlat, lat1, lat2, dlon) 2 * Math.atan2( Math.sqrt(a), Math.sqrt(1-a)) * EARTH_DIAMETER_KM * 1000 end def self.deg_to_rad(num) num * RAD_PER_DEG end def self.calc(dlat, lat1, lat2, dlon) (Math.sin(deg_to_rad(dlat)/2))**2 + Math.cos(deg_to_rad(lat1)) * Math.cos((deg_to_rad(lat2))) * (Math.sin(deg_to_rad(dlon)/2))**2 end end