From: Darafei Praliaskouski Date: Wed, 24 Oct 2018 21:56:42 +0000 (+0000) Subject: ST_LocateBetween[Elevations]: Support GEOMETRYCOLLECTION X-Git-Tag: 3.0.0alpha1~320 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=619bce0a24f257f2706c65a2e58c7b69cdaec722;p=postgis ST_LocateBetween[Elevations]: Support GEOMETRYCOLLECTION References #4155 git-svn-id: http://svn.osgeo.org/postgis/trunk@16949 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/NEWS b/NEWS index 82a24099e..292fd421d 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,8 @@ PostGIS 3.0.0 Praliaskouski) - #3457, Fix raster envelope shortcut in ST_Clip (Sai-bot) - #4215, Use floating point compare in ST_DumpAsPolygons (Darafei Praliaskouski) + - #4155, Support for GEOMETRYCOLLECTION in ST_LocateBetween (Darafei + Praliaskouski) PostGIS 2.5.0 2018/09/23 diff --git a/configure.ac b/configure.ac index 88f6dbacc..5369d6a92 100644 --- a/configure.ac +++ b/configure.ac @@ -60,8 +60,11 @@ AC_SUBST([PICFLAGS]) AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-math-errno], [_cv_nomatherrno], [-fno-math-errno], [], [CFLAGS="$CFLAGS -fno-math-errno"], []) AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-signed-zeros], [_cv_nosignedzeros], [-fno-signed-zeros], [], [CFLAGS="$CFLAGS -fno-signed-zeros"], []) +AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fopenmp], [_cv_openmp], [-fopenmp], [], [CFLAGS="$CFLAGS -fopenmp"], []) +AC_LIBTOOL_LINKER_OPTION([if $compiler supports -fopenmp], [_cv_openmp], [-fopenmp], [], [LDFLAGS="-fopenmp $LDFLAGS"], []) AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -std=gnu99], [_cv_std], -std=gnu99, [], [CFLAGS="-std=gnu99 $CFLAGS"], []) + dnl dnl For GCC enable additional warning flags -Wall and -Wmissing-prototypes (using macro included with libtool) dnl diff --git a/liblwgeom/cunit/cu_algorithm.c b/liblwgeom/cunit/cu_algorithm.c index 3e9741c6b..02d181236 100644 --- a/liblwgeom/cunit/cu_algorithm.c +++ b/liblwgeom/cunit/cu_algorithm.c @@ -665,7 +665,7 @@ static void test_lwmline_clip(void) mline = (LWMLINE*)lwgeom_from_wkt("MULTILINESTRING((0 0,0 1,0 2,0 3,0 4))", LW_PARSER_CHECK_NONE); /* Clip in the middle, mid-range. */ - c = lwmline_clip_to_ordinate_range(mline, 'Y', 1.5, 2.5); + c = lwcollection_clip_to_ordinate_range((LWCOLLECTION *)mline, 'Y', 1.5, 2.5); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0 1.5,0 2,0 2.5))"); @@ -680,7 +680,7 @@ static void test_lwmline_clip(void) mline = (LWMLINE*)lwgeom_from_wkt("MULTILINESTRING((1 0,1 1,1 2,1 3,1 4), (0 0,0 1,0 2,0 3,0 4))", LW_PARSER_CHECK_NONE); /* Clip off the top. */ - c = lwmline_clip_to_ordinate_range(mline, 'Y', 3.5, 5.5); + c = lwcollection_clip_to_ordinate_range((LWCOLLECTION *)mline, 'Y', 3.5, 5.5); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((1 3.5,1 4),(0 3.5,0 4))"); @@ -695,7 +695,7 @@ static void test_lwmline_clip(void) mline = (LWMLINE*)lwgeom_from_wkt("MULTILINESTRING((1 0,1 -1,1 -2,1 -3,1 -4), (0 0,0 1,0 2,0 3,0 4))", LW_PARSER_CHECK_NONE); /* Clip from 0 upwards.. */ - c = lwmline_clip_to_ordinate_range(mline, 'Y', 0.0, 2.5); + c = lwcollection_clip_to_ordinate_range((LWCOLLECTION *)mline, 'Y', 0.0, 2.5); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "GEOMETRYCOLLECTION(POINT(1 0),LINESTRING(0 0,0 1,0 2,0 2.5))"); diff --git a/liblwgeom/liblwgeom_internal.h b/liblwgeom/liblwgeom_internal.h index e92ba7974..a8cba1003 100644 --- a/liblwgeom/liblwgeom_internal.h +++ b/liblwgeom/liblwgeom_internal.h @@ -240,9 +240,9 @@ int point_interpolate(const POINT4D *p1, const POINT4D *p2, POINT4D *p, int hasz LWCOLLECTION *lwline_clip_to_ordinate_range(const LWLINE *line, char ordinate, double from, double to); /** -* Clip a multi-line based on the from/to range of one of its ordinates. Use for m- and z- clipping -*/ -LWCOLLECTION *lwmline_clip_to_ordinate_range(const LWMLINE *mline, char ordinate, double from, double to); + * Clip collection based on the from/to range of one of its ordinates. Use for m- and z- clipping + */ +LWCOLLECTION *lwcollection_clip_to_ordinate_range(const LWCOLLECTION *col, char ordinate, double from, double to); /** * Clip a multi-point based on the from/to range of one of its ordinates. Use for m- and z- clipping diff --git a/liblwgeom/lwgeom.c b/liblwgeom/lwgeom.c index f632dabb7..9ad889f4f 100644 --- a/liblwgeom/lwgeom.c +++ b/liblwgeom/lwgeom.c @@ -2190,22 +2190,29 @@ lwgeom_grid(const LWGEOM *lwgeom, const gridspec *grid) /* Prototype for recursion */ -static int lwgeom_subdivide_recursive(const LWGEOM *geom, uint8_t dimension, uint32_t maxvertices, uint32_t depth, LWCOLLECTION *col); - -static int -lwgeom_subdivide_recursive(const LWGEOM *geom, uint8_t dimension, uint32_t maxvertices, uint32_t depth, LWCOLLECTION *col) +static void lwgeom_subdivide_recursive(const LWGEOM *geom, + uint8_t dimension, + uint32_t maxvertices, + uint32_t depth, + LWCOLLECTION *col); + +static void +lwgeom_subdivide_recursive(const LWGEOM *geom, + uint8_t dimension, + uint32_t maxvertices, + uint32_t depth, + LWCOLLECTION *col) { const uint32_t maxdepth = 50; GBOX clip, subbox1, subbox2; uint32_t nvertices = 0; - uint32_t i, n = 0; + uint32_t i; uint32_t split_ordinate; double width; double height; double pivot = DBL_MAX; double center = DBL_MAX; LWPOLY *lwpoly = NULL; - LWGEOM *clipped; gbox_duplicate(lwgeom_get_bbox(geom), &clip); width = clip.xmax - clip.xmin; @@ -2217,12 +2224,8 @@ lwgeom_subdivide_recursive(const LWGEOM *geom, uint8_t dimension, uint32_t maxve if ( width == 0.0 && height == 0.0 ) { if ( geom->type == POINTTYPE && dimension == 0) - { lwcollection_add_lwgeom(col, lwgeom_clone_deep(geom)); - return 1; - } - else - return 0; + return; } if (width == 0.0) @@ -2242,19 +2245,18 @@ lwgeom_subdivide_recursive(const LWGEOM *geom, uint8_t dimension, uint32_t maxve if ( lwgeom_is_collection(geom) && geom->type != MULTIPOINTTYPE ) { LWCOLLECTION *incol = (LWCOLLECTION*)geom; - int n = 0; /* Don't increment depth yet, since we aren't actually * subdividing geometries yet */ for ( i = 0; i < incol->ngeoms; i++ ) - n += lwgeom_subdivide_recursive(incol->geoms[i], dimension, maxvertices, depth, col); - return n; + lwgeom_subdivide_recursive(incol->geoms[i], dimension, maxvertices, depth, col); + return; } if (lwgeom_dimension(geom) < dimension) { /* We've hit a lower dimension object produced by clipping at * a shallower recursion level. Ignore it. */ - return 0; + return; } /* But don't go too far. 2^50 ~= 10^15, that's enough subdivision */ @@ -2262,19 +2264,20 @@ lwgeom_subdivide_recursive(const LWGEOM *geom, uint8_t dimension, uint32_t maxve if ( depth > maxdepth ) { lwcollection_add_lwgeom(col, lwgeom_clone_deep(geom)); - return 1; + return; } nvertices = lwgeom_count_vertices(geom); /* Skip empties entirely */ - if (nvertices == 0) return 0; + if (nvertices == 0) + return; /* If it is under the vertex tolerance, just add it, we're done */ if (nvertices <= maxvertices) { lwcollection_add_lwgeom(col, lwgeom_clone_deep(geom)); - return 1; + return; } split_ordinate = (width > height) ? 0 : 1; @@ -2339,27 +2342,43 @@ lwgeom_subdivide_recursive(const LWGEOM *geom, uint8_t dimension, uint32_t maxve ++depth; - LWGEOM* subbox = (LWGEOM*) lwpoly_construct_envelope(geom->srid, subbox1.xmin, subbox1.ymin, subbox1.xmax, subbox1.ymax); - clipped = lwgeom_intersection(geom, subbox); - lwgeom_simplify_in_place(clipped, 0.0, LW_TRUE); - lwgeom_free(subbox); - if (clipped) + LWCOLLECTION *col1 = + lwcollection_construct_empty(COLLECTIONTYPE, geom->srid, lwgeom_has_z(geom), lwgeom_has_m(geom)); + LWCOLLECTION *col2 = + lwcollection_construct_empty(COLLECTIONTYPE, geom->srid, lwgeom_has_z(geom), lwgeom_has_m(geom)); + //#pragma omp parallel sections { - n += lwgeom_subdivide_recursive(clipped, dimension, maxvertices, depth, col); - lwgeom_free(clipped); - } - - subbox = (LWGEOM*) lwpoly_construct_envelope(geom->srid, subbox2.xmin, subbox2.ymin, subbox2.xmax, subbox2.ymax); - clipped = lwgeom_intersection(geom, subbox); - lwgeom_simplify_in_place(clipped, 0.0, LW_TRUE); - lwgeom_free(subbox); - if (clipped) - { - n += lwgeom_subdivide_recursive(clipped, dimension, maxvertices, depth, col); - lwgeom_free(clipped); + //#pragma omp section + { + LWGEOM *subbox = (LWGEOM *)lwpoly_construct_envelope( + geom->srid, subbox1.xmin, subbox1.ymin, subbox1.xmax, subbox1.ymax); + LWGEOM *clipped = lwgeom_intersection(geom, subbox); + lwgeom_simplify_in_place(clipped, 0.0, LW_TRUE); + lwgeom_free(subbox); + if (clipped) + { + lwgeom_subdivide_recursive(clipped, dimension, maxvertices, depth, col1); + lwgeom_free(clipped); + } + } + //#pragma omp section + { + LWGEOM *subbox = (LWGEOM *)lwpoly_construct_envelope( + geom->srid, subbox2.xmin, subbox2.ymin, subbox2.xmax, subbox2.ymax); + LWGEOM *clipped = lwgeom_intersection(geom, subbox); + lwgeom_simplify_in_place(clipped, 0.0, LW_TRUE); + lwgeom_free(subbox); + if (clipped) + { + lwgeom_subdivide_recursive(clipped, dimension, maxvertices, depth, col2); + lwgeom_free(clipped); + } + } } - - return n; + col = lwcollection_concat_in_place(col, col1); + lwcollection_release(col1); + col = lwcollection_concat_in_place(col, col2); + lwcollection_release(col2); } LWCOLLECTION * @@ -2385,7 +2404,6 @@ lwgeom_subdivide(const LWGEOM *geom, uint32_t maxvertices) return col; } - int lwgeom_is_trajectory(const LWGEOM *geom) { diff --git a/liblwgeom/lwlinearreferencing.c b/liblwgeom/lwlinearreferencing.c index 6f627de20..3d9b8e99d 100644 --- a/liblwgeom/lwlinearreferencing.c +++ b/liblwgeom/lwlinearreferencing.c @@ -462,80 +462,45 @@ lwmpoint_clip_to_ordinate_range(const LWMPOINT *mpoint, char ordinate, double fr } /** -* Clip an input MULTILINESTRING between two values, on any ordinate input. -*/ -LWCOLLECTION* -lwmline_clip_to_ordinate_range(const LWMLINE *mline, char ordinate, double from, double to) + * Clip an input COLLECTION between two values, on any ordinate input. + */ +LWCOLLECTION * +lwcollection_clip_to_ordinate_range(const LWCOLLECTION *icol, char ordinate, double from, double to) { LWCOLLECTION *lwgeom_out = NULL; - if ( ! mline ) + if (!icol) { lwerror("Null input geometry."); return NULL; } - if ( mline->ngeoms == 1) - { - lwgeom_out = lwline_clip_to_ordinate_range(mline->geoms[0], ordinate, from, to); - } + if (icol->ngeoms == 1) + lwgeom_out = lwgeom_clip_to_ordinate_range(icol->geoms[0], ordinate, from, to, 0); else { LWCOLLECTION *col; - char hasz = lwgeom_has_z(lwmline_as_lwgeom(mline)); - char hasm = lwgeom_has_m(lwmline_as_lwgeom(mline)); - uint32_t i, j; - char homogeneous = 1; - size_t geoms_size = 0; - lwgeom_out = lwcollection_construct_empty(MULTILINETYPE, mline->srid, hasz, hasm); + char hasz = lwgeom_has_z(lwcollection_as_lwgeom(icol)); + char hasm = lwgeom_has_m(lwcollection_as_lwgeom(icol)); + uint32_t i; + lwgeom_out = lwcollection_construct_empty(icol->type, icol->srid, hasz, hasm); FLAGS_SET_Z(lwgeom_out->flags, hasz); FLAGS_SET_M(lwgeom_out->flags, hasm); - for ( i = 0; i < mline->ngeoms; i ++ ) + for (i = 0; i < icol->ngeoms; i++) { - col = lwline_clip_to_ordinate_range(mline->geoms[i], ordinate, from, to); - if ( col ) + col = lwgeom_clip_to_ordinate_range(icol->geoms[i], ordinate, from, to, 0); + if (col) { - /* Something was left after the clip. */ - if ( lwgeom_out->ngeoms + col->ngeoms > geoms_size ) - { - geoms_size += 16; - if ( lwgeom_out->geoms ) - { - lwgeom_out->geoms = lwrealloc(lwgeom_out->geoms, geoms_size * sizeof(LWGEOM*)); - } - else - { - lwgeom_out->geoms = lwalloc(geoms_size * sizeof(LWGEOM*)); - } - } - for ( j = 0; j < col->ngeoms; j++ ) - { - lwgeom_out->geoms[lwgeom_out->ngeoms] = col->geoms[j]; - lwgeom_out->ngeoms++; - } - if ( col->type != mline->type ) - { - homogeneous = 0; - } - /* Shallow free the struct, leaving the geoms behind. */ - if ( col->bbox ) lwfree(col->bbox); - lwfree(col->geoms); - lwfree(col); + if (col->type != icol->type) + lwgeom_out->type = COLLECTIONTYPE; + lwgeom_out = lwcollection_concat_in_place(lwgeom_out, col); + lwcollection_release(col); } } - if ( lwgeom_out->bbox ) - { - lwgeom_refresh_bbox((LWGEOM*)lwgeom_out); - } - - if ( ! homogeneous ) - { - lwgeom_out->type = COLLECTIONTYPE; - } + if (lwgeom_out->bbox) + lwgeom_refresh_bbox((LWGEOM *)lwgeom_out); } - return lwgeom_out; - } @@ -789,18 +754,24 @@ lwgeom_clip_to_ordinate_range(const LWGEOM *lwin, char ordinate, double from, do case LINETYPE: out_col = lwline_clip_to_ordinate_range((LWLINE*)lwin, ordinate, from, to); break; - case MULTILINETYPE: - out_col = lwmline_clip_to_ordinate_range((LWMLINE*)lwin, ordinate, from, to); - break; case MULTIPOINTTYPE: out_col = lwmpoint_clip_to_ordinate_range((LWMPOINT*)lwin, ordinate, from, to); break; case POINTTYPE: out_col = lwpoint_clip_to_ordinate_range((LWPOINT*)lwin, ordinate, from, to); break; + // case TRIANGLETYPE: + // out_col = lwtriangle_clip_to_ordinate_range((LWTRIANGLE*)lwin, ordinate, from, to); + // break; + case TINTYPE: + case MULTILINETYPE: + case MULTIPOLYGONTYPE: + case COLLECTIONTYPE: + out_col = lwcollection_clip_to_ordinate_range((LWCOLLECTION *)lwin, ordinate, from, to); + break; default: lwerror("This function does not accept %s geometries.", lwtype_name(lwin->type)); - return NULL;; + return NULL; } /* Stop if result is NULL */ diff --git a/postgis/geography_inout.c b/postgis/geography_inout.c index 87a449f5b..844e828d8 100644 --- a/postgis/geography_inout.c +++ b/postgis/geography_inout.c @@ -712,7 +712,7 @@ Datum geography_send(PG_FUNCTION_ARGS) result = palloc(size_result + VARHDRSZ); SET_VARSIZE(result, size_result + VARHDRSZ); memcpy(VARDATA(result), wkb, size_result); - pfree(wkb); + lwfree(wkb); PG_RETURN_POINTER(result); } diff --git a/postgis/lwgeom_functions_lrs.c b/postgis/lwgeom_functions_lrs.c index d5170c3da..d6dac837e 100644 --- a/postgis/lwgeom_functions_lrs.c +++ b/postgis/lwgeom_functions_lrs.c @@ -85,7 +85,7 @@ Datum ST_LocateAlong(PG_FUNCTION_ARGS) GSERIALIZED *gout; LWGEOM *lwin = NULL, *lwout = NULL; double measure = PG_GETARG_FLOAT8(1); - double offset = PG_GETARG_FLOAT8(2);; + double offset = PG_GETARG_FLOAT8(2); lwin = lwgeom_from_gserialized(gin); lwout = lwgeom_locate_along(lwin, measure, offset); @@ -160,7 +160,7 @@ Datum ST_LocateBetweenElevations(PG_FUNCTION_ARGS) if ( ! gserialized_has_z(geom_in) ) { - elog(ERROR,"This function only accepts LINESTRING or MULTILINESTRING with Z dimensions."); + elog(ERROR, "This function only accepts geometries with Z dimensions."); PG_RETURN_NULL(); } diff --git a/regress/core/regress_lrs.sql b/regress/core/regress_lrs.sql index f504b9f70..b9aac3204 100644 --- a/regress/core/regress_lrs.sql +++ b/regress/core/regress_lrs.sql @@ -29,6 +29,9 @@ select '#3119a', ST_AsText(ST_LocateBetweenElevations('LINESTRING Z(0 0 0, 10 10 -- Multilinestrings -- #3119 -- select '#3119b', ST_AsText(ST_LocateBetweenElevations('MULTILINESTRING Z((0 0 0, 10 10 10))'::geometry, 11, 11)); +select '#4155.1', ST_AsText(ST_LocateBetweenElevations('GEOMETRYCOLLECTION(LINESTRING(0 0 0, 10 10 10))', 2, 5)); +select '#4155.2', ST_AsText(ST_LocateBetweenElevations('TIN Z EMPTY', 2, 5)); +select '#4155.3', ST_AsText(ST_LocateBetweenElevations('MULTIPOLYGON Z EMPTY', 2, 5)); --- line_locate_point diff --git a/regress/core/regress_lrs_expected b/regress/core/regress_lrs_expected index b6a54268e..90b724f30 100644 --- a/regress/core/regress_lrs_expected +++ b/regress/core/regress_lrs_expected @@ -17,6 +17,9 @@ LINEZM_5|MULTILINESTRING ZM ((0 9 90 2,0 1 10 18),(5.5 4.5 4.5 18,9.5 0.5 0.5 2) LINEZM_6|MULTIPOINT ZM (9.5 0.5 0.5 2) #3119a|MULTILINESTRING Z EMPTY #3119b|MULTILINESTRING Z EMPTY +#4155.1|MULTILINESTRING Z ((2 2 2,5 5 5)) +#4155.2|TIN Z EMPTY +#4155.3|MULTIPOLYGON Z EMPTY line_locate_point_1|0.528602749909894 line_locate_point_2|1 line_locate_point_3|0