Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions martin-tile-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ use std::fmt::{Display, Formatter, Result};

/// circumference of the earth in meters
pub const EARTH_CIRCUMFERENCE: f64 = 40_075_016.685_578_5;
/// circumference of the earth in degrees
pub const EARTH_CIRCUMFERENCE_DEGREES: u32 = 360;

/// radius of the earth in meters
pub const EARTH_RADIUS: f64 = EARTH_CIRCUMFERENCE / 2.0 / PI;

Expand Down
36 changes: 25 additions & 11 deletions martin/src/pg/query_tables.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use martin_tile_utils::EARTH_CIRCUMFERENCE_DEGREES;
use std::collections::HashMap;

use futures::pin_mut;
Expand Down Expand Up @@ -171,19 +172,32 @@ pub async fn table_to_query(

let extent = info.extent.unwrap_or(DEFAULT_EXTENT);
let buffer = info.buffer.unwrap_or(DEFAULT_BUFFER);
let margin = f64::from(buffer) / f64::from(extent);

// When calculating the bounding box to search within, a few considerations must be made when
// using a margin. The ST_TileEnvelope margin parameter is for use with SRID 3857.
// For SRID 4326, ST_Expand is used and provided with SRID 4326 specific units (degrees).
// If the table uses a non-standard SRID, it will fall back to existing behavior.
//
// For more context, if SRID 4326 were to be used with ST_TileEnvelope and margin
// parameter, the resultant bounding box for tiles on the antimeridian would be calculated
// incorrectly. For example, with a margin of 2 units, the antimeridian edge would transform
// from -180 to +178. This results in a bbox that stretches from the easternmost edge of a tile
// (plus margin) around the map to the westernmost edge of the tile (minus margin). The
// resulting bbox covers none of the original tile. In contrast, for this example, ST_Expand
// will result in a westernmost edge (minus margin) of -182.
let bbox_search = if buffer == 0 {
"ST_TileEnvelope($1::integer, $2::integer, $3::integer)".to_string()
} else if pool.supports_tile_margin() {
let margin = f64::from(buffer) / f64::from(extent);
format!("ST_TileEnvelope($1::integer, $2::integer, $3::integer, margin => {margin})")
format!("ST_Transform(ST_TileEnvelope($1::integer, $2::integer, $3::integer), {srid})")
} else if pool.supports_tile_margin() && srid == 3857 {
format!(
"ST_Transform(ST_TileEnvelope($1::integer, $2::integer, $3::integer, margin => {margin}), {srid})"
)
} else if srid == 4326 {
format!(
"ST_Expand(ST_Transform(ST_TileEnvelope($1::integer, $2::integer, $3::integer), {srid}), ({margin} * {EARTH_CIRCUMFERENCE_DEGREES}) / 2^$1::integer)"
)
} else {
// TODO: we should use ST_Expand here, but it may require a bit more math work,
// so might not be worth it as it is only used for PostGIS < v3.1.
// v3.1 has been out for 2+ years (december 2020)
// let val = EARTH_CIRCUMFERENCE * buffer as f64 / extent as f64;
// format!("ST_Expand(ST_TileEnvelope($1::integer, $2::integer, $3::integer), {val}/2^$1::integer)")
"ST_TileEnvelope($1::integer, $2::integer, $3::integer)".to_string()
format!("ST_Transform(ST_TileEnvelope($1::integer, $2::integer, $3::integer), {srid})")
};

let limit_clause = max_feature_count.map_or(String::new(), |v| format!("LIMIT {v}"));
Expand All @@ -204,7 +218,7 @@ FROM (
FROM
{schema}.{table}
WHERE
{geometry_column} && ST_Transform({bbox_search}, {srid})
{geometry_column} && {bbox_search}
{limit_clause}
) AS tile;
"
Expand Down
3 changes: 3 additions & 0 deletions martin/tests/pg_server_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ postgres:
MixPoints:
content_type: application/x-protobuf
description: a description from comment on table
antimeridian:
content_type: application/x-protobuf
description: public.antimeridian.geom
auto_table:
content_type: application/x-protobuf
description: autodetect.auto_table.geom
Expand Down
19 changes: 19 additions & 0 deletions martin/tests/pg_table_source_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ async fn table_source() {
MixPoints:
content_type: application/x-protobuf
description: a description from comment on table
antimeridian:
content_type: application/x-protobuf
description: public.antimeridian.geom
auto_table:
content_type: application/x-protobuf
description: autodetect.auto_table.geom
Expand Down Expand Up @@ -124,6 +127,22 @@ async fn table_source() {
properties:
gid: int4
");

let source3 = table(&mock, "points3857");
assert_yaml_snapshot!(source3, @r"
schema: public
table: points3857
srid: 3857
geometry_column: geom
bounds:
- -161.40590777554058
- -81.50727021609012
- 172.51549126768532
- 84.2440187164111
geometry_type: POINT
properties:
gid: int4
");
}

#[actix_rt::test]
Expand Down
Binary file added tests/expected/auto/antimeridian_4_0_4.pbf
Binary file not shown.
40 changes: 40 additions & 0 deletions tests/expected/auto/antimeridian_4_0_4.pbf.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"features": [
{
"geometry": {
"coordinates": [
[
[
3641,
2200
],
[
3641,
1448
],
[
2731,
1448
],
[
2731,
2200
],
[
3641,
2200
]
]
],
"type": "Polygon"
},
"properties": {
"gid": 3,
"source_mvt_layer": "antimeridian"
},
"type": "Feature"
}
],
"name": "merged",
"type": "FeatureCollection"
}
5 changes: 5 additions & 0 deletions tests/expected/auto/antimeridian_4_0_4.pbf.headers
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
content-encoding: gzip
content-length: 79
content-type: application/x-protobuf
etag: "171363189529507097744074158008402788299"
vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers
Binary file added tests/expected/auto/antimeridian_4_0_5.pbf
Binary file not shown.
74 changes: 74 additions & 0 deletions tests/expected/auto/antimeridian_4_0_5.pbf.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"features": [
{
"geometry": {
"coordinates": [
[
[
546,
2636
],
[
546,
3228
],
[
1456,
3228
],
[
1456,
2636
],
[
546,
2636
]
]
],
"type": "Polygon"
},
"properties": {
"gid": 1,
"source_mvt_layer": "antimeridian"
},
"type": "Feature"
},
{
"geometry": {
"coordinates": [
[
[
546,
2636
],
[
546,
3228
],
[
4096,
3228
],
[
4096,
2636
],
[
546,
2636
]
]
],
"type": "Polygon"
},
"properties": {
"gid": 2,
"source_mvt_layer": "antimeridian"
},
"type": "Feature"
}
],
"name": "merged",
"type": "FeatureCollection"
}
5 changes: 5 additions & 0 deletions tests/expected/auto/antimeridian_4_0_5.pbf.headers
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
content-encoding: gzip
content-length: 109
content-type: application/x-protobuf
etag: "11410412592260844908993902889337130111"
vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers
4 changes: 4 additions & 0 deletions tests/expected/auto/catalog_auto.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
"content_type": "application/x-protobuf",
"description": "a description from comment on table"
},
"antimeridian": {
"content_type": "application/x-protobuf",
"description": "public.antimeridian.geom"
},
"auto_table": {
"content_type": "application/x-protobuf",
"description": "autodetect.auto_table.geom"
Expand Down
13 changes: 13 additions & 0 deletions tests/expected/auto/save_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ postgres:
properties:
Gid: int4
TABLE: text
antimeridian:
schema: public
table: antimeridian
srid: 4326
geometry_column: geom
bounds:
- -182.0
- 51.0
- -160.0
- 62.0
geometry_type: GEOMETRY
properties:
gid: int4
auto_table:
schema: autodetect
table: auto_table
Expand Down
13 changes: 13 additions & 0 deletions tests/expected/martin-cp/flat-with-hash_save_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ postgres:
properties:
Gid: int4
TABLE: text
antimeridian:
schema: public
table: antimeridian
srid: 4326
geometry_column: geom
bounds:
- -182.0
- 51.0
- -160.0
- 62.0
geometry_type: GEOMETRY
properties:
gid: int4
auto_table:
schema: autodetect
table: auto_table
Expand Down
13 changes: 13 additions & 0 deletions tests/expected/martin-cp/flat_save_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ postgres:
properties:
Gid: int4
TABLE: text
antimeridian:
schema: public
table: antimeridian
srid: 4326
geometry_column: geom
bounds:
- -182.0
- 51.0
- -160.0
- 62.0
geometry_type: GEOMETRY
properties:
gid: int4
auto_table:
schema: autodetect
table: auto_table
Expand Down
13 changes: 13 additions & 0 deletions tests/expected/martin-cp/normalized_save_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ postgres:
properties:
Gid: int4
TABLE: text
antimeridian:
schema: public
table: antimeridian
srid: 4326
geometry_column: geom
bounds:
- -182.0
- 51.0
- -160.0
- 62.0
geometry_type: GEOMETRY
properties:
gid: int4
auto_table:
schema: autodetect
table: auto_table
Expand Down
19 changes: 19 additions & 0 deletions tests/fixtures/tables/antimeridian.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
DROP TABLE IF EXISTS antimeridian;

CREATE TABLE antimeridian
(
gid serial PRIMARY KEY,
geom GEOMETRY (GEOMETRY, 4326)
);

INSERT INTO antimeridian (geom) VALUES (
GEOMFROMEWKT('SRID=4326;POLYGON((-177 51, -172 51, -172 53, -177 53, -177 51))')
);
INSERT INTO antimeridian (geom) VALUES (
GEOMFROMEWKT('SRID=4326;POLYGON((-182 51, -177 51, -177 53, -182 53, -182 51))')
);
INSERT INTO antimeridian (geom) VALUES (
GEOMFROMEWKT('SRID=4326;POLYGON ((-160 60, -165 60, -165 62, -160 62, -160 60))')
);

CREATE INDEX ON antimeridian USING gist (geom);
4 changes: 4 additions & 0 deletions tests/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,10 @@ test_png rgba_u8_nodata_1_0_0 rgba_u8_nodata/1/0/0
>&2 echo "***** Test server response for table source with empty SRID *****"
test_pbf points_empty_srid_0_0_0 points_empty_srid/0/0/0

>&2 echo "***** Test server response for table source with antimeridian geometries *****"
test_pbf antimeridian_4_0_4 antimeridian/4/0/4
test_pbf antimeridian_4_0_5 antimeridian/4/0/5

>&2 echo "***** Test server response for comments *****"
test_jsn tbl_comment MixPoints
test_jsn fnc_comment function_Mixed_Name
Expand Down
Loading