Commit 930aef3b authored by Raúl Marín's avatar Raúl Marín

ST_AsMVTGeom: Transform coordinates space before clipping

References #4300


git-svn-id: http://svn.osgeo.org/postgis/branches/2.5@17170 b70326c6-7e19-0410-871a-916f4a2858ee
parent eea82b49
Pipeline #43869055 passed with stage
in 24 minutes and 38 seconds
......@@ -28,7 +28,7 @@ XXXX/XX/XX
- #4273, Tighter parsing of WKT (Paul Ramsey)
- #4292, ST_AsMVT: parse JSON numeric values with decimals as doubles (Raúl Marín)
- #4300, ST_AsMVTGeom: Always return the simplest geometry (Raúl Marín)
- #4301, ST_Subdivide: fix endless loop on coordinates near coincident to bounds
......@@ -36,6 +36,8 @@ XXXX/XX/XX
- #4261, Use AccessShareLock in spatial_index_read_extent (Paul Ramsey)
- #4300, ST_AsMVTGeom: Transform coordinates space before clipping (Raúl Marín)
PostGIS 2.5.1
2018/11/18
......
......@@ -790,6 +790,86 @@ lwgeom_to_basic_type(LWGEOM *geom, uint8 original_type)
return geom_out;
}
static LWGEOM *
mvt_clip_and_validate_geos(LWGEOM *lwgeom, uint8_t basic_type, uint32_t extent, uint32_t buffer, bool clip_geom)
{
LWGEOM *ng = lwgeom;
if (clip_geom)
{
GBOX bgbox, lwgeom_gbox;
gbox_init(&bgbox);
gbox_init(&lwgeom_gbox);
bgbox.xmax = bgbox.ymax = (double)extent + (double)buffer;
bgbox.xmin = bgbox.ymin = -(double)buffer;
FLAGS_SET_GEODETIC(lwgeom_gbox.flags, 0);
FLAGS_SET_GEODETIC(bgbox.flags, 0);
lwgeom_calculate_gbox(lwgeom, &lwgeom_gbox);
if (!gbox_overlaps_2d(&lwgeom_gbox, &bgbox))
{
POSTGIS_DEBUG(3, "mvt_geom: geometry outside clip box");
return NULL;
}
if (!gbox_contains_2d(&bgbox, &lwgeom_gbox))
{
LWGEOM *clipped_geom =
lwgeom_clip_by_rect(lwgeom, bgbox.xmin, bgbox.ymin, bgbox.xmax, bgbox.ymax);
if (clipped_geom == NULL || lwgeom_is_empty(clipped_geom))
{
POSTGIS_DEBUG(3, "mvt_geom: no geometry after clip");
return NULL;
}
/* For some polygons, the simplify step might have left them
* as invalid, which can cause clipping to return the complementary
* geometry of what it should */
if ((basic_type == POLYGONTYPE) &&
!gbox_contains_2d(&lwgeom_gbox, lwgeom_get_bbox(clipped_geom)))
{
/* TODO: Adapt this when and if Exception Policies are introduced.
* Other options would be to fix the geometry and retry
* or to calculate the difference between the 2 boxes.
*/
POSTGIS_DEBUG(3, "mvt_geom: Invalid geometry after clipping");
lwgeom_free(clipped_geom);
return NULL;
}
ng = clipped_geom;
}
}
if (basic_type == POLYGONTYPE)
{
/* Force validation as per MVT spec */
ng = lwgeom_make_valid(ng);
/* In image coordinates CW actually comes out a CCW, so we reverse */
lwgeom_force_clockwise(ng);
lwgeom_reverse_in_place(ng);
}
/* Make sure we return the most basic type after simplification and validation */
ng = lwgeom_to_basic_type(ng, basic_type);
if (basic_type != lwgeom_get_basic_type(ng))
{
/* Drop type changes to play nice with MVT renderers */
POSTGIS_DEBUG(3, "mvt_geom: Dropping geometry after type change");
return NULL;
}
/* Clipping and validation might produce float values. Grid again into int
* and pray that the output is still valid */
{
gridspec grid = {0, 0, 0, 0, 1, 1, 0, 0};
lwgeom_grid_in_place(ng, &grid);
}
return ng;
}
/**
* Transform a geometry into vector tile coordinate space.
*
......@@ -801,8 +881,8 @@ lwgeom_to_basic_type(LWGEOM *geom, uint8 original_type)
LWGEOM *mvt_geom(LWGEOM *lwgeom, const GBOX *gbox, uint32_t extent, uint32_t buffer,
bool clip_geom)
{
AFFINE affine;
gridspec grid;
AFFINE affine = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
gridspec grid = {0, 0, 0, 0, 1, 1, 0, 0};
double width = gbox->xmax - gbox->xmin;
double height = gbox->ymax - gbox->ymin;
double resx, resy, res, fx, fy;
......@@ -810,6 +890,9 @@ LWGEOM *mvt_geom(LWGEOM *lwgeom, const GBOX *gbox, uint32_t extent, uint32_t buf
const uint8_t basic_type = lwgeom_get_basic_type(lwgeom);
POSTGIS_DEBUG(2, "mvt_geom called");
/* Simplify it as soon as possible */
lwgeom = lwgeom_to_basic_type(lwgeom, basic_type);
/* Short circuit out on EMPTY */
if (lwgeom_is_empty(lwgeom))
return NULL;
......@@ -834,53 +917,7 @@ LWGEOM *mvt_geom(LWGEOM *lwgeom, const GBOX *gbox, uint32_t extent, uint32_t buf
if (lwgeom_is_empty(lwgeom))
return NULL;
if (clip_geom)
{
// We need to add an extra half pixel to include the points that
// fall into the bbox only after the coordinate transformation
double buffer_map_xunits = nextafterf(res, 0.0) + resx * buffer;
GBOX bgbox;
const GBOX *lwgeom_gbox = lwgeom_get_bbox(lwgeom);
bgbox = *gbox;
gbox_expand(&bgbox, buffer_map_xunits);
if (!gbox_overlaps_2d(lwgeom_gbox, &bgbox))
{
POSTGIS_DEBUG(3, "mvt_geom: geometry outside clip box");
return NULL;
}
if (!gbox_contains_2d(&bgbox, lwgeom_gbox))
{
double x0 = bgbox.xmin;
double y0 = bgbox.ymin;
double x1 = bgbox.xmax;
double y1 = bgbox.ymax;
const GBOX pre_clip_box = *lwgeom_get_bbox(lwgeom);
LWGEOM *clipped_geom = lwgeom_clip_by_rect(lwgeom, x0, y0, x1, y1);
if (clipped_geom == NULL || lwgeom_is_empty(clipped_geom))
{
POSTGIS_DEBUG(3, "mvt_geom: no geometry after clip");
return NULL;
}
/* For some polygons, the simplify step might have left them
* as invalid, which can cause clipping to return the complementary
* geometry of what it should */
if ((basic_type == POLYGONTYPE) &&
!gbox_contains_2d(&pre_clip_box, lwgeom_get_bbox(clipped_geom)))
{
/* TODO: Adapt this when and if Exception Policies are introduced.
* Other options would be to fix the geometry and retry
* or to calculate the difference between the 2 boxes.
*/
POSTGIS_DEBUG(3, "mvt_geom: Invalid geometry after clipping");
lwgeom_free(clipped_geom);
return NULL;
}
lwgeom = clipped_geom;
}
}
/* transform to tile coordinate space */
memset(&affine, 0, sizeof(affine));
affine.afac = fx;
affine.efac = fy;
affine.ifac = 1;
......@@ -889,37 +926,12 @@ LWGEOM *mvt_geom(LWGEOM *lwgeom, const GBOX *gbox, uint32_t extent, uint32_t buf
lwgeom_affine(lwgeom, &affine);
/* snap to integer precision, removing duplicate points */
memset(&grid, 0, sizeof(gridspec));
grid.ipx = 0;
grid.ipy = 0;
grid.xsize = 1;
grid.ysize = 1;
lwgeom_grid_in_place(lwgeom, &grid);
if (lwgeom == NULL || lwgeom_is_empty(lwgeom))
return NULL;
if (basic_type == POLYGONTYPE)
{
/* Force validation as per MVT spec */
lwgeom = lwgeom_make_valid(lwgeom);
/* In image coordinates CW actually comes out a CCW, so we reverse */
lwgeom_force_clockwise(lwgeom);
lwgeom_reverse_in_place(lwgeom);
}
/* if geometry collection extract highest dimensional geometry type */
lwgeom = lwgeom_to_basic_type(lwgeom, basic_type);
if (basic_type != lwgeom_get_basic_type(lwgeom))
{
/* Drop type changes to play nice with MVT renderers */
POSTGIS_DEBUG(3, "mvt_geom: Dropping geometry after type change");
return NULL;
}
lwgeom = mvt_clip_and_validate_geos(lwgeom, basic_type, extent, buffer, clip_geom);
if (lwgeom == NULL || lwgeom_is_empty(lwgeom))
return NULL;
......
This diff is collapsed.
......@@ -3,18 +3,19 @@ PG2|POINT(0 4095)
PG3|POINT(2 4092)
PG4|MULTIPOLYGON(((5 4096,10 4091,10 4096,5 4096)),((5 4096,0 4101,0 4096,5 4096)))
PG5|
PG6|POLYGON((894 2704,600 594,2791 594,894 2704))
PG6|POLYGON((2791 594,894 2704,600 594,2791 594))
PG7|POLYGON((1252 1904,1253 1905,1253 1906,1251 1904,1252 1904))
PG8|MULTIPOLYGON(((5 4096,10 4091,10 4096,5 4096)),((5 4096,0 4101,0 4096,5 4096)))
PG9|POLYGON((0 4096,0 0,4096 0,4096 4096,0 4096))
PG9|16777216
PG9.1|2|12.5|f
PG10|
PG11|POLYGON((0 10,0 0,10 0,10 10,0 10))
PG11|POLYGON((10 0,10 10,0 10,0 0,10 0))
PG12|POLYGON((0 10,0 0,10 0,10 10,0 10))
PG13|POLYGON((0 10,0 0,10 0,10 10,0 10),(1 9,9 9,9 1,1 1,1 9))
PG14|POLYGON((0 10,0 0,10 0,10 10,0 10),(1 9,9 9,9 1,1 1,1 9))
PG15|POLYGON((0 10,0 0,10 0,10 10,0 10),(1 9,9 9,9 1,1 1,1 9))
PG16|POLYGON((0 10,0 0,10 0,10 10,0 10),(1 9,9 9,9 1,1 1,1 9))
PG17|MULTIPOLYGON(((0 10,0 0,10 0,10 10,0 10),(1 9,9 9,9 1,1 1,1 9)),((2 8,2 2,8 2,8 8,2 8),(3 7,7 7,7 3,3 3,3 7)))
PG13|POLYGON((10 0,10 10,0 10,0 0,10 0),(9 1,1 1,1 9,9 9,9 1))
PG14|POLYGON((10 0,10 10,0 10,0 0,10 0),(1 9,9 9,9 1,1 1,1 9))
PG15|POLYGON((0 10,0 0,10 0,10 10,0 10),(9 1,1 1,1 9,9 9,9 1))
PG16|POLYGON((0 10,0 0,10 0,10 10,0 10),(9 1,1 1,1 9,9 9,9 1))
PG17|56
PG18|MULTIPOINT(1 9,3 8)
PG19|MULTIPOINT(25 4079,26 4078)
PG20|POINT(10 4086)
......@@ -36,26 +37,44 @@ PG35|POINT(4352 4352)
PG36|
PG37|
PG38|
PG39 - ON |POLYGON((0 0,10 0,9 2,10 2,10 10,0 10,0 0))
PG39 - OFF|POLYGON((0 0,10 0,9 2,10 2,10 10,0 10,0 0))
PG39 - ON |POLYGON((10 0,9 2,10 2,10 10,0 10,0 0,10 0))
PG39 - OFF|POLYGON((10 0,9 2,10 2,10 10,0 10,0 0,10 0))
PG40 - ON |LINESTRING(0 10,0 0)
PG40 - OFF|LINESTRING(0 10,0 0)
PG41 - ON |LINESTRING(0 10,0 4,0 2,0 0,1 0)
PG41 - OFF|LINESTRING(0 10,0 4,0 2,0 0,1 0)
PG42 - ON |LINESTRING(0 10,0 0,1 0)
PG42 - OFF|LINESTRING(0 10,0 0,1 0)
PG43 - ON |MULTIPOLYGON(((5 5,0 0,10 0,5 5)),((0 10,5 5,10 10,0 10)))
PG43 - ON |MULTIPOLYGON(((5 5,0 0,10 0,5 5)),((5 5,10 10,0 10,5 5)))
PG43 - OFF|MULTIPOLYGON(((5 5,-1 -1,11 -1,5 5)),((5 5,11 11,-1 11,5 5)))
PG44|
PG45|
PG46|SRID=3857;POLYGON((3245 2224,3262 2030,3253 2158,3245 2224))
PG46|SRID=3857;POLYGON((3262 2030,3253 2158,3245 2224,3262 2030))
PG47|
PG48|
PG49|
PG50|
PG51|10000
PG52|8000
PG53|600
PG54|
PG55|
PG56|
PG57|POLYGON((0 1,0 0,100 0,100 100,0 100,0 1))
PG58|POLYGON((0 100,0 90,10 90,10 100,0 100))
PG59|POLYGON((0 100,0 90,10 90,10 100,0 100))
PG60|POLYGON((0 100,0 90,10 90,10 100,0 100))
PG61|
PG62|POLYGON((0 100,0 90,10 90,10 100,0 100))
PG63|POLYGON((90 0,100 0,100 10,90 10,90 0))
PG64|
TG1|GiEKBHRlc3QSDBICAAAYASIECTLePxoCYzEiAigBKIAgeAI=
TG2|GiMKBHRlc3QSDhICAAAYASIGETLePwIBGgJjMSICKAEogCB4Ag==
TG3|GiYKBHRlc3QSERICAAAYAiIJCQCAQArQD88PGgJjMSICKAEogCB4Ag==
TG4|GiYKBHRlc3QSERICAAAYAiIJCQCAQArQD88PGgJjMSICKAEogCB4Ag==
TG5|GjAKBHRlc3QSGxICAAAYAiITCQL+PwrQD88PCc0Pzg8K0A/PDxoCYzEiAigBKIAgeAI=
TG6|GjIKBHRlc3QSHRICAAAYAyIVCUbsPxoxEwonPAkPCTEeEhQUCh0PGgJjMSICKAEogCB4Ag==
TG7|Gj0KBHRlc3QSKBICAAAYAyIgCVCwPxIKFDEdDwkAFCIyHh0eJwkAJw8JKBQSEwkAFA8aAmMxIgIo
TG6|GjIKBHRlc3QSHRICAAAYAyIVCVqmPxoTRjETCicPCSgKEh0KFBQPGgJjMSICKAEogCB4Ag==
TG7|Gj0KBHRlc3QSKBICAAAYAyIgCSi6PyIyHh0eJwkAJw8JFAoSABQUCQ8JEzESKAoKFA8aAmMxIgIo
ASiAIHgC
TG8|GiEKBHRlc3QSDBICAAAYASIECTLePxoCYzEiAigBKIAgeAI=
TG9|GiMKBHRlc3QSDhICAAAYASIGETLeP2VGGgJjMSICKAEogCB4Ag==
......@@ -98,4 +117,4 @@ D7|POINT(1 4094)
TU2
ERROR: pgis_asmvt_transfn: parameter row cannot be other than a rowtype
TU3|
#3922|POLYGON((2613 3664,2615 3662,2616 3662,2617 3665,2615 3665,2615 3664,2613 3664))
#3922|6.5
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment