Datum ST_LocateBetweenElevations(PG_FUNCTION_ARGS) { GSERIALIZED *geom_in = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); double from = PG_GETARG_FLOAT8(1); double to = PG_GETARG_FLOAT8(2); LWCOLLECTION *geom_out = NULL; LWGEOM *line_in = NULL; char geomtype = gserialized_get_type(geom_in); static int ordinate = 2; /* Z */ if ( ! ( geomtype == LINETYPE || geomtype == MULTILINETYPE ) ) { elog(ERROR,"This function only accepts LINESTRING or MULTILINESTRING as arguments."); PG_RETURN_NULL(); } line_in = lwgeom_from_gserialized(geom_in); if ( ! FLAGS_GET_Z(line_in->flags) ) { elog(ERROR,"This function only accepts LINESTRING or MULTILINESTRING with Z values as arguments."); PG_RETURN_NULL(); } if ( geomtype == LINETYPE ) { geom_out = lwline_clip_to_ordinate_range((LWLINE*)line_in, ordinate, from, to); } else if ( geomtype == MULTILINETYPE ) { geom_out = lwmline_clip_to_ordinate_range((LWMLINE*)line_in, ordinate, from, to); } lwgeom_free(line_in); if ( ! geom_out ) { elog(ERROR,"The lwline_clip_to_ordinate_range returned null."); PG_RETURN_NULL(); } PG_FREE_IF_COPY(geom_in, 0); PG_RETURN_POINTER(geometry_serialize((LWGEOM*)geom_out)); }
LWCOLLECTION* 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: 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; 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 out_offset; }
static void test_lwmline_clip(void) { LWCOLLECTION *c; char *ewkt; LWMLINE *mline = NULL; LWLINE *line = NULL; /* ** Set up the input line. Trivial one-member case. */ 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); 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))"); lwfree(ewkt); lwcollection_free(c); lwmline_free(mline); /* ** Set up the input line. Two-member case. */ 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); 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))"); lwfree(ewkt); lwcollection_free(c); lwmline_free(mline); /* ** Set up staggered input line to create multi-type output. */ 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); 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))"); lwfree(ewkt); lwcollection_free(c); lwmline_free(mline); /* ** Set up input line from MAC */ line = (LWLINE*)lwgeom_from_wkt("LINESTRING(0 0 0 0,1 1 1 1,2 2 2 2,3 3 3 3,4 4 4 4,3 3 3 5,2 2 2 6,1 1 1 7,0 0 0 8)", LW_PARSER_CHECK_NONE); /* Clip from 3 to 3.5 */ c = lwline_clip_to_ordinate_range(line, 'Z', 3.0, 3.5); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((3 3 3 3,3.5 3.5 3.5 3.5),(3.5 3.5 3.5 4.5,3 3 3 5))"); lwfree(ewkt); lwcollection_free(c); /* Clip from 2 to 3.5 */ c = lwline_clip_to_ordinate_range(line, 'Z', 2.0, 3.5); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((2 2 2 2,3 3 3 3,3.5 3.5 3.5 3.5),(3.5 3.5 3.5 4.5,3 3 3 5,2 2 2 6))"); lwfree(ewkt); lwcollection_free(c); /* Clip from 3 to 4 */ c = lwline_clip_to_ordinate_range(line, 'Z', 3.0, 4.0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((3 3 3 3,4 4 4 4,3 3 3 5))"); lwfree(ewkt); lwcollection_free(c); /* Clip from 2 to 3 */ c = lwline_clip_to_ordinate_range(line, 'Z', 2.0, 3.0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((2 2 2 2,3 3 3 3),(3 3 3 5,2 2 2 6))"); lwfree(ewkt); lwcollection_free(c); lwline_free(line); }