]> granicus.if.org Git - postgis/commitdiff
Add in an offset option to ST_LocateBetween
authorPaul Ramsey <pramsey@cleverelephant.ca>
Thu, 12 Jan 2012 21:43:56 +0000 (21:43 +0000)
committerPaul Ramsey <pramsey@cleverelephant.ca>
Thu, 12 Jan 2012 21:43:56 +0000 (21:43 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@8794 b70326c6-7e19-0410-871a-916f4a2858ee

liblwgeom/liblwgeom.h.in
liblwgeom/lwlinearreferencing.c
postgis/lwgeom_functions_lrs.c

index 524861ddbe3b1fa38a7f1e0c3eabf42abedfbb2f..e3c53cc73774f7114d44e6a1fbfbd28e849cdd9d 100644 (file)
@@ -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
index ae67086da05878404e39b2e333cbd92e3a6d5001..988e13147f1c0c3df894674f0f031712c3789ab9 100644 (file)
@@ -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;
 }
index 8e55c3f442c81651b62d24b219f8c4479a36a3ba..a39abbf874f35032be16185d8e6f45b9a4102161 100644 (file)
@@ -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);