]> granicus.if.org Git - postgis/commitdiff
#3428, ST_Points
authorDaniel Baston <dbaston@gmail.com>
Sat, 16 Jan 2016 15:45:37 +0000 (15:45 +0000)
committerDaniel Baston <dbaston@gmail.com>
Sat, 16 Jan 2016 15:45:37 +0000 (15:45 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@14604 b70326c6-7e19-0410-871a-916f4a2858ee

NEWS
doc/reference_accessor.xml
liblwgeom/cunit/cu_misc.c
liblwgeom/cunit/cu_tester.c
liblwgeom/cunit/cu_tester.h
liblwgeom/liblwgeom.h.in
liblwgeom/lwmpoint.c
postgis/lwgeom_functions_basic.c
postgis/postgis.sql.in
regress/regress.sql
regress/regress_expected

diff --git a/NEWS b/NEWS
index 55e5b210ddf05f3599df4652e487b43fa00a8bfa..56b7c0cda646f4cc48231daad4533d0d0e77b03b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,7 @@ PostGIS 2.3.0
   - populate_topology_layer (Sandro Santilli)
   - #2259 ST_Voronoi (Dan Baston)
   - #3339 ST_GeneratePoints (Paul Ramsey)
+  - #3428 ST_Points (Dan Baston)
 
 PostGIS 2.2.1
 2016/01/06
index 13f0fd6a1c017d2dfe56ef219684d48e1842e943..f2ce6d6b63a5df5cd473182efbbd02f14bb51295 100644 (file)
@@ -2081,6 +2081,60 @@ POINT(3 2)
          </refsection>
        </refentry>
 
+       <refentry id="ST_Points">
+               <refnamediv>
+                       <refname>ST_Points</refname>
+                       <refpurpose>Returns a MultiPoint containing all of the coordinates of a geometry.
+                       </refpurpose>
+               </refnamediv>
+
+               <refsynopsisdiv>
+                       <funcsynopsis>
+                               <funcprototype>
+                                       <funcdef>geometry <function>ST_Points</function></funcdef>
+                                       <paramdef>
+                                               <type>geometry</type>
+                                               <parameter>geom</parameter>
+                                       </paramdef>
+                               </funcprototype>
+                       </funcsynopsis>
+               </refsynopsisdiv>
+
+               <refsection>
+                       <title>Description</title>
+
+                       <para>
+                               Returns a MultiPoint containing all of the coordinates of a
+                               geometry.  Does not remove points that are duplicated in
+                               the input geometry, including start and end points of ring geometries.
+                               (If this behavior is undesired, duplicates may be removed using 
+                               <xref linkend="ST_RemoveRepeatedPoints" />).
+                       </para>
+                               
+                       <para>
+                               M and Z ordinates will be preserved if present.
+                       </para>
+
+                       <para>&curve_support;</para>
+                       <para>&Z_support;</para>
+               </refsection>
+
+               <refsection>
+                       <title>Examples</title>
+               
+                       <programlisting>SELECT ST_AsText(ST_Points('POLYGON Z ((30 10 4,10 30 5,40 40 6, 30 10))'));
+
+--result
+MULTIPOINT Z (30 10 4,10 30 5,40 40 6, 30 10 4)
+                       </programlisting>
+               </refsection>
+
+               <refsection>
+                       <title>See Also</title>
+                       <para><xref linkend="ST_RemoveRepeatedPoints" /></para>
+               </refsection>
+       </refentry>
+
        <refentry id="ST_SRID">
          <refnamediv>
                <refname>ST_SRID</refname>
index 11554c39c2dfce36255998c940a23ed6a5e57e05..3d6026e72f16ffc3e01aed7cadc53638c268047e 100644 (file)
@@ -156,6 +156,20 @@ static void test_clone(void)
        lwgeom_free(geom1);
 }
 
+static void test_lwmpoint_from_lwgeom(void)
+{
+       /* This cast is so ugly, we only want to do it once.  And not even that. */
+       LWGEOM* (*to_points)(LWGEOM*) = (LWGEOM* (*)(LWGEOM*)) &lwmpoint_from_lwgeom;
+
+       do_fn_test(to_points, "MULTIPOLYGON (EMPTY)", "MULTIPOINT EMPTY");
+       do_fn_test(to_points, "POINT (30 10)", "MULTIPOINT ((30 10))");
+       do_fn_test(to_points, "LINESTRING Z (30 10 4,10 30 5,40 40 6)", "MULTIPOINT Z (30 10 4,10 30 5, 40 40 6)");
+       do_fn_test(to_points, "POLYGON((35 10,45 45,15 40,10 20,35 10),(20 30,35 35,30 20,20 30))", "MULTIPOINT(35 10,45 45,15 40,10 20,35 10,20 30,35 35,30 20,20 30)");
+       do_fn_test(to_points, "MULTIPOINT M (10 40 1,40 30 2,20 20 3,30 10 4)", "MULTIPOINT M (10 40 1,40 30 2,20 20 3,30 10 4)");
+       do_fn_test(to_points, "COMPOUNDCURVE(CIRCULARSTRING(0 0,2 0, 2 1, 2 3, 4 3),(4 3, 4 5, 1 4, 0 0))", "MULTIPOINT(0 0, 2 0, 2 1, 2 3, 4 3, 4 3, 4 5, 1 4, 0 0)");
+       do_fn_test(to_points, "TIN(((80 130,50 160,80 70,80 130)),((50 160,10 190,10 70,50 160)))", "MULTIPOINT (80 130, 50 160, 80 70, 80 130, 50 160, 10 190, 10 70, 50 160)");
+}
+
 /*
 ** Used by the test harness to register the tests in this file.
 */
@@ -170,4 +184,5 @@ void misc_suite_setup(void)
        PG_ADD_TEST(suite, test_misc_wkb);
        PG_ADD_TEST(suite, test_grid);
        PG_ADD_TEST(suite, test_clone);
+       PG_ADD_TEST(suite, test_lwmpoint_from_lwgeom);
 }
index b760e479a6a63613a58ceb736ad5adaf5c2bae40..d1098c9c93a3a2a6710adb372c15be05250b8b1e 100644 (file)
@@ -278,3 +278,25 @@ cu_error_msg_reset()
 {
        memset(cu_error_msg, '\0', MAX_CUNIT_ERROR_LENGTH);
 }
+
+/* Utility functions for testing */
+
+/* do_transformation_test
+ * - reads input_wkt and expected_wkt
+ * - asserts output of transfn(input) = expected
+ * - cleans up
+ */
+void
+do_fn_test(LWGEOM* (*transfn)(LWGEOM*), char *input_wkt, char *expected_wkt)
+{
+       LWGEOM* input = lwgeom_from_wkt(input_wkt, LW_PARSER_CHECK_NONE);
+       LWGEOM* expected = lwgeom_from_wkt(expected_wkt, LW_PARSER_CHECK_NONE);
+       LWGEOM* observed = transfn(input);
+
+       ASSERT_LWGEOM_EQUAL(observed, expected);
+
+       lwgeom_free(input);
+       lwgeom_free(expected);
+       lwgeom_free(observed);
+}
+
index 918a0d153da9ae204952ac1dcf0b0b06e0836ad2..ea606d7d347398e3d3f481bd45fd0a732843ac6d 100644 (file)
@@ -10,6 +10,8 @@
  *
  **********************************************************************/
 
+#include "liblwgeom.h"
+
 #define MAX_CUNIT_ERROR_LENGTH 512
 
 #define PG_ADD_TEST(suite, testfunc) CU_add_test(suite, #testfunc, testfunc)
@@ -41,3 +43,16 @@ typedef void (*PG_SuiteSetup)(void);
   CU_ASSERT_STRING_EQUAL(o,e); \
 } while (0);
 
+#define ASSERT_LWGEOM_EQUAL(o, e) do { \
+       if ( !lwgeom_same(o, e) ) { \
+               char* wkt_o = lwgeom_to_ewkt(o); \
+               char* wkt_e = lwgeom_to_ewkt(e); \
+               fprintf(stderr, "[%s:%d]\n Expected: %s\n Obtained: %s\n", __FILE__, __LINE__, (wkt_o), (wkt_e)); \
+               lwfree(wkt_o); \
+               lwfree(wkt_e); \
+       } \
+       CU_ASSERT_TRUE(lwgeom_same(o, e)); \
+} while(0);
+
+/* Utility functions */
+void do_fn_test(LWGEOM* (*transfn)(LWGEOM*), char *input_wkt, char *expected_wkt);
index f2c7081c8985800d9a67fa87a364718dbf76c57d..59bfd11250a446d51cc81a3aec83a28bb5ebad77 100644 (file)
@@ -1337,7 +1337,7 @@ extern LWLINE *lwline_removepoint(LWLINE *line, uint32_t which);
 extern void lwline_setPoint4d(LWLINE *line, uint32_t which, POINT4D *newpoint);
 extern LWPOLY *lwpoly_from_lwlines(const LWLINE *shell, uint32_t nholes, const LWLINE **holes);
 extern LWTRIANGLE *lwtriangle_from_lwline(const LWLINE *shell);
-
+extern LWMPOINT *lwmpoint_from_lwgeom(const LWGEOM *g); /* Extract the coordinates of an LWGEOM into an LWMPOINT */
 
 /* Some point accessors */
 extern double lwpoint_get_x(const LWPOINT *point);
index d486d6ac02c0117c48b20591436bd0508525f2bf..5e6887564569825255e324b503c1cf99dedb60eb 100644 (file)
@@ -120,3 +120,20 @@ lwmpoint_remove_repeated_points(const LWMPOINT *mpoint, double tolerance)
 
 }
 
+LWMPOINT*
+lwmpoint_from_lwgeom(const LWGEOM *g)
+{
+       LWPOINTITERATOR* it = lwpointiterator_create(g);
+       int has_z = lwgeom_has_z(g);
+       int has_m = lwgeom_has_m(g);
+       LWMPOINT* result = lwmpoint_construct_empty(g->srid, has_z, has_m);
+       POINT4D p;
+
+       while(lwpointiterator_next(it, &p)) {
+               LWPOINT* lwp = lwpoint_make(g->srid, has_z, has_m, &p);
+               lwmpoint_add_lwpoint(result, lwp);
+       }
+
+       lwpointiterator_destroy(it);
+       return result;
+}
index b4634c747d6ba26c11ff3ab196e9aa98f03c42e7..051e52ee40a4f3743b83f04aa8a0a564f2f4e52c 100644 (file)
@@ -2806,3 +2806,26 @@ Datum ST_Scale(PG_FUNCTION_ARGS)
 
   PG_RETURN_POINTER(ret);
 }
+
+Datum ST_Points(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(ST_Points);
+Datum ST_Points(PG_FUNCTION_ARGS)
+{
+       if (PG_ARGISNULL(0))
+       {
+               PG_RETURN_NULL();
+       }
+       else
+       {
+               GSERIALIZED* geom = PG_GETARG_GSERIALIZED_P(0);
+               GSERIALIZED* ret;
+               LWGEOM* lwgeom = lwgeom_from_gserialized(geom);
+               LWMPOINT* result = lwmpoint_from_lwgeom(lwgeom);
+
+               lwgeom_free(lwgeom);
+
+               ret = geometry_serialize(lwmpoint_as_lwgeom(result));
+               lwmpoint_free(result);
+               PG_RETURN_POINTER(ret);
+       }
+}
index b470c6d21d8085de39afeceb17f9bb8856f89e3d..fb18e055766a4fae6509d938f602bf99fe1db525 100644 (file)
@@ -3313,6 +3313,12 @@ CREATE OR REPLACE FUNCTION ST_Boundary(geometry)
        AS 'MODULE_PATHNAME','boundary'
        LANGUAGE 'c' IMMUTABLE STRICT;
 
+-- Availability: 2.3.0
+CREATE OR REPLACE FUNCTION ST_Points(geometry)
+       RETURNS geometry
+       AS 'MODULE_PATHNAME', 'ST_Points'
+       LANGUAGE 'c' IMMUTABLE STRICT;
+
 -- PostGIS equivalent function: symdifference(geom1 geometry, geom2 geometry)
 CREATE OR REPLACE FUNCTION ST_SymDifference(geom1 geometry, geom2 geometry)
        RETURNS geometry
index d2034dee95ae59d97a1c7d440d9a20cdc8c89ac2..1023118cd6217ecf3415224e4102ec5e7cda89dd 100644 (file)
@@ -238,6 +238,9 @@ select '179', ST_AsText('MULTICURVE EMPTY');
 select '180', ST_AsText('GEOMETRYCOLLECTION EMPTY');
 select '181', ST_AsText('GEOMETRYCOLLECTION(TRIANGLE EMPTY,TIN EMPTY)');
 
+select '190', ST_Points(NULL) IS NULL;
+select '191', ST_AsText(ST_Points('MULTICURVE EMPTY'));
+select '192', ST_AsText(ST_Points('POLYGON((35 10,45 45,15 40,10 20,35 10),(20 30,35 35,30 20,20 30))'));
 
 -- Drop test table
 DROP table test;
index 41672fb6b08f59fce3412239b6b6b5a365c6301b..157e1cf6f1156803704b1a2750c2405813034bdc 100644 (file)
@@ -165,3 +165,6 @@ ERROR:  geometry contains non-closed rings
 179|MULTICURVE EMPTY
 180|GEOMETRYCOLLECTION EMPTY
 181|GEOMETRYCOLLECTION(TRIANGLE EMPTY,TIN EMPTY)
+190|t
+191|MULTIPOINT EMPTY
+192|MULTIPOINT(35 10,45 45,15 40,10 20,35 10,20 30,35 35,30 20,20 30)