Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ use approx::assert_relative_eq;
let longitude = -3.7038;
let latitude = 40.4168;
let resolution = 10_u8;
let qb = Cell::from_point(longitude, latitude, resolution);
let qb = Cell::from_point(latitude, longitude, resolution);
assert_eq!(qb, Cell::new(5234261499580514303_u64));

// Get a point from a Quadbin cell
let coords = Cell::new(5209574053332910079_u64).to_point();
assert_eq!(coords, (33.75, -11.178401873711776));
assert_eq!(coords, (-11.178401873711776, 33.75));

// Quadbin resolution at equator in m²
let area = Cell::from_point(0.0, 0.0, 26).area_m2();
Expand Down
22 changes: 11 additions & 11 deletions src/cells.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub(crate) fn tile_to_cell(tile: Tile) -> Cell {
}

/// Convert Quadbin cell into a tile
pub(crate) fn cell_to_tile(cell: Cell) -> Tile {
pub(crate) fn cell_to_tile(cell: &Cell) -> Tile {
assert!(cell.is_valid(), "Quadbin cell index is not valid");

let cell64 = cell.get();
Expand Down Expand Up @@ -83,38 +83,38 @@ pub(crate) fn cell_to_tile(cell: Cell) -> Tile {
}

/// Convert a geographic point into a cell.
pub(crate) fn point_to_cell(longitude: f64, latitude: f64, resolution: u8) -> Cell {
let long = clip_longitude(longitude);
let lat = clip_latitude(latitude);
pub(crate) fn point_to_cell(lat: f64, lng: f64, res: u8) -> Cell {
let lng = clip_longitude(lng);
let lat = clip_latitude(lat);

let tile = Tile::from_point(long, lat, resolution);
let tile = Tile::from_point(lat, lng, res);

tile.to_cell()
}

/// Convert cell into point
pub(crate) fn cell_to_point(cell: Cell) -> (f64, f64) {
pub(crate) fn cell_to_point(cell: &Cell) -> (f64, f64) {
assert!(cell.is_valid(), "Quadbin cell index is not valid");

let tile = cell.to_tile();
let lat = tile.to_latitude(0.5);
let lon = tile.to_longitude(0.5);

(lon, lat)
(lat, lon)
}

/// Compute the parent cell for a specific resolution.
pub(crate) fn cell_to_parent(cell: Cell, parent_resolution: u8) -> Cell {
pub(crate) fn cell_to_parent(cell: &Cell, parent_res: u8) -> Cell {
// Check resolution
let resolution = cell.resolution();
assert!(
parent_resolution < resolution,
parent_res < resolution,
"parent resolution should be greater than current resolution"
);

let result = (cell.get() & !(0x1F << 52))
| ((parent_resolution as u64) << 52)
| (FOOTER >> ((parent_resolution as u64) << 1));
| ((parent_res as u64) << 52)
| (FOOTER >> ((parent_res as u64) << 1));

Cell::new(result)
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod constants;
pub mod utils;

mod types;
pub use crate::types::{Cell, Tile};
pub use crate::types::Cell;

#[cfg(test)]
mod test;
12 changes: 8 additions & 4 deletions src/test/cells.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ fn test_point_to_cell() {
];

for (x, y, res, cell) in cases.iter() {
assert_eq!(Cell::from_point(*x, *y, *res), Cell::new(*cell));
assert_eq!(Cell::from_point(*y, *x, *res), Cell::new(*cell));
}
}

Expand All @@ -79,15 +79,19 @@ fn test_point_to_cell() {
fn test_cell_to_point() {
assert_eq!(
Cell::new(5209574053332910079_u64).to_point(),
(33.75, -11.178401873711776)
)
(-11.178401873711776, 33.75)
);

let coords = Cell::new(5309133744805926483_u64).to_point();
assert_relative_eq!(coords.0, -41.28303708488909, epsilon = 1e-6);
assert_relative_eq!(coords.1, 174.77727502584457, epsilon = 1e-6)
}

// Get cell resolution
#[test]
fn test_get_cell_resolution() {
let qb_cell = Cell::new(5209574053332910079_u64);
assert_eq!(Cell::resolution(qb_cell), 4_u8)
assert_eq!(qb_cell.resolution(), 4_u8)
}

// Get parent cell
Expand Down
4 changes: 2 additions & 2 deletions src/test/hashing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ fn test_tile_hashing() {

for (tile, hash) in cases.iter() {
// Tile to hash
assert_eq!(Tile::to_hash(*tile), *hash);
assert_eq!(Tile::to_hash(&tile), *hash);
// Hash to tile
assert_eq!(Tile::from_hash(*hash), *tile);
}
Expand All @@ -31,6 +31,6 @@ fn test_point_hashing() {
];

for (coords, res, hash) in cases.iter() {
assert_eq!(point_cover(coords.0, coords.1, *res), *hash);
assert_eq!(point_cover(coords.1, coords.0, *res), *hash);
}
}
24 changes: 12 additions & 12 deletions src/test/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const ACC: f64 = 1e-10;
// See https://github.com/CartoDB/quadbin-py/blob/master/tests/unit/test_utils.py
#[test]
fn test_point_to_tile_fraction() {
let tile = point_to_tile_fraction(-95.93965530395508_f64, 41.26000108568697_f64, 9_u8);
let tile = point_to_tile_fraction(41.26000108568697_f64, -95.93965530395508_f64, 9_u8);
assert_relative_eq!(tile.0, 119.552490234375_f64, epsilon = ACC);
assert_relative_eq!(tile.1, 191.47119140625_f64, epsilon = ACC);
assert_eq!(tile.2, 9_u8);
Expand All @@ -18,15 +18,15 @@ fn test_point_to_tile_fraction() {
#[test]
fn test_point_to_tile() {
// X axis
assert_eq!(Tile::from_point(-180.0, 0.0, 0), Tile::new(0, 0, 0));
assert_eq!(Tile::from_point(-180.0, 85.0, 2), Tile::new(0, 0, 2));
assert_eq!(Tile::from_point(180.0, 85.0, 2), Tile::new(0, 0, 2));
assert_eq!(Tile::from_point(-185.0, 85.0, 2), Tile::new(3, 0, 2));
assert_eq!(Tile::from_point(185.0, 85.0, 2), Tile::new(0, 0, 2));
assert_eq!(Tile::from_point(0.0, -180.0, 0), Tile::new(0, 0, 0));
assert_eq!(Tile::from_point(85.0, -180.0, 2), Tile::new(0, 0, 2));
assert_eq!(Tile::from_point(85.0, 180.0, 2), Tile::new(0, 0, 2));
assert_eq!(Tile::from_point(85.0, -185.0, 2), Tile::new(3, 0, 2));
assert_eq!(Tile::from_point(85.0, 185.0, 2), Tile::new(0, 0, 2));

// Y-axis
assert_eq!(Tile::from_point(-175.0, -95.0, 2), Tile::new(0, 3, 2));
assert_eq!(Tile::from_point(-175.0, 95.0, 2), Tile::new(0, 0, 2));
assert_eq!(Tile::from_point(-95.0, -175.0, 2), Tile::new(0, 3, 2));
assert_eq!(Tile::from_point(95.0, -175.0, 2), Tile::new(0, 0, 2));
}

// Estimate tile's area
Expand Down Expand Up @@ -60,7 +60,7 @@ fn test_tile_conversion() {

let lon = -45.0_f64;
let lat = 45.0_f64;
let tile = Tile::from_point(lon, lat, 10);
let tile = Tile::from_point(lat, lon, 10);

// Check Tile conversion
assert_eq!(tile.x, 384_u32);
Expand All @@ -85,17 +85,17 @@ fn test_tile_conversion() {
#[test]
fn test_tile_scalefactor() {
assert_relative_eq!(
tile_scalefactor(Tile::new(384, 368, 10)),
tile_scalefactor(&Tile::new(384, 368, 10)),
0.7075410884638627_f64,
epsilon = ACC
);
assert_relative_eq!(
tile_scalefactor(Tile::new(384, 368, 26)),
tile_scalefactor(&Tile::new(384, 368, 26)),
0.08626970361752928_f64,
epsilon = ACC
);
assert_relative_eq!(
tile_scalefactor(Tile::new(100, 100, 10)),
tile_scalefactor(&Tile::new(100, 100, 10)),
0.15910754230624527_f64,
epsilon = ACC
);
Expand Down
96 changes: 30 additions & 66 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,17 @@ use crate::utils::*;
use core::num::NonZeroU64;

/// A single tile coordinates
///
/// _Internal struct_
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct Tile {
pub(crate) struct Tile {
pub x: u32,
pub y: u32,
pub z: u8,
}

impl Tile {
/// Create a new tile.
///
/// # Examples
///
/// ```
/// let tile = quadbin::Tile::new(8108, 14336, 14);
/// ```
pub fn new(x: u32, y: u32, z: u8) -> Tile {
Tile { x, y, z }
}
Expand All @@ -28,82 +24,40 @@ impl Tile {
}

/// Compute the tile for a longitude and latitude in a specific resolution.
///
/// # Examples
/// ```
/// use quadbin::Tile;
/// // Create a tile from geographic coordinates:
/// let tile = Tile::from_point(-175.0, 95.0, 2);
/// assert_eq!(tile, Tile::new(0, 0, 2));
/// ```
pub fn from_point(longitude: f64, latitude: f64, resolution: u8) -> Self {
point_to_tile(longitude, latitude, resolution)
pub fn from_point(lat: f64, lng: f64, res: u8) -> Self {
point_to_tile(lat, lng, res)
}

/// Approximate tile area in square meters.
///
/// # Examples
/// ```
/// use quadbin::Tile;
/// use approx::assert_relative_eq;
///
/// // Create new tile
/// let tile = Tile::new(8108, 14336, 14);
/// // Estimate tile's area in m2
/// let area = Tile::area(tile);
/// assert_relative_eq!(area, 210619.87609208928_f64, epsilon = 1e-10);
/// ```
pub fn area(self) -> f64 {
pub fn area(&self) -> f64 {
tile_area(self)
}

/// Return tile's latitude.
///
/// See also [Tile::to_longitude].
///
/// # Examples
/// ```
/// use quadbin::Tile;
/// use approx::assert_relative_eq;
///
/// // Create new tile
/// let tile = Tile::new(8108, 14336, 14);
/// // Retrieve tile's latitude
/// let lat = tile.to_latitude(0.0);
/// assert_relative_eq!(lat, -79.17133464081944_f64, epsilon = 1e-10);
/// ```
pub fn to_latitude(self, offset: f64) -> f64 {
pub fn to_latitude(&self, offset: f64) -> f64 {
tile_to_latitude(self, offset)
}

/// Return tile's longitude.
///
/// See also [Tile::to_latitude].
///
/// # Examples
/// ```
/// use quadbin::Tile;
/// use approx::assert_relative_eq;
///
/// // Create new tile
/// let tile = Tile::new(8108, 14336, 14);
/// // Retrieve tile's latitude
/// let lat = tile.to_longitude(0.0);
/// assert_relative_eq!(lat, -1.845703125_f64, epsilon = 1e-10);
/// ```
pub fn to_longitude(self, offset: f64) -> f64 {
pub fn to_longitude(&self, offset: f64) -> f64 {
tile_to_longitude(self, offset)
}

/// Get tile's siblings.
// TODO:
// Add examples. See how to properly document direction
pub fn get_sibling(self, direction: u8) -> Option<Self> {
pub fn get_sibling(&self, direction: u8) -> Option<Self> {
tile_sibling(self, direction)
}

/// Compute a hash from the tile.
pub fn to_hash(self) -> u64 {
pub fn to_hash(&self) -> u64 {
to_tile_hash(self)
}

Expand Down Expand Up @@ -164,7 +118,7 @@ impl Cell {
/// let qb_cell = quadbin::Cell::new(5234261499580514303);
/// assert_eq!(qb_cell.is_valid(), true)
/// ```
pub fn is_valid(self) -> bool {
pub fn is_valid(&self) -> bool {
is_valid_cell(self.get())
}

Expand All @@ -176,7 +130,7 @@ impl Cell {
/// let res = qb_cell.resolution();
/// assert_eq!(res, 10)
/// ```
pub fn resolution(self) -> u8 {
pub fn resolution(&self) -> u8 {
((self.0.get() >> 52) & 0x1F) as u8
}

Expand All @@ -188,8 +142,8 @@ impl Cell {
/// let parent = qb_cell.parent(2_u8);
/// assert_eq!(parent, quadbin::Cell::new(5200813144682790911))
/// ```
pub fn parent(self, parent_resolution: u8) -> Cell {
cell_to_parent(self, parent_resolution)
pub fn parent(&self, parent_res: u8) -> Cell {
cell_to_parent(self, parent_res)
}

/// Computes the area of this Quadbin cell, in m².
Expand All @@ -204,7 +158,7 @@ impl Cell {
/// assert_relative_eq!(area, 888546364.7859862, epsilon = 1e-6)
///
/// ```
pub fn area_m2(self) -> f64 {
pub fn area_m2(&self) -> f64 {
self.to_tile().area()
}

Expand All @@ -220,22 +174,32 @@ impl Cell {
/// assert_relative_eq!(area, 888.5463647859862, epsilon = 1e-6)
///
/// ```
pub fn area_km2(self) -> f64 {
pub fn area_km2(&self) -> f64 {
self.area_m2() / 1_000_000_f64
}

/// Convert a Quadbin cell into geographic point.
pub fn to_point(self) -> (f64, f64) {
///
/// Returns a tuple with latitude and longitude in degrees.
///
pub fn to_point(&self) -> (f64, f64) {
cell_to_point(self)
}

/// Convert a geographic point into a Quadbin cell.
pub fn from_point(longitude: f64, latitude: f64, resolution: u8) -> Cell {
point_to_cell(longitude, latitude, resolution)
///
/// # Example
///
/// ```
/// let cell = quadbin::Cell::from_point(-41.28303675124842, 174.77727344223067, 26);
/// assert_eq!(cell.get(), 5309133744805926483_u64)
/// ```
pub fn from_point(lat: f64, lng: f64, res: u8) -> Cell {
point_to_cell(lat, lng, res)
}

/// Convert a Quadbin cell into a tile.
pub fn to_tile(self) -> Tile {
pub(crate) fn to_tile(&self) -> Tile {
cell_to_tile(self)
}
}
Loading