[postgis-tickets] r15913 - Add ST_LineInterpolatePoints
Daniel Baston
dbaston at gmail.com
Thu Oct 5 18:00:28 PDT 2017
Author: dbaston
Date: 2017-10-05 18:00:27 -0700 (Thu, 05 Oct 2017)
New Revision: 15913
Added:
trunk/doc/html/image_src/st_line_interpolate_points01.wkt
Modified:
trunk/NEWS
trunk/doc/html/image_src/Makefile.in
trunk/doc/reference_lrs.xml
trunk/liblwgeom/cunit/cu_algorithm.c
trunk/liblwgeom/cunit/cu_tester.h
trunk/liblwgeom/liblwgeom.h.in
trunk/liblwgeom/lwgeom_api.c
trunk/liblwgeom/lwline.c
trunk/postgis/lwgeom_functions_analytic.c
trunk/postgis/postgis.sql.in
trunk/regress/regress_lrs.sql
trunk/regress/regress_lrs_expected
Log:
Add ST_LineInterpolatePoints
Closes #3564
Modified: trunk/NEWS
===================================================================
--- trunk/NEWS 2017-10-05 20:12:51 UTC (rev 15912)
+++ trunk/NEWS 2017-10-06 01:00:27 UTC (rev 15913)
@@ -2,6 +2,7 @@
2018/xx/xx
* New Features *
- #3876, ST_Angle function (RĂ©mi Cura)
+ - #3564, ST_LineInterpolatePoints (Dan Baston)
PostGIS 2.4.0
2017/09/30
Modified: trunk/doc/html/image_src/Makefile.in
===================================================================
--- trunk/doc/html/image_src/Makefile.in 2017-10-05 20:12:51 UTC (rev 15912)
+++ trunk/doc/html/image_src/Makefile.in 2017-10-06 01:00:27 UTC (rev 15913)
@@ -91,6 +91,7 @@
../images/st_linecrossingdirection03.png \
../images/st_linecrossingdirection04.png \
../images/st_line_interpolate_point01.png \
+ ../images/st_line_interpolate_points01.png \
../images/st_line_substring01.png \
../images/st_longestline01.png \
../images/st_longestline02.png \
Added: trunk/doc/html/image_src/st_line_interpolate_points01.wkt
===================================================================
--- trunk/doc/html/image_src/st_line_interpolate_points01.wkt (rev 0)
+++ trunk/doc/html/image_src/st_line_interpolate_points01.wkt 2017-10-06 01:00:27 UTC (rev 15913)
@@ -0,0 +1,3 @@
+Style2;LINESTRING(25 50, 100 125, 150 190)
+Style1-thinline;MULTIPOINT(51.5974135047432 76.5974135047432,78.1948270094864 103.194827009486,104.132163186446 130.37181214238,127.066081593223 160.18590607119,150 190)
+
Modified: trunk/doc/reference_lrs.xml
===================================================================
--- trunk/doc/reference_lrs.xml 2017-10-05 20:12:51 UTC (rev 15912)
+++ trunk/doc/reference_lrs.xml 2017-10-06 01:00:27 UTC (rev 15913)
@@ -83,10 +83,85 @@
<refsection>
<title>See Also</title>
- <para><xref linkend="ST_AsText" />, <xref linkend="ST_AsEWKT" />, <xref linkend="ST_Length" />, <xref linkend="ST_LineLocatePoint" /></para>
+ <para>
+ <xref linkend="ST_AsText" />,
+ <xref linkend="ST_AsEWKT" />,
+ <xref linkend="ST_Length" />,
+ <xref linkend="ST_LineInterpolatePoints" />
+ <xref linkend="ST_LineLocatePoint" />
+ O</para>
</refsection>
</refentry>
+ <refentry id="ST_LineInterpolatePoints">
+ <refnamediv>
+ <refname>ST_LineInterpolatePoints</refname>
+
+ <refpurpose>
+ Returns one or more points interpolated along a line.
+ </refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>geometry <function>ST_LineInterpolatePoints</function></funcdef>
+ <paramdef><type>geometry </type> <parameter>a_linestring</parameter></paramdef>
+ <paramdef><type>float8 </type> <parameter>a_fraction</parameter></paramdef>
+ <paramdef><type>boolean </type> <parameter>repeat</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsection>
+ <title>Description</title>
+
+ <para>Returns one or more points interpolated along a line. First argument
+ must be a LINESTRING. Second argument is a float8 between 0 and 1
+ representing the spacing between the points as a fraction of total
+ LineString length. If the third argument is false, at most one point
+ will be constructed (the function will be equivalent to <xref linkend="ST_LineInterpolatePoint" />.)
+ </para>
+
+ <para>
+ If the result has zero or one points, it will be returned as a POINT.
+ If it has two or more points, it will be returned as a MULTIPOINT.
+ </para>
+
+
+ <para>Availability: 2.5.0</para>
+ <para>&Z_support;</para>
+ <para>&M_support;</para>
+ </refsection>
+
+ <refsection>
+ <title>Examples</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/st_line_interpolate_points01.png" />
+ </imageobject>
+ <caption><para>A linestring with the interpolated points every 20% </para></caption>
+ </mediaobject>
+ </informalfigure>
+ <programlisting>--Return points each 20% along a 2D line
+SELECT ST_AsText(ST_LineInterpolatePoints('LINESTRING(25 50, 100 125, 150 190)', 0.20))
+ st_astext
+----------------
+ MULTIPOINT(51.5974135047432 76.5974135047432,78.1948270094864 103.194827009486,104.132163186446 130.37181214238,127.066081593223 160.18590607119,150 190)
+</programlisting>
+ </refsection>
+
+ <refsection>
+ <title>See Also</title>
+
+ <para>
+ <xref linkend="ST_LineInterpolatePoint" />
+ <xref linkend="ST_LineLocatePoint" />
+ </para>
+ </refsection>
+ </refentry>
+
<refentry id="ST_LineLocatePoint">
<refnamediv>
<refname>ST_LineLocatePoint</refname>
Modified: trunk/liblwgeom/cunit/cu_algorithm.c
===================================================================
--- trunk/liblwgeom/cunit/cu_algorithm.c 2017-10-05 20:12:51 UTC (rev 15912)
+++ trunk/liblwgeom/cunit/cu_algorithm.c 2017-10-06 01:00:27 UTC (rev 15913)
@@ -464,6 +464,84 @@
}
+static void test_lwline_interpolate_points(void)
+{
+ LWLINE* line = lwgeom_as_lwline(lwgeom_from_wkt("LINESTRING ZM (0 0 3 1, 1 1 2 2, 10 10 4 3)", LW_PARSER_CHECK_NONE));
+ LWLINE* line2d = lwgeom_as_lwline(lwgeom_from_wkt("LINESTRING (1 1, 3 7, 9 12)", LW_PARSER_CHECK_NONE));
+ LWLINE* empty_line = lwgeom_as_lwline(lwgeom_from_wkt("LINESTRING EMPTY", LW_PARSER_CHECK_NONE));
+
+ POINTARRAY* rpa;
+ POINT4D pta;
+ POINT4D ptb;
+ double eps = 1e-10;
+
+ /* Empty line gives empty point */
+ rpa = lwline_interpolate_points(empty_line, 0.5, LW_TRUE);
+ ASSERT_INT_EQUAL(rpa->npoints, 0);
+ ptarray_free(rpa);
+
+ /* Get first endpoint when fraction = 0 */
+ rpa = lwline_interpolate_points(line, 0, LW_TRUE);
+ ASSERT_INT_EQUAL(rpa->npoints, 1);
+ pta = getPoint4d(line->points, 0);
+ ptb = getPoint4d(rpa, 0);
+ ASSERT_POINT4D_EQUAL(pta, ptb, eps);
+ ptarray_free(rpa);
+
+ /* Get last endpoint when fraction = 0 */
+ rpa = lwline_interpolate_points(line, 1, LW_TRUE);
+ ASSERT_INT_EQUAL(rpa->npoints, 1);
+ pta = getPoint4d(line->points, line->points->npoints - 1);
+ ptb = getPoint4d(rpa, 0);
+ ASSERT_POINT4D_EQUAL(pta, ptb, eps);
+ ptarray_free(rpa);
+
+ /* Interpolate a single point */
+ /* First vertex is at 10% */
+ rpa = lwline_interpolate_points(line, 0.1, LW_FALSE);
+ ASSERT_INT_EQUAL(rpa->npoints, 1);
+ pta = getPoint4d(line->points, 1);
+ ptb = getPoint4d(rpa, 0);
+ ASSERT_POINT4D_EQUAL(pta, ptb, eps);
+ ptarray_free(rpa);
+
+ /* 5% is halfway to first vertex */
+ rpa = lwline_interpolate_points(line, 0.05, LW_FALSE);
+ ASSERT_INT_EQUAL(rpa->npoints, 1);
+ pta.x = 0.5;
+ pta.y = 0.5;
+ pta.m = 1.5;
+ pta.z = 2.5;
+ ptb = getPoint4d(rpa, 0);
+ ASSERT_POINT4D_EQUAL(pta, ptb, eps);
+ ptarray_free(rpa);
+
+ /* Now repeat points */
+ rpa = lwline_interpolate_points(line, 0.4, LW_TRUE);
+ ASSERT_INT_EQUAL(rpa->npoints, 2);
+ pta.x = 4;
+ pta.y = 4;
+ ptb = getPoint4d(rpa, 0);
+ ASSERT_POINT2D_EQUAL(pta, ptb, eps);
+
+ pta.x = 8;
+ pta.y = 8;
+ ptb = getPoint4d(rpa, 1);
+ ASSERT_POINT2D_EQUAL(pta, ptb, eps);
+ ptarray_free(rpa);
+
+ /* Make sure it works on 2D lines */
+ rpa = lwline_interpolate_points(line2d, 0.4, LW_TRUE);
+ ASSERT_INT_EQUAL(rpa->npoints, 2);
+ CU_ASSERT_FALSE(ptarray_has_z(rpa));
+ CU_ASSERT_FALSE(ptarray_has_m(rpa));
+ ptarray_free(rpa);
+
+ lwgeom_free(lwline_as_lwgeom(line));
+ lwgeom_free(lwline_as_lwgeom(line2d));
+ lwgeom_free(lwline_as_lwgeom(empty_line));
+}
+
static void test_lwline_clip(void)
{
LWCOLLECTION *c;
@@ -1198,6 +1276,7 @@
PG_ADD_TEST(suite,test_lwpoint_set_ordinate);
PG_ADD_TEST(suite,test_lwpoint_get_ordinate);
PG_ADD_TEST(suite,test_point_interpolate);
+ PG_ADD_TEST(suite,test_lwline_interpolate_points);
PG_ADD_TEST(suite,test_lwline_clip);
PG_ADD_TEST(suite,test_lwline_clip_big);
PG_ADD_TEST(suite,test_lwmline_clip);
Modified: trunk/liblwgeom/cunit/cu_tester.h
===================================================================
--- trunk/liblwgeom/cunit/cu_tester.h 2017-10-05 20:12:51 UTC (rev 15912)
+++ trunk/liblwgeom/cunit/cu_tester.h 2017-10-06 01:00:27 UTC (rev 15913)
@@ -73,5 +73,17 @@
CU_PASS(); \
} while(0);
+#define ASSERT_POINT2D_EQUAL(o, e, eps) do { \
+ CU_ASSERT_DOUBLE_EQUAL(o.x, e.x, eps); \
+ CU_ASSERT_DOUBLE_EQUAL(o.y, e.y, eps); \
+} while(0);
+
+#define ASSERT_POINT4D_EQUAL(o, e, eps) do { \
+ CU_ASSERT_DOUBLE_EQUAL(o.x, e.x, eps); \
+ CU_ASSERT_DOUBLE_EQUAL(o.y, e.y, eps); \
+ CU_ASSERT_DOUBLE_EQUAL(o.z, e.z, eps); \
+ CU_ASSERT_DOUBLE_EQUAL(o.m, e.m, eps); \
+} while(0);
+
/* Utility functions */
void do_fn_test(LWGEOM* (*transfn)(LWGEOM*), char *input_wkt, char *expected_wkt);
Modified: trunk/liblwgeom/liblwgeom.h.in
===================================================================
--- trunk/liblwgeom/liblwgeom.h.in 2017-10-05 20:12:51 UTC (rev 15912)
+++ trunk/liblwgeom/liblwgeom.h.in 2017-10-06 01:00:27 UTC (rev 15913)
@@ -1013,6 +1013,11 @@
*/
extern int lwline_add_lwpoint(LWLINE *line, LWPOINT *point, int where);
+/**
+ * Interpolate one or more points along a line
+ */
+extern POINTARRAY* lwline_interpolate_points(const LWLINE *line, double length_fraction, char repeat);
+
/******************************************************************
* LWPOLY functions
******************************************************************/
@@ -1214,7 +1219,7 @@
extern char* lwpoint_to_latlon(const LWPOINT *p, const char *format);
extern int lwgeom_startpoint(const LWGEOM* lwgeom, POINT4D* pt);
-extern void interpolate_point4d(POINT4D *A, POINT4D *B, POINT4D *I, double F);
+extern void interpolate_point4d(const POINT4D *A, const POINT4D *B, POINT4D *I, double F);
/**
* Ensure the outer ring is clockwise oriented and all inner rings
Modified: trunk/liblwgeom/lwgeom_api.c
===================================================================
--- trunk/liblwgeom/lwgeom_api.c 2017-10-05 20:12:51 UTC (rev 15912)
+++ trunk/liblwgeom/lwgeom_api.c 2017-10-06 01:00:27 UTC (rev 15913)
@@ -703,7 +703,7 @@
* F=.2 : A-I-------B
*/
void
-interpolate_point4d(POINT4D *A, POINT4D *B, POINT4D *I, double F)
+interpolate_point4d(const POINT4D *A, const POINT4D *B, POINT4D *I, double F)
{
#if PARANOIA_LEVEL > 0
double absF=fabs(F);
Modified: trunk/liblwgeom/lwline.c
===================================================================
--- trunk/liblwgeom/lwline.c 2017-10-05 20:12:51 UTC (rev 15912)
+++ trunk/liblwgeom/lwline.c 2017-10-06 01:00:27 UTC (rev 15913)
@@ -547,3 +547,79 @@
}
+POINTARRAY* lwline_interpolate_points(const LWLINE *line, double length_fraction, char repeat) {
+ POINT4D pt;
+ uint32_t i;
+ uint32_t points_to_interpolate;
+ uint32_t points_found = 0;
+ double length;
+ double length_fraction_increment = length_fraction;
+ double length_fraction_consumed = 0;
+ char has_z = (char) lwgeom_has_z(lwline_as_lwgeom(line));
+ char has_m = (char) lwgeom_has_m(lwline_as_lwgeom(line));
+ const POINTARRAY* ipa = line->points;
+ POINTARRAY* opa;
+
+ /* Empty.InterpolatePoint == Point Empty */
+ if ( lwline_is_empty(line) )
+ {
+ return ptarray_construct_empty(has_z, has_m, 0);
+ }
+
+ /* If distance is one of the two extremes, return the point on that
+ * end rather than doing any computations
+ */
+ if ( length_fraction == 0.0 || length_fraction == 1.0 )
+ {
+ if ( length_fraction == 0.0 )
+ getPoint4d_p(ipa, 0, &pt);
+ else
+ getPoint4d_p(ipa, ipa->npoints-1, &pt);
+
+ opa = ptarray_construct(has_z, has_m, 1);
+ ptarray_set_point4d(opa, 0, &pt);
+
+ return opa;
+ }
+
+ /* Interpolate points along the line */
+ length = ptarray_length_2d(ipa);
+ points_to_interpolate = repeat ? (uint32_t) floor(1 / length_fraction) : 1;
+ opa = ptarray_construct(has_z, has_m, points_to_interpolate);
+
+ const POINT2D* p1 = getPoint2d_cp(ipa, 0);
+ for ( i = 0; i < ipa->npoints - 1 && points_found < points_to_interpolate; i++ )
+ {
+ const POINT2D* p2 = getPoint2d_cp(ipa, i+1);
+ double segment_length_frac = distance2d_pt_pt(p1, p2) / length;
+
+ /* If our target distance is before the total length we've seen
+ * so far. create a new point some distance down the current
+ * segment.
+ */
+ while ( length_fraction < length_fraction_consumed + segment_length_frac && points_found < points_to_interpolate )
+ {
+ POINT4D p1_4d = getPoint4d(ipa, i);
+ POINT4D p2_4d = getPoint4d(ipa, i+1);
+
+ double segment_fraction = (length_fraction - length_fraction_consumed) / segment_length_frac;
+ interpolate_point4d(&p1_4d, &p2_4d, &pt, segment_fraction);
+ ptarray_set_point4d(opa, points_found++, &pt);
+ length_fraction += length_fraction_increment;
+ }
+
+ length_fraction_consumed += segment_length_frac;
+
+ p1 = p2;
+ }
+
+ /* Return the last point on the line. This shouldn't happen, but
+ * could if there's some floating point rounding errors. */
+ if (points_found < points_to_interpolate) {
+ getPoint4d_p(ipa, ipa->npoints - 1, &pt);
+ ptarray_set_point4d(opa, points_found, &pt);
+ }
+
+ return opa;
+}
+
Modified: trunk/postgis/lwgeom_functions_analytic.c
===================================================================
--- trunk/postgis/lwgeom_functions_analytic.c 2017-10-05 20:12:51 UTC (rev 15912)
+++ trunk/postgis/lwgeom_functions_analytic.c 2017-10-06 01:00:27 UTC (rev 15913)
@@ -36,18 +36,10 @@
#include "access/htup_details.h"
-/***********************************************************************
- * Simple Douglas-Peucker line simplification.
- * No checks are done to avoid introduction of self-intersections.
- * No topology relations are considered.
- *
- * --strk at kbt.io;
- ***********************************************************************/
-
-
/* Prototypes */
Datum LWGEOM_simplify2d(PG_FUNCTION_ARGS);
Datum LWGEOM_SetEffectiveArea(PG_FUNCTION_ARGS);
+Datum LWGEOM_line_interpolate_point(PG_FUNCTION_ARGS);
Datum ST_LineCrossingDirection(PG_FUNCTION_ARGS);
Datum ST_MinimumBoundingRadius(PG_FUNCTION_ARGS);
Datum ST_MinimumBoundingCircle(PG_FUNCTION_ARGS);
@@ -61,6 +53,13 @@
static int point_in_ring(POINTARRAY *pts, const POINT2D *point);
static int point_in_ring_rtree(RTREE_NODE *root, const POINT2D *point);
+/***********************************************************************
+ * Simple Douglas-Peucker line simplification.
+ * No checks are done to avoid introduction of self-intersections.
+ * No topology relations are considered.
+ *
+ * --strk at kbt.io;
+ ***********************************************************************/
PG_FUNCTION_INFO_V1(LWGEOM_simplify2d);
Datum LWGEOM_simplify2d(PG_FUNCTION_ARGS)
@@ -137,111 +136,50 @@
* Interpolate a point along a line, useful for Geocoding applications
* SELECT line_interpolate_point( 'LINESTRING( 0 0, 2 2'::geometry, .5 )
* returns POINT( 1 1 ).
- * Works in 2d space only.
- *
- * Initially written by: jsunday at rochgrp.com
- * Ported to LWGEOM by: strk at refractions.net
***********************************************************************/
-
-Datum LWGEOM_line_interpolate_point(PG_FUNCTION_ARGS);
-
PG_FUNCTION_INFO_V1(LWGEOM_line_interpolate_point);
Datum LWGEOM_line_interpolate_point(PG_FUNCTION_ARGS)
{
GSERIALIZED *gser = PG_GETARG_GSERIALIZED_P(0);
GSERIALIZED *result;
- double distance = PG_GETARG_FLOAT8(1);
- LWLINE *line;
- LWGEOM *geom;
- LWPOINT *point;
- POINTARRAY *ipa, *opa;
- POINT4D pt;
- int nsegs, i;
- double length, slength, tlength;
+ double distance_fraction = PG_GETARG_FLOAT8(1);
+ int repeat = PG_NARGS() > 2 && PG_GETARG_BOOL(2);
+ int srid = gserialized_get_srid(gser);
+ LWLINE* lwline;
+ LWGEOM* lwresult;
+ POINTARRAY* opa;
- if ( distance < 0 || distance > 1 )
+ if ( distance_fraction < 0 || distance_fraction > 1 )
{
elog(ERROR,"line_interpolate_point: 2nd arg isn't within [0,1]");
+ PG_FREE_IF_COPY(gser, 0);
PG_RETURN_NULL();
}
if ( gserialized_get_type(gser) != LINETYPE )
{
elog(ERROR,"line_interpolate_point: 1st arg isn't a line");
+ PG_FREE_IF_COPY(gser, 0);
PG_RETURN_NULL();
}
- /* Empty.InterpolatePoint == Point Empty */
- if ( gserialized_is_empty(gser) )
- {
- point = lwpoint_construct_empty(gserialized_get_srid(gser), gserialized_has_z(gser), gserialized_has_m(gser));
- result = geometry_serialize(lwpoint_as_lwgeom(point));
- lwpoint_free(point);
- PG_RETURN_POINTER(result);
- }
+ lwline = lwgeom_as_lwline(lwgeom_from_gserialized(gser));
+ opa = lwline_interpolate_points(lwline, distance_fraction, repeat);
- geom = lwgeom_from_gserialized(gser);
- line = lwgeom_as_lwline(geom);
- ipa = line->points;
+ lwgeom_free(lwline_as_lwgeom(lwline));
+ PG_FREE_IF_COPY(gser, 0);
- /* If distance is one of the two extremes, return the point on that
- * end rather than doing any expensive computations
- */
- if ( distance == 0.0 || distance == 1.0 )
+ if (opa->npoints <= 1)
{
- if ( distance == 0.0 )
- getPoint4d_p(ipa, 0, &pt);
- else
- getPoint4d_p(ipa, ipa->npoints-1, &pt);
-
- opa = ptarray_construct(lwgeom_has_z(geom), lwgeom_has_m(geom), 1);
- ptarray_set_point4d(opa, 0, &pt);
-
- point = lwpoint_construct(line->srid, NULL, opa);
- PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(point)));
+ lwresult = lwpoint_as_lwgeom(lwpoint_construct(srid, NULL, opa));
+ } else {
+ lwresult = lwmpoint_as_lwgeom(lwmpoint_construct(srid, opa));
}
- /* Interpolate a point on the line */
- nsegs = ipa->npoints - 1;
- length = ptarray_length_2d(ipa);
- tlength = 0;
- for ( i = 0; i < nsegs; i++ )
- {
- POINT4D p1, p2;
- POINT4D *p1ptr=&p1, *p2ptr=&p2; /* don't break
- * strict-aliasing rules
- */
+ result = geometry_serialize(lwresult);
+ lwgeom_free(lwresult);
- getPoint4d_p(ipa, i, &p1);
- getPoint4d_p(ipa, i+1, &p2);
-
- /* Find the relative length of this segment */
- slength = distance2d_pt_pt((POINT2D*)p1ptr, (POINT2D*)p2ptr)/length;
-
- /* If our target distance is before the total length we've seen
- * so far. create a new point some distance down the current
- * segment.
- */
- if ( distance < tlength + slength )
- {
- double dseg = (distance - tlength) / slength;
- interpolate_point4d(&p1, &p2, &pt, dseg);
- opa = ptarray_construct(lwgeom_has_z(geom), lwgeom_has_m(geom), 1);
- ptarray_set_point4d(opa, 0, &pt);
- point = lwpoint_construct(line->srid, NULL, opa);
- PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(point)));
- }
- tlength += slength;
- }
-
- /* Return the last point on the line. This shouldn't happen, but
- * could if there's some floating point rounding errors. */
- getPoint4d_p(ipa, ipa->npoints-1, &pt);
- opa = ptarray_construct(lwgeom_has_z(geom), lwgeom_has_m(geom), 1);
- ptarray_set_point4d(opa, 0, &pt);
- point = lwpoint_construct(line->srid, NULL, opa);
- PG_FREE_IF_COPY(gser, 0);
- PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(point)));
+ PG_RETURN_POINTER(result);
}
/***********************************************************************
* --jsunday at rochgrp.com;
Modified: trunk/postgis/postgis.sql.in
===================================================================
--- trunk/postgis/postgis.sql.in 2017-10-05 20:12:51 UTC (rev 15912)
+++ trunk/postgis/postgis.sql.in 2017-10-06 01:00:27 UTC (rev 15913)
@@ -3128,6 +3128,12 @@
AS 'MODULE_PATHNAME', 'LWGEOM_line_interpolate_point'
LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL;
+-- Availability: 2.5.0
+CREATE OR REPLACE FUNCTION ST_LineInterpolatePoints(geometry, float8, repeat boolean DEFAULT true)
+ RETURNS geometry
+ AS 'MODULE_PATHNAME', 'LWGEOM_line_interpolate_point'
+ LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL;
+
-- Availability: 1.2.2
-- Deprecation in 2.1.0
CREATE OR REPLACE FUNCTION ST_line_interpolate_point(geometry, float8)
Modified: trunk/regress/regress_lrs.sql
===================================================================
--- trunk/regress/regress_lrs.sql 2017-10-05 20:12:51 UTC (rev 15912)
+++ trunk/regress/regress_lrs.sql 2017-10-06 01:00:27 UTC (rev 15913)
@@ -69,7 +69,13 @@
select 'line_interpolate_point', ST_AsText(ST_LineInterpolatePoint('LINESTRING(0 0, 1 1)', 0));
select 'line_interpolate_point', ST_AsText(ST_LineInterpolatePoint('LINESTRING(0 0 10, 1 1 5)', 0.5));
+--
+--- ST_LineInterpolatePoints
+--
+select 'line_interpolate_points', ST_AsText(ST_LineInterpolatePoints('LINESTRING(0 0, 1 1)', 0.7));
+select 'line_interpolate_points', ST_AsText(ST_LineInterpolatePoints('LINESTRING(0 0, 1 1)', 0.3));
+
--
-- ST_AddMeasure
--
Modified: trunk/regress/regress_lrs_expected
===================================================================
--- trunk/regress/regress_lrs_expected 2017-10-05 20:12:51 UTC (rev 15912)
+++ trunk/regress/regress_lrs_expected 2017-10-06 01:00:27 UTC (rev 15913)
@@ -36,6 +36,8 @@
line_substring_12|POINT Z (0.5 0.5 7.5)
line_interpolate_point|POINT(0 0)
line_interpolate_point|POINT Z (0.5 0.5 7.5)
+line_interpolate_points|POINT(0.7 0.7)
+line_interpolate_points|MULTIPOINT(0.3 0.3,0.6 0.6,0.9 0.9)
addMeasure1|LINESTRING M (0 0 10,2 0 15,4 0 20)
addMeasure2|LINESTRING M (0 0 10,9 0 19,10 0 20)
interpolatePoint1|2
More information about the postgis-tickets
mailing list