Skip to content

Commit

Permalink
info about distance calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
mamantoha committed Apr 12, 2024
1 parent 5f00596 commit bccffb3
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 0 deletions.
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,39 @@ puts "Nearest to London: #{nearest_point.first.name} (longitude #{nearest_point.
# Nearest to London: London (longitude -0.127647, latitude 51.507322)
```

### Distance

For distance calculations, the squared Euclidean distance is used. However, you can easily monkey-patch the `Kd::Tree#distance` method to implement another algorithm, such as the Haversine formula, to calculate distances between two points given their latitudes and longitudes.

```crystal
require "haversine"
module Kd
class Tree(T)
private def distance(m : T, n : T)
# Calling `Haversine.distance` with 2 pairs of latitude/longitude coordinates.
# Returns a distance in meters.
Haversine.distance({m.latitude, m.longitude}, {n.latitude, n.longitude}).to_meters
end
end
end
points = [
GeoLocation.new("New York", -73.935242, 40.730610),
GeoLocation.new("Los Angeles", -118.243683, 34.052235),
GeoLocation.new("London", -0.127647, 51.507322),
GeoLocation.new("Tokyo", 139.691711, 35.689487),
]
kd_tree = Kd::Tree(GeoLocation).new(points)
# Find the nearest point to London
target = GeoLocation.new("Near London", -0.125740, 51.508530)
nearest_point = kd_tree.nearest(target, 1)
puts "Nearest to London: #{nearest_point.first.name} (longitude #{nearest_point.first.longitude}, latitude #{nearest_point.first.latitude})"
# Nearest to London: London (longitude -0.127647, latitude 51.507322)
```

## Performance

Using a tree with 1 million points `[x, y] of Float64` on my i7-8550U CPU @ 1.80GHz:
Expand Down
55 changes: 55 additions & 0 deletions samples/haversine_distance.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
require "haversine"
require "../src/kd_tree"

class GeoLocation
property name : String
property longitude : Float64
property latitude : Float64

def initialize(@name : String, @longitude : Float64, @latitude : Float64)
end

# Define an indexer to allow easy access by index for longitude and latitude
def [](index : Int32) : Float64
case index
when 0 then @longitude
when 1 then @latitude
else raise "Index out of bounds"
end
end

# Assuming all GeoLocation objects are 2-dimensional
def size
2
end
end

module Kd
class Tree(T)
private def distance(m : T, n : T)
# Calling `Haversine.distance` with 2 pairs of latitude/longitude coordinates.
# Returns a distance in meters.
Haversine.distance({m.latitude, m.longitude}, {n.latitude, n.longitude}).to_meters
end
end
end

# Example Usage:
# Create an array of GeoLocation points
points = [
GeoLocation.new("New York", -73.935242, 40.730610),
GeoLocation.new("Los Angeles", -118.243683, 34.052235),
GeoLocation.new("London", -0.127647, 51.507322),
GeoLocation.new("Paris", 2.349014, 48.864716),
GeoLocation.new("Tokyo", 139.691711, 35.689487),
]

# Initialize the KD-tree with these points
kd_tree = Kd::Tree(GeoLocation).new(points)

# Find the nearest point to London
target = GeoLocation.new("Near London", -0.125740, 51.508530)
nearest_point = kd_tree.nearest(target, 3)
puts "First: #{nearest_point[0].name} (longitude #{nearest_point[0].longitude}, latitude #{nearest_point[0].latitude})"
puts "Second: #{nearest_point[1].name} (longitude #{nearest_point[1].longitude}, latitude #{nearest_point[1].latitude})"
puts "Third: #{nearest_point[2].name} (longitude #{nearest_point[2].longitude}, latitude #{nearest_point[2].latitude})"
2 changes: 2 additions & 0 deletions shard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ dependencies:
development_dependencies:
ameba:
github: crystal-ameba/ameba
haversine:
github: geocrystal/haversine

crystal: ">= 1.0.0"

Expand Down

0 comments on commit bccffb3

Please sign in to comment.