Skip to content

Commit

Permalink
add contains cmd to cli (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
dan-costello authored Nov 21, 2023
1 parent 433847d commit 32f227d
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 2 deletions.
10 changes: 10 additions & 0 deletions crates/utiles-cli/src/args.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::shapes::ShapesArgs;
use clap::{Parser, Subcommand};
use utiles::LngLat;

/// A fictional versioning CLI
#[derive(Debug, Parser)] // requires `derive` feature
Expand Down Expand Up @@ -66,6 +67,15 @@ pub enum Commands {
min: bool,
},

#[command(name = "contains", about = "Determine if mbtiles contains a latlong", long_about = None)]
Contains {
#[arg(required = true, help = "mbtiles filepath")]
filepath: String,

#[arg(required = true, help = "lat/long")]
lnglat: LngLat,
},

#[command(name = "metadata", visible_alias = "md", about = "Echo metadata (table) as json", long_about = None)]
Meta {
#[arg(required = true, help = "mbtiles filepath")]
Expand Down
24 changes: 24 additions & 0 deletions crates/utiles-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,30 @@ pub async fn cli_main(argv: Option<Vec<String>>, loop_fn: Option<&dyn Fn()>) ->
println!("{s}");
}

Commands::Contains { filepath, lnglat } => {
debug!("contains: {filepath}");
// check that filepath exists and is file
let filepath = Path::new(&filepath);
assert!(
filepath.exists(),
"File does not exist: {}",
filepath.display()
);
assert!(
filepath.is_file(),
"Not a file: {filepath}",
filepath = filepath.display()
);
let mbtiles: Mbtiles = Mbtiles::from(filepath);
let contains = mbtiles.contains(lnglat);
if contains.is_err() {
error!("contains error: {:?}", contains);
println!("contains error: {:?}", contains);
} else {
println!("{}", contains.unwrap());
}
}

// mercantile cli like
Commands::Quadkey { input } => {
let lines = stdinterator_filter::stdin_filtered(input);
Expand Down
8 changes: 7 additions & 1 deletion crates/utiles/src/bbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::parsing::parse_bbox;
use crate::tile::Tile;
use geo_types::Coord;
use serde::{Deserialize, Serialize};

use tilejson::Bounds;
#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)]
pub struct BBoxTuple(f64, f64, f64, f64);

Expand Down Expand Up @@ -247,6 +247,12 @@ impl From<BBox> for BBoxTuple {
}
}

impl From<&Bounds> for BBox {
fn from(bounds: &Bounds) -> Self {
BBox::new(bounds.left, bounds.bottom, bounds.right, bounds.top)
}
}

impl From<BBoxTuple> for BBox {
fn from(tuple: BBoxTuple) -> Self {
BBox::new(tuple.0, tuple.1, tuple.2, tuple.3)
Expand Down
13 changes: 13 additions & 0 deletions crates/utiles/src/lnglat.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use geo_types::{coord, Coord};
use std::str::FromStr;

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct LngLat {
Expand All @@ -17,6 +18,18 @@ impl From<(f64, f64)> for LngLat {
}
}

impl FromStr for LngLat {
type Err = std::num::ParseFloatError; // Change this to your correct Error type

fn from_str(s: &str) -> Result<Self, Self::Err> {
// Split the string, parse the parts into float and return LngLat.
let parts: Vec<&str> = s.split(',').collect();
// parse parts to float
let x = parts[0].parse::<f64>()?;
let y = parts[1].parse::<f64>()?;
Ok(LngLat::new(x, y))
}
}
impl LngLat {
#[must_use]
pub fn new(lng: f64, lat: f64) -> Self {
Expand Down
22 changes: 21 additions & 1 deletion crates/utilesqlite/src/mbtiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ use std::path::Path;
use rusqlite::{Connection, Result as RusqliteResult};
use tilejson::TileJSON;
use tracing::error;
use utiles::bbox::BBox;
use utiles::mbtiles::metadata_row::MbtilesMetadataRow;
use utiles::mbtiles::{metadata2tilejson, MinZoomMaxZoom};

use utiles::LngLat;
pub struct Mbtiles {
conn: Connection,
}
Expand All @@ -32,6 +33,25 @@ impl Mbtiles {
}
}

pub fn bbox(&self) -> Result<BBox, Box<dyn Error>> {
let bounding = self.tilejson()?.bounds;
match bounding {
Some(bounding) => {
let bbox = BBox::from(&bounding);
Ok(bbox)
}
None => Err("Error parsing metadata to TileJSON: no data available".into()),
}
// convert boundsd to BBox
}

pub fn contains(&self, lnglat: LngLat) -> Result<bool, Box<dyn Error>> {
let bbox = self.bbox()?;
let contains = bbox.contains_lnglat(lnglat);
// return false if not ok
Ok(contains)
}

pub fn tj(&self) -> Result<TileJSON, Box<dyn Error>> {
self.tilejson()
}
Expand Down

0 comments on commit 32f227d

Please sign in to comment.