Skip to content

Commit

Permalink
002
Browse files Browse the repository at this point in the history
  • Loading branch information
jessekrubin committed Aug 4, 2023
1 parent 25bcfcd commit 32bf63f
Show file tree
Hide file tree
Showing 11 changed files with 211 additions and 26 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# 0.0.2

- Added `__len__` to TilesGenerator for pbars
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pyutiles"
version = "0.0.1"
version = "0.0.2"
edition = "2021"
include = ["src/**/*", "Cargo.toml", "LICENSE", "README.md"]
license = "MIT OR Apache-2.0"
Expand Down
162 changes: 148 additions & 14 deletions crates/utiles/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -814,12 +814,20 @@ impl Tile {
Tile::new(x, y, z)
}

pub fn fmt_zxy(&self) -> String {
format!("{}/{}/{}", self.z, self.x, self.y)
pub fn fmt_zxy(&self, sep: Option<&str>) -> String {
match sep {
Some(sep) => format!("{}{}{}{}{}", self.z, sep, self.x, sep, self.y),
None => format!("{}/{}/{}", self.z, self.x, self.y),
}
}

pub fn fmt_zxy_ext(&self, ext: &str) -> String {
format!("{}/{}/{}.{}", self.z, self.x, self.y, ext)
pub fn fmt_zxy_ext(&self, ext: &str, sep: Option<&str>) -> String {
match sep {
Some(sep) => {
format!("{}{}{}{}{}.{}", self.z, sep, self.x, sep, self.y, ext)
}
None => format!("{}/{}/{}.{}", self.z, self.x, self.y, ext),
}
}

pub fn parent_id(&self) -> u64 {
Expand Down Expand Up @@ -1031,17 +1039,51 @@ pub fn as_zooms(zoom_or_zooms: ZoomOrZooms) -> Vec<u8> {
}
}

pub struct TilesRange {
pub struct TileRange {
curx: u32,
cury: u32,
pub minx: u32,
pub maxx: u32,
pub miny: u32,
pub maxy: u32,
pub zoom: u8,
minx: u32,
maxx: u32,
miny: u32,
maxy: u32,
zoom: u8,
}

impl Iterator for TilesRange {
impl TileRange {
pub fn new(minx: u32, maxx: u32, miny: u32, maxy: u32, zoom: u8) -> Self {
Self {
curx: minx,
cury: miny,
minx,
maxx,
miny,
maxy,
zoom,
}
}

pub fn minx(&self) -> u32 {
self.minx
}
pub fn maxx(&self) -> u32 {
self.maxx
}
pub fn miny(&self) -> u32 {
self.miny
}
pub fn maxy(&self) -> u32 {
self.maxy
}
pub fn zoom(&self) -> u8 {
self.zoom
}

pub fn length(&self) -> u64 {
((self.maxx - self.minx + 1) * (self.maxy - self.miny + 1)) as u64
}
}

impl Iterator for TileRange {
type Item = (u32, u32, u8);

fn next(&mut self) -> Option<Self::Item> {
Expand All @@ -1063,11 +1105,37 @@ impl Iterator for TilesRange {
}
}

pub struct TilesRanges {
ranges: Vec<TilesRange>,
pub struct TileRanges {
ranges: Vec<TileRange>,
}

impl TileRanges {
pub fn new(minx: u32, maxx: u32, miny: u32, maxy: u32, zoom: u8) -> Self {
Self {
ranges: vec![TileRange::new(minx, maxx, miny, maxy, zoom)],
}
}

pub fn length(&self) -> u64 {
self.ranges.iter().map(|r| r.length()).sum()
}
}

impl From<TileRange> for TileRanges {
fn from(range: TileRange) -> Self {
Self {
ranges: vec![range],
}
}
}

impl From<Vec<TileRange>> for TileRanges {
fn from(ranges: Vec<TileRange>) -> Self {
Self { ranges }
}
}

impl Iterator for TilesRanges {
impl Iterator for TileRanges {
type Item = (u32, u32, u8);

fn next(&mut self) -> Option<Self::Item> {
Expand Down Expand Up @@ -1137,6 +1205,69 @@ pub fn bounding_tile(bbox: BBox, truncate: Option<bool>) -> Tile {
// (minx, miny, maxx, maxy)
// }

pub fn tile_ranges(bounds: (f64, f64, f64, f64), zooms: ZoomOrZooms) -> TileRanges {
let zooms = as_zooms(zooms);
let bboxthing = BBox {
north: bounds.3,
south: bounds.1,
east: bounds.2,
west: bounds.0,
};
let bboxes: Vec<BBox> = bboxthing
.bboxes()
.into_iter()
.map(|bbox| {
// clip to web mercator extent
BBox {
north: bbox.north.min(85.051_129),
south: bbox.south.max(-85.051_129),
east: bbox.east.min(180.0),
west: bbox.west.max(-180.0),
}
})
.collect();
let ranges: Vec<TileRange> = bboxes
.into_iter()
.flat_map(move |bbox| {
let zooms = zooms.clone();
zooms.into_iter().map(move |zoom| {
let upper_left_lnglat = LngLat {
xy: coord! { x: bbox.west, y: bbox.north },
};
let lower_right_lnglat = LngLat {
xy: coord! { x: bbox.east, y: bbox.south },
};
let top_left_tile = Tile::from_lnglat_zoom(
upper_left_lnglat.lng(),
upper_left_lnglat.lat(),
zoom,
Some(false),
);
let bottom_right_tile = Tile::from_lnglat_zoom(
lower_right_lnglat.lng() - LL_EPSILON,
lower_right_lnglat.lat() + LL_EPSILON,
zoom,
Some(false),
);
TileRange::new(
top_left_tile.x,
bottom_right_tile.x,
top_left_tile.y,
bottom_right_tile.y,
zoom,
)
})
})
.collect();

TileRanges::from(ranges)
}

pub fn tiles_count(bounds: (f64, f64, f64, f64), zooms: ZoomOrZooms) -> u64 {
let ranges = tile_ranges(bounds, zooms);
ranges.length()
}

pub fn tiles(
bounds: (f64, f64, f64, f64),
zooms: ZoomOrZooms,
Expand Down Expand Up @@ -1289,6 +1420,9 @@ mod tests {
let tiles = tiles(bounds, 14.into());
let expect = vec![Tile::new(3413, 6202, 14), Tile::new(3413, 6203, 14)];
assert_eq!(tiles.collect::<Vec<Tile>>(), expect);

let ntiles = tiles_count(bounds, 14.into());
assert_eq!(ntiles, 2);
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "maturin"

[project]
name = "utiles"
version = "0.0.1"
version = "0.0.2"
description = "utiles = (utils + tiles) * rust"
requires-python = ">=3.7"
classifiers = [
Expand Down
2 changes: 1 addition & 1 deletion python/utiles/__about__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
__title__ = "utiles"
__description__ = "utiles = utils + tiles + rust"
__pkgroot__ = __file__.replace("__about__.py", "").rstrip("/\\")
__version__ = "0.0.1"
__version__ = "0.0.2"
1 change: 1 addition & 0 deletions python/utiles/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
"simplify",
"tile",
"tiles",
"tiles_count",
"tiles_list",
"tiletype",
"tiletype2headers",
Expand Down
7 changes: 6 additions & 1 deletion python/utiles/libutiles.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ from __future__ import annotations

from typing import (
Any,
Collection,
Iterable,
Iterator,
Optional,
Expand Down Expand Up @@ -127,6 +128,10 @@ class Tile:
def ur(self) -> LngLat: ...
def __eq__(self, other: Any) -> bool: ...
def __ge__(self, other: Tile | tuple[int, int, int]) -> bool: ...
def qk(self) -> str: ...
def quadkey(self) -> str: ...
def fmt_zxy(self, sep: str | None) -> str: ...
def fmt_zxy_ext(self, ext: str, sep: str | None) -> str: ...
# def __getitem__(self, index: int) -> bool: ...

@overload
Expand Down Expand Up @@ -192,7 +197,7 @@ def tiles(
north: float,
zooms: list[int] | tuple[int, ...] | int,
truncate: bool = ...,
) -> Iterable[Tile]: ...
) -> Collection[Tile]: ...
def tiles_list(
west: float,
south: float,
Expand Down
38 changes: 35 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,16 +429,37 @@ impl From<PyZoomOrZooms> for ZoomOrZooms {
#[pyclass]
struct TilesGenerator {
iter: Box<dyn Iterator<Item = PyTile> + Send>,
length: u64,
}

#[pymethods]
impl TilesGenerator {
fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {
slf
}

fn __next__(mut slf: PyRefMut<'_, Self>) -> Option<PyTile> {
slf.iter.next()
}

fn __len__(slf: PyRefMut<'_, Self>) -> PyResult<usize> {
Ok(slf.length as usize)
}
}

#[pyfunction]
fn tiles_count(
west: f64,
south: f64,
east: f64,
north: f64,
zooms: PyZoomOrZooms,
truncate: Option<bool>,
) -> u64 {
let (west, south, east, north) =
utiles::bbox_truncate(west, south, east, north, truncate);

utiles::tiles_count((west, south, east, north), ZoomOrZooms::from(zooms))
}

#[pyfunction]
Expand All @@ -452,11 +473,21 @@ fn tiles(
) -> TilesGenerator {
let (west, south, east, north) =
utiles::bbox_truncate(west, south, east, north, truncate);

let xyzs = utiles::tiles((west, south, east, north), ZoomOrZooms::from(zooms))
.map(PyTile::from);
let zooms_vec = match zooms {
PyZoomOrZooms::Zoom(z) => vec![z],
PyZoomOrZooms::Zooms(zs) => zs,
};
let zooms_vec_iter = zooms_vec.clone();
let ntiles =
utiles::tiles_count((west, south, east, north), ZoomOrZooms::from(zooms_vec));
let xyzs = utiles::tiles(
(west, south, east, north),
ZoomOrZooms::from(zooms_vec_iter),
)
.map(PyTile::from);
TilesGenerator {
iter: Box::new(xyzs),
length: ntiles,
}
}

Expand Down Expand Up @@ -760,6 +791,7 @@ fn libutiles(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(feature, m)?)?;

// utiles functions
m.add_function(wrap_pyfunction!(tiles_count, m)?)?;
m.add_function(wrap_pyfunction!(tiles_list, m)?)?;
m.add_function(wrap_pyfunction!(xyz, m)?)?;
m.add_function(wrap_pyfunction!(parse_tiles, m)?)?;
Expand Down
8 changes: 4 additions & 4 deletions src/pyutiles/pytile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,12 @@ impl PyTile {
Py::new(slf.py(), iter)
}

pub fn fmt_zxy(&self) -> String {
self.xyz.fmt_zxy()
pub fn fmt_zxy(&self, sep: Option<&str>) -> String {
self.xyz.fmt_zxy(sep)
}

pub fn fmt_zxy_ext(&self, ext: &str) -> String {
self.xyz.fmt_zxy_ext(ext)
pub fn fmt_zxy_ext(&self, ext: &str, sep: Option<&str>) -> String {
self.xyz.fmt_zxy_ext(ext, sep)
}

#[classmethod]
Expand Down
10 changes: 10 additions & 0 deletions tests/test_utiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,3 +269,13 @@ def test_tile_feature() -> None:

assert f == expected
assert t.feature(props={"x": 1, "y": 2, "z": 3}) == expected


def test_tiles_len() -> None:
tiles_list = list(utiles.tiles(-180, -90, 180, 90, [1]))
assert len(tiles_list) == 4

tiles_iter = utiles.tiles(-180, -90, 180, 90, [1])
assert len(tiles_iter) == 4
for t in tiles_iter:
assert isinstance(t, utiles.Tile)

0 comments on commit 32bf63f

Please sign in to comment.