Skip to content

Commit

Permalink
Indoor geodata server (#1442)
Browse files Browse the repository at this point in the history
* made sure that geodata is queryable

* made sure that geodata is queryable

* linting fixes
  • Loading branch information
CommanderStorm authored Aug 14, 2024
1 parent 002caea commit 7c9a207
Show file tree
Hide file tree
Showing 6 changed files with 239 additions and 1 deletion.
4 changes: 3 additions & 1 deletion data/output/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
133 changes: 133 additions & 0 deletions server/Cargo.lock

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

10 changes: 10 additions & 0 deletions server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ time = "0.3.36"
polars = { version = "0.42.0", features = ["dtype-struct", "parquet"] }
#polars = { git = "https://github.com/CommanderStorm/polars.git", branch = "serialisation-experiment", features = ["parquet", "serde", "dtype-full"] }

# geodata
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"] }
pretty_assertions = "1.4.0"
Expand Down Expand Up @@ -112,5 +117,10 @@ 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" }

[features]
test-with-geodata = []
2 changes: 2 additions & 0 deletions server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
90 changes: 90 additions & 0 deletions server/src/maps/indoor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
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 fetch_indoor_maps_inside_of(
pool: &PgPool,
geom: Geometry,
) -> anyhow::Result<Vec<i64>> {
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::<i64>::new();
for group in filtered_groups {
let group_id = group.get_unchecked(0);
filtered_group_ids.push(group_id);
}

Ok(filtered_group_ids)
}
#[tracing::instrument(skip(pool))]
pub async fn fetch_indoor_map(pool: &PgPool, id: i64) -> anyhow::Result<Geometry> {
let row = sqlx::query("SELECT features from indoor_features where group_id = $1")
.bind(id)
.fetch_one(pool)
.await?;
let value: geozero::wkb::Decode<Geometry> = 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<i64>,
data: web::Data<crate::AppData>,
) -> 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<Arguments>,
data: web::Data<crate::AppData>,
) -> 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)
}
1 change: 1 addition & 0 deletions server/src/maps/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod fetch_tile;
pub(crate) mod indoor;
pub(crate) mod overlay_map;
pub(crate) mod overlay_text;

0 comments on commit 7c9a207

Please sign in to comment.