]> granicus.if.org Git - postgis/commitdiff
Add ST_LineInterpolatePoints
authorDaniel Baston <dbaston@gmail.com>
Fri, 6 Oct 2017 01:00:27 +0000 (01:00 +0000)
committerDaniel Baston <dbaston@gmail.com>
Fri, 6 Oct 2017 01:00:27 +0000 (01:00 +0000)
Closes #3564

git-svn-id: http://svn.osgeo.org/postgis/trunk@15913 b70326c6-7e19-0410-871a-916f4a2858ee

13 files changed:
NEWS
doc/html/image_src/Makefile.in
doc/html/image_src/st_line_interpolate_points01.wkt [new file with mode: 0644]
doc/reference_lrs.xml
liblwgeom/cunit/cu_algorithm.c
liblwgeom/cunit/cu_tester.h
liblwgeom/liblwgeom.h.in
liblwgeom/lwgeom_api.c
liblwgeom/lwline.c
postgis/lwgeom_functions_analytic.c
postgis/postgis.sql.in
regress/regress_lrs.sql
regress/regress_lrs_expected

diff --git a/NEWS b/NEWS
index 56ec4bfe5f5c438e667047f9a0adaac2b63ad82d..da959d363cb39ebaa9aec03412f4542947fb3927 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,7 @@ PostGIS 2.5.0
 2018/xx/xx
 * New Features *
   - #3876, ST_Angle function (RĂ©mi Cura)
+  - #3564, ST_LineInterpolatePoints (Dan Baston)
 
 PostGIS 2.4.0
 2017/09/30
index 4339f600a2dca2d8ebc8d46f4c8c5d90fe4f3aca..a895274e871c4fc0985ae870acce7865b7cc3573 100644 (file)
@@ -91,6 +91,7 @@ IMAGES= \
        ../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 \
diff --git a/doc/html/image_src/st_line_interpolate_points01.wkt b/doc/html/image_src/st_line_interpolate_points01.wkt
new file mode 100644 (file)
index 0000000..4885510
--- /dev/null
@@ -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)
+
index 43167200718927f6acb6d7754ba4407ed08b86a2..0a3bf2bb7dab49944bf895b495f0a663a6725b33 100644 (file)
@@ -83,7 +83,82 @@ FROM (SELECT ST_GeomFromText('LINESTRING(1 2, 4 5, 6 7)') As the_line) As foo;
                  <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>
 
index ea661235032a8b334576846fea7bdcb9850e6749..ae85074377467f5b881afa2ae35c3cea646707f5 100644 (file)
@@ -464,6 +464,84 @@ static void test_point_interpolate(void)
 
 }
 
+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 @@ void algorithms_suite_setup(void)
        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);
index 9e245df31dd3edc87fc4f6b5baa4e2cf597bbadf..c5e6ccfac1e20904cb48c970fe74e4ea632188ae 100644 (file)
@@ -73,5 +73,17 @@ typedef void (*PG_SuiteSetup)(void);
        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);
index 32877403ce4ea2146c2f091f8eed972e5b185ae6..6bb314dd51bc5706976c1d84b71891f3e676fd71 100644 (file)
@@ -1013,6 +1013,11 @@ extern int lwpoint_getPoint4d_p(const LWPOINT *point, POINT4D *out);
  */
 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* lwgeom_summary(const LWGEOM *lwgeom, int offset);
 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
index 1c7112c34b3e4fefe5e48c475ff8281b5c73e92e..abce26397391e3cdc039d0c250feea4577b907be 100644 (file)
@@ -703,7 +703,7 @@ deparse_hex(uint8_t str, char *result)
  *   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);
index eec96cab59e2be45155f4b056c4490bd8ab24b05..14dc6436e1331a42554162f6c11c5fd86a2bacf4 100644 (file)
@@ -547,3 +547,79 @@ double lwline_length_2d(const LWLINE *line)
 }
 
 
+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;
+}
+
index 5c35ecfc2a6d7c8d22b34b5acfc07a4c03f004f7..1904f1994000df16fe64cd788980e05bcfda7874 100644 (file)
 
 #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@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 isOnSegment(const POINT2D *seg1, const POINT2D *seg2, const POINT2D *
 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@kbt.io;
+ ***********************************************************************/
 
 PG_FUNCTION_INFO_V1(LWGEOM_simplify2d);
 Datum LWGEOM_simplify2d(PG_FUNCTION_ARGS)
@@ -137,111 +136,50 @@ Datum LWGEOM_SetEffectiveArea(PG_FUNCTION_ARGS)
  * 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@rochgrp.com
- * Ported to LWGEOM by: strk@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;
-
-       if ( distance < 0 || distance > 1 )
+       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_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@rochgrp.com;
index 8775fc6e24f48317affb912649824000ccb46146..90cae08c8577ad2e17abbb3fc2bfe91157095137 100644 (file)
@@ -3128,6 +3128,12 @@ CREATE OR REPLACE FUNCTION ST_LineInterpolatePoint(geometry, float8)
        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)
index a362d9a1becb86c3f06f9b746fc81a9455c9aedd..7ba36bedc04bea301aceb201c3b92205aeef3b13 100644 (file)
@@ -69,6 +69,12 @@ select 'line_substring_12', ST_AsText(ST_LineSubstring('LINESTRING(0 0 10, 1 1 5
 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
index a61cc04b3dc93d135c1a1c34fdb8457066485f05..b6a54268e997c6019340c6e76c063e0f2617396a 100644 (file)
@@ -36,6 +36,8 @@ line_substring_11|POINT(0 0)
 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