///|
const MAX_MERCATOR_LAT : Double = 85.05112878
///|
pub fn point_to_tile(point : Point, zoom : Int) -> Result[Tile, RouteError] {
match validate_zoom(zoom) {
Ok(_) => ()
Err(err) => return Err(err)
}
match validate_point(point, 0) {
Ok(_) => ()
Err(err) => return Err(err)
}
let tile_count = 1 << zoom
let lat = point.lat.clamp(min=-MAX_MERCATOR_LAT, max=MAX_MERCATOR_LAT)
let lat_rad = deg_to_rad(lat)
let raw_x = ((point.lon + 180.0) / 360.0 * tile_count.to_double())
.floor()
.to_int()
let mercator = @math.ln(@math.tan(lat_rad) + 1.0 / @math.cos(lat_rad))
let raw_y = ((1.0 - mercator / @math.PI) / 2.0 * tile_count.to_double())
.floor()
.to_int()
Ok({
z: zoom,
x: raw_x.clamp(min=0, max=tile_count - 1),
y: raw_y.clamp(min=0, max=tile_count - 1),
})
}
///|
pub fn tile_cover(
points : ArrayView[Point],
zoom : Int,
) -> Result[Array[Tile], RouteError] {
match validate_zoom(zoom) {
Ok(_) => ()
Err(err) => return Err(err)
}
match require_points(points) {
Ok(_) => ()
Err(err) => return Err(err)
}
let tiles = Array::new()
if points.length() == 1 {
match point_to_tile(points[0], zoom) {
Ok(tile) => push_unique_tile(tiles, tile)
Err(err) => return Err(err)
}
return Ok(tiles)
}
for i in 1.. ()
Err(err) => return Err(err)
}
}
Ok(tiles)
}
///|
pub fn tiles_to_string(tiles : ArrayView[Tile]) -> String {
let parts = Array::new(capacity=tiles.length())
for tile in tiles {
parts.push(tile.key())
}
parts.join(", ")
}
///|
fn add_segment_tiles(
out : Array[Tile],
a : Point,
b : Point,
zoom : Int,
) -> Result[Unit, RouteError] {
let start_tile = match point_to_tile(a, zoom) {
Ok(tile) => tile
Err(err) => return Err(err)
}
let end_tile = match point_to_tile(b, zoom) {
Ok(tile) => tile
Err(err) => return Err(err)
}
let steps = max_int(
(end_tile.x - start_tile.x).abs(),
(end_tile.y - start_tile.y).abs(),
)
if steps == 0 {
push_unique_tile(out, start_tile)
return Ok(())
}
let mut step = 0
while step <= steps {
let t = step.to_double() / steps.to_double()
// Follow the shortest longitude arc so antimeridian routes stay local.
let point = interpolate_point_unchecked(a, b, t)
match point_to_tile(point, zoom) {
Ok(tile) => push_unique_tile(out, tile)
Err(err) => return Err(err)
}
step = step + 1
}
Ok(())
}