Förderjahr 2016 / Projekt Call #11 / ProjektID: 1983 / Projekt: Prometheus
Distance between two locations
To get the distance between two locations (in latitude and longitude) you can use the haversine formula.
The haversine formula determines the great-circle distance between two points on a sphere given their longitudes and latitudes. Important in navigation, it is a special case of a more general formula in spherical trigonometry, the law of haversines, that relates the sides and angles of spherical triangles.
Fortunately there already exists a Clojure library that does this for us: haversine.
To use the library add [haversine "0.1.1"]
to the :dependencies
of your project.clj
file. Then you start your server or repl again to fetch the new dependency.
Now you can require the library in your code by adding it to your namespace macro at the top of your file or by executing this in your repl.
(ns facebook-example.core (:require [haversine.core :as haversine]))
Here is an example of calculating the distance from Museumsquartier to Burggarten:
(def mq {:latitude 48.2033369 :longitude 16.3564279}) (def bg {:latitude 48.2048528 :longitude 16.3650968}) (haversine/haversine mq bg); 0.6643769594161104 (kilometers)
Now let's say you are building a game with millions of treasure chests and your player owns a treasure chest detection device which reveals all treasure chests within 1km of the player's location.
One way to figure out which treasure chests the player can detect would be to compute all the distances between the player and the treasure chests.
; millions of treasure chests represented by lat/long (def treasure-chests [{:latitude 48.2033369 :longitude 16.3564279}, {:latitude 48.2048528 :longitude 16.3650968}, …]) ; the current location of our player (Museumsquartier) (def player-location {:latitude 48.2033369 :longitude 16.3564279}) ; a helper function that tells us if a treasure chest is within 1km of our player (defn detectable? [player-location treasure-chest] (<= (haversine/haversine player-location treasure-chest) 1.0)) ; go through all treasure-chests and select all that are within 1km of the player (detectable) ; by calculating all the distances and comparing whether they are are <= 1km (filter (partial detectable? player-location) treasure-chests)
Optimization for calculating a lot of distances
Depending on how your game is designed it might be quite common to check which of the treasure chests a player can detect in a given moment (or rather location).
You might want to compute this for all players over and over again as their locations change over time. Another way to think about this is to define a range (bounding box) of 1km around the player (detection-range
) and to check which treasure chests are within that range.
This way you don't have to calculate all the distances between the player and all the treasure chests. Instead you can use simple comparisons to figure out if a given treasure chest is within the detection-range
or not.
; calculating and defining the detection range (1km distance from our player) (def detection-range (haversine/neighborhood (assoc player-location :distance-from 1))) ; a helper function that tells us if a treasure chest is within a given detection range (defn in-range? [detection-range treasure-chest] (and (<= (:latitude location) (:maxlatitude detection-range)) (<= (:longitude location) (:maxlongitude detection-range)) (>= (:latitude location) (:minlatitude detection-range)) (>= (:longitude location) (:minlongitude detection-range)))) ; go through all treasure-chests and select all that are within 1km of the player (detectable) ; this time using the detection range instead of calculating the distances (filter (partial in-range? detection-range) treasure-chests)
Further reading
https://en.wikipedia.org/wiki/Haversine_formula