Datum ST_AddMeasure(PG_FUNCTION_ARGS) { GSERIALIZED *gin = PG_GETARG_GSERIALIZED_P(0); GSERIALIZED *gout; double start_measure = PG_GETARG_FLOAT8(1); double end_measure = PG_GETARG_FLOAT8(2); LWGEOM *lwin, *lwout; int type = gserialized_get_type(gin); /* Raise an error if input is not a linestring or multilinestring */ if ( type != LINETYPE && type != MULTILINETYPE ) { lwpgerror("Only LINESTRING and MULTILINESTRING are supported"); PG_RETURN_NULL(); } lwin = lwgeom_from_gserialized(gin); if ( type == LINETYPE ) lwout = (LWGEOM*)lwline_measured_from_lwline((LWLINE*)lwin, start_measure, end_measure); else lwout = (LWGEOM*)lwmline_measured_from_lwmline((LWMLINE*)lwin, start_measure, end_measure); lwgeom_free(lwin); if ( lwout == NULL ) PG_RETURN_NULL(); gout = geometry_serialize(lwout); lwgeom_free(lwout); PG_RETURN_POINTER(gout); }
/** * Re-write the measure ordinate (or add one, if it isn't already there) interpolating * the measure between the supplied start and end values. */ LWMLINE* lwmline_measured_from_lwmline(const LWMLINE *lwmline, double m_start, double m_end) { int i = 0; int hasm = 0, hasz = 0; double length = 0.0, length_so_far = 0.0; double m_range = m_end - m_start; LWGEOM **geoms = NULL; if ( lwmline->type != MULTILINETYPE ) { lwerror("lwmline_measured_from_lmwline: only multiline types supported"); return NULL; } hasz = FLAGS_GET_Z(lwmline->flags); hasm = 1; /* Calculate the total length of the mline */ for ( i = 0; i < lwmline->ngeoms; i++ ) { LWLINE *lwline = (LWLINE*)lwmline->geoms[i]; if ( lwline->points && lwline->points->npoints > 1 ) { length += ptarray_length_2d(lwline->points); } } if ( lwgeom_is_empty((LWGEOM*)lwmline) ) { return (LWMLINE*)lwcollection_construct_empty(MULTILINETYPE, lwmline->srid, hasz, hasm); } geoms = lwalloc(sizeof(LWGEOM*) * lwmline->ngeoms); for ( i = 0; i < lwmline->ngeoms; i++ ) { double sub_m_start, sub_m_end; double sub_length = 0.0; LWLINE *lwline = (LWLINE*)lwmline->geoms[i]; if ( lwline->points && lwline->points->npoints > 1 ) { sub_length = ptarray_length_2d(lwline->points); } sub_m_start = (m_start + m_range * length_so_far / length); sub_m_end = (m_start + m_range * (length_so_far + sub_length) / length); geoms[i] = (LWGEOM*)lwline_measured_from_lwline(lwline, sub_m_start, sub_m_end); length_so_far += sub_length; } return (LWMLINE*)lwcollection_construct(lwmline->type, lwmline->srid, NULL, lwmline->ngeoms, geoms); }
static LWMPOINT* lwline_locate_along(const LWLINE *lwline, double m, double offset) { POINTARRAY *opa = NULL; LWMPOINT *mp = NULL; LWGEOM *lwg = lwline_as_lwgeom(lwline); int hasz, hasm, srid; /* Return degenerates upwards */ if ( ! lwline ) return NULL; /* Create empty return shell */ srid = lwgeom_get_srid(lwg); hasz = lwgeom_has_z(lwg); hasm = lwgeom_has_m(lwg); if ( hasm ) { /* Find points along */ opa = ptarray_locate_along(lwline->points, m, offset); } else { LWLINE *lwline_measured = lwline_measured_from_lwline(lwline, 0.0, 1.0); opa = ptarray_locate_along(lwline_measured->points, m, offset); lwline_free(lwline_measured); } /* Return NULL as EMPTY */ if ( ! opa ) return lwmpoint_construct_empty(srid, hasz, hasm); /* Convert pointarray into a multipoint */ mp = lwmpoint_construct(srid, opa); ptarray_free(opa); return mp; }