New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mvt serialized #358
Mvt serialized #358
Changes from 2 commits
638590c
35ea21c
6aa7c58
8f09945
dce045b
7bade58
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -45,26 +45,76 @@ Datum ST_AsMVTGeom(PG_FUNCTION_ARGS) | |||||
elog(ERROR, "Missing libprotobuf-c"); | ||||||
PG_RETURN_NULL(); | ||||||
#else | ||||||
LWGEOM *lwgeom_in, *lwgeom_out; | ||||||
GBOX *bounds = NULL; | ||||||
int32_t extent = 0; | ||||||
int32_t buffer = 0; | ||||||
bool clip_geom = true; | ||||||
GSERIALIZED *geom_in, *geom_out; | ||||||
GBOX *bounds; | ||||||
int extent, buffer; | ||||||
bool clip_geom; | ||||||
LWGEOM *lwgeom_in, *lwgeom_out; | ||||||
uint8_t type = 0; | ||||||
|
||||||
if (PG_ARGISNULL(0)) | ||||||
{ | ||||||
PG_RETURN_NULL(); | ||||||
geom_in = PG_GETARG_GSERIALIZED_P_COPY(0); | ||||||
lwgeom_in = lwgeom_from_gserialized(geom_in); | ||||||
} | ||||||
|
||||||
if (PG_ARGISNULL(1)) | ||||||
{ | ||||||
elog(ERROR, "%s: parameter bounds cannot be null", __func__); | ||||||
bounds = (GBOX *) PG_GETARG_POINTER(1); | ||||||
PG_RETURN_NULL(); | ||||||
} | ||||||
bounds = (GBOX *)PG_GETARG_POINTER(1); | ||||||
if (bounds->xmax - bounds->xmin <= 0 || bounds->ymax - bounds->ymin <= 0) | ||||||
{ | ||||||
elog(ERROR, "%s: bounds width or height cannot be 0", __func__); | ||||||
PG_RETURN_NULL(); | ||||||
} | ||||||
|
||||||
extent = PG_ARGISNULL(2) ? 4096 : PG_GETARG_INT32(2); | ||||||
if (extent <= 0) | ||||||
{ | ||||||
elog(ERROR, "%s: extent cannot be 0", __func__); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. check is <=, message is about =0 sharp. can lead to hours of looking for 0 in code :) |
||||||
PG_RETURN_NULL(); | ||||||
} | ||||||
|
||||||
buffer = PG_ARGISNULL(3) ? 256 : PG_GETARG_INT32(3); | ||||||
clip_geom = PG_ARGISNULL(4) ? true : PG_GETARG_BOOL(4); | ||||||
// NOTE: can both return in clone and in place modification so | ||||||
// not known if lwgeom_in can be freed | ||||||
|
||||||
geom_in = PG_GETARG_GSERIALIZED_P_COPY(0); | ||||||
type = gserialized_get_type(geom_in); | ||||||
|
||||||
/* If possible, peak into the bounding box before deserializating it to discard small geometries | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
* We don't check COLLECTIONTYPE since that might be a collection of points */ | ||||||
if (type == LINETYPE || type == POLYGONTYPE || type == MULTILINETYPE || type == MULTIPOLYGONTYPE) | ||||||
{ | ||||||
GBOX gserialized_box; | ||||||
/* We only apply the optimization if the bounding box is available */ | ||||||
if (gserialized_read_gbox_p(geom_in, &gserialized_box) == LW_SUCCESS) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there was a _peek function that also worked for two-point linestrings without box, maybe use it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wanted to avoid repeating work in the common case (where this speedup isn't applied): in that case he bounding box would be calculated first for this check and later when deserializing the geometry. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. here, _peek is only used in trivial cases: postgis/liblwgeom/g_serialized.c Line 639 in d1e5a63
I suggest going first two if-branches, not all three. It feels it can be refactored so that _peek calls _read first instead of failing on present box, and here you just call a _peek. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it really that common for geometries to not have a bounding box? I'm expecting basically everything (except points) to have it available, and if not the general path isn't There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Box is not written out for everything that _peek has code for. Line 1181 in 682db5d
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll make |
||||||
{ | ||||||
/* Shortcut to drop geometries smaller than the resolution */ | ||||||
double geom_width = gserialized_box.xmax - gserialized_box.xmin; | ||||||
double geom_height = gserialized_box.ymax - gserialized_box.ymin; | ||||||
double geom_area = geom_width * geom_height; | ||||||
|
||||||
double bounds_width = (bounds->xmax - bounds->xmin) / extent; | ||||||
double bounds_height = (bounds->ymax - bounds->ymin) / extent; | ||||||
|
||||||
/* We use half the area of the grid square as minimun resolution */ | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
double min_resolution_area = bounds_width * bounds_height / 2.0; | ||||||
|
||||||
if (geom_area < min_resolution_area) | ||||||
{ | ||||||
PG_RETURN_NULL(); | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
lwgeom_in = lwgeom_from_gserialized(geom_in); | ||||||
|
||||||
lwgeom_out = mvt_geom(lwgeom_in, bounds, extent, buffer, clip_geom); | ||||||
if (lwgeom_out == NULL) | ||||||
PG_RETURN_NULL(); | ||||||
|
||||||
geom_out = geometry_serialize(lwgeom_out); | ||||||
lwgeom_free(lwgeom_out); | ||||||
PG_FREE_IF_COPY(geom_in, 0); | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why? why not just return null?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was already like that (but it was done in
mvt_geom
). I didn't want to change the behaviourThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
then still <=0 and =0 mixup at least needs patching :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tried but I haven't found a way to create an invalid box (where max < min). Do you prefer using FP_LTEQ instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that we're checking for one thing and outputting a message about failing different check. It's never a good idea.
<= 0 are usually checks for math sanity, so there are no things like div0 or negative unsigned area, so FP_* aren't that good for them. If there wasn't such a check here, your later box size shortcut will filter all the geometries, so technically we can just emit a warning here that box is too small but output a valid empty thing instead of crashing the query. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like it. Passing a tiny (or invalid) bounding box is clearly an error. I'm not saying that it can't be done, but when I use ST_AsMVT functions I iterate over the geometry, not the bounding box, so in that case I'd end up with an empty tile without a way to know that this was a programming error.
I'll change it to something along the lines of
The geometric bounds are too small
.