<?xml version="1.0" encoding="UTF-8"?>
<sect1 id="Linear_Referencing">
<title>Linear Referencing</title>
+
<refentry id="ST_Line_Interpolate_Point">
<refnamediv>
<refname>ST_Line_Interpolate_Point</refname>
</refsection>
</refentry>
- <refentry id="ST_Locate_Along_Measure">
+ <refentry id="ST_LocateAlong">
<refnamediv>
- <refname>ST_Locate_Along_Measure</refname>
+ <refname>ST_LocateAlong</refname>
<refpurpose>Return a derived geometry collection value with elements
that match the specified measure. Polygonal elements are not
<refsynopsisdiv>
<funcsynopsis>
<funcprototype>
- <funcdef>geometry <function>ST_Locate_Along_Measure</function></funcdef>
+ <funcdef>geometry <function>ST_LocateAlong</function></funcdef>
<paramdef><type>geometry </type> <parameter>ageom_with_measure</parameter></paramdef>
<paramdef><type>float </type> <parameter>a_measure</parameter></paramdef>
+ <paramdef choice='opt'><type>float </type> <parameter>offset</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<para>Return a derived geometry collection value with elements
that match the specified measure. Polygonal elements are not
supported.</para>
+
+ <para>If an offset is provided, the resultant will be offset to the
+ left or right of the input line by the specified number of units.
+ A positive offset will be to the left, and a negative one to the
+ right.</para>
<para>Semantic is specified by: ISO/IEC CD 13249-3:200x(E) - Text
for Continuation CD Editing Meeting</para>
<refsection>
<title>Examples</title>
- <programlisting>SELECT ST_AsEWKT(the_geom)
+ <programlisting>SELECT ST_AsText(the_geom)
FROM
- (SELECT ST_Locate_Along_Measure(
- ST_GeomFromEWKT('MULTILINESTRINGM((1 2 3, 3 4 2, 9 4 3),
+ (SELECT ST_LocateAlong(
+ ST_GeomFromText('MULTILINESTRINGM((1 2 3, 3 4 2, 9 4 3),
(1 2 3, 5 4 5))'),3) As the_geom) As foo;
st_asewkt
-----------------------------------------------------------
- GEOMETRYCOLLECTIONM(MULTIPOINT(1 2 3,9 4 3),POINT(1 2 3))
+ MULTIPOINT M (1 2 3)
--Geometry collections are difficult animals so dump them
--to make them more digestable
-SELECT ST_AsEWKT((ST_Dump(the_geom)).geom)
+SELECT ST_AsText((ST_Dump(the_geom)).geom)
FROM
- (SELECT ST_Locate_Along_Measure(
- ST_GeomFromEWKT('MULTILINESTRINGM((1 2 3, 3 4 2, 9 4 3),
+ (SELECT ST_LocateAlong(
+ ST_GeomFromText('MULTILINESTRINGM((1 2 3, 3 4 2, 9 4 3),
(1 2 3, 5 4 5))'),3) As the_geom) As foo;
st_asewkt
<refsection>
<title>See Also</title>
- <para><xref linkend="ST_Dump" />, <xref linkend="ST_Locate_Between_Measures" /></para>
+ <para><xref linkend="ST_Dump" />, <xref linkend="ST_LocateBetween" /></para>
</refsection>
</refentry>
- <refentry id="ST_Locate_Between_Measures">
+ <refentry id="ST_LocateBetween">
<refnamediv>
- <refname>ST_Locate_Between_Measures</refname>
+ <refname>ST_LocateBetween</refname>
<refpurpose>Return a derived geometry collection value with elements
that match the specified range of measures inclusively. Polygonal
<refsynopsisdiv>
<funcsynopsis>
<funcprototype>
- <funcdef>geometry <function>ST_Locate_Between_Measures</function></funcdef>
+ <funcdef>geometry <function>ST_LocateBetween</function></funcdef>
<paramdef><type>geometry </type> <parameter>geomA</parameter></paramdef>
<paramdef><type>float </type> <parameter>measure_start</parameter></paramdef>
<paramdef><type>float </type> <parameter>measure_end</parameter></paramdef>
+ <paramdef choice='opt'><type>float </type> <parameter>offset</parameter></paramdef>
</funcprototype>
</funcsynopsis>
<refsection>
<title>Examples</title>
- <programlisting>SELECT ST_AsEWKT(the_geom)
+ <programlisting>SELECT ST_AsText(the_geom)
FROM
- (SELECT ST_Locate_Between_Measures(
- ST_GeomFromEWKT('MULTILINESTRINGM((1 2 3, 3 4 2, 9 4 3),
+ (SELECT ST_LocateBetween(
+ ST_GeomFromText('MULTILINESTRING M ((1 2 3, 3 4 2, 9 4 3),
(1 2 3, 5 4 5))'),1.5, 3) As the_geom) As foo;
st_asewkt
------------------------------------------------------------------
- GEOMETRYCOLLECTIONM(LINESTRING(1 2 3,3 4 2,9 4 3),POINT(1 2 3))
+------------------------------------------------------------------------
+ GEOMETRYCOLLECTION M (LINESTRING M (1 2 3,3 4 2,9 4 3),POINT M (1 2 3))
--Geometry collections are difficult animals so dump them
--to make them more digestable
-SELECT ST_AsEWKT((ST_Dump(the_geom)).geom)
+SELECT ST_AsText((ST_Dump(the_geom)).geom)
FROM
- (SELECT ST_Locate_Between_Measures(
- ST_GeomFromEWKT('MULTILINESTRINGM((1 2 3, 3 4 2, 9 4 3),
+ (SELECT ST_LocateBetween(
+ ST_GeomFromText('MULTILINESTRING M ((1 2 3, 3 4 2, 9 4 3),
(1 2 3, 5 4 5))'),1.5, 3) As the_geom) As foo;
st_asewkt
--------------------------------
- LINESTRINGM(1 2 3,3 4 2,9 4 3)
- POINTM(1 2 3)</programlisting>
+ LINESTRING M (1 2 3,3 4 2,9 4 3)
+ POINT M (1 2 3)</programlisting>
</refsection>
<!-- Optionally add a "See Also" section -->
<refsection>
<title>See Also</title>
- <para><xref linkend="ST_Dump" />, <xref linkend="ST_Locate_Along_Measure" /></para>
+ <para><xref linkend="ST_Dump" />, <xref linkend="ST_LocateAlong" /></para>
</refsection>
</refentry>
</refentry>
+ <refentry id="ST_InterpolatePoint">
+ <refnamediv>
+ <refname>ST_InterpolatePoint</refname>
+
+ <refpurpose>Return the value of the measure dimension of a geometry at the point closed to the provided point.</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>float <function>ST_InterpolatePoint</function></funcdef>
+ <paramdef><type>geometry </type> <parameter>line</parameter></paramdef>
+ <paramdef><type>geometry </type> <parameter>point</parameter></paramdef>
+ </funcprototype>
+
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsection>
+ <title>Description</title>
+
+ <para>Return the value of the measure dimension of a geometry at the point closed to the provided point.</para>
+
+ <para>Availability: 2.0.0</para>
+
+ <para>&Z_support;</para>
+ </refsection>
+
+ <refsection>
+ <title>Examples</title>
+
+ <programlisting>SELECT ST_InterpolatePoint('LINESTRING M (0 0 0, 10 0 20)', 'POINT(5 5)');
+ st_interpolatepoint
+ ---------------------
+ 10
+ </programlisting>
+ </refsection>
+
+ <refsection>
+ <title>See Also</title>
+
+ <para><xref linkend="ST_AddMeasure" /><xref linkend="ST_LocateAlong" /><xref linkend="ST_LocateBetween" /></para>
+ </refsection>
+
+ </refentry>
+
+
<refentry id="ST_AddMeasure">
<refnamediv>
<refname>ST_AddMeasure</refname>
<refsection>
<title>Examples</title>
- <programlisting>SELECT ST_AsEWKT(ST_AddMeasure(
+ <programlisting>SELECT ST_AsText(ST_AddMeasure(
ST_GeomFromEWKT('LINESTRING(1 0, 2 0, 4 0)'),1,4)) As ewelev;
ewelev
--------------------------------
LINESTRINGM(1 0 1,2 0 2,4 0 4)
-SELECT ST_AsEWKT(ST_AddMeasure(
+SELECT ST_AsText(ST_AddMeasure(
ST_GeomFromEWKT('LINESTRING(1 0 4, 2 0 4, 4 0 4)'),10,40)) As ewelev;
ewelev
----------------------------------------
LINESTRING(1 0 4 10,2 0 4 20,4 0 4 40)
-SELECT ST_AsEWKT(ST_AddMeasure(
+SELECT ST_AsText(ST_AddMeasure(
ST_GeomFromEWKT('LINESTRINGM(1 0 4, 2 0 4, 4 0 4)'),10,40)) As ewelev;
ewelev
----------------------------------------
LINESTRINGM(1 0 10,2 0 20,4 0 40)
-SELECT ST_AsEWKT(ST_AddMeasure(
+SELECT ST_AsText(ST_AddMeasure(
ST_GeomFromEWKT('MULTILINESTRINGM((1 0 4, 2 0 4, 4 0 4),(1 0 4, 2 0 4, 4 0 4))'),10,70)) As ewelev;
ewelev
-----------------------------------------------------------------
in = lwgeom_from_wkt(wkt, LW_PARSER_CHECK_NONE);
out = lwgeom_node(in);
tmp = lwgeom_to_ewkt(out);
- printf("%s\n", tmp);
+ /* printf("%s\n", tmp); */
CU_ASSERT_STRING_EQUAL("MULTILINESTRING((0 0,5 5,10 0),(10 0,11 0,12 0,20 0),(20 0,22 0))", tmp);
lwfree(tmp); lwgeom_free(out); lwgeom_free(in);
in = lwgeom_from_wkt(wkt, LW_PARSER_CHECK_NONE);
out = lwgeom_node(in);
tmp = lwgeom_to_ewkt(out);
- printf("%s\n", tmp);
+ /* printf("%s\n", tmp); */
CU_ASSERT_STRING_EQUAL(
"MULTILINESTRING((0 0,2.5 2.5),(0 5,2.5 2.5),(22 0,20 0),(20 0,12 0,11 0,10 0),(10 0,5 5,2.5 2.5),(2.5 2.5,5 0))",
tmp);
static void test_ptarray_locate_point(void)
{
- LWLINE *line;
+ LWLINE *line;
double loc, dist;
- POINT2D p;
+ POINT4D p, l;
- line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 4)"));
+ line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 4)"));
- p = getPoint2d(line->points, 0);
- loc = ptarray_locate_point(line->points, &p, &dist);
+ p = getPoint4d(line->points, 0);
+ loc = ptarray_locate_point(line->points, &p, &dist, &l);
CU_ASSERT_EQUAL(loc, 0);
CU_ASSERT_EQUAL(dist, 0.0);
- p = getPoint2d(line->points, 1);
- loc = ptarray_locate_point(line->points, &p, &dist);
+ p = getPoint4d(line->points, 1);
+ loc = ptarray_locate_point(line->points, &p, &dist, &l);
CU_ASSERT_EQUAL(loc, 1);
CU_ASSERT_EQUAL(dist, 0.0);
p.x = 21; p.y = 4;
- loc = ptarray_locate_point(line->points, &p, &dist);
+ loc = ptarray_locate_point(line->points, &p, &dist, NULL);
CU_ASSERT_EQUAL(loc, 1);
CU_ASSERT_EQUAL(dist, 1.0);
p.x = 0; p.y = 2;
- loc = ptarray_locate_point(line->points, &p, &dist);
+ loc = ptarray_locate_point(line->points, &p, &dist, &l);
CU_ASSERT_EQUAL(loc, 0);
CU_ASSERT_EQUAL(dist, 1.0);
line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,20 0,40 0)"));
p.x = 20; p.y = 0;
- loc = ptarray_locate_point(line->points, &p, &dist);
+ loc = ptarray_locate_point(line->points, &p, &dist, &l);
CU_ASSERT_EQUAL(loc, 0.5);
CU_ASSERT_EQUAL(dist, 0.0);
line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-40 0,0 0,20 0,40 0)"));
p.x = 20; p.y = 0;
- loc = ptarray_locate_point(line->points, &p, &dist);
+ loc = ptarray_locate_point(line->points, &p, &dist, &l);
CU_ASSERT_EQUAL(loc, 0.75);
CU_ASSERT_EQUAL(dist, 0.0);
static void test_ptarray_isccw(void)
{
- LWLINE *line;
+ LWLINE *line;
LWPOLY* poly;
int ccw;
/* clockwise rectangle */
- line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10,10 10,10 0, 0 0)"));
+ line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10,10 10,10 0, 0 0)"));
ccw = ptarray_isccw(line->points);
CU_ASSERT_EQUAL(ccw, 0);
lwline_free(line);
/* clockwise triangle */
- line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 4,20 3, 0 3)"));
+ line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 4,20 3, 0 3)"));
ccw = ptarray_isccw(line->points);
CU_ASSERT_EQUAL(ccw, 0);
lwline_free(line);
/* counterclockwise triangle */
- line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 3,20 4, 0 3)"));
+ line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 3,20 4, 0 3)"));
ccw = ptarray_isccw(line->points);
CU_ASSERT_EQUAL(ccw, 1);
lwline_free(line);
/* counterclockwise narrow ring (see ticket #1302) */
- line = lwgeom_as_lwline(lwgeom_from_hexwkb("01020000000500000000917E9BA468294100917E9B8AEA284137894120A4682941C976BE9F8AEA2841B39ABE1FA46829415ACCC29F8AEA2841C976BE1FA4682941C976BE9F8AEA284100917E9BA468294100917E9B8AEA2841", LW_PARSER_CHECK_NONE));
+ line = lwgeom_as_lwline(lwgeom_from_hexwkb("01020000000500000000917E9BA468294100917E9B8AEA284137894120A4682941C976BE9F8AEA2841B39ABE1FA46829415ACCC29F8AEA2841C976BE1FA4682941C976BE9F8AEA284100917E9BA468294100917E9B8AEA2841", LW_PARSER_CHECK_NONE));
ccw = ptarray_isccw(line->points);
CU_ASSERT_EQUAL(ccw, 1);
lwline_free(line);
* If not-null, the third argument will be set to the actual distance
* of the point from the pointarray.
*/
-extern double ptarray_locate_point(POINTARRAY *, POINT2D *, double *);
+extern double ptarray_locate_point(const POINTARRAY *pa, const POINT4D *pt, double *dist, POINT4D *p_located);
/**
* Add a measure dimension to a line, interpolating linearly from the start
/**
* Determine the location(s) along a measured line where m occurs and
-* return as a multipoint. Offset to left (negative) or right (positive).
+* return as a multipoint. Offset to left (positive) or right (negative).
*/
extern LWGEOM* lwgeom_locate_along(const LWGEOM *lwin, double m, double offset);
+/**
+* Determine the segments along a measured line that fall within the m-range
+* given. Return as a multiline or geometrycollection.
+* Offset to left (positive) or right (negative).
+*/
+extern LWCOLLECTION* lwgeom_locate_between(const LWGEOM *lwin, double from, double to, double offset);
+
+/**
+* Find the measure value at the location on the line closest to the point.
+*/
+extern double lwgeom_interpolate_point(const LWGEOM *lwin, const LWPOINT *lwpt);
+
/*
* Ensure every segment is at most 'dist' long.
* Returned LWGEOM might is unchanged if a POINT.
/*
* Point comparisons
*/
-int p4d_same(POINT4D p1, POINT4D p2);
+int p4d_same(const POINT4D *p1, const POINT4D *p2);
+int p2d_same(const POINT2D *p1, const POINT2D *p2);
/*
* Area calculations
* Write into *ret the coordinates of the closest point on
* segment A-B to the reference input point R
*/
-void closest_point_on_segment(POINT2D *R, POINT2D *A, POINT2D *B, POINT2D *ret);
+void closest_point_on_segment(const POINT4D *R, const POINT4D *A, const POINT4D *B, POINT4D *ret);
/*
* Repeated points
LWMLINE* v)
{
double loc, dist;
- POINT2D pt;
+ POINT4D pt, pt_projected;
POINTARRAY* pa1;
POINTARRAY* pa2;
double vstol; /* vertex snap tolerance */
* -> Return 1
*/
- getPoint2d_p(blade_in->point, 0, &pt);
- loc = ptarray_locate_point(lwline_in->points, &pt, &dist);
+ getPoint4d_p(blade_in->point, 0, &pt);
+ loc = ptarray_locate_point(lwline_in->points, &pt, &dist, &pt_projected);
/* lwnotice("Location: %g -- Distance: %g", loc, dist); */
return lwmpoint;
}
-static LWPOINT*
+static LWMPOINT*
lwpoint_locate_along(const LWPOINT *lwpoint, double m, double offset)
{
- LWGEOM *lwg = lwpoint_as_lwgeom(lwpoint);
double point_m = lwpoint_get_m(lwpoint);
+ LWGEOM *lwg = lwpoint_as_lwgeom(lwpoint);
+ LWMPOINT *r = lwmpoint_construct_empty(lwgeom_get_srid(lwg), lwgeom_has_z(lwg), lwgeom_has_m(lwg));
if ( FP_EQUALS(m, point_m) )
- return lwpoint_clone(lwpoint);
- else
- return lwpoint_construct_empty(lwgeom_get_srid(lwg), lwgeom_has_z(lwg), lwgeom_has_m(lwg));
+ {
+ lwmpoint_add_lwpoint(r, lwpoint_clone(lwpoint));
+ }
+ return r;
}
static LWMPOINT*
return out_offset;
}
+
+LWCOLLECTION*
+lwgeom_locate_between(const LWGEOM *lwin, double from, double to, double offset)
+{
+ if ( ! lwgeom_has_m(lwin) )
+ lwerror("Input geometry does not have a measure dimension");
+
+ return lwgeom_clip_to_ordinate_range(lwin, 'M', from, to, offset);
+}
+
+double
+lwgeom_interpolate_point(const LWGEOM *lwin, const LWPOINT *lwpt)
+{
+ POINT4D p, p_proj;
+ double ret = 0.0;
+
+ if ( ! lwin )
+ lwerror("lwgeom_interpolate_point: null input geometry!");
+
+ if ( ! lwgeom_has_m(lwin) )
+ lwerror("Input geometry does not have a measure dimension");
+
+ if ( lwgeom_is_empty(lwin) || lwpoint_is_empty(lwpt) )
+ lwerror("Input geometry is empty");
+
+ switch ( lwin->type )
+ {
+ case LINETYPE:
+ {
+ LWLINE *lwline = lwgeom_as_lwline(lwin);
+ lwpoint_getPoint4d_p(lwpt, &p);
+ ret = ptarray_locate_point(lwline->points, &p, NULL, &p_proj);
+ ret = p_proj.m;
+ break;
+ }
+ default:
+ lwerror("This function does not accept %s geometries.", lwtype_name(lwin->type));
+ }
+ return ret;
+}
\ No newline at end of file
getPoint4d_p(pa2, 0, &tmp2);
/* If the end point and start point are the same, then strip off the end point */
- if (p4d_same(tmp1, tmp2))
+ if (p4d_same(&tmp1, &tmp2))
{
pa1->npoints--;
}
* the given segment to the reference input point.
*/
void
-closest_point_on_segment(POINT2D *p, POINT2D *A, POINT2D *B, POINT2D *ret)
+closest_point_on_segment(const POINT4D *p, const POINT4D *A, const POINT4D *B, POINT4D *ret)
{
double r;
- if ( ( A->x == B->x) && (A->y == B->y) )
+ if ( FP_EQUALS(A->x, B->x) && FP_EQUALS(A->y, B->y) )
{
*ret = *A;
return;
ret->x = A->x + ( (B->x - A->x) * r );
ret->y = A->y + ( (B->y - A->y) * r );
+ ret->z = A->z + ( (B->z - A->z) * r );
+ ret->m = A->m + ( (B->m - A->m) * r );
}
/*
* and, optionally, it's actual distance from the point array.
*/
double
-ptarray_locate_point(POINTARRAY *pa, POINT2D *p, double* mindistout)
+ptarray_locate_point(const POINTARRAY *pa, const POINT4D *p4d, double *mindistout, POINT4D *proj4d)
{
double mindist=-1;
double tlen, plen;
int t, seg=-1;
- POINT2D start, end;
- POINT2D proj;
+ POINT4D start4d, end4d, projtmp;
+ POINT2D start, end, proj, p;
+
+ /* Initialize our 2D copy of the input parameter */
+ p.x = p4d->x;
+ p.y = p4d->y;
+
+ if ( ! proj4d ) proj4d = &projtmp;
getPoint2d_p(pa, 0, &start);
for (t=1; t<pa->npoints; t++)
{
double dist;
getPoint2d_p(pa, t, &end);
- dist = distance2d_pt_seg(p, &start, &end);
+ dist = distance2d_pt_seg(&p, &start, &end);
if (t==1 || dist < mindist )
{
* If mindist is not 0 we need to project the
* point on the closest segment.
*/
- if ( mindist > 0 )
+ if ( FP_GT(mindist, 0.0) )
{
- getPoint2d_p(pa, seg, &start);
- getPoint2d_p(pa, seg+1, &end);
- closest_point_on_segment(p, &start, &end, &proj);
+ getPoint4d_p(pa, seg, &start4d);
+ getPoint4d_p(pa, seg+1, &end4d);
+ closest_point_on_segment(p4d, &start4d, &end4d, proj4d);
}
else
{
- proj = *p;
+ if ( proj4d)
+ *proj4d = *p4d;
}
+
+ /* Copy 4D values into 2D holder */
+ proj.x = proj4d->x;
+ proj.y = proj4d->y;
LWDEBUGF(3, "Closest segment:%d, npoints:%d", seg, pa->npoints);
/* For robustness, force 1 when closest point == endpoint */
- if ( seg >= (pa->npoints-2) &&
- ( proj.x == end.x) && (proj.y == end.y) )
+ if ( (seg >= (pa->npoints-2)) && p2d_same(&proj, &end) )
{
- return 1;
+ return 1.0;
}
LWDEBUGF(3, "Closest point on segment: %g,%g", proj.x, proj.y);
int
-p4d_same(POINT4D p1, POINT4D p2)
+p4d_same(const POINT4D *p1, const POINT4D *p2)
+{
+ if( FP_EQUALS(p1->x,p2->x) && FP_EQUALS(p1->y,p2->y) && FP_EQUALS(p1->z,p2->z) && FP_EQUALS(p1->m,p2->m) )
+ return LW_TRUE;
+ else
+ return LW_FALSE;
+}
+
+int
+p2d_same(const POINT2D *p1, const POINT2D *p2)
{
- if( FP_EQUALS(p1.x,p2.x) && FP_EQUALS(p1.y,p2.y) && FP_EQUALS(p1.z,p2.z) && FP_EQUALS(p1.m,p2.m) )
+ if( FP_EQUALS(p1->x,p2->x) && FP_EQUALS(p1->y,p2->y) )
return LW_TRUE;
else
return LW_FALSE;
}
-Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS);
-
-PG_FUNCTION_INFO_V1(LWGEOM_line_locate_point);
-Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS)
-{
- GSERIALIZED *geom1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
- GSERIALIZED *geom2 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
- LWLINE *lwline;
- LWPOINT *lwpoint;
- POINTARRAY *pa;
- POINT2D p;
- double ret;
-
- if ( gserialized_get_type(geom1) != LINETYPE )
- {
- elog(ERROR,"line_locate_point: 1st arg isnt a line");
- PG_RETURN_NULL();
- }
- if ( gserialized_get_type(geom2) != POINTTYPE )
- {
- elog(ERROR,"line_locate_point: 2st arg isnt a point");
- PG_RETURN_NULL();
- }
- if ( gserialized_get_srid(geom1) != gserialized_get_srid(geom2) )
- {
- elog(ERROR, "Operation on two geometries with different SRIDs");
- PG_RETURN_NULL();
- }
-
- lwline = lwgeom_as_lwline(lwgeom_from_gserialized(geom1));
- lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom2));
-
- pa = lwline->points;
- lwpoint_getPoint2d_p(lwpoint, &p);
-
- ret = ptarray_locate_point(pa, &p, NULL);
-
- PG_RETURN_FLOAT8(ret);
-}
-
/*******************************************************************************
* The following is based on the "Fast Winding Number Inclusion of a Point
* in a Polygon" algorithm by Dan Sunday.
#include "lwgeom_pg.h"
#include "math.h"
+/*
+* Add a measure dimension to a line, interpolating linearly from the
+* start value to the end value.
+* ST_AddMeasure(Geometry, StartMeasure, EndMeasure) returns Geometry
+*/
+Datum ST_AddMeasure(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(ST_AddMeasure);
+Datum ST_AddMeasure(PG_FUNCTION_ARGS)
+{
+ GSERIALIZED *gin = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(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 )
+ {
+ lwerror("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_release(lwin);
+
+ if ( lwout == NULL )
+ PG_RETURN_NULL();
+
+ gout = geometry_serialize(lwout);
+ lwgeom_free(lwout);
+
+ PG_RETURN_POINTER(gout);
+}
+
+
+/*
+* Locate a point along a feature based on a measure value.
+* ST_LocateAlong(Geometry, Measure, [Offset]) returns Geometry
+*/
+Datum ST_LocateAlong(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(ST_LocateAlong);
+Datum ST_LocateAlong(PG_FUNCTION_ARGS)
+{
+ GSERIALIZED *gin = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+ GSERIALIZED *gout;
+ LWGEOM *lwin = NULL, *lwout = NULL;
+ double measure = PG_GETARG_FLOAT8(1);
+ double offset = PG_GETARG_FLOAT8(2);;
+
+ lwin = lwgeom_from_gserialized(gin);
+ lwout = lwgeom_locate_along(lwin, measure, offset);
+ lwgeom_free(lwin);
+ PG_FREE_IF_COPY(gin, 0);
+
+ if ( ! lwout )
+ PG_RETURN_NULL();
+
+ gout = geometry_serialize(lwout);
+ lwgeom_free(lwout);
+
+ PG_RETURN_POINTER(gout);
+}
+
+
+/*
+* Locate the portion of a line between the specified measures
+*/
+Datum ST_LocateBetween(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(ST_LocateBetween);
+Datum ST_LocateBetween(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);
+ double offset = PG_GETARG_FLOAT8(3);
+ LWCOLLECTION *geom_out = NULL;
+ LWGEOM *line_in = NULL;
+ static char ordinate = 'M'; /* M */
+
+ if ( ! gserialized_has_m(geom_in) )
+ {
+ elog(ERROR,"This function only accepts geometries that have an M dimension.");
+ PG_RETURN_NULL();
+ }
+
+ /* This should be a call to ST_LocateAlong! */
+ if ( to == from )
+ {
+ PG_RETURN_DATUM(DirectFunctionCall3(ST_LocateAlong, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1), PG_GETARG_DATUM(3)));
+ }
+
+ line_in = lwgeom_from_gserialized(geom_in);
+ 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");
+ PG_RETURN_NULL();
+ }
+
+ PG_RETURN_POINTER(geometry_serialize((LWGEOM*)geom_out));
+}
+
+/*
+* Locate the portion of a line between the specified elevations
+*/
+Datum ST_LocateBetweenElevations(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(ST_LocateBetweenElevations);
+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;
+ static char ordinate = 'Z'; /* Z */
+ static double offset = 0.0;
+
+ if ( ! gserialized_has_z(geom_in) )
+ {
+ elog(ERROR,"This function only accepts LINESTRING or MULTILINESTRING with Z dimensions.");
+ PG_RETURN_NULL();
+ }
+
+ line_in = lwgeom_from_gserialized(geom_in);
+ 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");
+ PG_RETURN_NULL();
+ }
+
+ PG_RETURN_POINTER(geometry_serialize((LWGEOM*)geom_out));
+}
+
+
+Datum ST_InterpolatePoint(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(ST_InterpolatePoint);
+Datum ST_InterpolatePoint(PG_FUNCTION_ARGS)
+{
+ GSERIALIZED *gser_line = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+ GSERIALIZED *gser_point = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+ LWGEOM *lwline;
+ LWPOINT *lwpoint;
+
+ if ( gserialized_get_type(gser_line) != LINETYPE )
+ {
+ elog(ERROR,"ST_InterpolatePoint: 1st argument isn't a line");
+ PG_RETURN_NULL();
+ }
+ if ( gserialized_get_type(gser_point) != POINTTYPE )
+ {
+ elog(ERROR,"ST_InterpolatePoint: 2st argument isn't a point");
+ PG_RETURN_NULL();
+ }
+ if ( gserialized_get_srid(gser_line) != gserialized_get_srid(gser_point) )
+ {
+ elog(ERROR, "Operation on two geometries with different SRIDs");
+ PG_RETURN_NULL();
+ }
+ if ( ! gserialized_has_m(gser_line) )
+ {
+ elog(ERROR,"ST_InterpolatePoint only accepts geometries that have an M dimension");
+ PG_RETURN_NULL();
+ }
+
+ lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(gser_point));
+ lwline = lwgeom_from_gserialized(gser_line);
+
+ PG_RETURN_FLOAT8(lwgeom_interpolate_point(lwline, lwpoint));
+}
+
+
+Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(LWGEOM_line_locate_point);
+Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS)
+{
+ GSERIALIZED *geom1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+ GSERIALIZED *geom2 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+ LWLINE *lwline;
+ LWPOINT *lwpoint;
+ POINTARRAY *pa;
+ POINT4D p, p_proj;
+ double ret;
+
+ if ( gserialized_get_type(geom1) != LINETYPE )
+ {
+ elog(ERROR,"line_locate_point: 1st arg isnt a line");
+ PG_RETURN_NULL();
+ }
+ if ( gserialized_get_type(geom2) != POINTTYPE )
+ {
+ elog(ERROR,"line_locate_point: 2st arg isnt a point");
+ PG_RETURN_NULL();
+ }
+ if ( gserialized_get_srid(geom1) != gserialized_get_srid(geom2) )
+ {
+ elog(ERROR, "Operation on two geometries with different SRIDs");
+ PG_RETURN_NULL();
+ }
+
+ lwline = lwgeom_as_lwline(lwgeom_from_gserialized(geom1));
+ lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom2));
+
+ pa = lwline->points;
+ lwpoint_getPoint4d_p(lwpoint, &p);
+
+ ret = ptarray_locate_point(pa, &p, NULL, &p_proj);
+
+ PG_RETURN_FLOAT8(ret);
+}
+
+
+/***********************************************************************
+* LEGACY SUPPORT FOR locate_between_measures and locate_along_measure
+* Deprecated at PostGIS 2.0. To be removed.
+*/
-Datum LWGEOM_locate_between_m(PG_FUNCTION_ARGS);
typedef struct
{
* See ISO/IEC CD 13249-3:200x(E)
*
*/
+Datum LWGEOM_locate_between_m(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(LWGEOM_locate_between_m);
Datum LWGEOM_locate_between_m(PG_FUNCTION_ARGS)
{
int hasm = gserialized_has_m(gin);
int type;
+ elog(NOTICE,"ST_Locate_Between_Measures and ST_Locate_Along_Measure are deprecated. Use ST_LocateAlong and ST_LocateBetween.");
+
if ( end_measure < start_measure )
{
lwerror("locate_between_m: 2nd arg must be bigger then 1st arg");
PG_RETURN_POINTER(gout);
}
-
-/*
-* Add a measure dimension to a line, interpolating linearly from the
-* start value to the end value.
-* ST_AddMeasure(Geometry, StartMeasure, EndMeasure) returns Geometry
-*/
-Datum ST_AddMeasure(PG_FUNCTION_ARGS);
-PG_FUNCTION_INFO_V1(ST_AddMeasure);
-Datum ST_AddMeasure(PG_FUNCTION_ARGS)
-{
- GSERIALIZED *gin = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(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 )
- {
- lwerror("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_release(lwin);
-
- if ( lwout == NULL )
- PG_RETURN_NULL();
-
- gout = geometry_serialize(lwout);
- lwgeom_free(lwout);
-
- PG_RETURN_POINTER(gout);
-}
-
-
-/*
-* Locate a point along a feature based on a measure value.
-* ST_LocateAlong(Geometry, Measure, [Offset]) returns Geometry
-*/
-Datum ST_LocateAlong(PG_FUNCTION_ARGS);
-PG_FUNCTION_INFO_V1(ST_LocateAlong);
-Datum ST_LocateAlong(PG_FUNCTION_ARGS)
-{
- GSERIALIZED *gin = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
- GSERIALIZED *gout;
- LWGEOM *lwin = NULL, *lwout = NULL;
- double measure = PG_GETARG_FLOAT8(1);
- double offset = PG_GETARG_FLOAT8(2);;
-
- lwin = lwgeom_from_gserialized(gin);
- lwout = lwgeom_locate_along(lwin, measure, offset);
- lwgeom_free(lwin);
- PG_FREE_IF_COPY(gin, 0);
-
- if ( ! lwout )
- PG_RETURN_NULL();
-
- gout = geometry_serialize(lwout);
- lwgeom_free(lwout);
-
- PG_RETURN_POINTER(gout);
-}
-
-
-/*
-* Locate the portion of a line between the specified measures
-*/
-Datum ST_LocateBetween(PG_FUNCTION_ARGS);
-PG_FUNCTION_INFO_V1(ST_LocateBetween);
-Datum ST_LocateBetween(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);
- double offset = PG_GETARG_FLOAT8(3);
- LWCOLLECTION *geom_out = NULL;
- LWGEOM *line_in = NULL;
- static char ordinate = 'M'; /* M */
-
- if ( ! gserialized_has_m(geom_in) )
- {
- elog(ERROR,"This function only accepts geometries that have an M dimension.");
- PG_RETURN_NULL();
- }
-
- line_in = lwgeom_from_gserialized(geom_in);
- 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");
- PG_RETURN_NULL();
- }
-
- PG_RETURN_POINTER(geometry_serialize((LWGEOM*)geom_out));
-}
-
-/*
-* Locate the portion of a line between the specified elevations
-*/
-Datum ST_LocateBetweenElevations(PG_FUNCTION_ARGS);
-PG_FUNCTION_INFO_V1(ST_LocateBetweenElevations);
-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;
- static char ordinate = 'Z'; /* Z */
- static double offset = 0.0;
-
- if ( ! gserialized_has_z(geom_in) )
- {
- elog(ERROR,"This function only accepts LINESTRING or MULTILINESTRING with Z dimensions.");
- PG_RETURN_NULL();
- }
-
- line_in = lwgeom_from_gserialized(geom_in);
- 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");
- PG_RETURN_NULL();
- }
-
- PG_RETURN_POINTER(geometry_serialize((LWGEOM*)geom_out));
-}
\ No newline at end of file
AS 'MODULE_PATHNAME', 'ST_LocateBetweenElevations'\r
LANGUAGE 'C' IMMUTABLE STRICT;\r
\r
+-- Availability: 2.0.0\r
+CREATE OR REPLACE FUNCTION ST_InterpolatePoint(Line geometry, Point geometry)\r
+ RETURNS float8\r
+ AS 'MODULE_PATHNAME', 'ST_InterpolatePoint'\r
+ LANGUAGE 'C' IMMUTABLE STRICT;\r
\r
- \r
---------------------------------------------------------------\r
-- END\r
---------------------------------------------------------------\r
-- Repeat all tests with the new function names.
-- No M value
-select '2d',ST_asewkt(ST_locate_along_measure('POINT(1 2)', 1));
-select '3dz',ST_asewkt(ST_locate_along_measure('POINT(1 2 3)', 1));
+select '2d',ST_AsText(ST_LocateAlong('POINT(1 2)', 1));
+select '3dz',ST_AsText(ST_LocateAlong('POINT(1 2 3)', 1));
-- Points
-select 'PNTM_1',ST_asewkt(ST_locate_along_measure('POINTM(1 2 3)', 1));
-select 'PNTM_2',ST_asewkt(ST_locate_along_measure('POINTM(1 2 3)', 3));
-select 'PNTM_3',ST_asewkt(ST_locate_between_measures('POINTM(1 2 3)', 2, 3));
-select 'PNTM_4',ST_asewkt(ST_locate_between_measures('POINTM(1 2 3)', 3, 4));
-select 'PNTM_5',ST_asewkt(ST_locate_between_measures('POINTM(1 2 4.00001)', 3, 4));
+select 'PNTM_1',ST_AsText(ST_LocateAlong('POINTM(1 2 3)', 1));
+select 'PNTM_2',ST_AsText(ST_LocateAlong('POINTM(1 2 3)', 3));
+select 'PNTM_3',ST_AsText(ST_LocateBetween('POINTM(1 2 3)', 2, 3));
+select 'PNTM_4',ST_AsText(ST_LocateBetween('POINTM(1 2 3)', 3, 4));
+select 'PNTM_5',ST_AsText(ST_LocateBetween('POINTM(1 2 4.00001)', 3, 4));
-- Multipoints
-select 'MPNT_1',ST_asewkt(ST_locate_between_measures('MULTIPOINTM(1 2 2)', 2, 5));
-select 'MPNT_2', ST_asewkt(ST_locate_between_measures('MULTIPOINTM(1 2 8, 2 2 5, 2 1 0)', 2, 5));
-select 'MPNT_3', ST_asewkt(ST_locate_between_measures('MULTIPOINTM(1 2 8, 2 2 5.1, 2 1 0)', 2, 5));
-select 'MPNT_4', ST_asewkt(ST_locate_between_measures('MULTIPOINTM(1 2 8, 2 2 5, 2 1 0)', 4, 8));
+select 'MPNT_1',ST_AsText(ST_LocateBetween('MULTIPOINTM(1 2 2)', 2, 5));
+select 'MPNT_2', ST_AsText(ST_LocateBetween('MULTIPOINTM(1 2 8, 2 2 5, 2 1 0)', 2, 5));
+select 'MPNT_3', ST_AsText(ST_LocateBetween('MULTIPOINTM(1 2 8, 2 2 5.1, 2 1 0)', 2, 5));
+select 'MPNT_4', ST_AsText(ST_LocateBetween('MULTIPOINTM(1 2 8, 2 2 5, 2 1 0)', 4, 8));
-- Linestrings
-select 'LINEZM_1', ST_asewkt(ST_locate_between_measures('LINESTRING(0 10 100 0, 0 0 0 10)', 2, 18));
-select 'LINEZM_2', ST_asewkt(ST_locate_between_measures('LINESTRING(0 10 0 0, 0 0 100 10)', 2, 18));
-select 'LINEZM_3', ST_asewkt(ST_locate_between_measures('LINESTRING(0 10 100 0, 0 0 0 10, 10 0 0 0)', 2, 18));
-select 'LINEZM_4', ST_asewkt(ST_locate_between_measures('LINESTRING(0 10 100 0, 0 0 0 20, 10 0 0 0)', 2, 18));
-select 'LINEZM_5', ST_asewkt(ST_locate_between_measures('LINESTRING(0 10 100 0, 0 0 0 20, 0 10 10 40, 10 0 0 0)', 2, 18));
-select 'LINEZM_6', ST_asewkt(ST_locate_between_measures('LINESTRING(0 10 10 40, 10 0 0 0)', 2, 2));
+select 'LINEZM_1', ST_AsText(ST_LocateBetween('LINESTRING(0 10 100 0, 0 0 0 10)', 2, 18));
+select 'LINEZM_2', ST_AsText(ST_LocateBetween('LINESTRING(0 10 0 0, 0 0 100 10)', 2, 18));
+select 'LINEZM_3', ST_AsText(ST_LocateBetween('LINESTRING(0 10 100 0, 0 0 0 10, 10 0 0 0)', 2, 18));
+select 'LINEZM_4', ST_AsText(ST_LocateBetween('LINESTRING(0 10 100 0, 0 0 0 20, 10 0 0 0)', 2, 18));
+select 'LINEZM_5', ST_AsText(ST_LocateBetween('LINESTRING(0 10 100 0, 0 0 0 20, 0 10 10 40, 10 0 0 0)', 2, 18));
+select 'LINEZM_6', ST_AsText(ST_LocateBetween('LINESTRING(0 10 10 40, 10 0 0 0)', 2, 2));
--- line_locate_point
--- line_substring / line_interpolate_point
--- postgis-devel/2006-January/001951.html
-select 'line_substring_1', ST_asewkt(ST_line_substring(ST_geomfromewkt('SRID=4326;LINESTRING(0 0 0 0, 1 1 1 1, 2 2 2 2, 3 3 3 3, 4 4 4 4)'), 0.5, 0.8));
-
-select 'line_substring_2', ST_asewkt(ST_line_substring('LINESTRING(0 0 0 0, 1 1 1 1, 2 2 2 2, 3 3 3 3, 4 4 4 4)', 0.5, 0.75));
-select 'line_substring_3', ST_asewkt(ST_line_substring('LINESTRING(0 0, 1 1, 2 2)', 0, 0.5));
-select 'line_substring_4', ST_asewkt(ST_line_substring('LINESTRING(0 0, 1 1, 2 2)', 0.5, 1));
-select 'line_substring_5', ST_asewkt(ST_line_substring('LINESTRING(0 0, 2 2)', 0.5, 1));
-select 'line_substring_6', ST_asewkt(ST_line_substring('LINESTRING(0 0, 2 2)', 0, 0.5));
-select 'line_substring_7', ST_asewkt(ST_line_substring('LINESTRING(0 0, 4 4)', .25, 0.5));
-select 'line_substring_8', ST_asewkt(ST_line_substring('LINESTRINGM(0 0 0, 4 4 4)', .25, 0.5));
-select 'line_substring_9', ST_asewkt(ST_line_substring('LINESTRINGM(0 0 4, 4 4 0)', .25, 0.5));
-select 'line_substring_10', ST_asewkt(ST_line_substring('LINESTRING(0 0 4, 4 4 0)', .25, 0.5));
-
-select 'line_substring_11', ST_asewkt(ST_line_substring('LINESTRING(0 0, 1 1)', 0, 0));
-select 'line_substring_12', ST_asewkt(ST_line_substring('LINESTRING(0 0 10, 1 1 5)', 0.5, .5));
+with substr as (
+ select ST_line_substring(ST_geomfromewkt('SRID=4326;LINESTRING(0 0 0 0, 1 1 1 1, 2 2 2 2, 3 3 3 3, 4 4 4 4)'), 0.5, 0.8) as ln
+)
+select 'line_substring_1', ST_SRID(ln), ST_AsText(ln) from substr;
+
+select 'line_substring_2', ST_AsText(ST_line_substring('LINESTRING(0 0 0 0, 1 1 1 1, 2 2 2 2, 3 3 3 3, 4 4 4 4)', 0.5, 0.75));
+select 'line_substring_3', ST_AsText(ST_line_substring('LINESTRING(0 0, 1 1, 2 2)', 0, 0.5));
+select 'line_substring_4', ST_AsText(ST_line_substring('LINESTRING(0 0, 1 1, 2 2)', 0.5, 1));
+select 'line_substring_5', ST_AsText(ST_line_substring('LINESTRING(0 0, 2 2)', 0.5, 1));
+select 'line_substring_6', ST_AsText(ST_line_substring('LINESTRING(0 0, 2 2)', 0, 0.5));
+select 'line_substring_7', ST_AsText(ST_line_substring('LINESTRING(0 0, 4 4)', .25, 0.5));
+select 'line_substring_8', ST_AsText(ST_line_substring('LINESTRINGM(0 0 0, 4 4 4)', .25, 0.5));
+select 'line_substring_9', ST_AsText(ST_line_substring('LINESTRINGM(0 0 4, 4 4 0)', .25, 0.5));
+select 'line_substring_10', ST_AsText(ST_line_substring('LINESTRING(0 0 4, 4 4 0)', .25, 0.5));
+
+select 'line_substring_11', ST_AsText(ST_line_substring('LINESTRING(0 0, 1 1)', 0, 0));
+select 'line_substring_12', ST_AsText(ST_line_substring('LINESTRING(0 0 10, 1 1 5)', 0.5, .5));
--- line_interpolate_point
-select 'line_interpolate_point', ST_asewkt(ST_line_interpolate_point('LINESTRING(0 0, 1 1)', 0));
-select 'line_interpolate_point', ST_asewkt(ST_line_interpolate_point('LINESTRING(0 0 10, 1 1 5)', 0.5));
+select 'line_interpolate_point', ST_AsText(ST_line_interpolate_point('LINESTRING(0 0, 1 1)', 0));
+select 'line_interpolate_point', ST_AsText(ST_line_interpolate_point('LINESTRING(0 0 10, 1 1 5)', 0.5));
-ERROR: Geometry argument does not have an 'M' ordinate
-ERROR: Geometry argument does not have an 'M' ordinate
-PNTM_1|GEOMETRYCOLLECTIONM EMPTY
-PNTM_2|POINTM(1 2 3)
-PNTM_3|POINTM(1 2 3)
-PNTM_4|POINTM(1 2 3)
-PNTM_5|GEOMETRYCOLLECTIONM EMPTY
-MPNT_1|GEOMETRYCOLLECTIONM(POINTM(1 2 2))
-MPNT_2|GEOMETRYCOLLECTIONM(POINTM(2 2 5))
-MPNT_3|GEOMETRYCOLLECTIONM EMPTY
-MPNT_4|GEOMETRYCOLLECTIONM(POINTM(1 2 8),POINTM(2 2 5))
-LINEZM_1|LINESTRING(0 8 80 2,0 0 0 10)
-LINEZM_2|LINESTRING(0 8 20 2,0 0 100 10)
-LINEZM_3|LINESTRING(0 8 80 2,0 0 0 10,8 0 0 2)
-LINEZM_4|GEOMETRYCOLLECTION(LINESTRING(0 9 90 2,0 1 10 18),LINESTRING(1 0 0 18,9 0 0 2))
-LINEZM_5|GEOMETRYCOLLECTION(LINESTRING(0 9 90 2,0 1 10 18),LINESTRING(5.5 4.5 4.5 18,9.5 0.5 0.5 2))
-LINEZM_6|POINT(9.5 0.5 0.5 2)
+ERROR: Input geometry does not have a measure dimension
+ERROR: Input geometry does not have a measure dimension
+PNTM_1|MULTIPOINT M EMPTY
+PNTM_2|MULTIPOINT M (1 2 3)
+PNTM_3|MULTIPOINT M (1 2 3)
+PNTM_4|MULTIPOINT M (1 2 3)
+PNTM_5|MULTIPOINT M EMPTY
+MPNT_1|MULTIPOINT M (1 2 2)
+MPNT_2|MULTIPOINT M (2 2 5)
+MPNT_3|MULTIPOINT M EMPTY
+MPNT_4|MULTIPOINT M (1 2 8,2 2 5)
+LINEZM_1|MULTILINESTRING ZM ((0 8 80 2,0 0 0 10))
+LINEZM_2|MULTILINESTRING ZM ((0 8 20 2,0 0 100 10))
+LINEZM_3|MULTILINESTRING ZM ((0 8 80 2,0 0 0 10,8 0 0 2))
+LINEZM_4|MULTILINESTRING ZM ((0 9 90 2,0 1 10 18),(1 0 0 18,9 0 0 2))
+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)
line_locate_point_1|0.528602749909894
line_locate_point_2|1
line_locate_point_3|0
-line_substring_1|SRID=4326;LINESTRING(2 2 2 2,3 3 3 3,3.2 3.2 3.2 3.2)
-line_substring_2|LINESTRING(2 2 2 2,3 3 3 3)
+line_substring_1|4326|LINESTRING ZM (2 2 2 2,3 3 3 3,3.2 3.2 3.2 3.2)
+line_substring_2|LINESTRING ZM (2 2 2 2,3 3 3 3)
line_substring_3|LINESTRING(0 0,1 1)
line_substring_4|LINESTRING(1 1,2 2)
line_substring_5|LINESTRING(1 1,2 2)
line_substring_6|LINESTRING(0 0,1 1)
line_substring_7|LINESTRING(1 1,2 2)
-line_substring_8|LINESTRINGM(1 1 1,2 2 2)
-line_substring_9|LINESTRINGM(1 1 3,2 2 2)
-line_substring_10|LINESTRING(1 1 3,2 2 2)
+line_substring_8|LINESTRING M (1 1 1,2 2 2)
+line_substring_9|LINESTRING M (1 1 3,2 2 2)
+line_substring_10|LINESTRING Z (1 1 3,2 2 2)
line_substring_11|POINT(0 0)
-line_substring_12|POINT(0.5 0.5 7.5)
+line_substring_12|POINT Z (0.5 0.5 7.5)
line_interpolate_point|POINT(0 0)
-line_interpolate_point|POINT(0.5 0.5 7.5)
+line_interpolate_point|POINT Z (0.5 0.5 7.5)
#2|POLYGON((1 1,1 2,2 2,3 2,3 1,2 1,1 1))
#11|0
+NOTICE: ST_Locate_Between_Measures and ST_Locate_Along_Measure are deprecated. Use ST_LocateAlong and ST_LocateBetween.
#21|SRID=31293;POINTM(6220.13 5337367.145 4566)
t
ERROR: AddGeometryColumn() - invalid SRID
#83|MULTICURVE(CIRCULARSTRING(220268 150415,220227 150505,220227 150406))
ERROR: Unsupported geometry type: CircularString
#112|GEOMETRYCOLLECTION(POINT(-10 50))
+NOTICE: ST_Locate_Between_Measures and ST_Locate_Along_Measure are deprecated. Use ST_LocateAlong and ST_LocateBetween.
ERROR: Geometry argument does not have an 'M' ordinate
#116|POLYGON EMPTY
#122|CIRCULARSTRING(220268 150415,220227 150505,220227 150406)