From: Paul Ramsey Date: Thu, 12 Jan 2012 21:43:56 +0000 (+0000) Subject: Add in an offset option to ST_LocateBetween X-Git-Tag: 2.0.0alpha1~86 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6f1e0a2f48b0e7ec8d4b98bf7294a6744c8821b2;p=postgis Add in an offset option to ST_LocateBetween git-svn-id: http://svn.osgeo.org/postgis/trunk@8794 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in index 524861ddb..e3c53cc73 100644 --- a/liblwgeom/liblwgeom.h.in +++ b/liblwgeom/liblwgeom.h.in @@ -1272,7 +1272,7 @@ int lwline_crossing_direction(const LWLINE *l1, const LWLINE *l2); /** * Given a geometry clip based on the from/to range of one of its ordinates (x, y, z, m). Use for m- and z- clipping. */ -LWCOLLECTION* lwgeom_clip_to_ordinate_range(const LWGEOM *lwin, char ordinate, double from, double to); +LWCOLLECTION* lwgeom_clip_to_ordinate_range(const LWGEOM *lwin, char ordinate, double from, double to, double offset); /* * Export functions diff --git a/liblwgeom/lwlinearreferencing.c b/liblwgeom/lwlinearreferencing.c index ae67086da..988e13147 100644 --- a/liblwgeom/lwlinearreferencing.c +++ b/liblwgeom/lwlinearreferencing.c @@ -740,24 +740,70 @@ lwline_clip_to_ordinate_range(const LWLINE *line, char ordinate, double from, do } LWCOLLECTION* -lwgeom_clip_to_ordinate_range(const LWGEOM *lwin, char ordinate, double from, double to) +lwgeom_clip_to_ordinate_range(const LWGEOM *lwin, char ordinate, double from, double to, double offset) { + LWCOLLECTION *out_col; + LWCOLLECTION *out_offset; + int i; + if ( ! lwin ) lwerror("lwgeom_clip_to_ordinate_range: null input geometry!"); switch ( lwin->type ) { case LINETYPE: - return lwline_clip_to_ordinate_range((LWLINE*)lwin, ordinate, from, to); + out_col = lwline_clip_to_ordinate_range((LWLINE*)lwin, ordinate, from, to); + break; case MULTILINETYPE: - return lwmline_clip_to_ordinate_range((LWMLINE*)lwin, ordinate, from, to); + out_col = lwmline_clip_to_ordinate_range((LWMLINE*)lwin, ordinate, from, to); + break; case MULTIPOINTTYPE: - return lwmpoint_clip_to_ordinate_range((LWMPOINT*)lwin, ordinate, from, to); + out_col = lwmpoint_clip_to_ordinate_range((LWMPOINT*)lwin, ordinate, from, to); + break; case POINTTYPE: - return lwpoint_clip_to_ordinate_range((LWPOINT*)lwin, ordinate, from, to); + out_col = lwpoint_clip_to_ordinate_range((LWPOINT*)lwin, ordinate, from, to); + break; default: lwerror("This function does not accept %s geometries.", lwtype_name(lwin->type)); + return NULL;; + } + + /* Stop if result is NULL */ + if ( out_col == NULL ) + lwerror("lwgeom_clip_to_ordinate_range clipping routine returned NULL"); + + /* Return if we aren't going to offset the result */ + if ( FP_EQUALS(offset, 0.0) || lwgeom_is_empty(lwcollection_as_lwgeom(out_col)) ) + return out_col; + + /* Construct a collection to hold our outputs. */ + /* Things get ugly: GEOS offset drops Z's and M's so we have to drop ours */ + out_offset = lwcollection_construct_empty(MULTILINETYPE, lwin->srid, 0, 0); + + /* Try and offset the linear portions of the return value */ + for ( i = 0; i < out_col->ngeoms; i++ ) + { + int type = out_col->geoms[i]->type; + if ( type == POINTTYPE ) + { + lwnotice("lwgeom_clip_to_ordinate_range cannot offset a clipped point"); + continue; + } + else if ( type == LINETYPE ) + { + /* lwgeom_offsetcurve(line, offset, quadsegs, joinstyle (round), mitrelimit) */ + LWGEOM *lwoff = lwgeom_offsetcurve(lwgeom_as_lwline(out_col->geoms[i]), offset, 8, 1, 5.0); + if ( ! lwoff ) + { + lwerror("lwgeom_offsetcurve returned null"); + } + lwcollection_add_lwgeom(out_offset, lwoff); + } + else + { + lwerror("lwgeom_clip_to_ordinate_range found an unexpected type (%s) in the offset routine",lwtype_name(type)); + } } - return NULL; + return out_offset; } diff --git a/postgis/lwgeom_functions_lrs.c b/postgis/lwgeom_functions_lrs.c index 8e55c3f44..a39abbf87 100644 --- a/postgis/lwgeom_functions_lrs.c +++ b/postgis/lwgeom_functions_lrs.c @@ -610,10 +610,10 @@ Datum ST_LocateBetween(PG_FUNCTION_ARGS) } line_in = lwgeom_from_gserialized(geom_in); - geom_out = lwgeom_clip_to_ordinate_range(line_in, ordinate, from, to); + geom_out = lwgeom_clip_to_ordinate_range(line_in, ordinate, from, to, offset); lwgeom_free(line_in); PG_FREE_IF_COPY(geom_in, 0); - + if ( ! geom_out ) { elog(ERROR,"lwline_clip_to_ordinate_range returned null"); @@ -636,6 +636,7 @@ Datum ST_LocateBetweenElevations(PG_FUNCTION_ARGS) LWCOLLECTION *geom_out = NULL; LWGEOM *line_in = NULL; static char ordinate = 'Z'; /* Z */ + static double offset = 0.0; if ( ! gserialized_has_z(geom_in) ) { @@ -644,7 +645,7 @@ Datum ST_LocateBetweenElevations(PG_FUNCTION_ARGS) } line_in = lwgeom_from_gserialized(geom_in); - geom_out = lwgeom_clip_to_ordinate_range(line_in, ordinate, from, to); + geom_out = lwgeom_clip_to_ordinate_range(line_in, ordinate, from, to, offset); lwgeom_free(line_in); PG_FREE_IF_COPY(geom_in, 0);