From a3e93afb5ce1ec9a2d50f6aeaaf73a10216d1a17 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Wed, 14 Aug 2024 13:50:28 +0200 Subject: [PATCH 1/3] made sure that geodata is queryable --- server/Cargo.lock | 165 ++++++++++++++++++++++++++++++++++++++ server/Cargo.toml | 10 +++ server/src/maps/indoor.rs | 16 ++++ server/src/maps/mod.rs | 1 + 4 files changed, 192 insertions(+) create mode 100644 server/src/maps/indoor.rs diff --git a/server/Cargo.lock b/server/Cargo.lock index 496c99363..5f31e32c5 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -1285,6 +1285,16 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +[[package]] +name = "earcutr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79127ed59a85d7687c409e9978547cffb7dc79675355ed22da6b66fd5f6ead01" +dependencies = [ + "itertools 0.11.0", + "num-traits", +] + [[package]] name = "either" version = "1.13.0" @@ -1442,6 +1452,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "float_next_after" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8" + [[package]] name = "flume" version = "0.11.0" @@ -1630,6 +1646,71 @@ dependencies = [ "version_check", ] +[[package]] +name = "geo" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f811f663912a69249fa620dcd2a005db7254529da2d8a0b23942e81f47084501" +dependencies = [ + "earcutr", + "float_next_after", + "geo-types", + "geographiclib-rs", + "log", + "num-traits", + "robust", + "rstar", + "spade", +] + +[[package]] +name = "geo-types" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff16065e5720f376fbced200a5ae0f47ace85fd70b7e54269790281353b6d61" +dependencies = [ + "approx", + "num-traits", + "rstar", + "serde", +] + +[[package]] +name = "geographiclib-rs" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e5ed84f8089c70234b0a8e0aedb6dc733671612ddc0d37c6066052f9781960" +dependencies = [ + "libm", +] + +[[package]] +name = "geojson" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d728c1df1fbf328d74151efe6cb0586f79ee813346ea981add69bd22c9241b" +dependencies = [ + "log", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "geozero" +version = "0.13.0" +source = "git+https://github.com/georust/geozero.git?rev=f8ab4363b0660cd84a58212039651fd68c3a8567#f8ab4363b0660cd84a58212039651fd68c3a8567" +dependencies = [ + "geo-types", + "geojson", + "log", + "scroll", + "serde_json", + "sqlx", + "thiserror", + "wkt", +] + [[package]] name = "getrandom" version = "0.2.15" @@ -1733,6 +1814,15 @@ dependencies = [ "crunchy", ] +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -1763,6 +1853,16 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + [[package]] name = "heck" version = "0.4.1" @@ -2310,6 +2410,15 @@ dependencies = [ "nom", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.12.1" @@ -2810,6 +2919,9 @@ dependencies = [ "cached", "chrono", "futures", + "geo", + "geo-types", + "geozero", "image", "imageproc", "insta", @@ -4429,6 +4541,12 @@ dependencies = [ "serde", ] +[[package]] +name = "robust" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf4a6aa5f6d6888f39e980649f3ad6b666acdce1d78e95b8a2cb076e687ae30" + [[package]] name = "rsa" version = "0.9.6" @@ -4449,6 +4567,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rstar" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "133315eb94c7b1e8d0cb097e5a710d850263372fd028fff18969de708afc7008" +dependencies = [ + "heapless", + "num-traits", + "smallvec", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -4621,6 +4750,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scroll" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" + [[package]] name = "sct" version = "0.7.1" @@ -5115,6 +5250,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spade" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd14cf9e23b5241e1b1289ed3b9afc7746c95ead8df52d9254f5ed2d40c561b" +dependencies = [ + "hashbrown 0.14.5", + "num-traits", + "robust", + "smallvec", +] + [[package]] name = "spin" version = "0.9.8" @@ -5363,6 +5510,12 @@ dependencies = [ "url", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "stacker" version = "0.1.15" @@ -6575,6 +6728,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wkt" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c2252781f8927974e8ba6a67c965a759a2b88ea2b1825f6862426bbb1c8f41" +dependencies = [ + "geo-types", + "log", + "num-traits", + "thiserror", +] + [[package]] name = "xxhash-rust" version = "0.8.12" diff --git a/server/Cargo.toml b/server/Cargo.toml index 41cbda33d..4df0eff43 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -75,6 +75,11 @@ time = "0.3.36" polars = { version = "0.41.3", features = ["dtype-struct", "parquet"] } #polars = { git = "https://github.com/CommanderStorm/polars.git", branch = "serialisation-experiment", features = ["parquet", "serde", "dtype-full"] } +# geodata +geo = "0.28.0" +geozero = { version = "0.13.0", features = ["with-postgis-sqlx", "with-geojson"] } +geo-types = "0.7.13" + [dev-dependencies] insta = { version = "1.39.0", features = ["json", "redactions", "yaml"] } pretty_assertions = "1.4.0" @@ -111,3 +116,8 @@ similar.opt-level = 3 ignored = [ "rustls", # we need to configure between ring and aws crypto library ] + +[patch.crates-io] +# needs release after 0.13 +# https://github.com/georust/geozero/tags +geozero = { git = "https://github.com/georust/geozero.git", rev = "f8ab4363b0660cd84a58212039651fd68c3a8567" } diff --git a/server/src/maps/indoor.rs b/server/src/maps/indoor.rs new file mode 100644 index 000000000..055e625b6 --- /dev/null +++ b/server/src/maps/indoor.rs @@ -0,0 +1,16 @@ +use sqlx::{PgPool, Row}; +#[tracing::instrument(skip(pool))] +pub async fn list_indoor_inside_of(pool:&PgPool) ->anyhow::Result>{ + let geom: geo_types::Geometry = geo::Point::new(10.0, 20.0).into(); + let filtered_groups = sqlx::query("SELECT group_id from indoor_features where ST_Contains(convex_hull::geometry, $1::geometry)") + .bind(geozero::wkb::Encode(geom)) + .fetch_all(pool) + .await?; + let mut filtered_group_ids =Vec::::new(); + for group in filtered_groups { + let group_id = group.get_unchecked(0); + filtered_group_ids.push(group_id); + } + + Ok(filtered_group_ids) +} \ No newline at end of file diff --git a/server/src/maps/mod.rs b/server/src/maps/mod.rs index 9b25c6bf8..97f661dc9 100644 --- a/server/src/maps/mod.rs +++ b/server/src/maps/mod.rs @@ -1,3 +1,4 @@ mod fetch_tile; pub(crate) mod overlay_map; pub(crate) mod overlay_text; +mod indoor; From 196cef742541c3526b5614a2fb5612495c80ebbc Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Wed, 14 Aug 2024 15:40:12 +0200 Subject: [PATCH 2/3] made sure that geodata is queryable --- data/output/openapi.yaml | 4 +- server/Cargo.lock | 34 +---------------- server/Cargo.toml | 6 +-- server/src/main.rs | 2 + server/src/maps/indoor.rs | 78 +++++++++++++++++++++++++++++++++++++-- server/src/maps/mod.rs | 2 +- 6 files changed, 84 insertions(+), 42 deletions(-) diff --git a/data/output/openapi.yaml b/data/output/openapi.yaml index 73c958285..6d5d9d500 100644 --- a/data/output/openapi.yaml +++ b/data/output/openapi.yaml @@ -1339,8 +1339,10 @@ components: type: object properties: name: + description: name of the map type: string - path: + url: + description: where the indoor geojson is located at type: string required: - name diff --git a/server/Cargo.lock b/server/Cargo.lock index 5f31e32c5..e39f83ec6 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -1285,16 +1285,6 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" -[[package]] -name = "earcutr" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79127ed59a85d7687c409e9978547cffb7dc79675355ed22da6b66fd5f6ead01" -dependencies = [ - "itertools 0.11.0", - "num-traits", -] - [[package]] name = "either" version = "1.13.0" @@ -1652,7 +1642,6 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f811f663912a69249fa620dcd2a005db7254529da2d8a0b23942e81f47084501" dependencies = [ - "earcutr", "float_next_after", "geo-types", "geographiclib-rs", @@ -1660,7 +1649,7 @@ dependencies = [ "num-traits", "robust", "rstar", - "spade", + "serde", ] [[package]] @@ -2410,15 +2399,6 @@ dependencies = [ "nom", ] -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.12.1" @@ -5250,18 +5230,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "spade" -version = "2.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd14cf9e23b5241e1b1289ed3b9afc7746c95ead8df52d9254f5ed2d40c561b" -dependencies = [ - "hashbrown 0.14.5", - "num-traits", - "robust", - "smallvec", -] - [[package]] name = "spin" version = "0.9.8" diff --git a/server/Cargo.toml b/server/Cargo.toml index 4df0eff43..b71553a08 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -76,9 +76,9 @@ polars = { version = "0.41.3", features = ["dtype-struct", "parquet"] } #polars = { git = "https://github.com/CommanderStorm/polars.git", branch = "serialisation-experiment", features = ["parquet", "serde", "dtype-full"] } # geodata -geo = "0.28.0" -geozero = { version = "0.13.0", features = ["with-postgis-sqlx", "with-geojson"] } -geo-types = "0.7.13" +geo = { version = "0.28.0", features = ["use-serde"], default-features = false } +geozero = { version = "0.13.0", features = ["with-postgis-sqlx", "with-geojson", "with-wkt", "with-geo", "with-geojson", ], default-features = false } +geo-types = { version = "0.7.13", default-features = false } [dev-dependencies] insta = { version = "1.39.0", features = ["json", "redactions", "yaml"] } diff --git a/server/src/main.rs b/server/src/main.rs index 33286f86f..93490c956 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -198,6 +198,8 @@ async fn run() -> anyhow::Result<()> { .app_data(web::Data::new(data.clone())) .service(health_status_handler) .service(calendar::calendar_handler) + .service(maps::indoor::list_indoor_maps) + .service(maps::indoor::get_indoor_map) .service(search::search_handler) .service(web::scope("/api/feedback").configure(feedback::configure)) .service(web::scope("/api/locations").configure(locations::configure)) diff --git a/server/src/maps/indoor.rs b/server/src/maps/indoor.rs index 055e625b6..a65a7b0f3 100644 --- a/server/src/maps/indoor.rs +++ b/server/src/maps/indoor.rs @@ -1,16 +1,86 @@ +use actix_web::{post, web, HttpResponse}; +use geo_types::Geometry; +use reqwest::Url; +use serde::{Deserialize, Serialize}; use sqlx::{PgPool, Row}; +use tracing::{error, info}; + #[tracing::instrument(skip(pool))] -pub async fn list_indoor_inside_of(pool:&PgPool) ->anyhow::Result>{ - let geom: geo_types::Geometry = geo::Point::new(10.0, 20.0).into(); +pub async fn fetch_indoor_maps_inside_of(pool: &PgPool, geom: Geometry) -> anyhow::Result> { let filtered_groups = sqlx::query("SELECT group_id from indoor_features where ST_Contains(convex_hull::geometry, $1::geometry)") .bind(geozero::wkb::Encode(geom)) .fetch_all(pool) .await?; - let mut filtered_group_ids =Vec::::new(); + let mut filtered_group_ids = Vec::::new(); for group in filtered_groups { let group_id = group.get_unchecked(0); filtered_group_ids.push(group_id); } Ok(filtered_group_ids) -} \ No newline at end of file +} +#[tracing::instrument(skip(pool))] +pub async fn fetch_indoor_map(pool: &PgPool, id: i64) -> anyhow::Result { + let row = sqlx::query("SELECT features from indoor_features where group_id = $1") + .bind(id) + .fetch_one(pool) + .await?; + let value: geozero::wkb::Decode = row.get(0); + + Ok(value.geometry.unwrap()) +} + +#[derive(Deserialize)] +struct Arguments { + bbox: geo::Rect, +} + +#[post("/api/maps/indoor/{id}")] +pub async fn get_indoor_map( + params: web::Path, + data: web::Data, +) -> HttpResponse { + let id = params.into_inner(); + let map=fetch_indoor_map(&data.pool,id).await; + let geometry=match map { + Ok(g) => g, + Err(err) => { + error!("Failed to fetch indoor map {id} because {err:?}"); + return HttpResponse::InternalServerError().finish(); + }, + }; + info!("fetched {geometry:?}"); + HttpResponse::Ok().finish() +} + + +#[derive(Serialize)] +struct RemoteMap{ + name:String, + url:Url, +} + +#[post("/api/maps/indoor")] +pub async fn list_indoor_maps( + web::Query(args): web::Query, + data: web::Data, +) -> HttpResponse { + let maps=fetch_indoor_maps_inside_of(&data.pool,args.bbox.into()).await; + let maps=match maps{ + Ok(m)=>m, + Err(e) => { + error!("could not list maps because {e:?}"); + return HttpResponse::InternalServerError().body("could not get indoor maps, please try again later"); + }, + }; + let mut response = Vec::new(); + for map in maps{ + response.push(RemoteMap{ + name: map.to_string(), + url: format!("https://nav.tum.de/api/maps/indoor/{map}").parse().unwrap(), + }) + } + + HttpResponse::Ok().json(response) +} + diff --git a/server/src/maps/mod.rs b/server/src/maps/mod.rs index 97f661dc9..e64a55df0 100644 --- a/server/src/maps/mod.rs +++ b/server/src/maps/mod.rs @@ -1,4 +1,4 @@ mod fetch_tile; +pub(crate) mod indoor; pub(crate) mod overlay_map; pub(crate) mod overlay_text; -mod indoor; From 084c2895ec96f76c9e921f65e479f7be9a733a99 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Wed, 14 Aug 2024 18:02:18 +0200 Subject: [PATCH 3/3] linting fixes --- server/src/maps/indoor.rs | 42 +++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/server/src/maps/indoor.rs b/server/src/maps/indoor.rs index a65a7b0f3..270c96e14 100644 --- a/server/src/maps/indoor.rs +++ b/server/src/maps/indoor.rs @@ -6,7 +6,10 @@ use sqlx::{PgPool, Row}; use tracing::{error, info}; #[tracing::instrument(skip(pool))] -pub async fn fetch_indoor_maps_inside_of(pool: &PgPool, geom: Geometry) -> anyhow::Result> { +pub async fn fetch_indoor_maps_inside_of( + pool: &PgPool, + geom: Geometry, +) -> anyhow::Result> { let filtered_groups = sqlx::query("SELECT group_id from indoor_features where ST_Contains(convex_hull::geometry, $1::geometry)") .bind(geozero::wkb::Encode(geom)) .fetch_all(pool) @@ -41,23 +44,22 @@ pub async fn get_indoor_map( data: web::Data, ) -> HttpResponse { let id = params.into_inner(); - let map=fetch_indoor_map(&data.pool,id).await; - let geometry=match map { + let map = fetch_indoor_map(&data.pool, id).await; + let geometry = match map { Ok(g) => g, Err(err) => { error!("Failed to fetch indoor map {id} because {err:?}"); return HttpResponse::InternalServerError().finish(); - }, + } }; info!("fetched {geometry:?}"); HttpResponse::Ok().finish() } - #[derive(Serialize)] -struct RemoteMap{ - name:String, - url:Url, +struct RemoteMap { + name: String, + url: Url, } #[post("/api/maps/indoor")] @@ -65,22 +67,24 @@ pub async fn list_indoor_maps( web::Query(args): web::Query, data: web::Data, ) -> HttpResponse { - let maps=fetch_indoor_maps_inside_of(&data.pool,args.bbox.into()).await; - let maps=match maps{ - Ok(m)=>m, + let maps = fetch_indoor_maps_inside_of(&data.pool, args.bbox.into()).await; + let maps = match maps { + Ok(m) => m, Err(e) => { error!("could not list maps because {e:?}"); - return HttpResponse::InternalServerError().body("could not get indoor maps, please try again later"); - }, + return HttpResponse::InternalServerError() + .body("could not get indoor maps, please try again later"); + } }; let mut response = Vec::new(); - for map in maps{ - response.push(RemoteMap{ - name: map.to_string(), - url: format!("https://nav.tum.de/api/maps/indoor/{map}").parse().unwrap(), + for map in maps { + response.push(RemoteMap { + name: map.to_string(), + url: format!("https://nav.tum.de/api/maps/indoor/{map}") + .parse() + .unwrap(), }) } - + HttpResponse::Ok().json(response) } -