]> granicus.if.org Git - postgis/commitdiff
Add ST_InterpolatePoint, deprecate ST_Locate_Between_Measures and ST_Locate_Along_Mea...
authorPaul Ramsey <pramsey@cleverelephant.ca>
Sat, 14 Jan 2012 01:03:37 +0000 (01:03 +0000)
committerPaul Ramsey <pramsey@cleverelephant.ca>
Sat, 14 Jan 2012 01:03:37 +0000 (01:03 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@8811 b70326c6-7e19-0410-871a-916f4a2858ee

14 files changed:
doc/reference_lrs.xml
liblwgeom/cunit/cu_node.c
liblwgeom/cunit/cu_ptarray.c
liblwgeom/liblwgeom.h.in
liblwgeom/liblwgeom_internal.h
liblwgeom/lwgeom_geos_split.c
liblwgeom/lwlinearreferencing.c
liblwgeom/ptarray.c
postgis/lwgeom_functions_analytic.c
postgis/lwgeom_functions_lrs.c
postgis/postgis.sql.in.c
regress/regress_lrs.sql
regress/regress_lrs_expected
regress/tickets_expected

index f4a94c3f5420a8643323dcfc266d7f9b7e089713..c25b44fed5f97ef18fc490ca4e141cca55bdc1b1 100644 (file)
@@ -1,6 +1,7 @@
 <?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>
@@ -263,9 +264,9 @@ WHERE n*100.00/length &lt; 1;
                  </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
@@ -275,9 +276,10 @@ WHERE n*100.00/length &lt; 1;
          <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>
@@ -288,6 +290,11 @@ WHERE n*100.00/length &lt; 1;
                <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>
@@ -301,22 +308,22 @@ WHERE n*100.00/length &lt; 1;
 
          <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
@@ -331,13 +338,13 @@ SELECT ST_AsEWKT((ST_Dump(the_geom)).geom)
          <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
@@ -347,10 +354,11 @@ SELECT ST_AsEWKT((ST_Dump(the_geom)).geom)
          <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>
@@ -374,35 +382,35 @@ SELECT ST_AsEWKT((ST_Dump(the_geom)).geom)
          <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>
 
@@ -478,6 +486,53 @@ LINESTRING(6.1 7.1 6,7 8 9)
        </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>
@@ -510,25 +565,25 @@ LINESTRING(6.1 7.1 6,7 8 9)
          <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                              
 -----------------------------------------------------------------
index 1c5196e5ef70b9647b41b636244533f9ae83a7d8..350ae1d997126406ea2c2b68d4f4bc9b35279887 100644 (file)
@@ -44,7 +44,7 @@ static void test_lwgeom_node(void)
        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);
 
@@ -52,7 +52,7 @@ static void test_lwgeom_node(void)
        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);
index 086d179d849aa6de2cd398360caf572eba75cb0b..9082a7233d5e216c6e6a2bb9c9874149bf5da8bb 100644 (file)
@@ -64,29 +64,29 @@ static void test_ptarray_append_ptarray(void)
 
 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);
 
@@ -94,7 +94,7 @@ static void test_ptarray_locate_point(void)
        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);
 
@@ -102,7 +102,7 @@ static void test_ptarray_locate_point(void)
        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);
 
@@ -111,30 +111,30 @@ static void test_ptarray_locate_point(void)
 
 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);
index e3c53cc73774f7114d44e6a1fbfbd28e849cdd9d..bdcdf3aca870224900f62dbbc30159a337aa962f 100644 (file)
@@ -1220,7 +1220,7 @@ extern int lwgeom_ndims(const LWGEOM *geom);
  * 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 
@@ -1231,10 +1231,22 @@ extern LWMLINE* lwmline_measured_from_lwmline(const LWMLINE *lwmline, double m_s
 
 /**
 * 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.
index f128f93ae75c1c2f78e90773af79b1d3c2f70e07..d2017376a3564b1e1537595fe486491c6fd00b8b 100644 (file)
@@ -250,7 +250,8 @@ char *geohash_point(double longitude, double latitude, int precision);
 /*
 * 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
@@ -318,7 +319,7 @@ LWCOLLECTION *lwcollection_clone_deep(const LWCOLLECTION *lwgeom);
  * 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
index b550a48f757b61bae8cf64e23a2c69c07f6edf80..c0f8320af052e1a2dbc42dbdfb73b62ec005c568 100644 (file)
@@ -160,7 +160,7 @@ lwline_split_by_point_to(const LWLINE* lwline_in, const LWPOINT* blade_in,
                          LWMLINE* v)
 {
        double loc, dist;
-       POINT2D pt;
+       POINT4D pt, pt_projected;
        POINTARRAY* pa1;
        POINTARRAY* pa2;
        double vstol; /* vertex snap tolerance */
@@ -176,8 +176,8 @@ lwline_split_by_point_to(const LWLINE* lwline_in, const LWPOINT* blade_in,
         *      -> 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); */
 
index 988e13147f1c0c3df894674f0f031712c3789ab9..e80b6287552587ab9a3fd8ee3fd88c558ebc6b11 100644 (file)
@@ -154,15 +154,17 @@ lwmline_locate_along(const LWMLINE *lwmline, double m, double offset)
        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*
@@ -807,3 +809,43 @@ lwgeom_clip_to_ordinate_range(const LWGEOM *lwin, char ordinate, double from, do
 
        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
index 51da16992a0a255151bfe3d22e8f347b7c678b87..701996bd7c9f76604ac9ed9a4599345f75fe2fb1 100644 (file)
@@ -191,7 +191,7 @@ ptarray_append_ptarray(POINTARRAY *pa1, POINTARRAY *pa2, int splice_ends)
                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--;
                }
@@ -879,11 +879,11 @@ END:
  * 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;
@@ -918,6 +918,8 @@ closest_point_on_segment(POINT2D *p, POINT2D *A, POINT2D *B, POINT2D *ret)
 
        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 );
 }
 
 /*
@@ -925,20 +927,26 @@ closest_point_on_segment(POINT2D *p, POINT2D *A, POINT2D *B, POINT2D *ret)
  * 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 )
                {
@@ -964,24 +972,28 @@ ptarray_locate_point(POINTARRAY *pa, POINT2D *p, double* mindistout)
         * 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);
@@ -1238,9 +1250,18 @@ ptarray_length(const POINTARRAY *pts)
 
 
 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;
index 98da739df5921db4eab09a6df6fd6c43fa6ddfc9..b8a4f96accfbd5e8a1bb4f47849c7f885f87157b 100644 (file)
@@ -820,46 +820,6 @@ Datum LWGEOM_line_substring(PG_FUNCTION_ARGS)
 
 }
 
-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.
index a39abbf874f35032be16185d8e6f45b9a4102161..a9cdaf0233596982c70ba46c818141d8f0edb1c5 100644 (file)
 #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
 {
@@ -459,6 +686,7 @@ lwgeom_locate_between_m(LWGEOM *lwin, double m0, double m1)
  * 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)
 {
@@ -471,6 +699,8 @@ 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");
@@ -517,143 +747,3 @@ Datum LWGEOM_locate_between_m(PG_FUNCTION_ARGS)
        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
index 7ac11cc4a0be81c759b7237e532fe92438b2712d..daf51bd464ddb2a1fac6e9dc7285f36283f7ea8c 100644 (file)
@@ -4536,8 +4536,12 @@ CREATE OR REPLACE FUNCTION ST_LocateBetweenElevations(Geometry geometry, FromEle
        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
index 5e58afa226550b4cb500e2513cfe987532a2ebd9..45f7df61f91508b76cbe8a28422cc5bd549fc5bd 100644 (file)
@@ -1,28 +1,28 @@
 -- 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
 
@@ -35,22 +35,25 @@ select 'line_locate_point_3', ST_line_locate_point(ST_geomfromtext('LINESTRING(-
 --- 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));
index 75a3918b0304a75ed3946b55d785862c22926e8f..aac8975156af351cdfbfa2ceba610893363d2372 100644 (file)
@@ -1,34 +1,34 @@
-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)
index 5df001be142af29b74f1273aebabbb4cddc9eb23..f8f17acf93ce3ee6511b03ee054b0c9343a20fe3 100644 (file)
@@ -1,5 +1,6 @@
 #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
@@ -16,6 +17,7 @@ ERROR:  lwgeom_longitude_shift: unsupported geom type: CircularString
 #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)