Places
Distances on the globe, bounding boxes for near-me queries in SQL, and geohashes to group points.
Version 1.0.0 · 5 functions · 1 crate
Functions
What use geo.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use distance_km, bounding_box from geo (Quillo 0.6).
distance_km(lat1: float, lon1: float, lat2: float, lon2: float) → floatHow far apart two points are, in kilometres, along the globe (haversine).
bounding_box(lat: float, lon: float, radius_km: float) → any{ min_lat, max_lat, min_lon, max_lon } around a point: where lat between ? and ? and lon between ? and ? finds the candidates, distance_km the exact ones.
geohash_encode(lat: float, lon: float, precision: int) → stror an errorThe geohash of a point, precision characters long (5 is about 5 km, 7 about 150 m).
geohash_decode(hash: str) → anyor an errorThe centre of a geohash's cell: { lat, lon }.
geohash_neighbors(hash: str) → listor an errorThe eight cells around a geohash's, to search a cell and its neighbours.
Get it
$ quillo install geo # geo.qwer into this folder$ quillo install geo --example # and its example, geo.qweOr with curl:
$ curl -O https://quillolang.org/plugins/files/geo.qwer$ curl -O https://quillolang.org/plugins/files/geo.qweThen, in your program, all of it or only what you call:
use geo.qweruse distance_km, bounding_box from geo // Quillo 0.6: only theseIt uses this crate, which cargo fetches the first time the plugin is built:
geohash = "0.13"Example
// Shops near a visitor, nearest first.//// quillo run geo.qwe then open http://localhost:8080/near?lat=52.37&lon=4.89use "geo.qwer"let shops = [ { name: "Centraal", lat: 52.3791, lon: 4.9003 }, { name: "Zuid", lat: 52.3389, lon: 4.8723 }, { name: "Utrecht", lat: 52.0907, lon: 5.1214 },]route GET /near ? { lat: float, lon: float } { let box = bounding_box(lat, lon, 10.0) shops | filter((s) => s.lat >= box.min_lat && s.lat <= box.max_lat && s.lon >= box.min_lon && s.lon <= box.max_lon) | map((s) => { name: s.name, km: round(distance_km(lat, lon, s.lat, s.lon), 2), cell: geohash_encode(s.lat, s.lon, 6)? }) | sort_by((s) => s.km)}$ quillo run geo.qwe$ curl 'localhost:8080/near?lat=52.37&lon=4.89'Source
//! Places: distances on the globe, bounding boxes for "near me" queries in SQL, and geohashes for grouping points.//! version: 1.0.0//!//! [dependencies]//! geohash = "0.13"use serde_json::{json, Value};const EARTH_KM: f64 = 6371.0088;/// How far apart two points are, in kilometres, along the globe (haversine).pub fn distance_km(lat1: f64, lon1: f64, lat2: f64, lon2: f64) -> f64 { let (p1, p2) = (lat1.to_radians(), lat2.to_radians()); let (dp, dl) = ((lat2 - lat1).to_radians(), (lon2 - lon1).to_radians()); let a = (dp / 2.0).sin().powi(2) + p1.cos() * p2.cos() * (dl / 2.0).sin().powi(2); 2.0 * EARTH_KM * a.sqrt().asin()}/// `{ min_lat, max_lat, min_lon, max_lon }` around a point: `where lat between ? and ? and lon between ? and ?` finds the candidates, `distance_km` the exact ones.pub fn bounding_box(lat: f64, lon: f64, radius_km: f64) -> Value { let dlat = (radius_km / EARTH_KM).to_degrees(); let dlon = (radius_km / (EARTH_KM * lat.to_radians().cos().abs().max(1e-6))).to_degrees(); json!({ "min_lat": (lat - dlat).max(-90.0), "max_lat": (lat + dlat).min(90.0), "min_lon": (lon - dlon).max(-180.0), "max_lon": (lon + dlon).min(180.0) })}/// The geohash of a point, `precision` characters long (5 is about 5 km, 7 about 150 m).pub fn geohash_encode(lat: f64, lon: f64, precision: i64) -> Result<String, String> { geohash::encode(geohash::Coord { x: lon, y: lat }, precision.clamp(1, 12) as usize).map_err(|e| e.to_string())}/// The centre of a geohash's cell: `{ lat, lon }`.pub fn geohash_decode(hash: &str) -> Result<Value, String> { let (c, _, _) = geohash::decode(hash).map_err(|e| e.to_string())?; Ok(json!({ "lat": c.y, "lon": c.x }))}/// The eight cells around a geohash's, to search a cell and its neighbours.pub fn geohash_neighbors(hash: &str) -> Result<Vec<String>, String> { let n = geohash::neighbors(hash).map_err(|e| e.to_string())?; Ok(vec![n.n, n.ne, n.e, n.se, n.s, n.sw, n.w, n.nw])}Related
h3.qwer · 1.0.0H3 hexagon cells: the cell of a point at a resolution, its neighbours within k rings, its outline for a map, and distances between cells.7 views · 8 downloadsSpatial index spatial_index.qwer · 1.0.0An R-tree of places in memory: the nearest ones to a point, all within a distance, those in a map's view, and markers clustered for it.6 views · 8 downloadsCoordinates coordinates.qwer · 1.0.0Coordinates as people write them, such as 52°22'N 4°53'E or N 52° 22.2', read as one, written as degrees-minutes-seconds, and converted to and from UTM.7 views · 8 downloadsGPX tracks gpx.qwer · 1.0.0GPX tracks from watches and phones read: distance, climbing, duration, moving pace, per-kilometre splits, and the points for a map line.7 views · 8 downloadsKML and KMZ kml.qwer · 1.0.0KML and KMZ files from Google Earth and My Maps read to GeoJSON, placemarks with their names, descriptions, folders and extended data, and GeoJSON written back as KML or KMZ.7 views · 8 downloadsMaidenhead locators maidenhead.qwer · 1.0.0Maidenhead grid locators as radio amateurs use them (FN31pr, JN58td): from a latitude and longitude at 2 to 10 characters, back to the square's centre and corners, and the distance and bearing between two.7 views · 8 downloadsThread 0 posts
On Places: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.