Commit 619bce0a authored by Darafei Praliaskouski's avatar Darafei Praliaskouski

ST_LocateBetween[Elevations]: Support GEOMETRYCOLLECTION

References #4155



git-svn-id: http://svn.osgeo.org/postgis/trunk@16949 b70326c6-7e19-0410-871a-916f4a2858ee
parent aad8424d
Pipeline #34227690 passed with stage
in 31 minutes and 10 seconds
......@@ -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
......
......@@ -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
......
......@@ -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))");
......
......@@ -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
......
......@@ -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)
{
......
......@@ -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 */
......
......@@ -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);
}
......@@ -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();
}
......
......@@ -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
......
......@@ -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
......
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