From d431c818cf575a87bf94f6f035fe51c60717734f Mon Sep 17 00:00:00 2001 From: sharkAndshark Date: Wed, 2 Aug 2023 22:02:02 +0800 Subject: [PATCH] add exclude small geometries CLI arg --- martin/src/args/pg.rs | 14 ++++++++++++++ martin/src/pg/config.rs | 2 ++ martin/src/pg/configurator.rs | 4 ++++ martin/src/pg/table_source.rs | 36 ++++++++++++++++++++++++++++++++--- 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/martin/src/args/pg.rs b/martin/src/args/pg.rs index 88c9a1f86..6f2aabc81 100644 --- a/martin/src/args/pg.rs +++ b/martin/src/args/pg.rs @@ -24,6 +24,9 @@ pub struct PgArgs { /// Limit the number of features in a tile from a PG table source. #[arg(short, long)] pub max_feature_count: Option, + /// Hide geometries which can not fullfill one single pixel + #[arg(short, long)] + pub exclude_small_geometries: Option, } impl PgArgs { @@ -48,6 +51,7 @@ impl PgArgs { None }, max_feature_count: self.max_feature_count, + exclude_small_geometries: self.exclude_small_geometries, pool_size: self.pool_size, auto_publish: None, tables: None, @@ -82,6 +86,16 @@ impl PgArgs { }); } + if self.exclude_small_geometries.is_some() { + info!( + "Overriding exclude small geometries to {} because of a CLI parameter", + self.exclude_small_geometries.unwrap() + ); + pg_config.iter_mut().for_each(|c| { + c.exclude_small_geometries = self.exclude_small_geometries; + }); + } + #[cfg(feature = "ssl")] if self.ca_root_file.is_some() { info!("Overriding root certificate file to {} on all Postgres connections because of a CLI parameter", diff --git a/martin/src/pg/config.rs b/martin/src/pg/config.rs index 4880fd24d..167171ac8 100644 --- a/martin/src/pg/config.rs +++ b/martin/src/pg/config.rs @@ -46,6 +46,8 @@ pub struct PgConfig { #[serde(skip_serializing_if = "Option::is_none")] pub max_feature_count: Option, #[serde(skip_serializing_if = "Option::is_none")] + pub exclude_small_geometries: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub pool_size: Option, #[serde(skip_serializing_if = "Option::is_none")] pub auto_publish: Option>, diff --git a/martin/src/pg/configurator.rs b/martin/src/pg/configurator.rs index e7b2147b2..cf8e0458c 100755 --- a/martin/src/pg/configurator.rs +++ b/martin/src/pg/configurator.rs @@ -35,6 +35,7 @@ pub struct PgBuilder { default_srid: Option, disable_bounds: bool, max_feature_count: Option, + exclude_small_geometries: Option, auto_functions: Option, auto_tables: Option, id_resolver: IdResolver, @@ -51,6 +52,7 @@ impl PgBuilder { default_srid: config.default_srid, disable_bounds: config.disable_bounds.unwrap_or_default(), max_feature_count: config.max_feature_count, + exclude_small_geometries: config.exclude_small_geometries, id_resolver, tables: config.tables.clone().unwrap_or_default(), functions: config.functions.clone().unwrap_or_default(), @@ -90,6 +92,7 @@ impl PgBuilder { self.pool.clone(), self.disable_bounds, self.max_feature_count, + self.exclude_small_geometries, )); } @@ -129,6 +132,7 @@ impl PgBuilder { self.pool.clone(), self.disable_bounds, self.max_feature_count, + self.exclude_small_geometries, )); } } diff --git a/martin/src/pg/table_source.rs b/martin/src/pg/table_source.rs index b7a8a1b59..d63d2078c 100644 --- a/martin/src/pg/table_source.rs +++ b/martin/src/pg/table_source.rs @@ -1,8 +1,7 @@ -use std::collections::HashMap; - use log::{info, warn}; use postgis::ewkb; use postgres_protocol::escape::{escape_identifier, escape_literal}; +use std::collections::HashMap; use tilejson::Bounds; use crate::pg::config::PgInfo; @@ -90,6 +89,7 @@ pub async fn table_to_query( pool: PgPool, disable_bounds: bool, max_feature_count: Option, + exclude_small_geometries: Option, ) -> Result<(String, PgSqlInfo, TableInfo)> { let schema = escape_identifier(&info.schema); let table = escape_identifier(&info.table); @@ -139,6 +139,17 @@ pub async fn table_to_query( let limit_clause = max_feature_count.map_or(String::new(), |v| format!("LIMIT {v}")); let layer_id = escape_literal(info.layer_id.as_ref().unwrap_or(&id)); let clip_geom = info.clip_geom.unwrap_or(DEFAULT_CLIP_GEOM); + + let small_geometries_condition = if let Some(allow_exclude_geoms) = exclude_small_geometries { + if allow_exclude_geoms { + create_small_geomtries_condition(&geometry_column, &info.geometry_type) + } else { + String::new() + } + } else { + String::new() + }; + let query = format!( r#" SELECT @@ -154,7 +165,7 @@ FROM ( FROM {schema}.{table} WHERE - {geometry_column} && ST_Transform({bbox_search}, {srid}) + {geometry_column} && ST_Transform({bbox_search}, {srid}) {small_geometries_condition} {limit_clause} ) AS tile; "# @@ -165,6 +176,25 @@ FROM ( Ok((id, PgSqlInfo::new(query, false, info.format_id()), info)) } +fn create_small_geomtries_condition( + geometry_column: &str, + geometry_type: &Option, +) -> String { + if let Some(t) = geometry_type { + match t.as_str() { + "LINESTRING" => format!(" AND ST_LENGTH(ST_Transform({geometry_column},3857)) >= ( 40075016.68 / ( 2 ^ $1::integer * 512 ) )"), + "MULTILineString" => format!(" AND ST_LENGTH(ST_Transform({geometry_column},3857)) >= ( 40075016.68 / ( 2 ^ $1::integer * 512 ))"), + "POLYGON" => format!(" AND ST_AREA(ST_Transform({geometry_column},3857)) >= ( 40075016.68 / ( 2 ^ $1::integer * 512 ) ) ^ 2 )"), + "MULTIPOLYGON" => format!(" AND ST_AREA(ST_Transform({geometry_column},3857)) >= ( 40075016.68 / ( 2 ^ $1::integer * 512 ) ) ^ 2)"), + _ =>{ + String::new() + } + } + } else { + String::new() + } +} + async fn calc_bounds( pool: &PgPool, schema: &str,