From 22490bd0571443daa62802ddd37bd738fe655e17 Mon Sep 17 00:00:00 2001 From: jesse Date: Mon, 23 Sep 2024 13:46:10 -0700 Subject: [PATCH] Cli children update (#165) * fix children to be fast and not create all tiles in memory * fix children and clippy * fix unused fn * cargo update --- Cargo.lock | 12 +++--- crates/utiles-core/src/tile_like.rs | 20 +++++++++- crates/utiles-core/src/tile_zbox.rs | 37 +++++++++++++++++++ .../src/cli/commands/children_parent.rs | 6 ++- utiles-pyo3/python/utiles/dev/testing.py | 17 +++++++++ utiles-pyo3/tests/cli/test_mt.py | 14 +++++-- 6 files changed, 93 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8c4071b8..b659b264 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1869,9 +1869,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plotters" @@ -2650,18 +2650,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", diff --git a/crates/utiles-core/src/tile_like.rs b/crates/utiles-core/src/tile_like.rs index 5852f491..81a61452 100644 --- a/crates/utiles-core/src/tile_like.rs +++ b/crates/utiles-core/src/tile_like.rs @@ -1,5 +1,5 @@ use crate::bbox::WebBBox; -use crate::{flipy, pmtiles, xyz2rmid, BBox, LngLat, Tile}; +use crate::{flipy, pmtiles, xyz2rmid, BBox, LngLat, Tile, TileZBox}; /// Trait def for tile-like objects/structs/things/whatevers pub trait TileLike { @@ -203,4 +203,22 @@ pub trait TileLike { flipy(self.y(), self.z()) ) } + + /// return zbox for tile-like + #[must_use] + fn zbox(&self) -> TileZBox { + TileZBox::from_tile(self) + } + + /// Return children-zbox for tile-like at optional depth (default 1) + #[must_use] + fn children_zbox(&self, depth: Option) -> TileZBox { + let d = depth.unwrap_or(1); + let target_zoom = self.z() + d; + let mut zbox = TileZBox::from_tile(self); + while zbox.z() < target_zoom { + zbox = zbox.zoom_in(); + } + zbox + } } diff --git a/crates/utiles-core/src/tile_zbox.rs b/crates/utiles-core/src/tile_zbox.rs index 1df21c7a..8e73628d 100644 --- a/crates/utiles-core/src/tile_zbox.rs +++ b/crates/utiles-core/src/tile_zbox.rs @@ -58,6 +58,12 @@ impl TileZBox { self.max.y } + /// Return the zoom level + #[must_use] + pub fn z(&self) -> u8 { + self.zoom + } + /// Return the zoom level #[must_use] pub fn zoom(&self) -> u8 { @@ -123,6 +129,37 @@ impl TileZBox { pub fn mbtiles_sql_where(&self) -> String { self.mbtiles_sql_where_prefix(None) } + + /// Create zbox from tile + #[must_use] + pub fn from_tile(tile: &T) -> Self { + Self { + zoom: tile.z(), + min: Point2d::new(tile.x(), tile.y()), + max: Point2d::new(tile.x(), tile.y()), + } + } + + /// Return new zbox one zoom level higher/down z2 -> z3 + #[must_use] + pub fn zoom_in(&self) -> Self { + Self { + zoom: self.zoom + 1, + min: Point2d::new(self.min.x * 2, self.min.y * 2), + max: Point2d::new(self.max.x * 2 + 1, self.max.y * 2 + 1), + } + } + + /// Return new zbox one zoom level lower/up z3 -> z2 + #[must_use] + pub fn zoom_depth(&self, depth: u8) -> Self { + let target_zoom = self.zoom + depth; + let mut zbox = *self; + while zbox.zoom < target_zoom { + zbox = zbox.zoom_in(); + } + zbox + } } impl TileZBoxIterator { diff --git a/crates/utiles/src/cli/commands/children_parent.rs b/crates/utiles/src/cli/commands/children_parent.rs index f063f3ee..46a759cf 100644 --- a/crates/utiles/src/cli/commands/children_parent.rs +++ b/crates/utiles/src/cli/commands/children_parent.rs @@ -21,12 +21,14 @@ pub fn parent_main(args: ParentChildrenArgs) -> UtilesResult<()> { pub fn children_main(args: ParentChildrenArgs) -> UtilesResult<()> { let lines = stdinterator_filter::stdin_filtered(args.inargs.input); + let rs = if args.fmtopts.seq { "\x1e\n" } else { "" }; for line in lines { let lstr = line?.trim_matches(|c| c == '"' || c == '\'').to_string(); let tile = Tile::from_json(&lstr)?; - let children = tile.children(Option::from(tile.z + args.depth)); + let tile_zbox = tile.children_zbox(Option::from(args.depth)); + + let children = tile_zbox.into_iter().map(Tile::from); for child in children { - let rs = if args.fmtopts.seq { "\x1e\n" } else { "" }; println!("{}{}", rs, child.json_arr()); } } diff --git a/utiles-pyo3/python/utiles/dev/testing.py b/utiles-pyo3/python/utiles/dev/testing.py index 0d54161c..d01e9e9f 100644 --- a/utiles-pyo3/python/utiles/dev/testing.py +++ b/utiles-pyo3/python/utiles/dev/testing.py @@ -2,6 +2,8 @@ from __future__ import annotations +import utiles + try: from orjson import loads as json_loads except ImportError: @@ -69,6 +71,21 @@ def parse_json(self) -> Any: """Parse json""" return json_loads(self.stdout) + @property + def parse_jsonl(self) -> list[Any]: + """Parse json""" + return [json_loads(line) for line in self.stdout.splitlines()] + + @property + def parse_tiles(self) -> list[utiles.Tile]: + """Parse tile lines""" + return [ + utiles.xyz(arr[0], arr[1], arr[2]) + for arr in ( + json_loads(line) for line in self.stdout.splitlines(keepends=False) + ) + ] + def fmt(self) -> str: return "\n".join( ( diff --git a/utiles-pyo3/tests/cli/test_mt.py b/utiles-pyo3/tests/cli/test_mt.py index 317a9f2e..146617e4 100644 --- a/utiles-pyo3/tests/cli/test_mt.py +++ b/utiles-pyo3/tests/cli/test_mt.py @@ -7,6 +7,7 @@ import pytest +import utiles as ut from utiles.dev.testing import run_cli as _run_cli @@ -280,11 +281,16 @@ def test_cli_parent_multidepth(self) -> None: class TestChildren: def test_cli_children(self) -> None: result = _run_cli(["children"], "[243, 166, 9]") + assert result.returncode == 0 - assert ( - result.stdout - == "[486, 332, 10]\n[487, 332, 10]\n[487, 333, 10]\n[486, 333, 10]\n" - ) + json_tiles = result.parse_tiles + expected_tiles = [ + (486, 332, 10), + (486, 333, 10), + (487, 332, 10), + (487, 333, 10), + ] + assert set(json_tiles) == set((ut.xyz(*el) for el in expected_tiles)) # ===================