]> granicus.if.org Git - postgis/commitdiff
Add SFCGAL support cf #2254. Include SFCGAL support, postgis backend handling (GEOS...
authorOlivier Courtin <olivier.courtin@camptocamp.com>
Thu, 9 May 2013 19:38:17 +0000 (19:38 +0000)
committerOlivier Courtin <olivier.courtin@camptocamp.com>
Thu, 9 May 2013 19:38:17 +0000 (19:38 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@11389 b70326c6-7e19-0410-871a-916f4a2858ee

57 files changed:
configure.ac
doc/Makefile.in
doc/postgis.xml
doc/reference.xml
doc/reference_measure.xml
doc/reference_processing.xml
doc/reference_sfcgal.xml [new file with mode: 0644]
doc/xsl/postgis_comments.sql.xsl
doc/xsl/sfcgal_cheatsheet.html.xsl [new file with mode: 0644]
doc/xsl/sfcgal_comments.sql.xsl [new file with mode: 0644]
liblwgeom/Makefile.in
liblwgeom/cunit/Makefile.in
liblwgeom/cunit/cu_force_sfs.c [new file with mode: 0644]
liblwgeom/cunit/cu_sfcgal.c [new file with mode: 0644]
liblwgeom/cunit/cu_tester.c
liblwgeom/liblwgeom.h.in
liblwgeom/lwgeom.c
liblwgeom/lwgeom_sfcgal.c [new file with mode: 0644]
liblwgeom/lwgeom_sfcgal.h [new file with mode: 0644]
postgis/Makefile.in
postgis/lwgeom_backend_api.c [new file with mode: 0644]
postgis/lwgeom_backend_api.h [new file with mode: 0644]
postgis/lwgeom_functions_basic.c
postgis/lwgeom_geos.c
postgis/lwgeom_geos.h
postgis/lwgeom_sfcgal.c [new file with mode: 0644]
postgis/lwgeom_sfcgal.h [new file with mode: 0644]
postgis/postgis.sql.in
postgis/postgis_module.c
postgis/sfcgal.sql.in [new file with mode: 0644]
postgis/uninstall_sfcgal.sql.in [new file with mode: 0644]
regress/Makefile.in
regress/regress_sfcgal.sql [new file with mode: 0644]
regress/regress_sfcgal_expected [new file with mode: 0644]
regress/run_test
regress/run_test.pl
regress/sfcgal/README [new file with mode: 0644]
regress/sfcgal/concave_hull.sql [new file with mode: 0644]
regress/sfcgal/concave_hull_expected [new file with mode: 0644]
regress/sfcgal/empty.sql [new file with mode: 0644]
regress/sfcgal/empty_expected [new file with mode: 0644]
regress/sfcgal/geography.sql [new file with mode: 0644]
regress/sfcgal/geography_expected [new file with mode: 0644]
regress/sfcgal/legacy.sql [new file with mode: 0644]
regress/sfcgal/legacy_expected [new file with mode: 0644]
regress/sfcgal/measures.sql [new file with mode: 0644]
regress/sfcgal/measures_expected [new file with mode: 0644]
regress/sfcgal/regress.sql [new file with mode: 0644]
regress/sfcgal/regress_expected [new file with mode: 0644]
regress/sfcgal/regress_ogc.sql [new file with mode: 0644]
regress/sfcgal/regress_ogc_expected [new file with mode: 0644]
regress/sfcgal/regress_ogc_prep.sql [new file with mode: 0644]
regress/sfcgal/regress_ogc_prep_expected [new file with mode: 0644]
regress/sfcgal/tickets.sql [new file with mode: 0644]
regress/sfcgal/tickets_expected [new file with mode: 0644]
regress/sfcgal/wmsservers.sql [new file with mode: 0644]
regress/sfcgal/wmsservers_expected [new file with mode: 0644]

index 4e1defe330c619d2d58b1ec77e1d8ea5a1350cda..80d31b505b05d8763f4e5aca058dae05b6272f29 100644 (file)
@@ -609,6 +609,45 @@ AC_DEFINE_UNQUOTED([POSTGIS_GEOS_VERSION], [$POSTGIS_GEOS_VERSION], [GEOS librar
 AC_SUBST([POSTGIS_GEOS_VERSION])
 
 
+dnl ===========================================================================
+dnl SFCGAL library support
+dnl ===========================================================================
+
+AC_ARG_WITH([sfcgal], 
+       [AS_HELP_STRING([--with-sfcgal=PATH], [Add SFCGAL support. ARG allows to specify an alternate PATH to sfcgal-config])], 
+       [SFCGAL_CONFIG="$withval"], 
+       [AC_PATH_PROG([SFCGAL_CONFIG], [sfcgal-config], [])])
+
+HAVE_SFCGAL="no"
+
+if test "x$with_sfcgal" != "xno"; then
+       if test -x "$SFCGAL_CONFIG"; then
+               SFCGAL_VERSION=`$SFCGAL_CONFIG --version`
+               SFCGAL_LDFLAGS=`$SFCGAL_CONFIG --libs`
+               SFCGAL_CPPFLAGS=`$SFCGAL_CONFIG --cflags`" -DHAVE_SFCGAL"
+
+               SFCGAL_STATIC=`$SFCGAL_CONFIG --static`
+               if test "x$SFCGAL_STATIC" = "xON"; then
+                       AC_MSG_WARN([The SFCGAL version found is not installed as a dynamic library.])
+               else
+                       SFCGAL="sfcgal"
+                       HAVE_SFCGAL="yes"
+               fi
+
+       else
+               if test "x$with_sfcgal" != "x"; then
+                       AC_MSG_ERROR([sfcgal-config cannot be found. Please install sfcgal])
+               fi
+       fi
+fi 
+
+AC_SUBST([SFCGAL_VERSION])
+AC_SUBST([SFCGAL_CPPFLAGS])
+AC_SUBST([SFCGAL_LDFLAGS])
+AC_SUBST([SFCGAL_OBJS])
+AC_SUBST([SFCGAL])
+AC_SUBST([HAVE_SFCGAL])
+
 dnl ===========================================================================
 dnl Detect gettext
 dnl ===========================================================================
@@ -854,10 +893,10 @@ dnl Always enable use of ANALYZE statistics by default
 AC_DEFINE_UNQUOTED([POSTGIS_USE_STATS], [1], [Enable use of ANALYZE statistics])
 
 
-CPPFLAGS="$PGSQL_CPPFLAGS $GEOS_CPPFLAGS $PROJ_CPPFLAGS $XML2_CPPFLAGS"
+CPPFLAGS="$PGSQL_CPPFLAGS $GEOS_CPPFLAGS $PROJ_CPPFLAGS $XML2_CPPFLAGS $SFCGAL_CPPFLAGS"
 dnl AC_MSG_RESULT([CPPFLAGS: $CPPFLAGS])
 
-SHLIB_LINK="$PGSQL_LDFLAGS $GEOS_LDFLAGS $PROJ_LDFLAGS -lgeos_c -lproj $JSON_LDFLAGS $XML2_LDFLAGS"
+SHLIB_LINK="$PGSQL_LDFLAGS $GEOS_LDFLAGS $PROJ_LDFLAGS -lgeos_c -lproj $JSON_LDFLAGS $XML2_LDFLAGS $SFCGAL_LDFLAGS"
 AC_SUBST([SHLIB_LINK])
 dnl AC_MSG_RESULT([SHLIB_LINK: $SHLIB_LINK])
 
@@ -1092,6 +1131,7 @@ else
        RT_MAKEFILE_LIST="raster/Makefile"
 fi
 
+
 dnl ===========================================================================
 dnl See if we have the requirements for building the extensions, namely
 dnl PostgreSQL 9.1 or better and the xlstproc tool for generating the commends
@@ -1164,6 +1204,10 @@ if test "x$RASTER" = "xraster"; then
     AC_MSG_RESULT([  GDAL config:          ${GDAL_CONFIG}])
     AC_MSG_RESULT([  GDAL version:         ${GDAL_FULL_VERSION}])
 fi
+if test "x$SFCGAL" = "xsfcgal"; then
+    AC_MSG_RESULT([  SFCGAL config:        ${SFCGAL_CONFIG}])
+    AC_MSG_RESULT([  SFCGAL version:       ${SFCGAL_VERSION}])
+fi
 AC_MSG_RESULT([  PostgreSQL config:    ${PG_CONFIG}])
 AC_MSG_RESULT([  PostgreSQL version:   ${PGSQL_FULL_VERSION}])
 AC_MSG_RESULT([  PROJ4 version:        ${POSTGIS_PROJ_VERSION}])
@@ -1185,6 +1229,11 @@ if test "x$TOPOLOGY" = "xtopology"; then
 else
     AC_MSG_RESULT([  PostGIS Topology:     disabled])
 fi
+if test "x$SFCGAL" = "xsfcgal"; then
+    AC_MSG_RESULT([  SFCGAL support:       enabled])
+else
+    AC_MSG_RESULT([  SFCGAL support:       disabled])
+fi
 AC_MSG_RESULT()
 AC_MSG_RESULT([ -------- Documentation Generation -------- ])
 AC_MSG_RESULT([  xsltproc:             ${XSLTPROC}])
index a107ce38577499536b0303f2965353218ae21ded..d7719c8384603c44e0b94dd5bb067f821c50674c 100644 (file)
@@ -108,7 +108,7 @@ XML_SOURCES = \
        installation.xml \
        introduction.xml \
        performance_tips.xml \
-  postgis.xml \
+       postgis.xml \
        reference_accessor.xml \
        reference_constructor.xml \
        reference_editor.xml \
@@ -181,6 +181,12 @@ topology_comments.sql: ./xsl/topology_comments.sql.xsl $(XML_INPUTS)
 topology_cheatsheet.html: ./xsl/topology_cheatsheet.html.xsl $(XML_INPUTS)
        $(XSLTPROC) --novalid ./xsl/topology_cheatsheet.html.xsl postgis-out.xml > $@
        
+sfcgal_comments.sql: ./xsl/sfcgal_comments.sql.xsl $(XML_INPUTS)
+       $(XSLTPROC) --novalid ./xsl/sfcgal_comments.sql.xsl postgis-out.xml > $@
+       
+sfcgal_cheatsheet.html: ./xsl/sfcgal_cheatsheet.html.xsl $(XML_INPUTS)
+       $(XSLTPROC) --novalid ./xsl/sfcgal_cheatsheet.html.xsl postgis-out.xml > $@
+       
 tiger_geocoder_comments.sql: ./xsl/tiger_geocoder_comments.sql.xsl $(XML_INPUTS)
        $(XSLTPROC) --novalid ./xsl/tiger_geocoder_comments.sql.xsl postgis-out.xml > $@
        
@@ -280,16 +286,17 @@ maintainer-clean: clean images-clean
 ifeq ($(XSLTPROC),)
 comments: requirements_not_met_xsltproc
 else
-comments: postgis_comments.sql raster_comments.sql topology_comments.sql tiger_geocoder_comments.sql
+comments: postgis_comments.sql raster_comments.sql topology_comments.sql sfcgal_comments.sql tiger_geocoder_comments.sql
 endif
 
-cheatsheets: postgis_cheatsheet.html raster_cheatsheet.html topology_cheatsheet.html tiger_geocoder_cheatsheet.html
+cheatsheets: postgis_cheatsheet.html raster_cheatsheet.html topology_cheatsheet.html sfcgal_cheatsheet.html tiger_geocoder_cheatsheet.html
 
 ifeq ($(XSLTPROC),)
 comments-install: 
        if test -e postgis_comments.sql  -a \
                -e raster_comments.sql   -a \
                -e topology_comments.sql -a \
+               -e sfcgal_comments.sql -a \
                -e tiger_geocoder_comments.sql; then \
          $(MAKE) -f Makefile.comments install; \
        fi
index 9956debb41f622c5b87af69c1f58780bcdb36daf..65d0de01d5ad05656a069f0090123c2b328cb377 100644 (file)
@@ -32,6 +32,7 @@
 <!ENTITY reference_output SYSTEM "reference_output.xml">
 <!ENTITY reference_operator SYSTEM "reference_operator.xml">
 <!ENTITY reference_measure SYSTEM "reference_measure.xml">
+<!ENTITY reference_sfcgal SYSTEM "reference_sfcgal.xml">
 <!ENTITY reference_processing SYSTEM "reference_processing.xml">
 <!ENTITY reference_lrs SYSTEM "reference_lrs.xml">
 <!ENTITY reference_transaction SYSTEM "reference_transaction.xml">
    </imageobject>
  </inlinemediaobject> This method implements the SQL/MM specification.">
 
+<!ENTITY sfcgal_enhanced 
+"<inlinemediaobject>
+   <imageobject>
+     <imagedata fileref='images/check.png' />
+   </imageobject>
+ </inlinemediaobject> This method is also provided by SFCGAL backend.">
+
 <!ENTITY curve_support 
 "<inlinemediaobject>
    <imageobject><imagedata fileref='images/check.png' /></imageobject>
index 72cccd2ea12dd4ed8fcd796a5d5b60cea293aac2..5d1449775a732b02c7a65e643332898f6316c281 100644 (file)
@@ -24,6 +24,7 @@
   &reference_output;
   &reference_operator;
   &reference_measure;
+  &reference_sfcgal;
   &reference_processing;
   &reference_lrs;
   &reference_transaction;
index bb527513c3a8c8c04db2dc961e75c06e31a6c99a..d9e0dde8e466b4a2d17278a2f10f0c57854f52d1 100644 (file)
@@ -127,6 +127,7 @@ SELECT ST_AsEWKT(ST_3DClosestPoint(line,pt)) AS cp3d_line_pt,
                <!-- Optionally mention supports Polyhedral Surface  -->
                <para>&P_support;</para>
                <para>&sqlmm_compliant; SQL-MM ?</para>
+                <para>&sfcgal_enhanced;</para>
 
                <para>Availability: 2.0.0</para>
          </refsection>
@@ -661,6 +662,7 @@ SELECT ST_AsEWKT(ST_3DShortestLine(line,pt)) AS shl3d_line_pt,
                        <para>&P_support;</para>
                        <note><para>For polyhedral surfaces, only supports 2D polyhedral surfaces (not 2.5D).  For 2.5D, may give a non-zero answer, but only for the faces that
                        sit completely in XY plane.</para></note>
+                        <para>&sfcgal_enhanced;</para>
                </refsection>
 
                  <refsection>
@@ -1971,6 +1973,7 @@ SELECT ST_Disjoint('POINT(0 0)'::geometry, 'LINESTRING ( 0 0, 0 2 )'::geometry);
                <para>&sfs_compliant;</para>
                <para>&sqlmm_compliant; SQL-MM 3: 5.1.23</para>
                <para>&curve_support;</para>
+                <para>&sfcgal_enhanced;</para>
 
                <para>Availability: 1.5.0 geography support was introduced in 1.5.  Speed improvements for planar to better handle large or many vertex geometries</para>
                <para>Enhanced: 2.1.0 improved speed for geography. See <ulink url="http://blog.opengeo.org/2012/07/12/making-geography-faster/">Making Geography faster</ulink> for details.</para>
@@ -2643,6 +2646,7 @@ SELECT ST_Equals(ST_Reverse(ST_GeomFromText('LINESTRING(0 0, 10 10)')),
                          - ST_Intersects(g1, g2 ) --&gt; Not (ST_Disjoint(g1, g2 ))
                        </para>
                        <para>&sqlmm_compliant; SQL-MM 3: 5.1.27</para>
+                        <para>&sfcgal_enhanced;</para>
                </refsection>
                <refsection>
                <title>Geometry Examples</title>
@@ -2708,6 +2712,7 @@ t
                        <para>&sfs_compliant; s2.1.5.1</para>
                        <para>&sqlmm_compliant; SQL-MM 3: 7.1.2, 9.3.4</para>
                        <para>Availability: 1.5.0 geography support was introduced in 1.5.</para>
+                        <para>&sfcgal_enhanced;</para>
                </refsection>
 
                  <refsection>
index bd50c450913514ba3d60d9decffabf52aad0d74a..f52200fb3fcea754f335be1977691e1344d67ffe 100644 (file)
@@ -1611,6 +1611,7 @@ POINT(2 1)
                  </important>
 
                  <para>Performed by the GEOS module</para>
+                  <para>&sfcgal_enhanced;</para>
                  
                  <para>Availability: 1.5 support for geography data type was introduced.</para>
 
diff --git a/doc/reference_sfcgal.xml b/doc/reference_sfcgal.xml
new file mode 100644 (file)
index 0000000..7a8d412
--- /dev/null
@@ -0,0 +1,238 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+  <sect1 id="reference_sfcgal">
+       <title>Using SFCGAL Advanced 2D/3D functions</title>
+        <para> 
+          TODO Introduction part
+        </para>
+        <para> 
+          TODO Install part
+        </para>
+
+       <refentry id="ST_Extrude">
+         <refnamediv>
+               <refname>ST_Extrude</refname>
+
+               <refpurpose>Extrude a surface to a related volume</refpurpose>
+         </refnamediv>
+
+         <refsynopsisdiv>
+               <funcsynopsis>
+                 <funcprototype>
+                       <funcdef>geometry <function>ST_Extrude</function></funcdef>
+                       <paramdef><type>geometry</type> <parameter>geom</parameter></paramdef>
+                       <paramdef><type>float</type> <parameter>x</parameter></paramdef>
+                       <paramdef><type>float</type> <parameter>y</parameter></paramdef>
+                       <paramdef><type>float</type> <parameter>z</parameter></paramdef>
+                 </funcprototype>
+               </funcsynopsis>
+         </refsynopsisdiv>
+
+         <refsection>
+               <title>Description</title>
+
+               <para>Availability</para>
+               <para>&Z_support;</para>
+               <para>&P_support;</para>
+               <para>&T_support;</para>
+         </refsection>
+
+       </refentry>
+
+
+       <refentry id="ST_MakeSolid">
+         <refnamediv>
+               <refname>ST_MakeSolid</refname>
+
+               <refpurpose>Make a Solid from a Geometry</refpurpose>
+         </refnamediv>
+
+         <refsynopsisdiv>
+               <funcsynopsis>
+                 <funcprototype>
+                       <funcdef>geometry <function>ST_MakeSolid</function></funcdef>
+                       <paramdef><type>geometry</type> <parameter>geom</parameter></paramdef>
+                 </funcprototype>
+               </funcsynopsis>
+         </refsynopsisdiv>
+
+         <refsection>
+               <title>Description</title>
+
+               <para>Availability</para>
+               <para>&Z_support;</para>
+               <para>&P_support;</para>
+               <para>&T_support;</para>
+         </refsection>
+
+       </refentry>
+
+
+       <refentry id="ST_StraightSkeleton">
+         <refnamediv>
+               <refname>ST_StraightSkeleton</refname>
+
+               <refpurpose>Compute a straight skeleton from a geometry</refpurpose>
+         </refnamediv>
+
+         <refsynopsisdiv>
+               <funcsynopsis>
+                 <funcprototype>
+                       <funcdef>geometry <function>ST_StraightSkeleton</function></funcdef>
+                       <paramdef><type>geometry</type> <parameter>geom</parameter></paramdef>
+                 </funcprototype>
+               </funcsynopsis>
+         </refsynopsisdiv>
+
+         <refsection>
+               <title>Description</title>
+
+               <para>Availability</para>
+               <para>&Z_support;</para>
+               <para>&P_support;</para>
+               <para>&T_support;</para>
+         </refsection>
+
+       </refentry>
+
+
+       <refentry id="ST_IsPlanar">
+         <refnamediv>
+               <refname>ST_IsPlanar</refname>
+
+               <refpurpose>Check if a surface is or not planar</refpurpose>
+         </refnamediv>
+
+         <refsynopsisdiv>
+               <funcsynopsis>
+                 <funcprototype>
+                       <funcdef>boolean <function>ST_IsPlanar</function></funcdef>
+                       <paramdef><type>geometry</type> <parameter>geom</parameter></paramdef>
+                 </funcprototype>
+               </funcsynopsis>
+         </refsynopsisdiv>
+
+         <refsection>
+               <title>Description</title>
+
+               <para>Availability</para>
+               <para>&Z_support;</para>
+               <para>&P_support;</para>
+               <para>&T_support;</para>
+         </refsection>
+
+       </refentry>
+
+
+       <refentry id="ST_Orientation">
+         <refnamediv>
+               <refname>ST_Orientation</refname>
+
+               <refpurpose>Determine surface orientation</refpurpose>
+         </refnamediv>
+
+         <refsynopsisdiv>
+               <funcsynopsis>
+                 <funcprototype>
+                       <funcdef>integer <function>ST_Orientation</function></funcdef>
+                       <paramdef><type>geometry</type> <parameter>geom</parameter></paramdef>
+                 </funcprototype>
+               </funcsynopsis>
+         </refsynopsisdiv>
+
+         <refsection>
+               <title>Description</title>
+
+               <para>Availability</para>
+               <para>&Z_support;</para>
+               <para>&P_support;</para>
+               <para>&T_support;</para>
+         </refsection>
+
+       </refentry>
+
+
+       <refentry id="ST_ForceLHR">
+         <refnamediv>
+               <refname>ST_ForceLHR</refname>
+
+               <refpurpose>Force LHR orientation</refpurpose>
+         </refnamediv>
+
+         <refsynopsisdiv>
+               <funcsynopsis>
+                 <funcprototype>
+                       <funcdef>geometry <function>ST_ForceLHR</function></funcdef>
+                       <paramdef><type>geometry</type> <parameter>geom</parameter></paramdef>
+                 </funcprototype>
+               </funcsynopsis>
+         </refsynopsisdiv>
+
+         <refsection>
+               <title>Description</title>
+
+               <para>Availability</para>
+               <para>&Z_support;</para>
+               <para>&P_support;</para>
+               <para>&T_support;</para>
+         </refsection>
+
+       </refentry>
+
+       <refentry id="ST_Triangulate">
+         <refnamediv>
+               <refname>ST_Minkowski</refname>
+
+               <refpurpose>Perform Minkowski sum</refpurpose>
+         </refnamediv>
+
+         <refsynopsisdiv>
+               <funcsynopsis>
+                 <funcprototype>
+                       <funcdef>geometry <function>ST_Minkowski</function></funcdef>
+                       <paramdef><type>geometry</type> <parameter>geom1</parameter></paramdef>
+                       <paramdef><type>geometry</type> <parameter>geom2</parameter></paramdef>
+                 </funcprototype>
+               </funcsynopsis>
+         </refsynopsisdiv>
+
+         <refsection>
+               <title>Description</title>
+
+               <para>Availability</para>
+               <para>&Z_support;</para>
+               <para>&P_support;</para>
+               <para>&T_support;</para>
+         </refsection>
+
+       </refentry>
+
+
+       <refentry id="ST_Tesselate">
+         <refnamediv>
+               <refname>ST_Tesselate</refname>
+
+               <refpurpose>Perform surface Tesselation</refpurpose>
+         </refnamediv>
+
+         <refsynopsisdiv>
+               <funcsynopsis>
+                 <funcprototype>
+                       <funcdef>geometry <function>ST_Tesselate</function></funcdef>
+                       <paramdef><type>geometry</type> <parameter>geom</parameter></paramdef>
+                 </funcprototype>
+               </funcsynopsis>
+         </refsynopsisdiv>
+
+         <refsection>
+               <title>Description</title>
+
+               <para>Availability</para>
+               <para>&Z_support;</para>
+               <para>&P_support;</para>
+               <para>&T_support;</para>
+         </refsection>
+
+       </refentry>
+
+  </sect1>
index 60630c08bee2b26ea2cdeac225db893915256eaa..82b36c800402723f866b00aafac871dac6ce9d1a 100644 (file)
@@ -18,7 +18,7 @@
         <xsl:template match="chapter">\r
                <xsl:variable name="ap"><xsl:text>'</xsl:text></xsl:variable>\r
 <!-- Pull out the purpose section for each ref entry and strip whitespace and put in a variable to be tagged unto each function comment  -->\r
-               <xsl:for-each select="sect1[not(contains(@id,'Operator'))]/refentry">\r
+               <xsl:for-each select="sect1[not(contains(@id,'Operator') or contains(@id,'sfcgal'))]/refentry">\r
                  <xsl:variable name='plaincomment'>\r
                        <xsl:value-of select="normalize-space(translate(translate(refnamediv/refpurpose,'&#x0d;&#x0a;', ' '), '&#09;', ' '))"/>\r
                  </xsl:variable>\r
diff --git a/doc/xsl/sfcgal_cheatsheet.html.xsl b/doc/xsl/sfcgal_cheatsheet.html.xsl
new file mode 100644 (file)
index 0000000..c7883ef
--- /dev/null
@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">\r
+<!-- ********************************************************************\r
+     $Id: topology_cheatsheet.html.xsl 11092 2013-02-09 06:08:30Z robe $\r
+     ********************************************************************\r
+        Copyright 2011, Regina Obe\r
+     License: BSD\r
+        Purpose: This is an xsl transform that generates PostgreSQL COMMENT ON FUNCTION ddl\r
+        statements from postgis xml doc reference\r
+     ******************************************************************** -->\r
+       <xsl:output method="text" />\r
+       <xsl:variable name='postgis_version'>2.1</xsl:variable>\r
+       <xsl:variable name='new_tag'>Availability: <xsl:value-of select="$postgis_version" /></xsl:variable>\r
+       <xsl:variable name='enhanced_tag'>Enhanced: <xsl:value-of select="$postgis_version" /></xsl:variable>\r
+       <xsl:variable name='include_examples'>false</xsl:variable>\r
+       <xsl:variable name='output_purpose'>true</xsl:variable>\r
+       <xsl:variable name='linkstub'>http://postgis.net/docs/manual-dev/</xsl:variable>\r
+<xsl:template match="/">\r
+       <xsl:text><![CDATA[<html><head><title>PostGIS SFCGAL Cheat Sheet</title>\r
+       <style type="text/css">\r
+<!--\r
+table { page-break-inside:avoid; page-break-after:auto }\r
+tr    { page-break-inside:avoid; page-break-after:avoid }\r
+thead { display:table-header-group }\r
+tfoot { display:table-footer-group }\r
+body {\r
+       font-family: Arial, sans-serif;\r
+       font-size: 8.5pt;\r
+}\r
+@media print { a , a:hover, a:focus, a:active{text-decoration: none;color:black} }\r
+@media screen { a , a:hover, a:focus, a:active{text-decoration: underline} }\r
+.comment {font-size:x-small;color:green;font-family:"courier new"}\r
+.notes {font-size:x-small;color:red}\r
+#example_heading {\r
+       border-bottom: 1px solid #000;\r
+       margin: 10px 15px 10px 85px;\r
+       color: #00d\r
+}\r
+\r
+#content_functions {\r
+       float: left;\r
+       width:100%;\r
+}\r
+\r
+#content_examples {\r
+       float: left;\r
+       width: 100%;\r
+}\r
+\r
+.section {\r
+       border: 1px solid #000; float:left;\r
+       margin: 4px;]]></xsl:text>\r
+       <xsl:choose><xsl:when test="$output_purpose = 'false'"><![CDATA[width: 45%;]]></xsl:when><xsl:otherwise><![CDATA[width: 100%;]]></xsl:otherwise></xsl:choose>\r
+<xsl:text><![CDATA[    }\r
+.section th {\r
+       border: 1px solid #000;\r
+       color: #fff;\r
+       background-color: #b63300;\r
+       font-size: 9.5pt;\r
+       \r
+}\r
+.section td {\r
+       font-family: Arial, sans-serif;\r
+       font-size: 8.5pt;\r
+       vertical-align: top;\r
+       border: 0;\r
+}\r
+\r
+.func {font-weight: 600}\r
+.func {font-weight: 600}\r
+.func_args {font-size: 7.5pt;font-family:courier;}\r
+.func_args ol {margin: 2px}\r
+.func_args ol li {margin: 5px}\r
+\r
+.evenrow {\r
+       background-color: #eee;\r
+}\r
+\r
+.oddrow {\r
+       background-color: #fff;\r
+}\r
+\r
+h1 {\r
+       margin: 0px;\r
+       padding: 0px;\r
+       font-size: 14pt;\r
+}\r
+\r
+-->\r
+</style>\r
+       </head><body><h1 style='text-align:center'>PostGIS ]]></xsl:text> <xsl:value-of select="$postgis_version" /><xsl:text><![CDATA[ PostGIS SFCGAL Cheatsheet</h1>]]></xsl:text>\r
+               <!--Beginning of section -->\r
+               <xsl:text><![CDATA[<table class="section"><tr><th colspan="2">]]></xsl:text>\r
+                       <xsl:value-of select="title" />\r
+                       <!-- end of section header beginning of function list -->\r
+                       <xsl:text><![CDATA[</th></tr>]]></xsl:text>\r
+\r
+                       <xsl:apply-templates select="/book/chapter/sect1[@id='reference_sfcgal']" name="function_list" />\r
+               <!--close section -->\r
+               <![CDATA[</table>]]>\r
+                       <xsl:text><![CDATA[</div>]]></xsl:text>\r
+                       <xsl:text><![CDATA[<div id="content_examples">]]></xsl:text>\r
+                       <!-- examples go here -->\r
+                       <xsl:if test="$include_examples='true'">\r
+                               <xsl:apply-templates select="/book/chapter/sect1[@id='reference_sfcgal']/refentry[count(//refsection//programlisting) &gt; 0]" />\r
+                       </xsl:if>\r
+                       <xsl:text><![CDATA[</div>]]></xsl:text>\r
+                       <xsl:text><![CDATA[</body></html>]]></xsl:text>\r
+</xsl:template>\r
+                       \r
+        \r
+    <xsl:template match="refentry" name="function_list">\r
+               <!-- add row for each function and alternate colors of rows -->\r
+               <!-- , hyperlink to online manual -->\r
+               <![CDATA[<tr]]> class="<xsl:choose><xsl:when test="position() mod 2 = 0">evenrow</xsl:when><xsl:otherwise>oddrow</xsl:otherwise></xsl:choose>" <![CDATA[><td colspan='2'><span class='func'>]]><xsl:text><![CDATA[<a href="]]></xsl:text><xsl:value-of select="$linkstub" /><xsl:value-of select="@id" />.html<xsl:text><![CDATA[" target="_blank">]]></xsl:text><xsl:value-of select="refnamediv/refname" /><xsl:text><![CDATA[</a>]]></xsl:text><![CDATA[</span>]]><xsl:if test="contains(.,$new_tag)"><![CDATA[<sup>1</sup> ]]></xsl:if> \r
+               <!-- enhanced tag -->\r
+               <xsl:if test="contains(.,$enhanced_tag)"><![CDATA[<sup>2</sup> ]]></xsl:if>\r
+               <xsl:if test="contains(.,'implements the SQL/MM')"><![CDATA[<sup>mm</sup> ]]></xsl:if>\r
+               <xsl:if test="contains(refsynopsisdiv/funcsynopsis,'geography') or contains(refsynopsisdiv/funcsynopsis/funcprototype/funcdef,'geography')"><![CDATA[<sup>G</sup>  ]]></xsl:if>\r
+               <xsl:if test="contains(.,'GEOS &gt;= 3.4')"><![CDATA[<sup>g3.4</sup> ]]></xsl:if>\r
+               <xsl:if test="contains(.,'This function supports 3d')"><![CDATA[<sup>3D</sup> ]]></xsl:if>\r
+               <!-- if only one proto just dispaly it on first line -->\r
+               <xsl:if test="count(refsynopsisdiv/funcsynopsis/funcprototype) = 1">\r
+                       (<xsl:call-template name="list_in_params"><xsl:with-param name="func" select="refsynopsisdiv/funcsynopsis/funcprototype" /></xsl:call-template>)\r
+               </xsl:if>\r
+                               \r
+               <![CDATA[&nbsp;&nbsp;]]>\r
+               <xsl:if test="$output_purpose = 'true'"><xsl:value-of select="refnamediv/refpurpose" /></xsl:if>\r
+               <!-- output different proto arg combos -->\r
+               <xsl:if test="count(refsynopsisdiv/funcsynopsis/funcprototype) &gt; 1"><![CDATA[<span class='func_args'><ol>]]><xsl:for-each select="refsynopsisdiv/funcsynopsis/funcprototype"><![CDATA[<li>]]><xsl:call-template name="list_in_params"><xsl:with-param name="func" select="." /></xsl:call-template><![CDATA[</li>]]></xsl:for-each>\r
+               <![CDATA[</ol></span>]]></xsl:if>\r
+               <![CDATA[</td></tr>]]>\r
+       </xsl:template>\r
+       \r
+        <xsl:template match="//refentry//refsection[contains(title,'Example')]">\r
+                       <!-- less than needed for converting html tags in listings so they are printable -->\r
+                       <xsl:variable name="lt"><xsl:text><![CDATA[<]]></xsl:text></xsl:variable>\r
+                       <!-- only print section header if it has examples - not sure why this is necessary -->\r
+                       <xsl:if test="contains(., 'Example')">\r
+                       <!--Beginning of section -->\r
+                               <xsl:text><![CDATA[<table><tr><th colspan="2" class="example_heading">]]></xsl:text>\r
+                               <xsl:value-of select="title" /> Examples\r
+                               <!--only pull the first example section of each function -->\r
+                       <xsl:for-each select="refentry//refsection[contains(title,'Example')][1]/programlisting[1]">\r
+                               <!-- end of section header beginning of function list -->\r
+                               <xsl:text><![CDATA[</th></tr>]]></xsl:text>\r
+                                <xsl:variable name='plainlisting'>\r
+                                       <xsl:call-template name="globalReplace">\r
+                                               <xsl:with-param name="outputString" select="."/>\r
+                                               <xsl:with-param name="target" select="$lt"/>\r
+                                               <xsl:with-param name="replacement" select="'&amp;lt;'"/>\r
+                                       </xsl:call-template>\r
+                               </xsl:variable>\r
+                               \r
+                               <xsl:variable name='listing'>\r
+                                       <xsl:call-template name="break">\r
+                                               <xsl:with-param name="text" select="$plainlisting" />\r
+                                       </xsl:call-template>\r
+                               </xsl:variable>\r
+                               \r
+\r
+\r
+                               <!-- add row for each function and alternate colors of rows -->\r
+                               <![CDATA[<tr]]> class="<xsl:choose><xsl:when test="position() mod 2 = 0">evenrow</xsl:when><xsl:otherwise>oddrow</xsl:otherwise></xsl:choose>"<![CDATA[>]]>\r
+                               <![CDATA[<td><b>]]><xsl:value-of select="ancestor::refentry/refnamediv/refname" /><![CDATA[</b><br /><code>]]><xsl:value-of select="$listing"  disable-output-escaping="no"/><![CDATA[</code></td></tr>]]>\r
+                       </xsl:for-each>\r
+                       <![CDATA[</table>]]>\r
+                       </xsl:if>\r
+                       <!--close section -->\r
+                \r
+               \r
+       </xsl:template>\r
+       \r
+<!--General replace macro hack to make up for the fact xsl 1.0 does not have a built in one.  \r
+       Not needed for xsl 2.0 lifted from http://www.xml.com/pub/a/2002/06/05/transforming.html -->\r
+       <xsl:template name="globalReplace">\r
+         <xsl:param name="outputString"/>\r
+         <xsl:param name="target"/>\r
+         <xsl:param name="replacement"/>\r
+         <xsl:choose>\r
+               <xsl:when test="contains($outputString,$target)">\r
+                 <xsl:value-of select=\r
+                       "concat(substring-before($outputString,$target),\r
+                                  $replacement)"/>\r
+                 <xsl:call-template name="globalReplace">\r
+                       <xsl:with-param name="outputString" \r
+                                select="substring-after($outputString,$target)"/>\r
+                       <xsl:with-param name="target" select="$target"/>\r
+                       <xsl:with-param name="replacement" \r
+                                select="$replacement"/>\r
+                 </xsl:call-template>\r
+               </xsl:when>\r
+               <xsl:otherwise>\r
+                 <xsl:value-of select="$outputString"/>\r
+               </xsl:otherwise>\r
+         </xsl:choose>\r
+       </xsl:template>\r
+       \r
+<xsl:template name="break">\r
+  <xsl:param name="text" select="."/>\r
+  <xsl:choose>\r
+    <xsl:when test="contains($text, '&#xa;')">\r
+      <xsl:value-of select="substring-before($text, '&#xa;')"/>\r
+      <![CDATA[<br/>]]>\r
+      <xsl:call-template name="break">\r
+        <xsl:with-param \r
+          name="text" \r
+          select="substring-after($text, '&#xa;')"\r
+        />\r
+      </xsl:call-template>\r
+    </xsl:when>\r
+    <xsl:otherwise>\r
+      <xsl:value-of select="$text"/>\r
+    </xsl:otherwise>\r
+  </xsl:choose>\r
+</xsl:template>\r
+\r
+<!--macro to pull out function parameter names so we can provide a pretty arg list prefix for each function -->\r
+<xsl:template name="list_in_params">\r
+       <xsl:param name="func" />\r
+       <xsl:for-each select="$func">\r
+               <xsl:if test="count(paramdef/parameter)  &gt; 0"> </xsl:if>\r
+               <xsl:for-each select="paramdef">\r
+                       <xsl:choose>\r
+                               <xsl:when test="not( contains(parameter, 'OUT') )"> \r
+                                       <xsl:value-of select="parameter" />\r
+                                       <xsl:if test="position()&lt;last()"><xsl:text>, </xsl:text></xsl:if>\r
+                               </xsl:when>\r
+                       </xsl:choose>\r
+               </xsl:for-each>\r
+       </xsl:for-each> \r
+</xsl:template>\r
+\r
+</xsl:stylesheet>\r
diff --git a/doc/xsl/sfcgal_comments.sql.xsl b/doc/xsl/sfcgal_comments.sql.xsl
new file mode 100644 (file)
index 0000000..28cfe97
--- /dev/null
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">\r
+<!-- ********************************************************************\r
+     $Id: raster_comments.sql.xsl 9237 2012-02-20 13:16:05Z strk $\r
+     ********************************************************************\r
+        Copyright 2008, Regina Obe\r
+     License: BSD\r
+        Purpose: This is an xsl transform that generates PostgreSQL COMMENT ON FUNCTION ddl\r
+        statements from postgis xml doc reference for WKT Raster section\r
+     ******************************************************************** -->\r
+       <xsl:output method="text" />\r
+\r
+       <!-- We deal only with the reference chapter -->\r
+        <xsl:template match="/">\r
+                <xsl:apply-templates select="/book/chapter/sect1[@id='reference_sfcgal']" />\r
+        </xsl:template>\r
+\r
+        <xsl:template match="refentry">\r
+               <xsl:variable name="ap"><xsl:text>'</xsl:text></xsl:variable>\r
+<!-- Pull out the purpose section for each ref entry and strip whitespace and put in a variable to be tagged unto each function comment  -->\r
+               <xsl:variable name='plaincomment'>\r
+                       <xsl:value-of select="normalize-space(translate(translate(refnamediv/refpurpose,'&#x0d;&#x0a;', ' '), '&#09;', ' '))"/>\r
+               </xsl:variable>\r
+<!-- Replace apostrophes with 2 apostrophes needed for escaping in SQL -->\r
+               <xsl:variable name='comment'>\r
+                       <xsl:call-template name="globalReplace">\r
+                               <xsl:with-param name="outputString" select="$plaincomment"/>\r
+                               <xsl:with-param name="target" select="$ap"/>\r
+                               <xsl:with-param name="replacement" select="''"/>\r
+                       </xsl:call-template>\r
+               </xsl:variable>\r
+<!-- For each function prototype generate the DDL comment statement\r
+       If its input is a geometry set - we know it is an aggregate function rather than a regular function.\r
+       Do not output OUT params since they define output rather than act as input and do not put a comma after argument just before an OUT parameter -->\r
+               <xsl:for-each select="refsynopsisdiv/funcsynopsis/funcprototype">\r
+COMMENT ON <xsl:choose><xsl:when test="contains(paramdef/type,'geometry set')">AGGREGATE</xsl:when><xsl:otherwise>FUNCTION</xsl:otherwise></xsl:choose><xsl:text> </xsl:text> <xsl:value-of select="funcdef/function" />(<xsl:for-each select="paramdef"><xsl:choose><xsl:when test="count(parameter) &gt; 0"> \r
+<xsl:choose><xsl:when test="contains(parameter,'OUT')"></xsl:when><xsl:when test="contains(type,'geometry set')">geometry</xsl:when><xsl:otherwise><xsl:value-of select="type" /></xsl:otherwise></xsl:choose><xsl:if test="position()&lt;last() and not(contains(parameter,'OUT')) and not(contains(following-sibling::paramdef[1],'OUT'))"><xsl:text>, </xsl:text></xsl:if></xsl:when>\r
+</xsl:choose></xsl:for-each>) IS '<xsl:call-template name="listparams"><xsl:with-param name="func" select="." /></xsl:call-template> <xsl:value-of select='$comment' />';\r
+               </xsl:for-each>\r
+       </xsl:template>\r
+       \r
+<!--General replace macro hack to make up for the fact xsl 1.0 does not have a built in one.  \r
+       Not needed for xsl 2.0 lifted from http://www.xml.com/pub/a/2002/06/05/transforming.html -->\r
+       <xsl:template name="globalReplace">\r
+         <xsl:param name="outputString"/>\r
+         <xsl:param name="target"/>\r
+         <xsl:param name="replacement"/>\r
+         <xsl:choose>\r
+               <xsl:when test="contains($outputString,$target)">\r
+                 <xsl:value-of select=\r
+                       "concat(substring-before($outputString,$target),\r
+                                  $replacement)"/>\r
+                 <xsl:call-template name="globalReplace">\r
+                       <xsl:with-param name="outputString" \r
+                                select="substring-after($outputString,$target)"/>\r
+                       <xsl:with-param name="target" select="$target"/>\r
+                       <xsl:with-param name="replacement" \r
+                                select="$replacement"/>\r
+                 </xsl:call-template>\r
+               </xsl:when>\r
+               <xsl:otherwise>\r
+                 <xsl:value-of select="$outputString"/>\r
+               </xsl:otherwise>\r
+         </xsl:choose>\r
+       </xsl:template>\r
+\r
+       <xsl:template name="escapesinglequotes">\r
+        <xsl:param name="arg1"/>\r
+        <xsl:variable name="apostrophe">'</xsl:variable>\r
+        <xsl:choose>\r
+         <!-- this string has at least on single quote -->\r
+         <xsl:when test="contains($arg1, $apostrophe)">\r
+         <xsl:if test="string-length(normalize-space(substring-before($arg1, $apostrophe))) > 0"><xsl:value-of select="substring-before($arg1, $apostrophe)" disable-output-escaping="yes"/>''</xsl:if>\r
+          <xsl:call-template name="escapesinglequotes">\r
+           <xsl:with-param name="arg1"><xsl:value-of select="substring-after($arg1, $apostrophe)" disable-output-escaping="yes"/></xsl:with-param>\r
+          </xsl:call-template>\r
+         </xsl:when>\r
+         <!-- no quotes found in string, just print it -->\r
+         <xsl:when test="string-length(normalize-space($arg1)) > 0"><xsl:value-of select="normalize-space($arg1)"/></xsl:when>\r
+        </xsl:choose>\r
+       </xsl:template>\r
+\r
+       <!--macro to pull out function parameter names so we can provide a pretty arg list prefix for each function -->\r
+       <xsl:template name="listparams">\r
+               <xsl:param name="func" />\r
+               <xsl:for-each select="$func">\r
+                       <xsl:if test="count(paramdef/parameter) &gt; 0">args: </xsl:if>\r
+                       <xsl:for-each select="paramdef">\r
+                               <xsl:choose>\r
+                               <xsl:when test="count(parameter) &gt; 0"> \r
+                                       <xsl:call-template name="escapesinglequotes">\r
+                                               <xsl:with-param name="arg1" select="parameter"/>\r
+                                       </xsl:call-template>\r
+                               </xsl:when>\r
+                               </xsl:choose>\r
+                               <xsl:if test="position()&lt;last()"><xsl:text>, </xsl:text></xsl:if>\r
+                       </xsl:for-each>\r
+                       <xsl:if test="count(paramdef/parameter) &gt; 0"> - </xsl:if>\r
+               </xsl:for-each> \r
+       </xsl:template>\r
+\r
+</xsl:stylesheet>\r
index f88fee4cd0ccc03490847347bb68622435b26fc7..3cc6256fdadca4277fb2f3b4c95c7c181bbc4c36 100644 (file)
@@ -91,6 +91,12 @@ SA_OBJS = \
 NM_OBJS = \
        lwspheroid.o 
 
+ifeq (@SFCGAL@,sfcgal)
+CFLAGS += @SFCGAL_CPPFLAGS@
+LDFLAGS += @SFCGAL_LDFLAGS@
+SA_OBJS += lwgeom_sfcgal.o
+endif
+
 LT_SA_OBJS = $(SA_OBJS:.o=.lo)
 LT_NM_OBJS = $(NM_OBJS:.o=.lo)
 LT_OBJS = $(LT_SA_OBJS) $(LT_NM_OBJS)
@@ -157,7 +163,6 @@ $(LT_NM_OBJS): %.lo: %.c
 parser:
        $(YACC) -o'lwin_wkt_parse.c' -d lwin_wkt_parse.y
        $(LEX) -i lwin_wkt_lex.l
-       
 #      $(YACC) --debug --verbose -o'$@' -d $<
 #      $(YACC) -o'$@' -d $^
 #      $(LEX) -i $<
index e5723aeb14e19ed62630604faee14b1bca8f2465..edac6093da27ae5b9cd8bc6f0dcba6f6d7541832 100644 (file)
@@ -38,6 +38,7 @@ OBJS= \
        cu_stringbuffer.o \
        cu_triangulate.o \
        cu_homogenize.o \
+       cu_force_sfs.o \
        cu_out_wkt.o \
        cu_out_wkb.o \
        cu_out_gml.o \
@@ -51,6 +52,12 @@ OBJS=        \
        cu_in_wkt.o \
        cu_tester.o 
 
+ifeq (@SFCGAL@,sfcgal)
+CXXFLAGS += @SFCGAL_CPPFLAGS@
+LDFLAGS += @SFCGAL_LDFLAGS@
+OBJS += cu_sfcgal.o
+endif
+
 # If we couldn't find the cunit library then display a helpful message
 ifeq ($(CUNIT_LDFLAGS),)
 all: requirements_not_met_cunit
diff --git a/liblwgeom/cunit/cu_force_sfs.c b/liblwgeom/cunit/cu_force_sfs.c
new file mode 100644 (file)
index 0000000..f329921
--- /dev/null
@@ -0,0 +1,175 @@
+/**********************************************************************
+ * $Id:$
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ * Copyright 2013 Olivier Courtin <olivier.courtin@oslandia.com>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "CUnit/Basic.h"
+
+#include "liblwgeom_internal.h"
+#include "cu_tester.h"
+
+static void do_geom_test(char * in, char * out)
+{
+       LWGEOM *g, *h;
+       char *tmp;
+
+       g = lwgeom_from_wkt(in, LW_PARSER_CHECK_NONE);
+       h = lwgeom_force_sfs(g);
+       tmp = lwgeom_to_ewkt(h);
+       if (strcmp(tmp, out))
+               fprintf(stderr, "\nIn:   %s\nOut:  %s\nExp:  %s\n",
+                       in, tmp, out);
+       CU_ASSERT_STRING_EQUAL(tmp, out);
+       lwfree(tmp);
+       lwgeom_free(g);
+       lwgeom_free(h);
+}
+
+
+static void do_type_test(char * in, int type)
+{
+       LWGEOM *g, *h;
+
+       g = lwgeom_from_wkt(in, LW_PARSER_CHECK_NONE);
+       h = lwgeom_force_sfs(g);
+       if(h->type != type)
+               fprintf(stderr, "\nIn:   %s\nOut:  %s\nExp:  %s\n", 
+                       in, lwtype_name(h->type), lwtype_name(type));
+       CU_ASSERT_EQUAL(h->type, type);
+       lwgeom_free(g);
+       lwgeom_free(h);
+}
+
+
+static void test_sqlmm(void)
+{
+       do_type_test("CIRCULARSTRING(-1 0,0 1,0 -1)",
+                    LINETYPE);
+
+        do_type_test("COMPOUNDCURVE(CIRCULARSTRING(-1 0,0 1,0 -1),(0 -1,-1 -1))",
+                    LINETYPE);
+
+        do_type_test("COMPOUNDCURVE((-3 -3,-1 0),CIRCULARSTRING(-1 0,0 1,0 -1),(0 -1,0 -1.5,0 -2),CIRCULARSTRING(0 -2,-1 -3,1 -3),(1 -3,5 5))",
+                    LINETYPE);
+
+        do_type_test("COMPOUNDCURVE(CIRCULARSTRING(-1 0,0 1,0 -1),CIRCULARSTRING(0 -1,-1 -2,1 -2))",
+                    LINETYPE);
+
+       do_type_test("CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING (0 0 2,1 1 2,1 0 2),(1 0 2,0 1 2),(0 1 2, 0 0 2)))",
+                    POLYGONTYPE);
+
+       do_type_test("CURVEPOLYGON (COMPOUNDCURVE (CIRCULARSTRING (0 0 2 5,1 1 2 6,1 0 2 5), (1 0 2 3,0 1 2 2), (0 1 2 2,30 1 2 2), CIRCULARSTRING (30 1 2 2,12 1 2 6,1 10 2 5, 1 10 3 5, 0 0 2 5)))",
+                    POLYGONTYPE);      
+
+       do_type_test("MULTISURFACE (CURVEPOLYGON (CIRCULARSTRING (-2 0, -1 -1, 0 0, 1 -1, 2 0, 0 2, -2 0), (-1 0, 0 0.5, 1 0, 0 1, -1 0)), ((7 8, 10 10, 6 14, 4 11, 7 8)))",
+                    MULTIPOLYGONTYPE);
+
+}
+
+static void test_sfs_12(void)
+{
+       do_geom_test("TRIANGLE((1 2,3 4,5 6,1 2))",
+                    "POLYGON((1 2,3 4,5 6,1 2))");
+
+       do_geom_test("GEOMETRYCOLLECTION(TRIANGLE((1 2,3 4,5 6,1 2)))",
+                    "GEOMETRYCOLLECTION(POLYGON((1 2,3 4,5 6,1 2)))");
+
+       do_geom_test("GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(TRIANGLE((1 2,3 4,5 6,1 2))))",
+                    "GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POLYGON((1 2,3 4,5 6,1 2))))");
+
+
+       do_geom_test("TIN(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))",
+                    "MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))");
+
+       do_geom_test("GEOMETRYCOLLECTION(TIN(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8))))",
+                    "GEOMETRYCOLLECTION(MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8))))");
+
+       do_geom_test("GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(TIN(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))))",
+                    "GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))))");
+
+
+       do_geom_test("POLYHEDRALSURFACE(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))",
+                    "MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))");
+
+       do_geom_test("GEOMETRYCOLLECTION(POLYHEDRALSURFACE(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8))))",
+                    "GEOMETRYCOLLECTION(MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8))))");
+
+       do_geom_test("GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POLYHEDRALSURFACE(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))))",
+                    "GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))))");
+
+}
+
+static void test_sfs_11(void)
+{
+       do_geom_test("POINT(1 2)",
+                    "POINT(1 2)");
+
+       do_geom_test("LINESTRING(1 2,3 4)",
+                    "LINESTRING(1 2,3 4)");
+
+       do_geom_test("POLYGON((1 2,3 4,5 6,1 2))",
+                    "POLYGON((1 2,3 4,5 6,1 2))");
+
+       do_geom_test("POLYGON((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8))",
+                    "POLYGON((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8))");
+
+       do_geom_test("MULTIPOINT(1 2,3 4)",
+                    "MULTIPOINT(1 2,3 4)");
+
+       do_geom_test("MULTILINESTRING((1 2,3 4),(5 6,7 8))",
+                    "MULTILINESTRING((1 2,3 4),(5 6,7 8))");
+
+       do_geom_test("MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))",
+                    "MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))");
+
+       do_geom_test("MULTIPOLYGON(((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8)),((13 14,15 16,17 18,13 14)))",
+                    "MULTIPOLYGON(((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8)),((13 14,15 16,17 18,13 14)))");
+
+       do_geom_test("GEOMETRYCOLLECTION(POINT(1 2),LINESTRING(3 4,5 6))",
+                    "GEOMETRYCOLLECTION(POINT(1 2),LINESTRING(3 4,5 6))");
+
+       do_geom_test("GEOMETRYCOLLECTION EMPTY",
+                    "GEOMETRYCOLLECTION EMPTY");
+
+       /* SRID */
+       do_geom_test("SRID=4326;GEOMETRYCOLLECTION EMPTY",
+                    "SRID=4326;GEOMETRYCOLLECTION EMPTY");
+
+       do_geom_test("SRID=4326;POINT(1 2)",
+                    "SRID=4326;POINT(1 2)");
+
+
+       /* 3D and 4D */
+        /* SFS 1.2 is only 2D but we choose here to keep 3D and 4D,
+           and let the user use force_2d if he want/need it */
+       do_geom_test("POINT(1 2 3)",
+                    "POINT(1 2 3)");
+
+       do_geom_test("POINTM(1 2 3)",
+                    "POINTM(1 2 3)");
+
+       do_geom_test("POINT(1 2 3 4)",
+                    "POINT(1 2 3 4)");
+}
+
+/*
+** Used by test harness to register the tests in this file.
+*/
+CU_TestInfo force_sfs_tests[] =
+{
+       PG_TEST(test_sfs_11),
+       PG_TEST(test_sfs_12),
+       PG_TEST(test_sqlmm),
+       CU_TEST_INFO_NULL
+};
+CU_SuiteInfo force_sfs_suite = {"force_sfs",  NULL,  NULL, force_sfs_tests};
diff --git a/liblwgeom/cunit/cu_sfcgal.c b/liblwgeom/cunit/cu_sfcgal.c
new file mode 100644 (file)
index 0000000..5ed921c
--- /dev/null
@@ -0,0 +1,100 @@
+/**********************************************************************
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ *
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "CUnit/Basic.h"
+
+#include "cu_tester.h"
+#include "liblwgeom.h"
+
+extern LWGEOM* lwgeom_sfcgal_noop( const LWGEOM* geom_in );
+
+static void test_sfcgal_noop(void)
+{
+       int i;
+
+       char *ewkt[] =
+       {
+               "POINT(0 0.2)",
+               "LINESTRING(-1 -1,-1 2.5,2 2,2 -1)",
+               "TRIANGLE((0 0,-1 1,0 -1,0 0))",
+               "MULTIPOINT(0.9 0.9,0.9 0.9,0.9 0.9,0.9 0.9,0.9 0.9,0.9 0.9)",
+               "SRID=1;MULTILINESTRING((-1 -1,-1 2.5,2 2,2 -1),(-1 -1,-1 2.5,2 2,2 -1),(-1 -1,-1 2.5,2 2,2 -1),(-1 -1,-1 2.5,2 2,2 -1))",
+               "SRID=1;MULTILINESTRING((-1 -1,-1 2.5,2 2,2 -1),(-1 -1,-1 2.5,2 2,2 -1),(-1 -1,-1 2.5,2 2,2 -1),(-1 -1,-1 2.5,2 2,2 -1))",
+               "POLYGON((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0))",
+               "SRID=4326;POLYGON((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0))",
+               "SRID=4326;POLYGON((-1 -1 1,-1 2.5 1,2 2 2,2 -1 2,-1 -1 2),(0 0 1,0 1 1,1 1 1,1 0 2,0 0 2))",
+               "SRID=4326;POLYGON((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0),(-0.5 -0.5,-0.5 -0.4,-0.4 -0.4,-0.4 -0.5,-0.5 -0.5))",
+               "SRID=100000;POLYGON((-1 -1 3,-1 2.5 3,2 2 3,2 -1 3,-1 -1 3),(0 0 3,0 1 3,1 1 3,1 0 3,0 0 3),(-0.5 -0.5 3,-0.5 -0.4 3,-0.4 -0.4 3,-0.4 -0.5 3,-0.5 -0.5 3))",
+               "SRID=4326;MULTIPOLYGON(((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0),(-0.5 -0.5,-0.5 -0.4,-0.4 -0.4,-0.4 -0.5,-0.5 -0.5)),((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0),(-0.5 -0.5,-0.5 -0.4,-0.4 -0.4,-0.4 -0.5,-0.5 -0.5)))",
+               "SRID=4326;GEOMETRYCOLLECTION(POINT(0 1),POLYGON((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0)),MULTIPOLYGON(((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0),(-0.5 -0.5,-0.5 -0.4,-0.4 -0.4,-0.4 -0.5,-0.5 -0.5))))",
+               "POLYHEDRALSURFACE(((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0),(-0.5 -0.5,-0.5 -0.4,-0.4 -0.4,-0.4 -0.5,-0.5 -0.5)),((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0),(-0.5 -0.5,-0.5 -0.4,-0.4 -0.4,-0.4 -0.5,-0.5 -0.5)))",
+               "POLYHEDRALSURFACE(((-1 -1 1,-1 2.5 1,2 2 1,2 -1 1,-1 -1 1),(0 0 1,0 1 1,1 1 1,1 0 1,0 0 1),(-0.5 -0.5 1,-0.5 -0.4 1,-0.4 -0.4 1,-0.4 -0.5 1,-0.5 -0.5 1)),((-1 -1 1,-1 2.5 1,2 2 1,2 -1 1,-1 -1 1),(0 0 1,0 1 1,1 1 1,1 0 1,0 0 1),(-0.5 -0.5 1,-0.5 -0.4 1,-0.4 -0.4 1,-0.4 -0.5 1,-0.5 -0.5 1)))",
+               "TIN(((0 0,0 -1,-1 1,0 0)),((0 0,1 0,0 -1,0 0)))",
+       };
+
+       char *expected_ewkt[] =
+       {
+               "POINT(0 0.2)",
+               "LINESTRING(-1 -1,-1 2.5,2 2,2 -1)",
+               "TRIANGLE((0 0,-1 1,0 -1,0 0))",
+               "MULTIPOINT(0.9 0.9,0.9 0.9,0.9 0.9,0.9 0.9,0.9 0.9,0.9 0.9)",
+               "SRID=1;MULTILINESTRING((-1 -1,-1 2.5,2 2,2 -1),(-1 -1,-1 2.5,2 2,2 -1),(-1 -1,-1 2.5,2 2,2 -1),(-1 -1,-1 2.5,2 2,2 -1))",
+               "SRID=1;MULTILINESTRING((-1 -1,-1 2.5,2 2,2 -1),(-1 -1,-1 2.5,2 2,2 -1),(-1 -1,-1 2.5,2 2,2 -1),(-1 -1,-1 2.5,2 2,2 -1))",
+               "POLYGON((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0))",
+               "SRID=4326;POLYGON((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0))",
+               "SRID=4326;POLYGON((-1 -1 1,-1 2.5 1,2 2 2,2 -1 2,-1 -1 2),(0 0 1,0 1 1,1 1 1,1 0 2,0 0 2))",
+               "SRID=4326;POLYGON((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0),(-0.5 -0.5,-0.5 -0.4,-0.4 -0.4,-0.4 -0.5,-0.5 -0.5))",
+               "SRID=100000;POLYGON((-1 -1 3,-1 2.5 3,2 2 3,2 -1 3,-1 -1 3),(0 0 3,0 1 3,1 1 3,1 0 3,0 0 3),(-0.5 -0.5 3,-0.5 -0.4 3,-0.4 -0.4 3,-0.4 -0.5 3,-0.5 -0.5 3))",
+               "SRID=4326;MULTIPOLYGON(((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0),(-0.5 -0.5,-0.5 -0.4,-0.4 -0.4,-0.4 -0.5,-0.5 -0.5)),((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0),(-0.5 -0.5,-0.5 -0.4,-0.4 -0.4,-0.4 -0.5,-0.5 -0.5)))",
+               "SRID=4326;GEOMETRYCOLLECTION(POINT(0 1),POLYGON((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0)),MULTIPOLYGON(((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0),(-0.5 -0.5,-0.5 -0.4,-0.4 -0.4,-0.4 -0.5,-0.5 -0.5))))",
+               "POLYHEDRALSURFACE(((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0),(-0.5 -0.5,-0.5 -0.4,-0.4 -0.4,-0.4 -0.5,-0.5 -0.5)),((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0),(-0.5 -0.5,-0.5 -0.4,-0.4 -0.4,-0.4 -0.5,-0.5 -0.5)))",
+               "POLYHEDRALSURFACE(((-1 -1 1,-1 2.5 1,2 2 1,2 -1 1,-1 -1 1),(0 0 1,0 1 1,1 1 1,1 0 1,0 0 1),(-0.5 -0.5 1,-0.5 -0.4 1,-0.4 -0.4 1,-0.4 -0.5 1,-0.5 -0.5 1)),((-1 -1 1,-1 2.5 1,2 2 1,2 -1 1,-1 -1 1),(0 0 1,0 1 1,1 1 1,1 0 1,0 0 1),(-0.5 -0.5 1,-0.5 -0.4 1,-0.4 -0.4 1,-0.4 -0.5 1,-0.5 -0.5 1)))",
+               "TIN(((0 0,0 -1,-1 1,0 0)),((0 0,1 0,0 -1,0 0)))",
+       };
+
+       for ( i = 0; i < (sizeof ewkt/sizeof(char *)); i++ )
+       {
+               LWGEOM *geom_in, *geom_out;
+               char *in_ewkt;
+               char *out_ewkt;
+
+               in_ewkt = ewkt[i];
+               geom_in = lwgeom_from_wkt(in_ewkt, LW_PARSER_CHECK_NONE);
+               geom_out = lwgeom_sfcgal_noop(geom_in);
+               if ( ! geom_out ) {
+                       fprintf(stderr, "\nNull return from lwgeom_sfcgal_noop with wkt:   %s\n", in_ewkt);
+                       lwgeom_free(geom_in);
+                       continue;
+               }
+               out_ewkt = lwgeom_to_ewkt(geom_out);
+               if (strcmp(expected_ewkt[i], out_ewkt))
+                       fprintf(stderr, "\nExp:   %s\nObt:  %s\n", expected_ewkt[i], out_ewkt);
+               CU_ASSERT_STRING_EQUAL(expected_ewkt[i], out_ewkt);
+               lwfree(out_ewkt);
+               lwgeom_free(geom_out);
+               lwgeom_free(geom_in);
+       }
+}
+
+
+/*
+** Used by test harness to register the tests in this file.
+*/
+CU_TestInfo sfcgal_tests[] =
+{
+       PG_TEST(test_sfcgal_noop),
+       CU_TEST_INFO_NULL
+};
+CU_SuiteInfo sfcgal_suite = {"SFCGAL",  NULL,  NULL, sfcgal_tests};
+
index 4c0c01a9493640d398c5b3e818da1d0b282cdd9b..9145d3f064237ddd160c8120b486d0570f002f18 100644 (file)
@@ -38,9 +38,11 @@ extern CU_SuiteInfo libgeom_suite;
 extern CU_SuiteInfo split_suite;
 extern CU_SuiteInfo geodetic_suite;
 extern CU_SuiteInfo geos_suite;
+extern CU_SuiteInfo sfcgal_suite;
 extern CU_SuiteInfo tree_suite;
 extern CU_SuiteInfo triangulate_suite;
 extern CU_SuiteInfo homogenize_suite;
+extern CU_SuiteInfo force_sfs_suite;
 extern CU_SuiteInfo in_geojson_suite;
 extern CU_SuiteInfo stringbuffer_suite;
 extern CU_SuiteInfo surface_suite;
@@ -76,11 +78,15 @@ int main(int argc, char *argv[])
                split_suite,
                geodetic_suite,
                geos_suite,
+#if HAVE_SFCGAL
+               sfcgal_suite,
+#endif
                tree_suite,
                triangulate_suite,
                stringbuffer_suite,
                surface_suite,
                homogenize_suite,
+               force_sfs_suite,
 #if HAVE_JSON
                in_geojson_suite,
 #endif
index fb20b5f8dde7b9a4f79e837aad5ccb09df72e04e..886f6324698fd95136deef68d26f879880b22005 100644 (file)
@@ -873,6 +873,12 @@ extern LWGEOM* lwgeom_force_4d(const LWGEOM *geom);
 
 extern LWGEOM* lwgeom_simplify(const LWGEOM *igeom, double dist);
 
+/* 
+ * Force to use SFS 1.1 geometry type
+ * (rather than SFS 1.2 and/or SQL/MM)
+ */
+extern LWGEOM* lwgeom_force_sfs(LWGEOM *geom);
+
 
 /*--------------------------------------------------------
  * all the base types (point/line/polygon) will have a
index a30ea0c2379cef7f4e9719ccd7586cb41500fb7a..cdabd1beb8dd3ea97b5479d62885c7d212b9a5c9 100644 (file)
@@ -705,6 +705,59 @@ lwgeom_force_dims(const LWGEOM *geom, int hasz, int hasm)
        }
 }
 
+LWGEOM*
+lwgeom_force_sfs(LWGEOM *geom)
+{      
+       LWCOLLECTION *col;
+       int i;
+       LWGEOM *g;
+
+
+       switch(geom->type)
+       {
+               /* SQL/MM types */
+               case CIRCSTRINGTYPE:
+               case COMPOUNDTYPE:
+               case CURVEPOLYTYPE:
+               case MULTICURVETYPE:
+               case MULTISURFACETYPE:
+                       return lwgeom_segmentize(geom, 32);
+
+               /* SFS 1.2 types */
+               case TRIANGLETYPE:
+                       g = lwpoly_as_lwgeom(lwpoly_from_lwlines((LWLINE*)geom, 0, NULL));
+                       lwgeom_free(geom);
+                       return g;
+
+               case TINTYPE:
+                       col = (LWCOLLECTION*) geom;
+                       for ( i = 0; i < col->ngeoms; i++ )
+                       {
+                               g = lwpoly_as_lwgeom(lwpoly_from_lwlines((LWLINE*)col->geoms[i], 0, NULL));
+                               lwgeom_free(col->geoms[i]);
+                               col->geoms[i] = g;
+                       }
+
+                       col->type = MULTIPOLYGONTYPE;
+                       return lwmpoly_as_lwgeom((LWMPOLY*)geom);
+               
+               case POLYHEDRALSURFACETYPE:
+                       geom->type = MULTIPOLYGONTYPE;
+                       return (LWGEOM *)geom;
+
+               /* Collection */
+               case COLLECTIONTYPE:
+                       col = (LWCOLLECTION*)geom;
+                       for ( i = 0; i < col->ngeoms; i++ ) 
+                               col->geoms[i] = lwgeom_force_sfs((LWGEOM*)col->geoms[i]);
+
+                       return lwcollection_as_lwgeom((LWCOLLECTION*)geom);
+               
+               default:
+                       return (LWGEOM *)geom;
+       }
+}
+
 int32_t 
 lwgeom_get_srid(const LWGEOM *geom)
 {
diff --git a/liblwgeom/lwgeom_sfcgal.c b/liblwgeom/lwgeom_sfcgal.c
new file mode 100644 (file)
index 0000000..57a56fc
--- /dev/null
@@ -0,0 +1,565 @@
+/**********************************************************************
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ *
+ * Wrapper around SFCGAL for 3D functions
+ *
+ * Copyright 2012-2013 Oslandia <infos@oslandia.com>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************/
+
+
+#include <assert.h>
+#include "lwgeom_sfcgal.h"
+
+static int SFCGAL_type_to_lwgeom_type(sfcgal_geometry_type_t type);
+static POINTARRAY* ptarray_from_SFCGAL(const sfcgal_geometry_t* geom, int force3D);
+static sfcgal_geometry_t* ptarray_to_SFCGAL(const POINTARRAY* pa, int type);
+
+
+
+/* Return SFCGAL version string */
+const char*
+lwgeom_sfcgal_version()
+{
+        const char *version = sfcgal_version();
+        return version;
+}
+
+
+/*
+ * Mapping between SFCGAL and PostGIS types
+ *
+ * Throw an error if type is unsupported
+ */
+static int
+SFCGAL_type_to_lwgeom_type(sfcgal_geometry_type_t type)
+{
+       switch (type)
+       {
+       case SFCGAL_TYPE_POINT:
+               return POINTTYPE;
+
+       case SFCGAL_TYPE_LINESTRING:
+               return LINETYPE;
+
+       case SFCGAL_TYPE_POLYGON:
+               return POLYGONTYPE;
+
+       case SFCGAL_TYPE_MULTIPOINT:
+               return MULTIPOINTTYPE;
+
+       case SFCGAL_TYPE_MULTILINESTRING:
+               return MULTILINETYPE;
+
+       case SFCGAL_TYPE_MULTIPOLYGON:
+               return MULTIPOLYGONTYPE;
+
+       case SFCGAL_TYPE_MULTISOLID:
+               return COLLECTIONTYPE;  /* Nota: PolyhedralSurface closed inside
+                                          aim is to use true solid type as soon
+                                          as available in OGC SFS */
+
+       case SFCGAL_TYPE_GEOMETRYCOLLECTION:
+               return COLLECTIONTYPE;
+
+#if 0
+       case SFCGAL_TYPE_CIRCULARSTRING:
+               return CIRCSTRINGTYPE;
+
+       case SFCGAL_TYPE_COMPOUNDCURVE:
+               return COMPOUNDTYPE;
+
+       case SFCGAL_TYPE_CURVEPOLYGON:
+               return CURVEPOLYTYPE;
+
+       case SFCGAL_TYPE_MULTICURVE:
+               return MULTICURVETYPE;
+
+       case SFCGAL_TYPE_MULTISURFACE:
+               return MULTISURFACETYPE;
+#endif
+
+       case SFCGAL_TYPE_POLYHEDRALSURFACE:
+               return POLYHEDRALSURFACETYPE;
+
+       case SFCGAL_TYPE_TRIANGULATEDSURFACE:
+               return TINTYPE;
+
+       case SFCGAL_TYPE_TRIANGLE:
+               return TRIANGLETYPE;
+
+       default:
+               lwerror("SFCGAL_type_to_lwgeom_type: Unknown Type");
+               return 0;
+       }
+}
+
+
+/*
+ * Return a PostGIS pointarray from a simple SFCGAL geometry:
+ * POINT, LINESTRING or TRIANGLE
+ *
+ * Trought an error on others types
+ */
+static POINTARRAY*
+ptarray_from_SFCGAL(const sfcgal_geometry_t* geom, int want3d)
+{
+       POINT4D point;
+       uint32_t i, npoints;
+       POINTARRAY* pa = NULL;
+
+       assert(geom);
+
+       switch (sfcgal_geometry_type_id(geom))
+       {
+       case SFCGAL_TYPE_POINT:
+       {
+               pa = ptarray_construct(want3d, 0, 1);
+               point.x = sfcgal_point_x(geom);
+               point.y = sfcgal_point_y(geom);
+
+               if (sfcgal_geometry_is_3d(geom))
+                       point.z = sfcgal_point_z(geom);
+               else if (want3d)
+                       point.z = 0.0;
+
+               ptarray_set_point4d(pa, 0, &point);
+       }
+       break;
+
+       case SFCGAL_TYPE_LINESTRING:
+       {
+               npoints = sfcgal_linestring_num_points(geom);
+               pa = ptarray_construct(want3d, 0, npoints);
+
+               for (i = 0; i < npoints; i++)
+               {
+                       const sfcgal_geometry_t* pt = sfcgal_linestring_point_n(geom, i);
+                       point.x = sfcgal_point_x(pt);
+                       point.y = sfcgal_point_y(pt);
+
+                       if (sfcgal_geometry_is_3d(geom))
+                               point.z = sfcgal_point_z(pt);
+                       else if (want3d)
+                               point.z = 0.0;
+
+                       ptarray_set_point4d(pa, i, &point);
+               }
+       }
+       break;
+
+       case SFCGAL_TYPE_TRIANGLE:
+       {
+               pa = ptarray_construct(want3d, 0, 4);
+
+               for (i = 0; i < 4; i++)
+               {
+                       const sfcgal_geometry_t* pt = sfcgal_triangle_vertex(geom, (i%3));
+                       point.x = sfcgal_point_x(pt);
+                       point.y = sfcgal_point_y(pt);
+
+                       if ( sfcgal_geometry_is_3d(geom))
+                               point.z = sfcgal_point_z(pt);
+                       else if (want3d)
+                               point.z = 0.0;
+
+                       ptarray_set_point4d(pa, i, &point);
+               }
+       }
+       break;
+
+       /* Other types should not be called directly ... */
+       default:
+               lwerror("ptarray_from_SFCGAL: Unknown Type");
+               break;
+       }
+       return pa;
+}
+
+
+/*
+ * Convert a PostGIS pointarray to SFCGAL structure
+ *
+ * Used for simple LWGEOM geometry POINT, LINESTRING, TRIANGLE
+ * and POLYGON rings
+ */
+static sfcgal_geometry_t*
+ptarray_to_SFCGAL(const POINTARRAY* pa, int type)
+{
+       POINT3DZ point;
+       int is_3d;
+       uint32_t i;
+
+       assert(pa);
+
+       is_3d = FLAGS_GET_Z(pa->flags) != 0;
+
+       switch (type)
+       {
+       case POINTTYPE:
+       {
+               getPoint3dz_p(pa, 0, &point);
+               if (is_3d) return sfcgal_point_create_from_xyz(point.x, point.y, point.z);
+               else       return sfcgal_point_create_from_xy(point.x, point.y);
+       }
+       break;
+
+       case LINETYPE:
+       {
+               sfcgal_geometry_t* line = sfcgal_linestring_create();
+
+               for (i = 0; i < pa->npoints; i++)
+               {
+                       getPoint3dz_p(pa, i, &point);
+                       if (is_3d)
+                       {
+                               sfcgal_linestring_add_point(line,
+                                                           sfcgal_point_create_from_xyz(point.x, point.y, point.z));
+                       }
+                       else
+                       {
+                               sfcgal_linestring_add_point(line,
+                                                           sfcgal_point_create_from_xy(point.x, point.y));
+                       }
+               }
+
+               return line;
+       }
+       break;
+
+       case TRIANGLETYPE:
+       {
+               sfcgal_geometry_t* triangle = sfcgal_triangle_create();
+
+               getPoint3dz_p(pa, 0, &point);
+               if (is_3d) sfcgal_triangle_set_vertex_from_xyz(triangle, 0, point.x, point.y, point.z);
+               else       sfcgal_triangle_set_vertex_from_xy (triangle, 0, point.x, point.y);
+
+               getPoint3dz_p(pa, 1, &point);
+               if (is_3d) sfcgal_triangle_set_vertex_from_xyz(triangle, 1, point.x, point.y, point.z);
+               else       sfcgal_triangle_set_vertex_from_xy (triangle, 1, point.x, point.y);
+
+               getPoint3dz_p(pa, 2, &point);
+               if (is_3d) sfcgal_triangle_set_vertex_from_xyz(triangle, 2, point.x, point.y, point.z);
+               else       sfcgal_triangle_set_vertex_from_xy (triangle, 2, point.x, point.y);
+
+               return triangle;
+       }
+       break;
+
+       /* Other SFCGAL types should not be called directly ... */
+       default:
+               lwerror("ptarray_from_SFCGAL: Unknown Type");
+               return NULL;
+       }
+}
+
+
+/*
+ * Convert a SFCGAL structure to PostGIS LWGEOM
+ *
+ * Throws an error on unsupported type
+ */
+LWGEOM*
+SFCGAL2LWGEOM(const sfcgal_geometry_t* geom, int force3D, int srid)
+{
+       uint32_t ngeoms, nshells;
+       uint32_t i, j, k;
+       int want3d;
+
+       assert(geom);
+
+       want3d = force3D || sfcgal_geometry_is_3d(geom);
+
+       switch (sfcgal_geometry_type_id(geom))
+       {
+       case SFCGAL_TYPE_POINT:
+       {
+               if (sfcgal_geometry_is_empty(geom))
+                       return (LWGEOM*) lwpoint_construct_empty(srid, want3d, 0);
+
+               POINTARRAY* pa = ptarray_from_SFCGAL(geom, want3d);
+               return (LWGEOM*) lwpoint_construct(srid, NULL, pa);
+       }
+
+       case SFCGAL_TYPE_LINESTRING:
+       {
+               if (sfcgal_geometry_is_empty(geom))
+                       return (LWGEOM*) lwline_construct_empty(srid, want3d, 0);
+
+               POINTARRAY* pa = ptarray_from_SFCGAL(geom, want3d);
+               return (LWGEOM*) lwline_construct(srid, NULL, pa);
+       }
+
+       case SFCGAL_TYPE_TRIANGLE:
+       {
+               if (sfcgal_geometry_is_empty(geom))
+                       return (LWGEOM*) lwtriangle_construct_empty(srid, want3d, 0);
+
+               POINTARRAY* pa = ptarray_from_SFCGAL(geom, want3d);
+               return (LWGEOM*) lwtriangle_construct(srid, NULL, pa);
+       }
+
+       case SFCGAL_TYPE_POLYGON:
+       {
+               if (sfcgal_geometry_is_empty(geom))
+                       return (LWGEOM*) lwpoly_construct_empty(srid, want3d, 0);
+
+               uint32_t nrings = sfcgal_polygon_num_interior_rings(geom) + 1;
+               POINTARRAY** pa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*) * nrings);
+
+               pa[0] = ptarray_from_SFCGAL(sfcgal_polygon_exterior_ring(geom), want3d);
+               for (i = 1; i < nrings; i++)
+                       pa[i] = ptarray_from_SFCGAL(sfcgal_polygon_interior_ring_n(geom, i-1), want3d);
+
+               return (LWGEOM*) lwpoly_construct(srid, NULL, nrings, pa);
+       }
+
+       case SFCGAL_TYPE_MULTIPOINT:
+       case SFCGAL_TYPE_MULTILINESTRING:
+       case SFCGAL_TYPE_MULTIPOLYGON:
+       case SFCGAL_TYPE_MULTISOLID:
+       case SFCGAL_TYPE_GEOMETRYCOLLECTION:
+       {
+               ngeoms = sfcgal_geometry_collection_num_geometries(geom);
+               LWGEOM** geoms = NULL;
+               if (ngeoms)
+               {
+                       geoms = (LWGEOM**) lwalloc(sizeof(LWGEOM*) * ngeoms);
+                       for (i = 0; i < ngeoms; i++)
+                       {
+                               const sfcgal_geometry_t* g = sfcgal_geometry_collection_geometry_n(geom, i);
+                               geoms[i] = SFCGAL2LWGEOM(g, 0, srid);
+                       }
+                       geoms = (LWGEOM**) lwrealloc(geoms, sizeof(LWGEOM*) * ngeoms);
+               }
+               return (LWGEOM*) lwcollection_construct(SFCGAL_type_to_lwgeom_type(
+                       sfcgal_geometry_type_id(geom)), srid, NULL, ngeoms, geoms);
+       }
+
+#if 0
+       case SFCGAL_TYPE_CIRCULARSTRING:
+       case SFCGAL_TYPE_COMPOUNDCURVE:
+       case SFCGAL_TYPE_CURVEPOLYGON:
+       case SFCGAL_TYPE_MULTICURVE:
+       case SFCGAL_TYPE_MULTISURFACE:
+       case SFCGAL_TYPE_CURVE:
+       case SFCGAL_TYPE_SURFACE:
+
+       /* TODO curve types handling */
+#endif
+
+       case SFCGAL_TYPE_POLYHEDRALSURFACE:
+       {
+               ngeoms = sfcgal_polyhedral_surface_num_polygons(geom);
+
+               LWGEOM** geoms = NULL;
+               if (ngeoms)
+               {
+                       geoms = (LWGEOM**) lwalloc(sizeof(LWGEOM*) * ngeoms);
+                       for (i = 0; i < ngeoms; i++)
+                       {
+                               const sfcgal_geometry_t* g = sfcgal_polyhedral_surface_polygon_n( geom, i );
+                               geoms[i] = SFCGAL2LWGEOM(g, 0, srid);
+                       }
+               }
+               return (LWGEOM*)lwcollection_construct(POLYHEDRALSURFACETYPE, srid, NULL, ngeoms, geoms);
+       }
+
+       /* Solid is map as a closed PolyhedralSurface (for now) */
+       case SFCGAL_TYPE_SOLID:
+       {
+               nshells = sfcgal_solid_num_shells(geom);
+
+               for (ngeoms = 0, i = 0; i < nshells; i++)
+                       ngeoms += sfcgal_polyhedral_surface_num_polygons(sfcgal_solid_shell_n(geom, i));
+
+               LWGEOM** geoms = 0;
+               if (ngeoms)
+               {
+                       geoms = (LWGEOM**) lwalloc( sizeof(LWGEOM*) * ngeoms);
+                       for (i = 0, k =0 ; i < nshells; i++)
+                       {
+                               const sfcgal_geometry_t* shell = sfcgal_solid_shell_n(geom, i);
+                               ngeoms = sfcgal_polyhedral_surface_num_polygons(shell);
+
+                               for (j = 0; j < ngeoms; j++)
+                               {
+                                       const sfcgal_geometry_t* g = sfcgal_polyhedral_surface_polygon_n(shell, j);
+                                       geoms[k] = SFCGAL2LWGEOM(g, 1, srid);
+                                       k++;
+                               }
+                       }
+               }
+               LWGEOM* rgeom =  (LWGEOM*) lwcollection_construct(POLYHEDRALSURFACETYPE, srid, NULL, ngeoms, geoms);
+               if (ngeoms) FLAGS_SET_SOLID( rgeom->flags, 1);
+               return rgeom;
+       }
+
+       case SFCGAL_TYPE_TRIANGULATEDSURFACE:
+       {
+               ngeoms = sfcgal_triangulated_surface_num_triangles(geom);
+               LWGEOM** geoms = NULL;
+               if (ngeoms)
+               {
+                       geoms = (LWGEOM**) lwalloc(sizeof(LWGEOM*) * ngeoms);
+                       for (i = 0; i < ngeoms; i++)
+                       {
+                               const sfcgal_geometry_t* g = sfcgal_triangulated_surface_triangle_n(geom, i);
+                               geoms[i] = SFCGAL2LWGEOM(g, 0, srid);
+                       }
+               }
+               return (LWGEOM*) lwcollection_construct(TINTYPE, srid, NULL, ngeoms, geoms);
+       }
+
+       default:
+               lwerror("SFCGAL2LWGEOM: Unknown Type");
+               return NULL;
+       }
+}
+
+
+sfcgal_geometry_t*
+LWGEOM2SFCGAL(const LWGEOM* geom)
+{
+       uint32_t i;
+       sfcgal_geometry_t* ret_geom = NULL;
+
+       assert(geom);
+
+       switch (geom->type)
+       {
+       case POINTTYPE:
+       {
+               const LWPOINT* lwp = (const LWPOINT*) geom;
+               if (lwgeom_is_empty(geom)) return sfcgal_point_create();
+
+               return ptarray_to_SFCGAL(lwp->point, POINTTYPE);
+       }
+       break;
+
+       case LINETYPE:
+       {
+               const LWLINE* line = (const LWLINE*) geom;
+               if (lwgeom_is_empty(geom)) return sfcgal_linestring_create();
+
+               return ptarray_to_SFCGAL(line->points, LINETYPE);
+       }
+       break;
+
+       case TRIANGLETYPE:
+       {
+               const LWTRIANGLE* triangle = (const LWTRIANGLE*) geom;
+               if (lwgeom_is_empty(geom)) return sfcgal_triangle_create();
+               return ptarray_to_SFCGAL(triangle->points, TRIANGLETYPE);
+       }
+       break;
+
+       case POLYGONTYPE:
+       {
+               const LWPOLY* poly = (const LWPOLY*) geom;
+               uint32_t nrings = poly->nrings - 1;
+
+               if (lwgeom_is_empty(geom)) return sfcgal_polygon_create();
+
+               sfcgal_geometry_t* exterior_ring = ptarray_to_SFCGAL(poly->rings[0], LINETYPE);
+               ret_geom = sfcgal_polygon_create_from_exterior_ring(exterior_ring);
+
+               for (i = 0; i < nrings; i++)
+               {
+                       sfcgal_geometry_t* ring = ptarray_to_SFCGAL(poly->rings[i + 1], LINETYPE);
+                       sfcgal_polygon_add_interior_ring(ret_geom, ring);
+               }
+               return ret_geom;
+       }
+       break;
+
+       case MULTIPOINTTYPE:
+       case MULTILINETYPE:
+       case MULTIPOLYGONTYPE:
+       case COLLECTIONTYPE:
+       {
+               if (geom->type == MULTIPOINTTYPE)        ret_geom = sfcgal_multi_point_create();
+               else if (geom->type == MULTILINETYPE)    ret_geom = sfcgal_multi_linestring_create();
+               else if (geom->type == MULTIPOLYGONTYPE) ret_geom = sfcgal_multi_polygon_create();
+               else                                     ret_geom = sfcgal_geometry_collection_create();
+
+               const LWCOLLECTION* lwc = (const LWCOLLECTION*)geom;
+               for (i = 0; i < lwc->ngeoms; i++)
+               {
+                       sfcgal_geometry_t* g = LWGEOM2SFCGAL(lwc->geoms[i]);
+                       sfcgal_geometry_collection_add_geometry(ret_geom, g);
+               }
+
+               return ret_geom;
+       }
+       break;
+
+       case POLYHEDRALSURFACETYPE:
+       {
+               const LWPSURFACE* lwp = (const LWPSURFACE*) geom;
+               ret_geom = sfcgal_polyhedral_surface_create();
+
+               for (i = 0; i < lwp->ngeoms; i++)
+               {
+                       sfcgal_geometry_t* g = LWGEOM2SFCGAL((const LWGEOM*) lwp->geoms[i]);
+                       sfcgal_polyhedral_surface_add_polygon(ret_geom, g);
+               }
+               /* We treat polyhedral surface as the only exterior shell,
+                  since we can't distinguish exterior from interior shells ... */
+               if (FLAGS_GET_SOLID(lwp->flags))
+               {
+                       return sfcgal_solid_create_from_exterior_shell(ret_geom);
+               }
+
+               return ret_geom;
+       }
+       break;
+
+       case TINTYPE:
+       {
+               const LWTIN* lwp = (const LWTIN*) geom;
+               ret_geom = sfcgal_triangulated_surface_create();
+
+               for (i = 0; i < lwp->ngeoms; i++)
+               {
+                       sfcgal_geometry_t* g = LWGEOM2SFCGAL((const LWGEOM*) lwp->geoms[i]);
+                       sfcgal_triangulated_surface_add_triangle(ret_geom, g);
+               }
+
+               return ret_geom;
+       }
+       break;
+
+       default:
+               lwerror("LWGEOM2SFCGAL: Unknown geometry type !");
+               return NULL;
+       }
+}
+
+
+/*
+ * No Operation SFCGAL function, used (only) for cunit tests
+ * Take a PostGIS geometry, send it to SFCGAL and return it unchanged (in theory)
+ */
+LWGEOM* lwgeom_sfcgal_noop(const LWGEOM* geom_in)
+{
+       sfcgal_geometry_t* converted;
+
+       assert(geom_in);
+
+       converted = LWGEOM2SFCGAL(geom_in);
+       assert(converted);
+
+       LWGEOM* geom_out = SFCGAL2LWGEOM(converted, 0, SRID_UNKNOWN);
+       sfcgal_geometry_delete(converted);
+
+       /* copy SRID (SFCGAL does not store the SRID) */
+       geom_out->srid = geom_in->srid;
+       return geom_out;
+}
diff --git a/liblwgeom/lwgeom_sfcgal.h b/liblwgeom/lwgeom_sfcgal.h
new file mode 100644 (file)
index 0000000..6316b69
--- /dev/null
@@ -0,0 +1,36 @@
+/**********************************************************************
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ *
+ * Wrapper around SFCGAL for 3D functions
+ *
+ * Copyright 2012-2013 Oslandia <infos@oslandia.com>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************/
+
+
+#include "liblwgeom.h"
+#include <SFCGAL/capi/sfcgal_c.h>
+
+
+/* return SFCGAL version string */
+const char*
+lwgeom_sfcgal_version();
+
+/* Convert SFCGAL structure to lwgeom PostGIS */
+LWGEOM*
+SFCGAL2LWGEOM(const sfcgal_geometry_t* geom, int force3D, int SRID);
+
+/* Convert lwgeom PostGIS to SFCGAL structure */
+sfcgal_geometry_t*
+LWGEOM2SFCGAL(const LWGEOM* geom);
+
+/* No Operation SFCGAL function, used (only) for cunit tests
+ * Take a PostGIS geometry, send it to SFCGAL and return it unchanged
+ */ 
+LWGEOM*
+lwgeom_sfcgal_noop(const LWGEOM* geom_in);
index c0976fd5be565ad06f4875a0a5c28f942bb5ad2a..da2487946023df4794fc212c1864f25a7d0f082f 100644 (file)
@@ -15,15 +15,30 @@ MODULE_big=postgis-@POSTGIS_MAJOR_VERSION@.@POSTGIS_MINOR_VERSION@
 MODULEDIR=contrib/$(MODULE_big)
 
 # Files to be copied to the contrib/ directory
-DATA_built=postgis.sql uninstall_postgis.sql postgis_upgrade_20_21.sql postgis_upgrade_21_minor.sql legacy.sql uninstall_legacy.sql legacy_minimal.sql legacy_gist.sql
+SQL_built=postgis.sql uninstall_postgis.sql postgis_upgrade_20_21.sql postgis_upgrade_21_minor.sql legacy.sql uninstall_legacy.sql legacy_minimal.sql legacy_gist.sql uninstall_sfcgal.sql
 DATA=../spatial_ref_sys.sql
 
+# SQL objects (files requiring pre-processing)
+SQL_objs=postgis.sql legacy.sql legacy_minimal.sql
+
+GEOM_BACKEND_OBJ = lwgeom_geos.o
+SFCGAL_BACKEND_OBJ = lwgeom_sfcgal.o
+
+ifeq (@SFCGAL@,sfcgal)
+DATA_built=$(SQL_built) sfcgal.sql
+SQL_OBJS=$(SQL_objs) sfcgal.sql
+BACKEND_OBJ=$(GEOM_BACKEND_OBJ) $(SFCGAL_BACKEND_OBJ)
+else
+BACKEND_OBJ=$(GEOM_BACKEND_OBJ)
+DATA_built=$(SQL_built)
+SQL_OBJS=$(SQL_objs)
+endif
+
+
+
 # SQL preprocessor
 SQLPP = @SQLPP@
 
-# SQL objects (files requiring pre-processing)
-SQL_OBJS=postgis.sql legacy.sql legacy_minimal.sql
-
 # PostgreSQL objects
 PG_OBJS= \
        postgis_module.o \
@@ -36,7 +51,8 @@ PG_OBJS= \
        lwgeom_btree.o \
        lwgeom_box.o \
        lwgeom_box3d.o \
-       lwgeom_geos.o \
+       $(BACKEND_OBJ) \
+       lwgeom_backend_api.o \
        lwgeom_geos_prepared.o \
        lwgeom_geos_clean.o \
        lwgeom_geos_relatematch.o \
@@ -73,13 +89,20 @@ OBJS=$(PG_OBJS)
 # to an existing liblwgeom.so in the PostgreSQL $libdir supplied by an
 # older version of PostGIS, rather than with the static liblwgeom.a 
 # supplied with newer versions of PostGIS
-PG_CPPFLAGS += @CPPFLAGS@ -I../liblwgeom -I../libpgcommon
-SHLIB_LINK_F = ../libpgcommon/libpgcommon.a ../liblwgeom/.libs/liblwgeom.a @SHLIB_LINK@ 
+PG_CPPFLAGS += @CPPFLAGS@ -I../liblwgeom -I../libpgcommon -fPIC
+SHLIB_LINK_F = ../libpgcommon/libpgcommon.a ../liblwgeom/.libs/liblwgeom.a @SHLIB_LINK@
+
+# Add SFCGAL Flags if defined
+ifeq (@SFCGAL@,sfcgal)
+PG_CPPFLAGS += @SFCGAL_CPPFLAGS@
+SHLIB_LINK_F += @SFCGAL_LDFLAGS@
+endif
 
 # Extra files to remove during 'make clean'
 EXTRA_CLEAN=$(SQL_OBJS) \
        uninstall_postgis.sql \
        uninstall_legacy.sql \
+       uninstall_sfcgal.sql \
        postgis_upgrade_20_21.sql.in \
        postgis_upgrade_20_21.sql \
        postgis_upgrade_21_minor.sql 
@@ -165,5 +188,8 @@ uninstall_postgis.sql: postgis.sql ../utils/create_undef.pl
 uninstall_legacy.sql: legacy.sql ../utils/create_undef.pl 
        $(PERL) ../utils/create_undef.pl $< $(POSTGIS_PGSQL_VERSION) > $@
 
+uninstall_sfcgal.sql: sfcgal.sql ../utils/create_undef.pl 
+       $(PERL) ../utils/create_undef.pl $< $(POSTGIS_PGSQL_VERSION) > $@
+
 distclean: clean
        rm -f Makefile
diff --git a/postgis/lwgeom_backend_api.c b/postgis/lwgeom_backend_api.c
new file mode 100644 (file)
index 0000000..cf4f716
--- /dev/null
@@ -0,0 +1,189 @@
+/**********************************************************************
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ *
+ * Wrapper around external librairies functions (GEOS/CGAL...)
+ *
+ * Copyright 2012-2013 Oslandia <infos@oslandia.com>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************/
+
+#include "postgres.h"
+#include "fmgr.h"
+#include "../liblwgeom/liblwgeom.h"
+
+/* for custom variables */
+#include "utils/guc.h"
+
+#include "../postgis_config.h"
+#include "lwgeom_backend_api.h"
+#include "lwgeom_geos.h"
+#include "lwgeom_sfcgal.h"
+
+Datum intersects(PG_FUNCTION_ARGS);
+Datum intersects3d(PG_FUNCTION_ARGS);
+Datum intersection(PG_FUNCTION_ARGS);
+Datum area(PG_FUNCTION_ARGS);
+Datum distance(PG_FUNCTION_ARGS);
+Datum distance3d(PG_FUNCTION_ARGS);
+
+Datum intersects3d_dwithin(PG_FUNCTION_ARGS);
+Datum postgis_sfcgal_version(PG_FUNCTION_ARGS);
+
+
+struct lwgeom_backend_definition
+{
+    const char* name;
+    Datum (*intersects_fn)    (PG_FUNCTION_ARGS);
+    Datum (*intersects3d_fn)  (PG_FUNCTION_ARGS);
+    Datum (*intersection_fn)  (PG_FUNCTION_ARGS);
+    Datum (*area_fn)          (PG_FUNCTION_ARGS);
+    Datum (*distance_fn)      (PG_FUNCTION_ARGS);
+    Datum (*distance3d_fn)    (PG_FUNCTION_ARGS);
+};
+
+#if HAVE_SFCGAL
+#define LWGEOM_NUM_BACKENDS   2
+#else
+#define LWGEOM_NUM_BACKENDS   1
+#endif
+
+struct lwgeom_backend_definition lwgeom_backends[LWGEOM_NUM_BACKENDS] = {
+    { .name = "geos",
+      .intersects_fn    = geos_intersects,
+      .intersects3d_fn  = intersects3d_dwithin,
+      .intersection_fn  = geos_intersection,
+      .area_fn          = LWGEOM_area_polygon,
+      .distance_fn      = LWGEOM_mindistance2d,
+      .distance3d_fn    = LWGEOM_mindistance3d
+    },
+#if HAVE_SFCGAL
+    { .name = "sfcgal",
+      .intersects_fn    = sfcgal_intersects,
+      .intersects3d_fn  = sfcgal_intersects3D,
+      .intersection_fn  = sfcgal_intersection,
+      .area_fn          = sfcgal_area,
+      .distance_fn      = sfcgal_distance,
+      .distance3d_fn    = sfcgal_distance3D
+    }
+#endif
+};
+
+
+/* Geometry Backend */
+char* lwgeom_backend_name;
+struct lwgeom_backend_definition* lwgeom_backend = &lwgeom_backends[0];
+
+void lwgeom_backend_switch( const char* newvalue, void* extra )
+{
+    int i;
+
+    if (!newvalue) { return; }
+
+    for ( i = 0; i < LWGEOM_NUM_BACKENDS; ++i ) {
+       if ( !strcmp(lwgeom_backends[i].name, newvalue) ) {
+           lwgeom_backend = &lwgeom_backends[i];
+           return;
+       }
+    }
+    lwerror("Can't find %s geometry backend", newvalue );
+}
+
+void lwgeom_init_backend()
+{
+    DefineCustomStringVariable( "postgis.backend", /* name */
+                               "Sets the PostGIS Geometry Backend.", /* short_desc */
+                               "Sets the PostGIS Geometry Backend (allowed values are 'geos' or 'sfcgal')", /* long_desc */
+                               &lwgeom_backend_name, /* valueAddr */
+                               (char *)lwgeom_backends[0].name, /* bootValue */
+                               PGC_USERSET, /* GucContext context */
+                               0, /* int flags */
+#if POSTGIS_PGSQL_VERSION >= 91
+                               NULL, /* GucStringCheckHook check_hook */
+#endif
+                               lwgeom_backend_switch, /* GucStringAssignHook assign_hook */
+                               NULL  /* GucShowHook show_hook */
+                               );
+}
+
+PG_FUNCTION_INFO_V1(intersects);
+Datum intersects(PG_FUNCTION_ARGS)
+{
+    return (*lwgeom_backend->intersects_fn)( fcinfo );
+}
+
+PG_FUNCTION_INFO_V1(intersection);
+Datum intersection(PG_FUNCTION_ARGS)
+{
+    return (*lwgeom_backend->intersection_fn)( fcinfo );
+}
+
+PG_FUNCTION_INFO_V1(area);
+Datum area(PG_FUNCTION_ARGS)
+{
+    return (*lwgeom_backend->area_fn)( fcinfo );
+}
+
+PG_FUNCTION_INFO_V1(distance);
+Datum distance(PG_FUNCTION_ARGS)
+{
+    return (*lwgeom_backend->distance_fn)( fcinfo );
+}
+
+PG_FUNCTION_INFO_V1(distance3d);
+Datum distance3d(PG_FUNCTION_ARGS)
+{
+    return (*lwgeom_backend->distance3d_fn)( fcinfo );
+}
+
+PG_FUNCTION_INFO_V1(intersects3d);
+Datum intersects3d(PG_FUNCTION_ARGS)
+{
+    return (*lwgeom_backend->intersects3d_fn)( fcinfo );
+}
+
+
+
+/* intersects3d through dwithin
+ * used by the 'geos' backend
+ */
+PG_FUNCTION_INFO_V1(intersects3d_dwithin);
+Datum intersects3d_dwithin(PG_FUNCTION_ARGS)
+{
+    double mindist;
+    GSERIALIZED *geom1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+    GSERIALIZED *geom2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+    LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
+    LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
+
+    if (lwgeom1->srid != lwgeom2->srid)
+    {
+       elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
+       PG_RETURN_NULL();
+    }
+    
+    mindist = lwgeom_mindistance3d_tolerance(lwgeom1,lwgeom2,0.0);
+    
+    PG_FREE_IF_COPY(geom1, 0);
+    PG_FREE_IF_COPY(geom2, 1);
+    /*empty geometries cases should be right handled since return from underlying
+      functions should be MAXFLOAT which causes false as answer*/
+    PG_RETURN_BOOL(0.0 == mindist);
+}
+
+
+PG_FUNCTION_INFO_V1(postgis_sfcgal_version);
+Datum postgis_sfcgal_version(PG_FUNCTION_ARGS)
+{
+#if HAVE_SFCGAL
+        const char *ver = lwgeom_sfcgal_version();
+        text *result = cstring2text(ver);
+#else 
+       text *result = NULL;
+#endif
+        PG_RETURN_POINTER(result);
+}
diff --git a/postgis/lwgeom_backend_api.h b/postgis/lwgeom_backend_api.h
new file mode 100644 (file)
index 0000000..3ce7719
--- /dev/null
@@ -0,0 +1,19 @@
+/**********************************************************************
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ *
+ * Wrapper around external librairies functions (GEOS/CGAL...)
+ *
+ * Copyright 2012-2013 Oslandia <infos@oslandia.com>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************/
+#ifndef LWGEOM_BACKEND_API_H_
+#define LWGEOM_BACKEND_API_H_ 1
+
+void lwgeom_init_backend(void);
+
+#endif
index a74a453a235f3531a087e59008390662b88c6f1d..a2f4a636d8485e9322f5d1933fcead323ce1c779 100644 (file)
@@ -69,6 +69,7 @@ Datum LWGEOM_isempty(PG_FUNCTION_ARGS);
 Datum LWGEOM_segmentize2d(PG_FUNCTION_ARGS);
 Datum LWGEOM_reverse(PG_FUNCTION_ARGS);
 Datum LWGEOM_force_clockwise_poly(PG_FUNCTION_ARGS);
+Datum LWGEOM_force_sfs(PG_FUNCTION_ARGS);
 Datum LWGEOM_noop(PG_FUNCTION_ARGS);
 Datum LWGEOM_zmflag(PG_FUNCTION_ARGS);
 Datum LWGEOM_hasz(PG_FUNCTION_ARGS);
@@ -508,6 +509,27 @@ Datum LWGEOM_force_multi(PG_FUNCTION_ARGS)
        PG_RETURN_POINTER(result);
 }
 
+/** transform input geometry to a SFS 1.1 geometry type compliant */
+PG_FUNCTION_INFO_V1(LWGEOM_force_sfs);
+Datum LWGEOM_force_sfs(PG_FUNCTION_ARGS)
+{
+       GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       GSERIALIZED *result;
+       LWGEOM *lwgeom;
+       LWGEOM *ogeom;
+
+       POSTGIS_DEBUG(2, "LWGEOM_force_sfs called");
+
+       lwgeom = lwgeom_from_gserialized(geom);
+       ogeom = lwgeom_force_sfs(lwgeom);
+
+       result = geometry_serialize(ogeom);
+
+       PG_FREE_IF_COPY(geom, 0);
+
+       PG_RETURN_POINTER(result);
+}
+
 /**
 Returns the point in first input geometry that is closest to the second input geometry in 2d
 */
index f342385f37802e5a1762d261287d514c6f790e61..474248fc6e3055d43286b832862c8b7b8b1ec6b2 100644 (file)
@@ -41,7 +41,7 @@ Datum relate_full(PG_FUNCTION_ARGS);
 Datum relate_pattern(PG_FUNCTION_ARGS);
 Datum disjoint(PG_FUNCTION_ARGS);
 Datum touches(PG_FUNCTION_ARGS);
-Datum intersects(PG_FUNCTION_ARGS);
+Datum geos_intersects(PG_FUNCTION_ARGS);
 Datum crosses(PG_FUNCTION_ARGS);
 Datum contains(PG_FUNCTION_ARGS);
 Datum containsproperly(PG_FUNCTION_ARGS);
@@ -51,7 +51,7 @@ Datum isvalid(PG_FUNCTION_ARGS);
 Datum isvalidreason(PG_FUNCTION_ARGS);
 Datum isvaliddetail(PG_FUNCTION_ARGS);
 Datum buffer(PG_FUNCTION_ARGS);
-Datum intersection(PG_FUNCTION_ARGS);
+Datum geos_intersection(PG_FUNCTION_ARGS);
 Datum convexhull(PG_FUNCTION_ARGS);
 Datum topologypreservesimplify(PG_FUNCTION_ARGS);
 Datum difference(PG_FUNCTION_ARGS);
@@ -1443,8 +1443,8 @@ Datum ST_OffsetCurve(PG_FUNCTION_ARGS)
 }
 
 
-PG_FUNCTION_INFO_V1(intersection);
-Datum intersection(PG_FUNCTION_ARGS)
+PG_FUNCTION_INFO_V1(geos_intersection);
+Datum geos_intersection(PG_FUNCTION_ARGS)
 {
        GSERIALIZED *geom1;
        GSERIALIZED *geom2;
@@ -2554,8 +2554,8 @@ Datum crosses(PG_FUNCTION_ARGS)
 }
 
 
-PG_FUNCTION_INFO_V1(intersects);
-Datum intersects(PG_FUNCTION_ARGS)
+PG_FUNCTION_INFO_V1(geos_intersects);
+Datum geos_intersects(PG_FUNCTION_ARGS)
 {
        GSERIALIZED *geom1;
        GSERIALIZED *geom2;
index c59135f6ab659a4ab197c5dd3b134ef5a4f71321..87487d94d4f005c987da113f28acfbc2e14139f2 100644 (file)
 GSERIALIZED *GEOS2POSTGIS(GEOSGeom geom, char want3d);
 GEOSGeometry * POSTGIS2GEOS(GSERIALIZED *g);
 
+Datum geos_intersects(PG_FUNCTION_ARGS);
+Datum geos_intersection(PG_FUNCTION_ARGS);
+Datum LWGEOM_area_polygon(PG_FUNCTION_ARGS);
+Datum LWGEOM_mindistance2d(PG_FUNCTION_ARGS);
+Datum LWGEOM_mindistance3d(PG_FUNCTION_ARGS);
 
 void errorIfGeometryCollection(GSERIALIZED *g1, GSERIALIZED *g2);
 
diff --git a/postgis/lwgeom_sfcgal.c b/postgis/lwgeom_sfcgal.c
new file mode 100644 (file)
index 0000000..38e86e0
--- /dev/null
@@ -0,0 +1,531 @@
+/**********************************************************************
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ *
+ * Wrapper around SFCGAL for 3D functions
+ *
+ * Copyright 2012-2013 Oslandia <infos@oslandia.com>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************/
+
+#include "postgres.h"
+#include "fmgr.h"
+#include "../liblwgeom/liblwgeom.h"
+
+#include "lwgeom_sfcgal.h"
+
+
+
+Datum sfcgal_from_ewkt(PG_FUNCTION_ARGS);
+Datum sfcgal_distance(PG_FUNCTION_ARGS);
+Datum sfcgal_distance3D(PG_FUNCTION_ARGS);
+Datum sfcgal_area(PG_FUNCTION_ARGS);
+Datum sfcgal_area3D(PG_FUNCTION_ARGS);
+Datum sfcgal_intersects(PG_FUNCTION_ARGS);
+Datum sfcgal_intersects3D(PG_FUNCTION_ARGS);
+Datum sfcgal_intersection(PG_FUNCTION_ARGS);
+Datum sfcgal_intersection3D(PG_FUNCTION_ARGS);
+Datum sfcgal_extrude(PG_FUNCTION_ARGS);
+Datum sfcgal_straight_skeleton(PG_FUNCTION_ARGS);
+Datum sfcgal_is_planar(PG_FUNCTION_ARGS);
+Datum sfcgal_orientation(PG_FUNCTION_ARGS);
+Datum sfcgal_force_lhr(PG_FUNCTION_ARGS);
+Datum sfcgal_triangulate(PG_FUNCTION_ARGS);
+Datum sfcgal_tesselate(PG_FUNCTION_ARGS);
+Datum sfcgal_minkowski_sum(PG_FUNCTION_ARGS);
+
+
+GSERIALIZED *geometry_serialize(LWGEOM *lwgeom);
+char* text2cstring(const text *textptr);
+
+static int __sfcgal_init = 0;
+
+void sfcgal_postgis_init(void)
+{
+    if ( ! __sfcgal_init ) {
+       sfcgal_init();
+       sfcgal_set_error_handlers((sfcgal_error_handler_t) lwnotice, (sfcgal_error_handler_t) lwerror);
+       sfcgal_set_alloc_handlers(lwalloc, lwfree);
+       __sfcgal_init = 1;
+    }
+}
+
+
+/* Conversion from GSERIALIZED* to SFCGAL::Geometry */
+sfcgal_geometry_t* POSTGIS2SFCGALGeometry(GSERIALIZED *pglwgeom)
+{
+       sfcgal_geometry_t* g;
+       LWGEOM *lwgeom = lwgeom_from_gserialized(pglwgeom);
+
+       if (! lwgeom)
+       {
+               lwerror("POSTGIS2SFCGALGeometry: Unable to deserialize input");
+       }
+       g = LWGEOM2SFCGAL(lwgeom);
+       lwgeom_free(lwgeom);
+
+       return g;
+}
+
+
+/* Conversion from GSERIALIZED* to SFCGAL::PreparedGeometry */
+sfcgal_prepared_geometry_t* POSTGIS2SFCGALPreparedGeometry(GSERIALIZED *pglwgeom)
+{
+       sfcgal_geometry_t* g;
+       LWGEOM *lwgeom = lwgeom_from_gserialized(pglwgeom);
+
+       if (!lwgeom)
+       {
+               lwerror("POSTGIS2SFCGALPreparedGeometry: Unable to deserialize input");
+       }
+       g = LWGEOM2SFCGAL(lwgeom);
+
+       lwgeom_free(lwgeom);
+
+       return sfcgal_prepared_geometry_create_from_geometry(g, gserialized_get_srid(pglwgeom));
+}
+
+
+/* Conversion from SFCGAL::Geometry to GSERIALIZED */
+GSERIALIZED* SFCGALGeometry2POSTGIS(const sfcgal_geometry_t* geom, int force3D, int SRID)
+{
+       GSERIALIZED *result;
+       LWGEOM* lwgeom = SFCGAL2LWGEOM(geom, force3D, SRID);
+
+       if (lwgeom_needs_bbox(lwgeom) == LW_TRUE)
+               lwgeom_add_bbox(lwgeom);
+
+       result = geometry_serialize(lwgeom);
+       lwgeom_free(lwgeom);
+
+       return result;
+}
+
+
+/* Conversion from SFCGAL::PreparedGeometry to GSERIALIZED */
+GSERIALIZED* SFCGALPreparedGeometry2POSTGIS(const sfcgal_prepared_geometry_t* geom, int force3D)
+{
+    return SFCGALGeometry2POSTGIS(sfcgal_prepared_geometry_geometry(geom),
+               force3D, sfcgal_prepared_geometry_srid(geom));
+}
+
+
+/* Conversion from EWKT to GSERIALIZED */
+PG_FUNCTION_INFO_V1(sfcgal_from_ewkt);
+Datum sfcgal_from_ewkt(PG_FUNCTION_ARGS)
+{
+       GSERIALIZED* result;
+       sfcgal_prepared_geometry_t* g;
+       text *wkttext = PG_GETARG_TEXT_P(0);
+       char *cstring = text2cstring(wkttext);
+
+       sfcgal_postgis_init();
+
+       g = sfcgal_io_read_ewkt( cstring, strlen(cstring) );
+
+       result = SFCGALPreparedGeometry2POSTGIS( g, 0 );
+       sfcgal_prepared_geometry_delete( g );
+       PG_RETURN_POINTER(result);
+}
+
+
+PG_FUNCTION_INFO_V1(sfcgal_area);
+Datum sfcgal_area(PG_FUNCTION_ARGS)
+    {
+       GSERIALIZED *input;
+       sfcgal_geometry_t *geom;
+       double result;
+
+       sfcgal_postgis_init();
+
+       input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       geom = POSTGIS2SFCGALGeometry(input);
+
+       result = sfcgal_geometry_area(geom);
+       sfcgal_geometry_delete(geom);
+
+       PG_FREE_IF_COPY(input, 0);
+
+       PG_RETURN_FLOAT8(result);
+}
+
+
+PG_FUNCTION_INFO_V1(sfcgal_area3D);
+Datum sfcgal_area3D(PG_FUNCTION_ARGS)
+    {
+       GSERIALIZED *input;
+       sfcgal_geometry_t *geom;
+       double result;
+
+       sfcgal_postgis_init();
+
+       input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       geom = POSTGIS2SFCGALGeometry(input);
+
+       result = sfcgal_geometry_area_3d(geom);
+       sfcgal_geometry_delete(geom);
+
+       PG_FREE_IF_COPY(input, 0);
+
+       PG_RETURN_FLOAT8(result);
+}
+
+
+PG_FUNCTION_INFO_V1(sfcgal_is_planar);
+Datum sfcgal_is_planar(PG_FUNCTION_ARGS)
+{
+       GSERIALIZED *input;
+       sfcgal_geometry_t *geom;
+       int result;
+
+       sfcgal_postgis_init();
+
+       input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       geom = POSTGIS2SFCGALGeometry(input);
+
+       result = sfcgal_geometry_is_planar(geom);
+       sfcgal_geometry_delete(geom);
+
+       PG_FREE_IF_COPY(input, 0);
+
+       PG_RETURN_BOOL(result);
+}
+
+
+PG_FUNCTION_INFO_V1(sfcgal_orientation);
+Datum sfcgal_orientation(PG_FUNCTION_ARGS)
+{
+       GSERIALIZED *input;
+       sfcgal_geometry_t *geom;
+       int result;
+
+       sfcgal_postgis_init();
+
+       input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       geom = POSTGIS2SFCGALGeometry(input);
+
+       result = sfcgal_geometry_orientation(geom);
+       sfcgal_geometry_delete(geom);
+
+       PG_FREE_IF_COPY(input, 0);
+
+       PG_RETURN_INT32(result);
+}
+
+
+PG_FUNCTION_INFO_V1(sfcgal_intersects);
+Datum sfcgal_intersects(PG_FUNCTION_ARGS)
+{
+       GSERIALIZED *input0, *input1;
+       sfcgal_geometry_t *geom0, *geom1;
+       int result;
+
+       sfcgal_postgis_init();
+
+       input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+       geom0 = POSTGIS2SFCGALGeometry(input0);
+       PG_FREE_IF_COPY(input0, 0);
+       geom1 = POSTGIS2SFCGALGeometry(input1);
+       PG_FREE_IF_COPY(input1, 1);
+
+       result = sfcgal_geometry_intersects(geom0, geom1);
+       sfcgal_geometry_delete(geom0);
+       sfcgal_geometry_delete(geom1);
+
+       PG_RETURN_BOOL(result);
+}
+
+
+PG_FUNCTION_INFO_V1(sfcgal_intersects3D);
+Datum sfcgal_intersects3D(PG_FUNCTION_ARGS)
+{
+       GSERIALIZED *input0, *input1;
+       sfcgal_geometry_t *geom0, *geom1;
+       int result;
+
+       sfcgal_postgis_init();
+
+       input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+       geom0 = POSTGIS2SFCGALGeometry(input0);
+       PG_FREE_IF_COPY(input0, 0);
+       geom1 = POSTGIS2SFCGALGeometry(input1);
+       PG_FREE_IF_COPY(input1, 1);
+
+       result = sfcgal_geometry_intersects_3d(geom0, geom1);
+       sfcgal_geometry_delete(geom0);
+       sfcgal_geometry_delete(geom1);
+
+       PG_RETURN_BOOL(result);
+}
+
+
+PG_FUNCTION_INFO_V1(sfcgal_distance);
+Datum sfcgal_distance(PG_FUNCTION_ARGS)
+{
+       GSERIALIZED *input0, *input1;
+       sfcgal_geometry_t *geom0, *geom1;
+       double result;
+
+       sfcgal_postgis_init();
+
+       input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+       geom0 = POSTGIS2SFCGALGeometry(input0);
+       PG_FREE_IF_COPY(input0, 0);
+       geom1 = POSTGIS2SFCGALGeometry(input1);
+       PG_FREE_IF_COPY(input1, 1);
+
+       result = sfcgal_geometry_distance(geom0, geom1);
+       sfcgal_geometry_delete(geom0);
+       sfcgal_geometry_delete(geom1);
+
+       PG_RETURN_FLOAT8(result);
+}
+
+
+PG_FUNCTION_INFO_V1(sfcgal_distance3D);
+Datum sfcgal_distance3D(PG_FUNCTION_ARGS)
+{
+       GSERIALIZED *input0, *input1;
+       sfcgal_geometry_t *geom0, *geom1;
+       double result;
+
+       sfcgal_postgis_init();
+
+       input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+       geom0 = POSTGIS2SFCGALGeometry(input0);
+       PG_FREE_IF_COPY(input0, 0);
+       geom1 = POSTGIS2SFCGALGeometry(input1);
+       PG_FREE_IF_COPY(input1, 1);
+
+       result = sfcgal_geometry_distance_3d(geom0, geom1);
+       sfcgal_geometry_delete(geom0);
+       sfcgal_geometry_delete(geom1);
+
+       PG_RETURN_FLOAT8(result);
+}
+
+
+PG_FUNCTION_INFO_V1(sfcgal_tesselate); 
+Datum sfcgal_tesselate(PG_FUNCTION_ARGS)
+{
+       GSERIALIZED *input, *output;
+       sfcgal_geometry_t *geom;
+       sfcgal_geometry_t *result;
+       srid_t srid;
+
+       sfcgal_postgis_init();
+
+       input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       srid = gserialized_get_srid(input);
+       geom = POSTGIS2SFCGALGeometry(input);
+       PG_FREE_IF_COPY(input, 0);
+
+       result = sfcgal_geometry_tesselate(geom);
+       sfcgal_geometry_delete(geom);
+
+       output = SFCGALGeometry2POSTGIS(result, 0, srid);
+       sfcgal_geometry_delete(result);
+
+       PG_RETURN_POINTER(output);
+}
+
+
+PG_FUNCTION_INFO_V1(sfcgal_triangulate);       
+Datum sfcgal_triangulate(PG_FUNCTION_ARGS)
+{
+       GSERIALIZED *input, *output;
+       sfcgal_geometry_t *geom;
+       sfcgal_geometry_t *result;
+       srid_t srid;
+
+       sfcgal_postgis_init();
+
+       input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       srid = gserialized_get_srid(input);
+       geom = POSTGIS2SFCGALGeometry(input);
+       PG_FREE_IF_COPY(input, 0);
+
+       result = sfcgal_geometry_triangulate_2dz(geom);
+       sfcgal_geometry_delete(geom);
+
+       output = SFCGALGeometry2POSTGIS(result, 0, srid);
+       sfcgal_geometry_delete(result);
+
+       PG_RETURN_POINTER(output);
+}
+
+
+PG_FUNCTION_INFO_V1(sfcgal_force_lhr); 
+Datum sfcgal_force_lhr(PG_FUNCTION_ARGS)
+{
+       GSERIALIZED *input, *output;
+       sfcgal_geometry_t *geom;
+       sfcgal_geometry_t *result;
+       srid_t srid;
+
+       sfcgal_postgis_init();
+
+       input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       srid = gserialized_get_srid(input);
+       geom = POSTGIS2SFCGALGeometry(input);
+       PG_FREE_IF_COPY(input, 0);
+
+       result = sfcgal_geometry_force_lhr(geom);
+       sfcgal_geometry_delete(geom);
+
+       output = SFCGALGeometry2POSTGIS(result, 0, srid);
+       sfcgal_geometry_delete(result);
+
+       PG_RETURN_POINTER(output);
+}
+
+
+PG_FUNCTION_INFO_V1(sfcgal_straight_skeleton); 
+Datum sfcgal_straight_skeleton(PG_FUNCTION_ARGS)
+{
+       GSERIALIZED *input, *output;
+       sfcgal_geometry_t *geom;
+       sfcgal_geometry_t *result;
+       srid_t srid;
+
+       sfcgal_postgis_init();
+
+       input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       srid = gserialized_get_srid(input);
+       geom = POSTGIS2SFCGALGeometry(input);
+       PG_FREE_IF_COPY(input, 0);
+
+       result = sfcgal_geometry_straight_skeleton(geom);
+       sfcgal_geometry_delete(geom);
+
+       output = SFCGALGeometry2POSTGIS(result, 0, srid);
+       sfcgal_geometry_delete(result);
+
+       PG_RETURN_POINTER(output);
+}
+
+
+PG_FUNCTION_INFO_V1(sfcgal_intersection);      
+Datum sfcgal_intersection(PG_FUNCTION_ARGS)
+{
+       GSERIALIZED *input0, *input1, *output;
+       sfcgal_geometry_t *geom0, *geom1;
+       sfcgal_geometry_t *result;
+       srid_t srid;
+
+       sfcgal_postgis_init();
+
+       input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       srid = gserialized_get_srid(input0);
+       input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+       geom0 = POSTGIS2SFCGALGeometry(input0);
+       PG_FREE_IF_COPY(input0, 0);
+       geom1 = POSTGIS2SFCGALGeometry(input1);
+       PG_FREE_IF_COPY(input1, 1);
+
+       result = sfcgal_geometry_intersection(geom0, geom1);
+       sfcgal_geometry_delete(geom0);
+       sfcgal_geometry_delete(geom1);
+
+       output = SFCGALGeometry2POSTGIS(result, 0, srid);
+       sfcgal_geometry_delete(result);
+
+       PG_RETURN_POINTER(output);
+}
+
+
+PG_FUNCTION_INFO_V1(sfcgal_intersection3D);    
+Datum sfcgal_intersection3D(PG_FUNCTION_ARGS)
+{
+       GSERIALIZED *input0, *input1, *output;
+       sfcgal_geometry_t *geom0, *geom1;
+       sfcgal_geometry_t *result;
+       srid_t srid;
+
+       sfcgal_postgis_init();
+
+       input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       srid = gserialized_get_srid(input0);
+       input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+       geom0 = POSTGIS2SFCGALGeometry(input0);
+       PG_FREE_IF_COPY(input0, 0);
+       geom1 = POSTGIS2SFCGALGeometry(input1);
+       PG_FREE_IF_COPY(input1, 1);
+
+       result = sfcgal_geometry_intersection_3d(geom0, geom1);
+       sfcgal_geometry_delete(geom0);
+       sfcgal_geometry_delete(geom1);
+
+       output = SFCGALGeometry2POSTGIS(result, 0, srid);
+       sfcgal_geometry_delete(result);
+
+       PG_RETURN_POINTER(output);
+}
+
+
+PG_FUNCTION_INFO_V1(sfcgal_minkowski_sum);     
+Datum sfcgal_minkowski_sum(PG_FUNCTION_ARGS)
+{
+       GSERIALIZED *input0, *input1, *output;
+       sfcgal_geometry_t *geom0, *geom1;
+       sfcgal_geometry_t *result;
+       srid_t srid;
+
+       sfcgal_postgis_init();
+
+       input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       srid = gserialized_get_srid(input0);
+       input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+       geom0 = POSTGIS2SFCGALGeometry(input0);
+       PG_FREE_IF_COPY(input0, 0);
+       geom1 = POSTGIS2SFCGALGeometry(input1);
+       PG_FREE_IF_COPY(input1, 1);
+
+       result = sfcgal_geometry_minkowski_sum(geom0, geom1);
+       sfcgal_geometry_delete(geom0);
+       sfcgal_geometry_delete(geom1);
+
+       output = SFCGALGeometry2POSTGIS(result, 0, srid);
+       sfcgal_geometry_delete(result);
+
+       PG_RETURN_POINTER(output);
+}
+
+
+PG_FUNCTION_INFO_V1(sfcgal_extrude);
+Datum sfcgal_extrude(PG_FUNCTION_ARGS)
+{
+    GSERIALIZED *input, *output;
+    sfcgal_geometry_t *geom;
+    sfcgal_geometry_t *result;
+    double dx, dy, dz;
+    srid_t srid;
+
+    sfcgal_postgis_init();
+    
+    input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+    srid = gserialized_get_srid(input);
+
+    geom = POSTGIS2SFCGALGeometry(input);
+    PG_FREE_IF_COPY(input, 0);
+    
+    dx = PG_GETARG_FLOAT8(1);
+    dy = PG_GETARG_FLOAT8(2);
+    dz = PG_GETARG_FLOAT8(3);
+    
+    result = sfcgal_geometry_extrude(geom, dx, dy, dz);
+    sfcgal_geometry_delete(geom);
+    
+    output = SFCGALGeometry2POSTGIS(result, 0, srid);
+    sfcgal_geometry_delete(result);
+    
+    PG_RETURN_POINTER(output);
+}
diff --git a/postgis/lwgeom_sfcgal.h b/postgis/lwgeom_sfcgal.h
new file mode 100644 (file)
index 0000000..6f1e3bb
--- /dev/null
@@ -0,0 +1,39 @@
+/**********************************************************************
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ *
+ * Wrapper around SFCGAL for 3D functions
+ *
+ * Copyright 2012-2013 Oslandia <infos@oslandia.com>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************/
+
+#include "../liblwgeom/lwgeom_sfcgal.h"
+
+/* Conversion from GSERIALIZED* to SFCGAL::Geometry */
+sfcgal_geometry_t* POSTGIS2SFCGALGeometry(GSERIALIZED *pglwgeom);
+
+/* Conversion from GSERIALIZED* to SFCGAL::PreparedGeometry */
+sfcgal_prepared_geometry_t* POSTGIS2SFCGALPreparedGeometry(GSERIALIZED *pglwgeom);
+
+/* Conversion from SFCGAL::Geometry to GSERIALIZED */
+GSERIALIZED* SFCGALGeometry2POSTGIS( const sfcgal_geometry_t* geom, int force3D, int SRID );
+
+/* Conversion from SFCGAL::PreparedGeometry to GSERIALIZED */
+GSERIALIZED* SFCGALPreparedGeometry2POSTGIS( const sfcgal_prepared_geometry_t* geom, int force3D );
+
+Datum sfcgal_intersects(PG_FUNCTION_ARGS);
+Datum sfcgal_intersects3D(PG_FUNCTION_ARGS);
+Datum sfcgal_intersection(PG_FUNCTION_ARGS);
+Datum sfcgal_triangulate(PG_FUNCTION_ARGS);
+Datum sfcgal_area(PG_FUNCTION_ARGS);
+Datum sfcgal_distance(PG_FUNCTION_ARGS);
+Datum sfcgal_distance3D(PG_FUNCTION_ARGS);
+
+
+/* Initialize sfcgal with PostGIS error handlers */
+void sfcgal_postgis_init(void);
index 1f7374d10e044a03b37f71eeb71ab7d46e6f556f..f2f6626229b7ea4b9aed6ef77d13b922257feee4 100644 (file)
@@ -1134,7 +1134,7 @@ CREATE OR REPLACE FUNCTION ST_area2d(geometry)
 -- PostGIS equivalent function: area(geometry)
 CREATE OR REPLACE FUNCTION ST_Area(geometry)
        RETURNS FLOAT8
-       AS 'MODULE_PATHNAME','LWGEOM_area_polygon'
+       AS 'MODULE_PATHNAME','area'
        LANGUAGE 'c' IMMUTABLE STRICT;
 
 -- Availability: 1.2.2
@@ -1149,7 +1149,7 @@ CREATE OR REPLACE FUNCTION ST_distance_spheroid(geom1 geometry, geom2 geometry,s
 -- PostGIS equivalent function: distance(geom1 geometry, geom2 geometry)
 CREATE OR REPLACE FUNCTION ST_Distance(geom1 geometry, geom2 geometry)
        RETURNS float8
-       AS 'MODULE_PATHNAME', 'LWGEOM_mindistance2d'
+       AS 'MODULE_PATHNAME', 'distance'
        LANGUAGE 'c' IMMUTABLE STRICT
        COST 100;
 
@@ -1223,6 +1223,12 @@ CREATE OR REPLACE FUNCTION ST_Multi(geometry)
        AS 'MODULE_PATHNAME', 'LWGEOM_force_multi'
        LANGUAGE 'c' IMMUTABLE STRICT;
 
+-- Availability: 2.1.0
+CREATE OR REPLACE FUNCTION ST_force_sfs(geometry)
+       RETURNS geometry
+       AS 'MODULE_PATHNAME', 'LWGEOM_force_sfs'
+       LANGUAGE 'c' IMMUTABLE STRICT;
+
 -- Availability: 1.2.2
 CREATE OR REPLACE FUNCTION ST_Expand(box3d,float8)
        RETURNS box3d
@@ -2437,6 +2443,10 @@ CREATE OR REPLACE FUNCTION postgis_geos_version() RETURNS text
        AS 'MODULE_PATHNAME'
        LANGUAGE 'c' IMMUTABLE;
 
+CREATE OR REPLACE FUNCTION postgis_sfcgal_version() RETURNS text
+       AS 'MODULE_PATHNAME'
+       LANGUAGE 'c' IMMUTABLE;
+
 CREATE OR REPLACE FUNCTION postgis_svn_version() RETURNS text
        AS 'MODULE_PATHNAME'
        LANGUAGE 'c' IMMUTABLE;
@@ -2460,6 +2470,8 @@ DECLARE
        svnver text;
        projver text;
        geosver text;
+       sfcgalver text;
+       cgalver text;
        gdalver text;
        libxmlver text;
        dbproc text;
@@ -2481,6 +2493,12 @@ BEGIN
                        gdalver := NULL;
                        RAISE NOTICE 'Function postgis_gdal_version() not found.  Is raster support enabled and rtpostgis.sql installed?';
        END;
+       BEGIN
+               SELECT postgis_sfcgal_version() INTO sfcgalver;
+       EXCEPTION
+               WHEN undefined_function THEN
+                       sfcgalver := NULL;
+       END;
        SELECT postgis_libxml_version() INTO libxmlver;
        SELECT postgis_scripts_installed() INTO dbproc;
        SELECT postgis_scripts_released() INTO relproc;
@@ -2521,6 +2539,10 @@ BEGIN
                fullver = fullver || ' GEOS="' || geosver || '"';
        END IF;
 
+       IF  sfcgalver IS NOT NULL THEN
+               fullver = fullver || ' SFCGAL="' || sfcgalver || '"';
+       END IF;
+
        IF  projver IS NOT NULL THEN
                fullver = fullver || ' PROJ="' || projver || '"';
        END IF;
@@ -4656,7 +4678,7 @@ CREATE OR REPLACE RULE geometry_columns_delete AS
 
 CREATE OR REPLACE FUNCTION ST_3DDistance(geom1 geometry, geom2 geometry)
        RETURNS float8
-       AS 'MODULE_PATHNAME', 'LWGEOM_mindistance3d'
+       AS 'MODULE_PATHNAME', 'distance3d'
        LANGUAGE 'c' IMMUTABLE STRICT
        COST 100;
        
@@ -4707,10 +4729,16 @@ CREATE OR REPLACE FUNCTION ST_3DDFullyWithin(geom1 geometry, geom2 geometry,floa
        AS 'SELECT $1 && ST_Expand($2,$3) AND $2 && ST_Expand($1,$3) AND _ST_3DDFullyWithin($1, $2, $3)'
        LANGUAGE 'sql' IMMUTABLE
        COST 100;
+
+CREATE OR REPLACE FUNCTION _ST_3DIntersects(geom1 geometry, geom2 geometry)
+       RETURNS boolean
+       AS 'MODULE_PATHNAME','intersects3d'
+       LANGUAGE 'c' IMMUTABLE STRICT
+       COST 100;
        
 CREATE OR REPLACE FUNCTION ST_3DIntersects(geom1 geometry, geom2 geometry)
        RETURNS boolean
-       AS 'SELECT $1 && $2 AND _ST_3DDWithin($1, $2, 0.0)'
+       AS 'SELECT $1 && $2 AND _ST_3DIntersects($1, $2)'
        LANGUAGE 'sql' IMMUTABLE
        COST 100;
        
@@ -5086,7 +5114,7 @@ $$
                                                                ORDER BY 1, 2
                                                        ) As foo        ) );
                                IF ST_IsValid(var_tempgeom) AND ST_GeometryType(var_tempgeom) = 'ST_Polygon' THEN
-                                       var_tempgeom := ST_Intersection(var_tempgeom, var_convhull);
+                                       var_tempgeom := ST_force_sfs(ST_Intersection(var_tempgeom, var_convhull));
                                        IF param_allow_holes THEN
                                                var_param_geom := var_tempgeom;
                                        ELSE
@@ -5094,7 +5122,7 @@ $$
                                        END IF;
                                        return var_param_geom;
                                ELSIF ST_IsValid(var_tempgeom) THEN
-                                       var_param_geom := ST_Intersection(var_tempgeom, var_convhull);  
+                                       var_param_geom := ST_force_sfs(ST_Intersection(var_tempgeom, var_convhull));    
                                END IF;
                        END IF;
 
@@ -5119,7 +5147,7 @@ $$
                     -- break envelope into 4 triangles about the centroid of the geometry and returned the clipped geometry in each quadrant
                     FOR i in 1 .. 4 LOOP
                        var_geoms[i] := ST_MakePolygon(ST_MakeLine(ARRAY[ST_PointN(var_enline,i), ST_PointN(var_enline,i+1), var_cent, ST_PointN(var_enline,i)]));
-                       var_geoms[i] := ST_Intersection(var_param_geom, ST_Buffer(var_geoms[i],var_buf));
+                       var_geoms[i] := ST_force_sfs(ST_Intersection(var_param_geom, ST_Buffer(var_geoms[i],var_buf)));
                        IF ST_IsValid(var_geoms[i]) THEN 
                             
                        ELSE
@@ -5165,7 +5193,7 @@ $$
                 ELSE
                     var_resultgeom := ST_Buffer(var_resultgeom,var_buf);
                 END IF;
-                var_resultgeom := ST_Intersection(var_resultgeom, ST_ConvexHull(var_param_geom));
+                var_resultgeom := ST_force_sfs(ST_Intersection(var_resultgeom, ST_ConvexHull(var_param_geom)));
             ELSE
                 -- dimensions are too small to cut
                 var_resultgeom := _ST_ConcaveHull(var_param_geom);
@@ -5195,4 +5223,5 @@ CREATE OR REPLACE FUNCTION ST_AsX3D(geom geometry, maxdecimaldigits integer DEFA
 GRANT SELECT ON TABLE geography_columns TO public;
 GRANT SELECT ON TABLE geometry_columns TO public;
 GRANT SELECT ON TABLE spatial_ref_sys TO public;
+
 COMMIT;
index 6082df55d3424604a586002234ad98b49956a6f5..2addefb622a594b2320fc8b585ab3ef2d8a3eb92 100644 (file)
@@ -21,6 +21,7 @@
 #include "lwgeom_log.h"
 #include "lwgeom_pg.h"
 #include "geos_c.h"
+#include "lwgeom_backend_api.h"
 
 /*
  * This is required for builds against pgsql
@@ -94,6 +95,9 @@ _PG_init(void)
 
     /* install PostgreSQL handlers */
     pg_install_lwgeom_handlers();
+
+    /* initialize geometry backend */
+    lwgeom_init_backend();
 }
 
 /*
diff --git a/postgis/sfcgal.sql.in b/postgis/sfcgal.sql.in
new file mode 100644 (file)
index 0000000..344cfa9
--- /dev/null
@@ -0,0 +1,70 @@
+---------------------------------------------------------------------------
+--
+-- PostGIS - SFCGAL functions
+-- Copyright 2012-2013 Oslandia <infos@oslandia.com>
+--
+-- This is free software; you can redistribute and/or modify it under
+-- the terms of the GNU General Public Licence. See the COPYING file.
+--
+---------------------------------------------------------------------------
+
+
+--
+-- New SFCGAL functions (meaning prototype not already provided by GEOS)
+--
+
+BEGIN;
+
+CREATE OR REPLACE FUNCTION postgis_sfcgal_version() RETURNS text
+        AS 'MODULE_PATHNAME'
+        LANGUAGE 'c' IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION ST_3DIntersection(geom1 geometry, geom2 geometry)
+       RETURNS geometry
+       AS 'MODULE_PATHNAME','sfcgal_intersection3D'
+       LANGUAGE 'c' IMMUTABLE STRICT
+       COST 100;
+
+CREATE OR REPLACE FUNCTION ST_Tesselate(geometry)
+       RETURNS geometry
+       AS 'MODULE_PATHNAME','sfcgal_tesselate'
+       LANGUAGE 'c' IMMUTABLE STRICT
+       COST 100;
+
+CREATE OR REPLACE FUNCTION ST_3DArea(geometry)
+       RETURNS FLOAT8
+       AS 'MODULE_PATHNAME','sfcgal_area3D'
+       LANGUAGE 'c' IMMUTABLE STRICT
+       COST 100;
+
+CREATE OR REPLACE FUNCTION ST_Extrude(geometry, float8, float8, float8)
+       RETURNS geometry
+       AS 'MODULE_PATHNAME','sfcgal_extrude'
+       LANGUAGE 'c' IMMUTABLE STRICT
+       COST 100;
+
+CREATE OR REPLACE FUNCTION ST_ForceLHR(geometry)
+       RETURNS geometry
+       AS 'MODULE_PATHNAME','sfcgal_force_lhr'
+       LANGUAGE 'c' IMMUTABLE STRICT
+       COST 100;
+
+CREATE OR REPLACE FUNCTION ST_Orientation(geometry)
+       RETURNS INT4
+       AS 'MODULE_PATHNAME','sfcgal_orientation'
+       LANGUAGE 'c' IMMUTABLE STRICT
+       COST 100;
+
+CREATE OR REPLACE FUNCTION ST_Minkowski(geometry, geometry)
+       RETURNS geometry
+       AS 'MODULE_PATHNAME','sfcgal_minkowski_sum'
+       LANGUAGE 'c' IMMUTABLE STRICT
+       COST 100;
+
+CREATE OR REPLACE FUNCTION ST_StraightSkeleton(geometry)
+       RETURNS geometry
+       AS 'MODULE_PATHNAME','sfcgal_straight_skeleton'
+       LANGUAGE 'c' IMMUTABLE STRICT
+       COST 100;
+
+COMMIT;
diff --git a/postgis/uninstall_sfcgal.sql.in b/postgis/uninstall_sfcgal.sql.in
new file mode 100644 (file)
index 0000000..cb5a2fe
--- /dev/null
@@ -0,0 +1,36 @@
+---------------------------------------------------------------------------
+--
+-- PostGIS - SFCGAL functions
+-- Copyright 2012-2013 Oslandia <infos@oslandia.com>
+--
+-- This is free software; you can redistribute and/or modify it under
+-- the terms of the GNU General Public Licence. See the COPYING file.
+--
+---------------------------------------------------------------------------
+
+
+--
+-- New SFCGAL functions (meaning prototype not already provided by GEOS)
+--
+
+BEGIN;
+
+DROP FUNCTION IF EXISTS postgis_sfcgal_version();
+
+DROP FUNCTION IF EXISTS ST_3DIntersection(geom1 geometry, geom2 geometry);
+
+DROP FUNCTION IF EXISTS ST_Tesselate(geometry);
+
+DROP FUNCTION IF EXISTS ST_3DArea(geometry);
+
+DROP FUNCTION IF EXISTS ST_Extrude(geometry, float8, float8, float8);
+
+DROP FUNCTION IF EXISTS ST_ForceLHR(geometry);
+
+DROP FUNCTION IF EXISTS ST_Orientation(geometry);
+
+DROP FUNCTION IF EXISTS ST_Minkowski(geometry, geometry);
+
+DROP FUNCTION IF EXISTS ST_StraightSkeleton(geometry);
+
+COMMIT;
index 83304f13795428ec5c3bad8103d6d636de9b9da0..a0d863f4af69afab79b4b1c3ff3a489b09e5b6c3 100644 (file)
@@ -19,6 +19,7 @@ POSTGIS_PGSQL_VERSION=@POSTGIS_PGSQL_VERSION@
 POSTGIS_GEOS_VERSION=@POSTGIS_GEOS_VERSION@
 POSTGIS_PROJ_VERSION=@POSTGIS_PROJ_VERSION@
 HAVE_JSON=@HAVE_JSON@
+HAVE_SFCGAL=@HAVE_SFCGAL@
 MINGWBUILD=@MINGWBUILD@
 
 # MingW hack: rather than use PGSQL_BINDIR directly, we change
@@ -158,6 +159,25 @@ ifeq ($(HAVE_JSON),yes)
                in_geojson 
 endif
 
+ifeq ($(HAVE_SFCGAL),yes)
+       # SFCGAL additionnal backend
+       TESTS += \
+               regress_sfcgal \
+               sfcgal/empty.sql \
+               sfcgal/geography.sql \
+               sfcgal/legacy.sql \
+               sfcgal/measures.sql \
+               sfcgal/regress_ogc_prep.sql \
+               sfcgal/regress_ogc.sql \
+               sfcgal/regress.sql \
+               sfcgal/tickets.sql \
+               sfcgal/concave_hull.sql \
+               sfcgal/wmsservers.sql
+
+       RUNTESTFLAGS = --sfcgal
+endif
+
+
 all install uninstall:
 
 distclean: clean
diff --git a/regress/regress_sfcgal.sql b/regress/regress_sfcgal.sql
new file mode 100644 (file)
index 0000000..efda63b
--- /dev/null
@@ -0,0 +1,27 @@
+---
+--- Regression tests for PostGIS SFCGAL backend
+---
+
+-- We only care about testing PostGIS prototype here
+-- Behaviour is already handled by SFCGAL own tests
+
+SELECT 'ST_Tesselate', ST_AsText(ST_Tesselate('GEOMETRYCOLLECTION(POINT(4 4),POLYGON((0 0,1 0,1 1,0 1,0 0)))'));
+SELECT 'ST_3DArea', ST_3DArea('POLYGON((0 0 0,1 0 0,1 1 0,0 1 0,0 0 0))');
+SELECT 'ST_Extrude_point', ST_AsText(ST_Extrude('POINT(0 0)', 1, 0, 0));
+SELECT 'ST_Extrude_line', ST_AsText(ST_Extrude(ST_Extrude('POINT(0 0)', 1, 0, 0), 0, 1, 0));
+SELECT 'ST_Extrude_surface', ST_AsText(ST_Extrude(ST_Extrude(ST_Extrude('POINT(0 0)', 1, 0, 0), 0, 1, 0), 0, 0, 1));
+SELECT 'ST_ForceLHR', ST_AsText(ST_ForceLHR('POLYGON((0 0,0 1,1 1,1 0,0 0))'));
+SELECT 'ST_Orientation_1', ST_Orientation(ST_ForceLHR('POLYGON((0 0,0 1,1 1,1 0,0 0))'));
+SELECT 'ST_Orientation_2', ST_Orientation(ST_ForceRHR('POLYGON((0 0,0 1,1 1,1 0,0 0))'));
+SELECT 'ST_Minkowski', ST_AsText(ST_Minkowski('LINESTRING(0 0,4 0)','POLYGON((0 0,1 0,1 1,0 1,0 0))'));
+SELECT 'ST_StraightSkeleton', ST_AsText(ST_StraightSkeleton('POLYGON((0 0,1 0,1 1,0 1,0 0))'));
+
+-- Backend switch tests
+SET postgis.backend = 'geos';
+SELECT 'intersection_geos', ST_astext(ST_intersection('LINESTRING(0 10, 0 -10)', 'LINESTRING(0 0, 1 1)'));
+
+SET postgis.backend = 'sfcgal';
+SELECT 'intersection_sfcgal', ST_astext(ST_intersection('LINESTRING(0 10, 0 -10)', 'LINESTRING(0 0, 1 1)'));
+
+SET postgis.backend = 'foo';
+SET postgis.backend = '';
diff --git a/regress/regress_sfcgal_expected b/regress/regress_sfcgal_expected
new file mode 100644 (file)
index 0000000..43bd333
--- /dev/null
@@ -0,0 +1,14 @@
+ST_Tesselate|GEOMETRYCOLLECTION(POINT(4 4),TIN(((0 1,1 0,1 1,0 1)),((0 1,0 0,1 0,0 1))))
+ST_3DArea|1
+ST_Extrude_point|LINESTRING Z (0 0 0,1 0 0)
+ST_Extrude_line|POLYHEDRALSURFACE Z (((0 0 0,1 0 0,1 1 0,0 1 0,0 0 0)))
+ST_Extrude_surface|POLYHEDRALSURFACE Z (((1 1 0,1 0 0,0 1 0,1 1 0)),((0 1 1,1 0 1,1 1 1,0 1 1)),((1 0 0,0 0 0,0 1 0,1 0 0)),((0 1 1,0 0 1,1 0 1,0 1 1)),((1 0 0,1 1 0,1 1 1,1 0 1,1 0 0)),((1 1 0,0 1 0,0 1 1,1 1 1,1 1 0)),((0 1 0,0 0 0,0 0 1,0 1 1,0 1 0)),((0 0 0,1 0 0,1 0 1,0 0 1,0 0 0)))
+ST_ForceLHR|POLYGON((0 0,1 0,1 1,0 1,0 0))
+ST_Orientation_1|-1
+ST_Orientation_2|1
+ST_Minkowski|MULTIPOLYGON(((0 0,1 0,5 0,5 1,4 1,0 1,0 0)))
+ST_StraightSkeleton|MULTILINESTRING((0 0,0.5 0.5),(1 0,0.5 0.5),(1 1,0.5 0.5),(0 1,0.5 0.5))
+intersection_geos|POINT(0 0)
+intersection_sfcgal|POINT(-0 -0)
+ERROR:  Can't find foo geometry backend
+ERROR:  Can't find  geometry backend
index 54b1e7fc97a443deaab9334f1570f21ac9629a00..2b1c9a5a4bf39fd7a001e7ead3bd105d24e5e427 100755 (executable)
@@ -57,6 +57,7 @@ OPT_CREATE=yes
 OPT_UPGRADE=no
 OPT_WITH_TOPO=no
 OPT_WITH_RASTER=no
+OPT_WITH_SFCGAL=no
 OPT_EXPECT=no
 OPT_EXTENSIONS=no
 
@@ -661,6 +662,23 @@ prepare_spatial ()
         init_db_error "raster comments"
                fi
        fi # }
+
+       if test x"$OPT_WITH_SFCGAL" = "xyes"; then # {
+               SCRIPT=${STAGED_SCRIPTS_DIR}/sfcgal.sql
+               if test -e ${SCRIPT}; then
+                       echo "Adding sfcgal support"
+                       ${PSQL} ${_psql_opts} -Xf ${SCRIPT} "${DB}" \
+        >> ${PGIS_REG_TMPDIR}/regress_log 2>&1 || init_db_error "raster module"
+               else
+                       echo "${SCRIPT} not found" >&2
+                       exit 1
+               fi
+               if test -e ${STAGED_SCRIPTS_DIR}/sfcgal_comments.sql; then
+                       ${PSQL} ${_psql_opts} -Xf ${STAGED_SCRIPTS_DIR}/sfcgal_comments.sql \
+        "${DB}" >> ${PGIS_REG_TMPDIR}/regress_log 2>&1 || \
+        init_db_error "sfcgal comments"
+               fi
+       fi # }
 }
 
 # Create the spatial database
@@ -848,6 +866,10 @@ while [ -n "$1" ]; do
                OPT_WITH_RASTER=yes
                shift
                continue
+       elif test "$1" = "--sfcgal"; then
+               OPT_WITH_SFCGAL=yes
+               shift
+               continue
        elif test "$1" = "--clean"; then
                OPT_CLEAN=yes
                shift
@@ -866,6 +888,7 @@ if [ -z "$1" ]; then
        echo " --nodrop     do not drop the regression database on exit" >&2
        echo " --raster     load also raster extension" >&2
        echo " --topology   load also topology extension" >&2
+       echo " --sfcgal     use also sfcgal backend" >&2
        echo " --clean      cleanup test logs on exit" >&2
        echo " --expect     save obtained output as expected" >&2
        exit 1
index 40800724d09ab72ed68b8d151f6976bc5dfca9b5..7ea6ef69f1ee3251e96aeb65a33902dd69960dbb 100755 (executable)
@@ -47,6 +47,7 @@ my $OPT_NOCREATE = 0;
 my $OPT_UPGRADE = 0;
 my $OPT_WITH_TOPO = 0;
 my $OPT_WITH_RASTER = 0;
+my $OPT_WITH_SFCGAL = 0;
 my $OPT_EXPECT = 0;
 my $OPT_EXTENSIONS = 0;
 my $VERBOSE = 0;
@@ -59,11 +60,11 @@ GetOptions (
        'nocreate' => \$OPT_NOCREATE,
        'topology' => \$OPT_WITH_TOPO,
        'raster' => \$OPT_WITH_RASTER,
+       'sfcgal' => \$OPT_WITH_SFCGAL,
        'expect' => \$OPT_EXPECT,
        'extensions' => \$OPT_EXTENSIONS
        );
 
-
 ##################################################################
 # Set the locale to "C" so error messages match
 # Save original locale to set back
@@ -305,7 +306,6 @@ foreach $TEST (@ARGV)
 }
 
 
-
 ################################################################### 
 # Uninstall postgis (serves as an uninstall test)
 ##################################################################
@@ -365,6 +365,7 @@ Options:
   --nodrop     do not drop the regression database on exit
   --raster     load also raster extension
   --topology   load also topology extension
+  --sfcgal     use also sfcgal backend
   --clean      cleanup test logs on exit
   --expect     save obtained output as expected
 };
@@ -1036,16 +1037,25 @@ sub prepare_spatial
        
        if ( $OPT_WITH_TOPO )
        {
+               print "Loading Topology";
                load_sql_file("${STAGED_SCRIPTS_DIR}/topology.sql", 1);
                load_sql_file("${STAGED_SCRIPTS_DIR}/topology_comments.sql", 0);
        }
        
        if ( $OPT_WITH_RASTER )
        {
+               print "Loading Raster";
                load_sql_file("${STAGED_SCRIPTS_DIR}/rtpostgis.sql", 1);
                load_sql_file("${STAGED_SCRIPTS_DIR}/raster_comments.sql", 0);
        }
 
+       if ( $OPT_WITH_SFCGAL )
+       {
+               print "Loading sfcgal";
+               load_sql_file("${STAGED_SCRIPTS_DIR}/sfcgal.sql", 1);
+               load_sql_file("${STAGED_SCRIPTS_DIR}/sfcgal_comments.sql", 0);
+       }
+
        return 1;
 }
 
@@ -1111,6 +1121,10 @@ sub drop_spatial
        {
                load_sql_file("${STAGED_SCRIPTS_DIR}/uninstall_rtpostgis.sql");
        }
+       if ( $OPT_WITH_SFCGAL )
+       {
+               load_sql_file("${STAGED_SCRIPTS_DIR}/uninstall_sfcgal.sql");
+       }
        load_sql_file("${STAGED_SCRIPTS_DIR}/uninstall_postgis.sql");
 
        return 1;
diff --git a/regress/sfcgal/README b/regress/sfcgal/README
new file mode 100644 (file)
index 0000000..892c2b0
--- /dev/null
@@ -0,0 +1,75 @@
+These regress/sfcgal directory contains several tests closely based on 
+current regress one. 
+
+Usually they should behave really the same (i.e with both backends)
+however some slightly differences beetween GEOS and SFCGAL backends 
+are listed below:
+
+
+==
+sfcgal/ticket
+==
+
+2.OBT: #11|1.31708901596544e-9
+2.EXP: #11|0
+
+=> Numerical precision issue
+   (We slightly modify the unit test to use SQL round)
+
+
+18.OBT: ERROR:  LWGEOM2SFCGAL: Unknown geometry type !
+18.EXP: #85|0
+
+=> Curves are not (yet) handled by SFCGAL
+   (To be done in future SFCGAL release)
+
+
+
+132.OBT: #834|GEOMETRYCOLLECTION(POINT(0 0),LINESTRING(10 0,10 10))
+132.EXP: #834|GEOMETRYCOLLECTION(POINT(0 0 5),LINESTRING(10 10 5,10 0 5))
+
+=> For SFCGAL a 2D Intersection even with both 2D and 3D input data
+   is assumed as 2D and so set output Z to 0
+
+
+
+228.OBT: #1957|inf
+228.EXP: #1957|1
+
+=> Initial line is OGC invalid (single point),
+   so SFCGAL return infinite distance,
+   which .. also make sense
+
+
+
+==
+sfcgal/regress_ogc
+==
+
+65.OBT: intersection|POINT(-0 -0)
+65.EXP: intersection|POINT(0 0)
+
+=> No comment, except that the test itself could be sligthly rewrited
+
+
+
+==
+sfcgal/empty
+==
+
+29.OBT: ST_Intersection(geometry, empty) == geometry|010700000000000000
+29.EXP: ST_Intersection(geometry, empty) == geometry|010300000000000000
+
+30.OBT: ST_Intersection(empty, empty) == empty|010700000000000000
+30.EXP: ST_Intersection(empty, empty) == empty|010300000000000000
+
+=> SFCGAL don't consider keeping initial geometry type when intersection is null
+   so a GEOMETRYCOLLECTION(EMPTY) is returned (for both tests)
+   (maybe could be improved in SFCGAL)
+
+
+33.OBT: ST_Distance(geometry, empty) == NULL|inf
+33.EXP: ST_Distance(geometry, empty) == NULL|
+
+=> SFCGAL returns an infinite distance to an empty geometry instead of null,
+   which .. also make sense
diff --git a/regress/sfcgal/concave_hull.sql b/regress/sfcgal/concave_hull.sql
new file mode 100644 (file)
index 0000000..82d867b
--- /dev/null
@@ -0,0 +1,44 @@
+SET postgis.backend = 'sfcgal';
+
+-- $Id: concave_hull.sql 9324 2012-02-27 22:08:12Z pramsey $
+-- Tests to confirm the concave hull area is <= convex hull and 
+-- covers the original geometry (can't use covers because always gives topo errors with 3.3
+SELECT 
+       'ST_ConcaveHull MultiPolygon 0.95', ST_Area(ST_Intersection(geom,ST_ConcaveHull(
+               geom, 0.95) )) = ST_Area(geom) As encloses_geom, 
+               (ST_Area(ST_ConvexHull(geom)) 
+               - ST_Area(ST_ConcaveHull(geom, 0.95))) < (0.95 * ST_Area(ST_ConvexHull(geom) ) ) As reached_target
+FROM ST_Union(ST_GeomFromText('POLYGON((175 150, 20 40, 
+                       50 60, 125 100, 175 150))'),
+               ST_Buffer(ST_GeomFromText('POINT(110 170)'), 20)
+               ) As geom;
+               
+SELECT 
+       'ST_ConcaveHull Lines 0.80', ST_Intersection(geom,ST_ConcaveHull(
+               geom, 0.80) ) = geom As encloses_geom, 
+               (ST_Area(ST_ConvexHull(geom)) 
+               - ST_Area(ST_ConcaveHull(geom, 0.80))) < (0.80 * ST_Area(ST_ConvexHull(geom) ) ) As reached_target
+
+FROM ST_GeomFromText('MULTILINESTRING((106 164,30 112,74 70,82 112,130 94,
+       130 62,122 40,156 32,162 76,172 88),
+(132 178,134 148,128 136,96 128,132 108,150 130,
+170 142,174 110,156 96,158 90,158 88),
+(22 64,66 28,94 38,94 68,114 76,112 30,
+132 10,168 18,178 34,186 52,184 74,190 100,
+190 122,182 148,178 170,176 184,156 164,146 178,
+132 186,92 182,56 158,36 150,62 150,76 128,88 118))') As geom;
+
+-- test holes vs. no holes - holes should still enclose but have smaller area than no holes --
+SELECT 
+       'ST_ConcaveHull Lines 0.80 holes', ST_Intersection(geom,ST_ConcaveHull(
+               geom, 0.80, true) ) = geom As encloses_geom, 
+               ST_Area(ST_ConcaveHull(geom, 0.80, true)) < ST_Area(ST_ConcaveHull(geom, 0.80)) As reached_target
+
+FROM ST_GeomFromText('MULTILINESTRING((106 164,30 112,74 70,82 112,130 94,
+       130 62,122 40,156 32,162 76,172 88),
+(132 178,134 148,128 136,96 128,132 108,150 130,
+170 142,174 110,156 96,158 90,158 88),
+(22 64,66 28,94 38,94 68,114 76,112 30,
+132 10,168 18,178 34,186 52,184 74,190 100,
+190 122,182 148,178 170,176 184,156 164,146 178,
+132 186,92 182,56 158,36 150,62 150,76 128,88 118))') As geom;
diff --git a/regress/sfcgal/concave_hull_expected b/regress/sfcgal/concave_hull_expected
new file mode 100644 (file)
index 0000000..f81537c
--- /dev/null
@@ -0,0 +1,3 @@
+ST_ConcaveHull MultiPolygon 0.95|t|t
+ST_ConcaveHull Lines 0.80|t|t
+ST_ConcaveHull Lines 0.80 holes|t|t
diff --git a/regress/sfcgal/empty.sql b/regress/sfcgal/empty.sql
new file mode 100644 (file)
index 0000000..496070f
--- /dev/null
@@ -0,0 +1,147 @@
+SET postgis.backend = 'sfcgal';
+
+-- ST_SnapToGrid
+SELECT 'T1.1', ST_AsEWKT(ST_SnapToGrid('POINT EMPTY', 1));
+SELECT 'T1.2', ST_AsEWKT(ST_SnapToGrid('LINESTRING EMPTY', 1));
+SELECT 'T1.3', ST_AsEWKT(ST_SnapToGrid('SRID=4326;POLYGON EMPTY', 1));
+
+-- ST_Buffer
+SELECT 'T2.1', ST_AsEWKT(ST_Buffer('SRID=4326;POINT EMPTY', 0));
+SELECT 'T2.2', ST_AsEWKT(ST_Buffer('SRID=4326;LINESTRING EMPTY', 0));
+SELECT 'T2.3', ST_AsEWKT(ST_Buffer('SRID=4326;MULTIPOLYGON EMPTY', 0));
+WITH b as ( SELECT ST_Buffer('SRID=4326;MULTIPOINT EMPTY', 1) as g )
+SELECT 'T2.4', ST_Srid(g), GeometryType(g) from b;
+
+-- ST_AsGML (output may need some tweaking)
+SELECT 'T3.1', ST_AsGML('POINT EMPTY');
+SELECT 'T3.2', ST_AsGML('LINESTRING EMPTY');
+SELECT 'T3.3', ST_AsGML('POLYGON EMPTY');
+SELECT 'T3.4', ST_AsGML('MULTIPOLYGON EMPTY');
+SELECT 'T3.5', ST_AsGML('MULTILINESTRING EMPTY');
+SELECT 'T3.6', ST_AsGML('GEOMETRYCOLLECTION EMPTY');
+SELECT 'T3.7', ST_AsGML(3,'POINT EMPTY'::geometry);
+SELECT 'T3.8', ST_AsGML(3,'LINESTRING EMPTY'::geometry);
+SELECT 'T3.9', ST_AsGML(3,'POLYGON EMPTY'::geometry);
+SELECT 'T3.10', ST_AsGML(3,'MULTIPOLYGON EMPTY'::geometry);
+SELECT 'T3.11', ST_AsGML(3,'MULTILINESTRING EMPTY'::geometry);
+SELECT 'T3.12', ST_AsGML(3,'GEOMETRYCOLLECTION EMPTY'::geometry);
+SELECT 'T3.13', ST_AsGML(3,'POINT EMPTY'::geometry);
+SELECT 'T3.14', ST_AsGML(3,'LINESTRING EMPTY'::geometry);
+SELECT 'T3.15', ST_AsGML(3,'POLYGON EMPTY'::geometry);
+SELECT 'T3.16', ST_AsGML(3,'MULTIPOLYGON EMPTY'::geometry);
+SELECT 'T3.17', ST_AsGML(3,'MULTILINESTRING EMPTY'::geometry);
+SELECT 'T3.18', ST_AsGML(3,'GEOMETRYCOLLECTION EMPTY'::geometry);
+
+-- See http://trac.osgeo.org/postgis/wiki/DevWikiEmptyGeometry
+
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty,
+ 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry,
+ 120 as tolerance
+ ) SELECT 'ST_Buffer(empty, tolerance) == empty', ST_Buffer(empty, tolerance) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty,
+ 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry
+ ) SELECT 'ST_Union(geometry, empty) == geometry', ST_Union(geometry, empty) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty
+ ) SELECT 'ST_Union(empty, empty) == empty', ST_Union(empty, empty) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty,
+ 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry
+ ) SELECT 'ST_Intersection(geometry, empty) == geometry', ST_Intersection(geometry, empty) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty
+ ) SELECT 'ST_Intersection(empty, empty) == empty', ST_Intersection(empty, empty) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty,
+ 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry
+ ) SELECT 'ST_Difference(geometry, empty) == geometry', ST_Difference(geometry, empty) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty,
+ 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry
+ ) SELECT 'ST_Difference(empty, geometry) == empty', ST_Difference(empty, geometry) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty,
+ 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry
+ ) SELECT 'ST_Distance(geometry, empty) == NULL', ST_Distance(geometry, empty) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty,
+ 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry,
+ 120 as tolerance
+ ) SELECT 'ST_DWithin(geometry, empty, tolerance) == FALSE', ST_DWithin(geometry, empty, tolerance) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty,
+ 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry
+ ) SELECT 'ST_Within(geometry, empty) == FALSE', ST_Within(geometry, empty) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty,
+ 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry
+ ) SELECT 'ST_Contains(empty, geometry) == FALSE', ST_Contains(empty, geometry) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty,
+ 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry
+ ) SELECT 'ST_Within(empty, geometry) == FALSE', ST_Within(empty, geometry) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty
+ ) SELECT 'ST_Contains(empty, empty) == FALSE', ST_Contains(empty, empty) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty,
+ 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry
+ ) SELECT 'ST_Intersects(geometry, empty) == FALSE', ST_Intersects(geometry, empty) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty
+ ) SELECT 'ST_Intersects(empty, empty) == FALSE', ST_Intersects(empty, empty) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty,
+ 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry
+ ) SELECT 'ST_Disjoint(empty, empty) == TRUE', ST_Disjoint(empty, empty) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty,
+ 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry
+ ) SELECT 'ST_Disjoint(geometry, empty) == TRUE', ST_Disjoint(geometry, empty) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty1,
+ 'POINT Z EMPTY'::geometry as empty2
+ ) SELECT 'ST_Equals(empty1, empty2) == TRUE', ST_Equals(empty1, empty2) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty
+ ) SELECT 'ST_IsSimple(empty) == TRUE', ST_IsSimple(empty) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty
+ ) SELECT 'ST_IsValid(empty) == TRUE', ST_IsValid(empty) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty
+ ) SELECT 'ST_NumGeometries(empty) == 0', ST_NumGeometries(empty) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty
+ ) SELECT 'ST_NRings(empty) == 0', ST_NRings(empty) FROM inp;
+WITH inp AS (SELECT
+ 'LINESTRING EMPTY'::geometry as empty
+ ) SELECT 'ST_NumPoints(empty) == 0', ST_NumPoints(empty) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty
+ ) SELECT 'ST_NPoints(empty) == 0', ST_NPoints(empty) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty,
+ 1 as n
+ ) SELECT 'ST_GeometryN(empty, n) == empty', ST_GeometryN(empty, n) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty
+ ) SELECT 'ST_ExteriorRing(empty) == empty', ST_ExteriorRing(empty) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty,
+ 1 as n
+ ) SELECT 'ST_InteriorRingN(empty, n) == NULL', ST_InteriorRingN(empty, n) FROM inp;
+WITH inp AS (SELECT
+ 'POLYGON EMPTY'::geometry as empty
+ ) SELECT 'ST_Area(empty) == 0', ST_Area(empty) FROM inp;
+WITH inp AS (SELECT
+ 'LINESTRING EMPTY'::geometry as empty
+ ) SELECT 'ST_Length(empty) == 0', ST_Length(empty) FROM inp;
+
+
+-- Operators
+
+-- same box, see http://trac.osgeo.org/postgis/ticket/1453
+SELECT '~=', 'POINT EMPTY'::geometry ~= 'POINT EMPTY'::geometry;
diff --git a/regress/sfcgal/empty_expected b/regress/sfcgal/empty_expected
new file mode 100644 (file)
index 0000000..4acf562
--- /dev/null
@@ -0,0 +1,55 @@
+T1.1|POINT EMPTY
+T1.2|LINESTRING EMPTY
+T1.3|SRID=4326;POLYGON EMPTY
+T2.1|SRID=4326;POLYGON EMPTY
+T2.2|SRID=4326;POLYGON EMPTY
+T2.3|SRID=4326;POLYGON EMPTY
+T2.4|4326|POLYGON
+T3.1|
+T3.2|
+T3.3|
+T3.4|
+T3.5|
+T3.6|
+T3.7|
+T3.8|
+T3.9|
+T3.10|
+T3.11|
+T3.12|
+T3.13|
+T3.14|
+T3.15|
+T3.16|
+T3.17|
+T3.18|
+ST_Buffer(empty, tolerance) == empty|010300000000000000
+ST_Union(geometry, empty) == geometry|0103000000010000000400000000000000000000000000000000000000000000000000244000000000000000000000000000001440000000000000144000000000000000000000000000000000
+ST_Union(empty, empty) == empty|010300000000000000
+ST_Intersection(geometry, empty) == geometry|010700000000000000
+ST_Intersection(empty, empty) == empty|010700000000000000
+ST_Difference(geometry, empty) == geometry|0103000000010000000400000000000000000000000000000000000000000000000000244000000000000000000000000000001440000000000000144000000000000000000000000000000000
+ST_Difference(empty, geometry) == empty|010300000000000000
+ST_Distance(geometry, empty) == NULL|inf
+ST_DWithin(geometry, empty, tolerance) == FALSE|f
+ST_Within(geometry, empty) == FALSE|f
+ST_Contains(empty, geometry) == FALSE|f
+ST_Within(empty, geometry) == FALSE|f
+ST_Contains(empty, empty) == FALSE|f
+ST_Intersects(geometry, empty) == FALSE|f
+ST_Intersects(empty, empty) == FALSE|f
+ST_Disjoint(empty, empty) == TRUE|t
+ST_Disjoint(geometry, empty) == TRUE|t
+ST_Equals(empty1, empty2) == TRUE|t
+ST_IsSimple(empty) == TRUE|t
+ST_IsValid(empty) == TRUE|t
+ST_NumGeometries(empty) == 0|0
+ST_NRings(empty) == 0|0
+ST_NumPoints(empty) == 0|0
+ST_NPoints(empty) == 0|0
+ST_GeometryN(empty, n) == empty|010300000000000000
+ST_ExteriorRing(empty) == empty|010200000000000000
+ST_InteriorRingN(empty, n) == NULL|
+ST_Area(empty) == 0|0
+ST_Length(empty) == 0|0
+~=|t
diff --git a/regress/sfcgal/geography.sql b/regress/sfcgal/geography.sql
new file mode 100644 (file)
index 0000000..1fa7db6
--- /dev/null
@@ -0,0 +1,79 @@
+SET postgis.backend = 'sfcgal';
+
+INSERT INTO spatial_ref_sys (srid, auth_name, auth_srid, srtext, proj4text)
+VALUES (
+ '4326',
+ 'EPSG',
+ '4326',
+ 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]',
+ '+proj=longlat +datum=WGS84 +no_defs'
+);
+
+-- Do cached and uncached distance agree?
+SELECT c, abs(ST_Distance(ply::geography, pt::geography) - _ST_DistanceUnCached(ply::geography, pt::geography)) < 0.01 FROM 
+( VALUES
+('geog_distance_cached_1a', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'),
+('geog_distance_cached_1b', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'),
+('geog_distance_cached_1c', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'),
+('geog_distance_cached_1e', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'),
+('geog_distance_cached_1f', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'),
+('geog_distance_cached_1g', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'),
+('geog_distance_cached_1h', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)')
+) AS u(c,ply,pt);
+
+-- Does tolerance based distance work cached? Inside tolerance
+SELECT c, ST_DWithin(ply::geography, pt::geography, 3000) from 
+( VALUES
+('geog_dithin_cached_1a', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(10.01 5)'),
+('geog_dithin_cached_1b', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(10.01 5)'),
+('geog_dithin_cached_1c', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(10.01 5)')
+) as p(c, ply, pt);
+
+-- Does tolerance based distance work cached? Outside tolerance
+SELECT c, ST_DWithin(ply::geography, pt::geography, 1000) from 
+( VALUES
+('geog_dithin_cached_2a', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(10.01 5)'),
+('geog_dithin_cached_2b', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(10.01 5)'),
+('geog_dithin_cached_2c', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(10.01 5)')
+) as p(c, ply, pt);
+
+-- Do things work when there's cache coherence on the point side but not the poly side?
+SELECT c, ST_DWithin(ply::geography, pt::geography, 3000) from 
+( VALUES
+('geog_dithin_cached_3a', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'),
+('geog_dithin_cached_3b', 'POLYGON((1 1, 1 10, 10 10, 10 1, 1 1))', 'POINT(5 5)'),
+('geog_dithin_cached_3c', 'POLYGON((2 2, 2 10, 10 10, 10 2, 2 2))', 'POINT(5 5)')
+) as p(c, ply, pt);
+
+-- Test a precision case near the south pole that came up during development.
+WITH pt AS ( 
+    SELECT point::geography FROM ( VALUES 
+    ('0101000020E61000006C5B94D920EB4CC0A0FD481119B24FC0'),
+    ('0101000020E610000097A8DE1AD8524CC09C8A54185B1050C0'),
+    ('0101000020E61000008FC2F5285C4F4CC0E5ED08A7050F50C0'),
+    ('0101000020E61000008FC2F5285C4F4CC0E5ED08A7050F50C0') ) AS p(point)
+),
+ply AS (
+    SELECT polygon::geography FROM ( VALUES
+    ('0106000020E610000001000000010300000001000000A10100005036E50AEF8E4FC0E3FC4D2844A443C000000000008046C000000000000047C033333333335346C000000000000047C066666666662646C000000000000047C09999999999F945C000000000000047C0CDCCCCCCCCCC45C000000000000047C00000000000A045C000000000000047C033333333337345C000000000000047C066666666664645C000000000000047C099999999991945C000000000000047C0CDCCCCCCCCEC44C000000000000047C00000000000C044C000000000000047C033333333339344C000000000000047C066666666666644C000000000000047C099999999993944C000000000000047C0CDCCCCCCCC0C44C000000000000047C00000000000E043C000000000000047C03333333333B343C000000000000047C066666666668643C000000000000047C099999999995943C000000000000047C0CDCCCCCCCC2C43C000000000000047C000000000000043C000000000000047C03333333333D342C000000000000047C06666666666A642C000000000000047C099999999997942C000000000000047C0CDCCCCCCCC4C42C000000000000047C000000000002042C000000000000047C03333333333F341C000000000000047C06666666666C641C000000000000047C099999999999941C000000000000047C0CDCCCCCCCC6C41C000000000000047C000000000004041C000000000000047C033333333331341C000000000000047C06666666666E640C000000000000047C09999999999B940C000000000000047C0CDCCCCCCCC8C40C000000000000047C000000000006040C000000000000047C033333333333340C000000000000047C066666666660640C000000000000047C03333333333B33FC000000000000047C09999999999593FC000000000000047C00000000000003FC000000000000047C06666666666A63EC000000000000047C0CCCCCCCCCC4C3EC000000000000047C03333333333F33DC000000000000047C09999999999993DC000000000000047C00000000000403DC000000000000047C06666666666E63CC000000000000047C0CCCCCCCCCC8C3CC000000000000047C03333333333333CC000000000000047C09999999999D93BC000000000000047C00000000000803BC000000000000047C06666666666263BC000000000000047C0CCCCCCCCCCCC3AC000000000000047C03333333333733AC000000000000047C09999999999193AC000000000000047C00000000000C039C000000000000047C066666666666639C000000000000047C0CCCCCCCCCC0C39C000000000000047C03333333333B338C000000000000047C099999999995938C000000000000047C000000000000038C000000000000047C06666666666A637C000000000000047C0CDCCCCCCCC4C37C000000000000047C03333333333F336C000000000000047C099999999999936C000000000000047C000000000004036C000000000000047C06666666666E635C000000000000047C0CDCCCCCCCC8C35C000000000000047C033333333333335C000000000000047C09999999999D934C000000000000047C000000000008034C000000000000047C066666666662634C000000000000047C0CDCCCCCCCCCC33C000000000000047C033333333337333C000000000000047C099999999991933C000000000000047C00000000000C032C000000000000047C066666666666632C000000000000047C0CDCCCCCCCC0C32C000000000000047C03333333333B331C000000000000047C099999999995931C000000000000047C000000000000031C000000000000047C06666666666A630C000000000000047C0CDCCCCCCCC4C30C000000000000047C06666666666E62FC000000000000047C03333333333332FC000000000000047C00000000000802EC000000000000047C0CCCCCCCCCCCC2DC000000000000047C09999999999192DC000000000000047C06666666666662CC000000000000047C03333333333B32BC000000000000047C00000000000002BC000000000000047C0CCCCCCCCCC4C2AC000000000000047C099999999999929C000000000000047C06666666666E628C000000000000047C033333333333328C000000000000047C000000000008027C000000000000047C0CDCCCCCCCCCC26C000000000000047C099999999991926C000000000000047C066666666666625C000000000000047C03333333333B324C000000000000047C000000000000024C000000000000047C000000000000024C03943F5FFFF7F56C000000000008052C03943F5FFFF7F56C000000000008052C00000000000004EC068774831407A52C00000000000004EC0B8ACC266807452C00000000000004EC020240B98C06E52C00000000000004EC0705985CD006952C00000000000004EC0D9D0CDFE406352C00000000000004EC029064834815D52C00000000000004EC0917D9065C15752C00000000000004EC0E1B20A9B015252C00000000000004EC0492A53CC414C52C00000000000004EC09A5FCD01824652C00000000000004EC002D71533C24052C00000000000004EC0520C9068023B52C00000000000004EC0BA83D899423552C00000000000004EC00AB952CF822F52C00000000000004EC072309B00C32952C00000000000004EC0C3651536032452C00000000000004EC02BDD5D67431E52C00000000000004EC09354A698831852C00000000000004EC0E38920CEC31252C00000000000004EC04B0169FF030D52C00000000000004EC09B36E334440752C00000000000004EC003AE2B66840152C00000000000004EC054E3A59BC4FB51C00000000000004EC0BC5AEECC04F651C00000000000004EC00C90680245F051C00000000000004EC07407B13385EA51C00000000000004EC0C43C2B69C5E451C00000000000004EC02DB4739A05DF51C00000000000004EC07DE9EDCF45D951C00000000000004EC0E560360186D351C00000000000004EC03596B036C6CD51C00000000000004EC09D0DF96706C851C00000000000004EC0EE42739D46C251C00000000000004EC056BABBCE86BC51C00000000000004EC0A6EF3504C7B651C00000000000004EC00E677E3507B151C00000000000004EC076DEC66647AB51C00000000000004EC0C613419C87A551C00000000000004EC02E8B89CDC79F51C00000000000004EC07FC00303089A51C00000000000004EC0E7374C34489451C00000000000004EC0376DC669888E51C00000000000004EC09FE40E9BC88851C00000000000004EC0EF1989D0088351C00000000000004EC05791D101497D51C00000000000004EC0A8C64B37897751C00000000000004EC0103E9468C97151C00000000000004EC060730E9E096C51C00000000000004EC0C8EA56CF496651C00000000000004EC01820D1048A6051C00000000000004EC081971936CA5A51C00000000000004EC0D1CC936B0A5551C00000000000004EC03944DC9C4A4F51C00000000000004EC0A1BB24CE8A4951C00000000000004EC0F1F09E03CB4351C00000000000004EC05968E7340B3E51C00000000000004EC0AA9D616A4B3851C00000000000004EC01215AA9B8B3251C00000000000004EC0624A24D1CB2C51C00000000000004EC0CAC16C020C2751C00000000000004EC01AF7E6374C2151C00000000000004EC0826E2F698C1B51C00000000000004EC0D3A3A99ECC1551C00000000000004EC03B1BF2CF0C1051C00000000000004EC08B506C054D0A51C00000000000004EC0F3C7B4368D0451C00000000000004EC043FD2E6CCDFE50C00000000000004EC0AB74779D0DF950C00000000000004EC0FCA9F1D24DF350C00000000000004EC064213A048EED50C00000000000004EC0CC988235CEE750C00000000000004EC01CCEFC6A0EE250C00000000000004EC08445459C4EDC50C00000000000004EC0D47ABFD18ED650C00000000000004EC0C2340C1F11D150C00000000000004EC0C2340C1F11D150C0FE7DC685032D4DC0C2340C1F11D150C0FE7DC685033D4CC0C2340C1F11D150C0713D0AD7A3304CC02AAC545051CB50C0703D0AD7A3304CC07AE1CE8591C550C0703D0AD7A3304CC0E25817B7D1BF50C0703D0AD7A3304CC0328E91EC11BA50C0703D0AD7A3304CC09A05DA1D52B450C0703D0AD7A3304CC0EB3A545392AE50C0703D0AD7A3304CC053B29C84D2A850C0703D0AD7A3304CC0A3E716BA12A350C0703D0AD7A3304CC00B5F5FEB529D50C0703D0AD7A3304CC05B94D920939750C0703D0AD7A3304CC0C30B2252D39150C0703D0AD7A3304CC014419C87138C50C0703D0AD7A3304CC07CB8E4B8538650C0703D0AD7A3304CC0CCED5EEE938050C0703D0AD7A3304CC03465A71FD47A50C0703D0AD7A3304CC0849A2155147550C0703D0AD7A3304CC0EC116A86546F50C0703D0AD7A3304CC03ECBF3E0EE6E50C0713D0AD7A3304CC0FF3EE3C2816E50C0A2EE0390DAB04BC0EC12D55B038550C01630815B77974BC05BCEA5B8AA9A50C0C173EFE1928F4BC0A5315A4755B550C00000000000804BC0014D840D4FD150C01899DB1896744BC05D05E7421B2A51C0B38EF4B3A2754BC0BB0F406A132751C068E89FE062C94AC03D6B1217DB2851C0413F9D3C76564AC09F268E97491D51C01E55A8C9E72D4AC014AE47E17A5051C05E770481DF154AC0DA531795F95E51C0ADA81CEE7E154AC033333333337351C0EACF7EA488084AC0DA835A1DCA8251C019479B994F014AC00473F4F8BDA551C0CB4A9352D0014AC0AD927EB12DFD51C0848FD2B6AB014AC07F11D9AC1FFF51C0D21D1F8887F249C01D4762388D1B52C06AE27899BCCA49C00AD7A3703D1252C08BAF2C87CCA049C0A323B9FC871A52C0ADCE20F4229449C056760B6E351352C0F866E5A8ED8449C024F83A04E91352C0DCDB8882745249C0F1F44A59863252C0DBCD42F1195049C01A97BBE09D4452C0EEEBC039236449C09A31BBDD014C52C0454B79083E6349C0A59421D8826352C004824AA6542849C04BABC6B71C6252C046216EF36B1449C0A4F55C4BED5D52C01CE7DB27EC0549C0D9BBF550916452C058CE39D3DFF648C0DD0E6844445C52C0937D46D8A6E648C098B4F347E26652C0F6FC1F1620C748C0AB37B412845D52C0D9A2BBDA40A948C048E17A14AE5F52C0D52137C30D9448C04B1A48BCE14B52C0BF901F3BB99848C0B26DAC1FF63552C0E4709CCA587B48C0287E8CB96B2652C0912CBBBB296948C0A59421D8822852C0D49AE61DA74048C0C009E0C1AA1452C0106734A8EC2E48C0A8D94D3ADB1452C004560E2DB21948C0687B4F40EE2452C06ECF3D35A8F047C089022269DC1552C0ADAC23FDACCD47C019B2158FE61652C07BC26DC89AB747C009B3BFA2910A52C095E70B6B74B447C01DF2857F47FF51C01D8AA7C3AF9A47C0F1248EE156F651C0E9482EFF219B47C07A45A6327BFE51C0711706D1FF8747C0A5315A4755FD51C000000000008047C0395BE5AE4AFB51C0CD6152D7356547C0182DF64DD0F451C00CC3EC0A226447C0B6CA5D95D5EA51C098E19A96B34A47C06ABC749318FA51C0E51E5C4B121247C0C1920612EFEE51C0780F2B37AC0847C09D2743FA12EA51C0653FE65EBBF546C01563AAAA61F351C0FA8271CBA2CB46C00775368966E151C08208CC9E5FC346C05DEF4806CAD651C03ECB98277C9C46C03760A12042E551C0FFF1B96EA57B46C073A7CF69710152C090A4FF40147346C03D5C1723B70152C0F46C567DAE6646C03505D78198E051C023DF008E985E46C08351499D80D451C037853A51B76646C09C46A4B789C751C0B515FBCBEE4546C09C33A2B437CF51C0BE82D9A95E3446C066E1462550F651C042CB5FC6B93046C09B6B3DE8FEF551C056212FB5EF0D46C075FBF6BFEDEB51C04E36D4DE96FF45C020578FA01DF251C0C967C3ABF6E845C05CA2C4F87AE651C0E5F21FD26FD745C0FD0978E3EEFB51C06CE3F49AC3BE45C09D11A5BDC1F951C00C11267B3AAB45C08A9DDFE643F051C037EE83E27DA645C0A922CB38FCEF51C0CCBE863B729645C008D5BC99070852C0865EDACB118745C088635DDC460952C01B09D91E624E45C01F85EB51B80652C07D96E7C1DD4D45C0A8188CB6CF0152C018135102513E45C00C7D0B46000852C0166646E4602945C06E2585C31C0352C039B0C167901345C0A499DD497AEF51C0BD1358A5991245C023DBF97E6AF251C0BEF15AAE230045C0EE7C3F355EF151C0F6FC1F1620E944C040529F3FC8F851C0BBF7CB82E4D344C0D27E5AFBF1F751C0F6D61B107CB444C0CA9C23938AF751C0B498EEF4A2B544C0624775BC1FF751C035958D13C7B644C0EA8B637FB1F651C040BEE654E8B744C0AADC49E43FF651C0298B1FA206B944C0AD7CCAF3CAF551C043D796E421BA44C0D6E6CDB652F551C0ECBDE6053ABB44C0532E8236D7F451C06B72E6EF4EBC44C07E585A7C58F451C08F13AC8C60BD44C01EB00D92D6F351C0DE7A8EC66EBE44C02712978151F351C01507278879BF44C0F9333455C9F251C0D96153BC80C044C015E364173EF251C08540374E84C144C0703EEAD2AFF151C0B21F3E2984C244C062E9C5921EF151C088F91C3980C344C0313839628AF051C083F6D36978C444C05856C44CF3EF51C0A018B0A76CC544C09366255E59EF51C0A5E04CDF5CC644C0AE9C57A2BCEE51C08AED95FD48C744C0495192251DEE51C09C95C8EF30C844C0760F48F47AED51C0747975A314C944C0739C251BD6EC51C060108206F4C944C061F910A72EEC51C0372E2A07CFCA44C0385F28A584EB51C066820194A5CB44C0E834C122D8EA51C01010F59B77CC44C0DDFF662D29EA51C0149F4C0E45CD44C0DA4EDAD277E951C0E725ACDA0DCE44C0669F0F21C4E851C0FB2B15F1D1CE44C0C53D2E260EE851C0B124E84191CF44C0A41F8FF055E751C09CC2E5BD4BD044C098B9BB8E9BE651C0F042305601D144C076CF6C0FDFE551C017B14CFCB1D144C0B73F898120E551C0192224A25DD244C0F9C924F45FE451C0E5E7043A04D344C0B2D07E769DE351C03EBCA3B6A5D344C047160118D9E251C039E31C0B42D444C095753EE812E251C01B45F52AD9D444C01596F1F64AE151C09D7F1B0A6BD544C0B79BFB5381E051C048EEE89CF7D544C096D2620FB6DF51C0F7A922D87ED644C0AA565139E9DE51C0497FFAB000D744C097B713E21ADE51C0FBDB0F1D7DD744C0BB98171A4BDD51C0FBB27012F4D744C0AC4DEAF179DC51C02D579A8765D844C03173377AA7DB51C0BC4C7A73D1D844C0FB84C7C3D3DA51C0FD106FCD37D944C027707EDFFED951C095D8488D98D944C0C8225ADE28D951C013444AABF3D944C08B1871D151D851C0B40A292049DA44C0ADE4F0C979D751C0529B0EE598DA44C061B91CD9A0D651C07AB398F3E2DA44C0D4EC4B10C7D551C076ECD94527DB44C0F97BE880ECD451C0633E5AD665DB44C0398B6D3C11D451C01F7917A09EDB44C04CE5655435D351C01FB3859ED1DB44C048786ADA58D251C018AE8FCDFEDB44C022D120E07BD151C05831972926DC44C0C89539779ED051C0F25975AF47DC44C0FEFD6EB1C0CF51C091E07A5C63DC44C02B4B83A0E2CE51C0EE54702E79DC44C03D3F3F5604CE51C0F24E962389DC44C0D69270E425CD51C07E95A53A93DC44C0EE6AE85C47CC51C0A93ACF7297DC44C00BCE79D168CB51C0C6ADBCCB95DC44C04F19F8538ACA51C0D7C28F458EDC44C06D7535F6ABC951C09FAFE2E080DC44C0CD4B01CACDC851C04CFEC79E6DDC44C000BC26E1EFC751C0B675CA8054DC44C09F116B4D12C751C029F7EC8835DC44C0DF3A8C2035C651C0DC51AAB910DC44C0F53F3F6C58C551C0FC0BF515E6DB44C073BB2E427CC451C0632137A1B5DB44C0D153F9B3A0C351C0F7B7515F7FDB44C04D3630D3C5C251C0CDC99C5443DB44C0459355B1EBC151C0F8C4E68501DB44C0451CDB5F12C151C0342174F8B9DA44C0DB8320F039C051C062EBFEB16CDA44C079FF717362BF51C0E546B6B819DA44C078CB06FB8BBE51C0F2E43D13C1D944C06DB1FF97B6BD51C0DC71ADC862D944C0F890655BE2BC51C088F88FE0FED844C03BEB27560FBC51C0E13BE36295D844C014711B993DBB51C09706175826D844C04F94F8346DBA51C02E710CC9B1D744C0F31B5A3A9EB951C04B1E15BF37D744C0C6BBBBB9D0B851C0976DF243B8D644C03FAF78C304B851C014A5D46133D644C0F757CA673AB751C01A115A23A9D544C0DADFC6B671B651C0141B8E9319D544C014DF5FC0AAB551C0FE56E8BD84D444C005066194E5B451C0E6874BAEEAD344C049CB6E4222B451C0629B04714BD344C0E91D05DA60B351C03E9CC912A7D244C0051C766AA1B251C04D9CB8A0FDD144C0D3CDE802E4B151C0CD9556284FD144C058E557B228B151C00E448EB79BD044C0C48290876FB051C0DCF3AE5CE3CF44C0ABFD3091B8AF51C0A54B6B2626CF44C034B3A7DD03AF51C06F0BD82364CE44C048D9317B51AE51C0DEC46A649DCD44C0FC56DA77A1AD51C05A8BF8F7D1CC44C032A278E1F3AC51C0709CB4EE01CC44C0A0A2AFC548AC51C0B9002F592DCB44C03F9AEC31A0AB51C03225534854CA44C05A136633FAAA51C0646D66CD76C944C02DD41AD756AA51C050BE06FA94C844C04CD8D029B6A951C0720229E0AEC744C0D34F143818A951C0DEA61792C4C644C075A4360E7DA851C0AF117122D6C544C082844DB8E4A751C0EE1126A4E3C444C0FDF331424FA751C02849782AEDC344C0B6637FB7BCA651C0B58EF8C8F2C244C0A5CE92232DA651C0FE4C8593F4C144C067DD8991A0A551C0EBD8489EF2C044C01010420C17A551C084C3B7FDECBF44C046EE579E90A451C006268FC6E3BE44C0C53D26520DA451C0AAE8D20DD7BD44C0473FC5318DA351C01B04CCE8C6BC44C0E1F1094710A351C0E0BD066DB3BB44C0E85C859B96A251C000E050B09CBA44C05AE0833820A251C0CAEBB7C882B944C0CF8B0C27ADA151C02F4887CC65B844C00B7CE06F3DA151C0B66B46D245B744C02E3F7A1BD1A051C03B02B7F022B644C0813F0D3268A051C0BA0ED33EFDB444C0E43485BB02A051C02C09CBD3D4B344C0FB9C85BFA09F51C0CBF803C7A9B244C0EB396945429F51C0D58A15307CB144C0E1974154E79E51C0FC25C8264CB044C03299D6F28F9E51C0ADFA12C319AF44C03D09A6273C9E51C076101A1DE5AD44C0EF35E3F8EB9D51C084502C4DAEAC44C0F98F766C9F9D51C0A08DC16B75AB44C09EB70C93849D51C08100BE8003AB44C05036E50AEF8E4FC0E3FC4D2844A443C0')
+    ) as q(polygon)
+)
+SELECT 'geog_precision_savffir', _ST_DistanceUnCached(pt.point, ply.polygon), ST_Distance(pt.point, ply.polygon) FROM pt, ply;
+
+-- Test another precision case near the north poly and over the dateline
+WITH pt AS ( 
+    SELECT point::geography FROM ( VALUES 
+    ('0101000020E610000000000000004065400000000000804840'),
+    ('0101000020E610000075C8CD70033965C02176A6D079315040') ) AS p(point)
+),
+ply AS (
+    SELECT polygon::geography FROM ( VALUES
+    ('0103000020E6100000010000004101000078A1B94E231F65C000000000000051400000000000C063C000000000000052400000000000C063C0000000000000524078A1B94E231F65C0000000000000514078A1B94E231F65C000000000008056400000000000A061C000000000008056400000000000A061C0EF940ED6FF7F56400000000000A061C0DD291DACFF7F56400000000000A061C0CBBE2B82FF7F56400000000000A061C0B9533A58FF7F56400000000000A061C0A8E8482EFF7F56400000000000A061C0967D5704FF7F56400000000000A061C072A774B0FE7F56400000000000A061C04FD1915CFE7F56400000000000A061C02BFBAE08FE7F56400000000000A061C0F6B9DA8AFD7F56400000000000A061C0C178060DFD7F56400000000000A061C079CC4065FC7F56400000000000A061C00F4A9869FB7F56400000000000A061C0A4C7EF6DFA7F56400000000000A061C0040473F4F87F56400000000000A061C052D50451F77F56400000000000A061C07DD0B359F57F56400000000000A061C0611F9DBAF27F56400000000000A061C00F2DB29DEF7F56400000000000A061C0642310AFEB7F56400000000000A061C06102B7EEE67F56400000000000A061C0E1F3C308E17F56400000000000A061C0AFB6627FD97F56400000000000A061C0DDB5847CD07F56400000000000A061C013DA722EC57F56400000000000A061C02C4D4A41B77F56400000000000A061C0CFF753E3A57F56400000000000A061C0B72DCA6C907F56400000000000A061C0776C04E2757F56400000000000A061C093C6681D557F56400000000000A061C05B0D897B2C7F56400000000000A061C01B12F758FA7E56400000000000A061C0B8239C16BC7E56400000000000A061C027FC523F6F7E56400000000000A061C0BD9179E40F7E56400000000000A061C0CFDA6D179A7D56400000000000A061C0F0332E1C087D56400000000000A061C07CB8E4B8537C56400000000000A061C0C53D963E747B56400000000000A061C08E40BCAE5F7A56400000000000A061C07F8CB96B097956400000000000A061C0FE65F7E4617756400000000000A061C0C9073D9B557556400000000000A061C0CDCCCCCCCC7256400000000000A061C07A01F6D1A96F56400000000000A061C053616C21C86B56400000000000A061C009A7052FFA6656400000000000A061C0F0332E1C086156400000000000A061C085471B47AC5956400000000000A061C0752497FF905056400000000000A061C08C84B69C4B4556400000000000A061C02C6519E2583756400000000000A061C02B357BA0152656400000000000A061C055C6BFCFB81056400000000000A061C0F988981249F655400000000000A061C08C321B6492D555400000000000A061C0ADC5A70018AD55400000000000A061C02254A9D9037B55400000000000A061C009E1D1C6113D55400000000000A061C0A0E5797077F054400000000000A061C0FA49B54FC79154400000000000A061C043959A3DD01C54400000000000A061C075EACA67798C53400000000000A061C00EE02D90A0DA52400000000000A061C000000000000052400000000000A061C000000000000052400000000000A061C00100000000004F400000000000A061C01730815B77274E408C45D3D9C99D61C04CAB21718F254E40C0120F289B9861C03EB324404D214E40745E6397A89061C0B9AAECBB221C4E406C3997E2AA8E61C09E465A2A6F274E4068666666667F61C0C9EA56CF49174E40F8D005F52D7661C01FF98381E72A4E408499B67F656261C01B69A9BC1D2D4E40C04351A04F6261C01CD82AC1E2284E40EC7C3F355E6661C0097250C24C0B4E40E8525C55F66161C001E31934F4FF4D406431B1F9B86161C0EDDD1FEF55FF4D407C4963B48E5961C06749809A5AF64D40703D0AD7A35661C0D60451F701F44D4080608E1EBF5561C0F22900C633EC4D40008750A5665561C048C49448A2E74D40205036E50A5461C0C481902C60E24D40283108AC1C4161C0C1E78711C2BB4D40B08009DCBA4061C0CA1F0C3CF7BA4D4010751F80D43E61C0029F1F4608B74D40A47EDE54A43E61C03CFC3559A3B64D405C3D27BD6F3361C00938842A359F4D40E85BE674593161C0F7D1A92B9F8D4D409820EA3E003061C019E76F42217E4D402883A3E4D53061C08833BF9A03744D40605E807D742E61C04E7FF62345744D40182B6A300D2961C06B82A8FB00804D40D0FBC6D79E2561C0C8F484251E844D4044DD0720B52261C0E46BCF2C09884D40DC9DB5DB2E2161C0AF47E17A148A4D40303D6189071F61C02A5C8FC2F58C4D40F8F719170E1C61C02259C0046E914D405031CEDF841A61C0AB2B9FE579944D401C649291B31261C077DB85E63A954D40A07A6B60AB0F61C03E963E7441A14D40247F30F0DC0F61C026E99AC937A34D402054A9D9030F61C04EB9C2BB5CA44D40C051F2EA1C0F61C0CE920035B5A84D409CF9D51C200F61C05B2A6F4738A94D40C86C9049460F61C05D8FC2F528B04D4008D3307C440F61C073BF4351A0BB4D40285C8FC2F50B61C03E61890794B94D40080C59DDEA0B61C030FA0AD28CB94D40D8166536C80B61C04C7155D977B94D400079AF5A990B61C005392861A6B94D40F836FDD98F0B61C0E8A4F78DAFB94D40D03FC1C58A0B61C0DA5A5F24B4B94D4058087250C20961C0650113B875BB4D401C5A643BDF0861C0C32FF5F3A6BE4D407862D68BA10761C0E627D53E1DC34D4020680586AC0761C03A5D16139BC74D40D02C0950530B61C07194BC3AC7CC4D4030EBC5504E0961C0988BF84ECCCE4D40CCAFE600C10861C07411DF8959CF4D40B81457957D0861C0EC8B84B69CCF4D400825CCB4FD0761C0F2EF332E1CD04D40703D0AD7A30761C023F8DF4A76D04D403837A6272C0661C0BD3AC780ECD14D40602D3E05C00261C05F2EE23B31D34D4018601F9DBA0161C057F146E691D34D409820EA3E000161C03AEE940ED6D34D406CB2463D440061C041C1C58A1AD44D4010FC6F253B0061C0C8F484251ED44D402CBCCB457CFE60C038328FFCC1D44D40C0BC00FBE8FB60C065AF777FBCD74D4080BC57AD4CFB60C0C7BFCFB870D84D40102DB29DEFF860C0BB490C022BDB4D40242D95B723F760C0E25D2EE23BDD4D402CE7525C55EF60C00B9DD7D825E64D40CC1E680586EB60C0EE9925016ADE4D400C022B8716E860C0B7B9313D61D94D40CC0182397AE760C0FFB7921D1BD94D40C095ECD808E760C0B1389CF9D5D44D40E47E87A240E560C0079E7B0F97D04D401C5036E50AE560C0013ACC9717D04D40C01C3D7E6FE460C03A2861A6EDCF4D40988F6B43C5E360C05665DF15C1CF4D40148733BF9AE360C0252367614FCF4D40D0A5B8AAECE060C040DEAB5626C84D40D4CA845FEAE060C09AB67F65A5C54D40901EBFB7E9E060C01B2FDD2406C54D40B05582C5E1E060C055E3A59BC4BC4D405014E81379E260C0537E52EDD3B94D40483D44A33BE360C08A07944DB9B64D40E8263108ACDF60C09A7CB3CD8DB14D4080F10C1AFAE060C04052448655AC4D40D8D825AAB7DE60C06B65C22FF5A34D40E874594C6CD660C01D5A643BDF9F4D40F82CCF83BBD560C063D68BA19C984D40B0683A3B19D260C046990D32C9904D407047382D78CF60C0CDE9B298D8904D4078978BF84ECE60C017139B8F6B8B4D4008B64AB038CC60C094DE37BEF6844D40303D618907CD60C069CBB914577D4D40140A117008CA60C0E644BB0A297B4D4054E3A59BC4CA60C0763C66A032764D40044CE0D6DDC960C025404D2D5B734D40A818E76F42C860C0FD6F253B366E4D40A41EA2D11DBF60C067F2CD3637624D40D0A92B9FE5BA60C07732384A5E5D4D4030B610E4A0B660C059FFE7305F4E4D40A0BE654E97B560C02CC1E270E64B4D4044813E9127B560C08A5E46B1DC4A4D40C09F1A2FDDB460C044FF04172B4A4D40DCD26A48DCB460C0284EEE77284A4D4028E3DF675CB360C04A29E8F692464D4048D74CBED9B160C05F9D6340F6424D4098395D1613AC60C09F7B0F971C374D40F00390DAC4AE60C0A80018CFA0314D40F8F719170EAB60C0AC730CC85E234D400C5EF415A4A860C01B4CC3F0111D4D4008E1D1C611A760C03208AC1C5A184D40E422BE13B3A660C08221AB5B3D174D404833164D67A660C0FCC6D79E59164D4070641EF983A560C073DC291DAC134D4020E527D53EA260C06B9F8EC70C004D40B0BAD573D29B60C0DEEA39E97DEB4C40F4D6C056099860C07884D38217D94C4064B48EAA269560C0D869A4A5F2CE4C4054C6BFCFB89160C081ECF5EE8FBF4C405CC47762D68B60C02AE8F692C6AC4C40446E861BF08760C0ADA8C1340C9B4C4060C8EA56CF8B60C096CFF23CB88B4C40D005F52D738160C07E5C1B2AC6854C40AC6EF59CF48360C088BF266BD46F4C40D8EBDD1FEF7B60C026CCB4FD2B674C402883A3E4D57C60C040A9F6E978604C40D03FC1C58A7B60C0448B6CE7FB594C40747632384A7B60C07D96E7C1DD554C40D0747632387B60C03815A930B6544C40F8B31F29227B60C074F4F8BD4D534C40D8868A71FE7A60C0FF7DC68503514C40600CE544BB7A60C0F88DAF3DB34C4C40C8D2872EA87960C046F0BF95EC4C4C40E04F8D976E7860C0A2B94E232D4D4C4054910A630B7860C08642041C424D4C40540E2DB29D7760C03ED00A0C594D4C40808B1535987660C005FF5BC98E4D4C40D09B8A54187560C036EA211ADD4D4C406891ED7C3F7460C019ADA3AA094E4C4050EDD3F1987260C059FFE7305F4E4C40446458C51B6F60C02EEC6987BF464C40280AF4893C6A60C0E46BCF2C09404C40E0AFC91AF56960C03A7AFCDEA63F4C408872A25D856960C0ADA8C1340C3F4C4018B2BAD5736960C043EC4CA1F33E4C4044088F368E6560C0C57762D68B394C40CCCCCCCCCC6260C0A4C7EF6DFA334C4058DDEA39E95E60C0613C8386FE314C4034164D67275E60C0709EEA909B314C40C8F99B50885D60C0FE2B2B4D4A314C40E07A14AE475D60C0D4D9C9E028314C4098F56228275C60C0EAEC647094304C40C0D84290835B60C0F246E6913F304C40981C774A075960C0CA1F0C3CF72E4C40900A630B415860C0B1AC3429052D4C40205ED72FD85760C0E44EE960FD2B4C40DC240681955760C0ECDD1FEF552B4C407C74EACA675760C0E6965643E22A4C40B04B546F0D5760C0CBBE2B82FF294C4034936FB6B95660C05B0D897B2C294C40285C8FC2F55560C0C9CD70033E274C40342905DD5E5560C08CA6B393C1254C4098728577B95460C07923F3C81F244C4044C02154A95460C01D9430D3F6234C40A82688BA0F5460C067834C3272224C4030815B77F35360C044FF04172B224C40E422BE13B35360C0DAEBDD1FEF214C40A47EDE54A45260C038A6272CF1204C403C1405FA445260C0079E7B0F97204C40C8681D554D5160C0B3632310AF1F4C4080F10C1AFA4E60C050AA7D3A1E1F4C405C33F9669B4E60C0DE0720B5891B4C409CC420B0724E60C03641D47D001A4C40C0FF56B2634E60C0B7D617096D194C40B46CAD2F124E60C092442FA358164C402891442FA34D60C0AF64C74620124C4090ED7C3F354B60C023F8DF4A76104C405CE15D2EE24760C0C7850321590C4C400CB08F4E5D4760C07177D66EBB0C4C40E097FA79534360C048FE60E0B90F4C40C8D2872EA84260C0EA263108AC0C4C4098395D16134260C052F2EA1C030A4C40902232ACE24160C029D027F224094C40B87EC16ED84160C094DE37BEF6084C40F00703CFBD4160C0EAB298D87C084C40DC9DB5DB2E4160C0DAEBDD1FEF054C40200C3CF71E4160C09AB67F65A5054C40686AD95A5F4060C067F2CD3637024C40A41EA2D11D4060C0A2629CBF09014C40C4724BAB214060C05D8FC2F528004C40F8B31F29224060C00FA14ACD1E004C409C16BCE82B4060C034F9669B1BFF4B40CC457C27664060C04DC3F01131F94B405C5A0D897B4060C0E6ED08A705F74B40DC0720B5894060C0B72DCA6C90F54B40BCD05CA7914060C0EA60FD9FC3F44B4054F146E6914060C07177D66EBBF44B40601A868F884060C07177D66EBBF44B409CF9D51C204060C07177D66EBBF44B409CF9D51C204060C0F20C1AFA27F44B406414CB2DAD4260C077BE9F1A2FE94B40B8533A58FF4360C06D5B94D920E74B40B05582C5E14460C0CBF8F71917E24B40F82CCF83BB4460C0174D672783DB4B40188BA6B3934360C0AC90F2936AD74B4004DD5ED2184460C00B2E56D460CA4B4044D3D9C9E04260C03AB4C876BEBF4B40EC5F5969524160C0E8FBA9F1D2B94B406414CB2DAD4060C05001309E41AB4B40900A630B413F60C0D205F52D73A64B40E4C281902C3F60C096B7239C16A44B4020020EA14A4360C0F870C971A7984B400035B56CAD4460C00BF4893C49924B40E0F3C308E14460C001E31934F48F4B402866BD18CA4560C0B3632310AF8B4B4048ACC5A7004660C0011DE6CB0B884B401881785DBF4860C07FA4880CAB7C4B40B46CAD2F124B60C0B7F3FDD478754B40480C022B874D60C0A553573ECB6F4B40C0D4CF9B8A4E60C0FF60E0B9F76C4B40889D29745E4F60C0F4716DA8186B4B40DC9DB5DB2E5260C0A96F99D365654B4000D9EBDD1F5460C0D678E92631644B4054AEF02E175560C0A81DFE9AAC614B40182FDD24065460C0E06C73637A5E4B403C3F8C101E5460C055E3A59BC45C4B408043A852B35360C0597380608E5A4B40044CE0D6DD9560C0CDCCCCCCCC544B406866666666DE60C01E03B2D7BB1B4B4000000000000061C00100000000004B400000000000E060C01E03B2D7BB5B4A400000000000F862C0132C0E677E614C4000000000002063C00100000000004C4000000000000064C00100000000C04A40F8B31F2922FA64C03433333333B34940F8B31F29221266C0B0C91AF51011494034333333332366401D03B2D7BB1B49402EE7525C555D64409A99999999D946400000000000E063404A63B48EAA0A494000000000002065400100000000004B40000000000040654003F1BA7EC1564B406766666666466540EACF7EA488684B4000000000008066400100000000004E4068666666668665C03433333333035040E8C6F484251F65C00000000000405040E8C6F484251F65C00000000000C0504078A1B94E231F65C00000000000005140')
+    ) as q(polygon)
+)
+SELECT 'geog_precision_pazafir', _ST_DistanceUnCached(pt.point, ply.polygon), ST_Distance(pt.point, ply.polygon) FROM pt, ply;
+
+
+-- Clean up spatial_ref_sys
+DELETE FROM spatial_ref_sys WHERE srid = 4326;
+    
diff --git a/regress/sfcgal/geography_expected b/regress/sfcgal/geography_expected
new file mode 100644 (file)
index 0000000..3359d12
--- /dev/null
@@ -0,0 +1,22 @@
+geog_distance_cached_1a|t
+geog_distance_cached_1b|t
+geog_distance_cached_1c|t
+geog_distance_cached_1e|t
+geog_distance_cached_1f|t
+geog_distance_cached_1g|t
+geog_distance_cached_1h|t
+geog_dithin_cached_1a|t
+geog_dithin_cached_1b|t
+geog_dithin_cached_1c|t
+geog_dithin_cached_2a|f
+geog_dithin_cached_2b|f
+geog_dithin_cached_2c|f
+geog_dithin_cached_3a|t
+geog_dithin_cached_3b|t
+geog_dithin_cached_3c|t
+geog_precision_savffir|0|0
+geog_precision_savffir|0|0
+geog_precision_savffir|0|0
+geog_precision_savffir|0|0
+geog_precision_pazafir|0|0
+geog_precision_pazafir|0|0
diff --git a/regress/sfcgal/legacy.sql b/regress/sfcgal/legacy.sql
new file mode 100644 (file)
index 0000000..db80f9a
--- /dev/null
@@ -0,0 +1,58 @@
+--
+-- These tests serve the purpose of ensuring compatibility with 
+-- old versions of postgis users.
+--
+-- Their use rely on loading the legacy.sql script.
+-- This file also serves as a testcase for uninstall_legacy.sql
+--
+
+SET postgis.backend = 'sfcgal';
+SET client_min_messages TO WARNING;
+
+\i 00-regress-install/share/contrib/postgis/legacy.sql
+
+INSERT INTO "spatial_ref_sys" ("srid","auth_name","auth_srid","srtext","proj4text") VALUES (4326,'EPSG',4326,'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs ');
+
+SELECT 'Starting up MapServer/Geoserver tests...';
+-- Set up the data table
+SELECT 'Setting up the data table...';
+CREATE TABLE public.wmstest ( id INTEGER );
+SELECT AddGeometryColumn( 'wmstest', 'pt', 4326, 'POLYGON', 2 );
+INSERT INTO wmstest SELECT lon * 100 + lat AS id, st_setsrid(st_buffer(st_makepoint(lon, lat),1.0),4326) AS pt
+FROM (select lon, generate_series(-80,80, 5) AS lat FROM (SELECT generate_series(-175, 175, 5) AS lon) AS sq1) AS sq2;
+ALTER TABLE wmstest add PRIMARY KEY ( id );
+CREATE INDEX wmstest_geomidx ON wmstest using gist ( pt );
+
+-- Geoserver 2.0 NG tests
+SELECT 'Running Geoserver 2.0 NG tests...';
+-- Run a Geoserver 2.0 NG metadata query
+SELECT 'Geoserver1', TYPE FROM GEOMETRY_COLUMNS WHERE F_TABLE_SCHEMA = 'public' AND F_TABLE_NAME = 'wmstest' AND F_GEOMETRY_COLUMN = 'pt';
+SELECT 'Geoserver2', SRID FROM GEOMETRY_COLUMNS WHERE F_TABLE_SCHEMA = 'public' AND F_TABLE_NAME = 'wmstest' AND F_GEOMETRY_COLUMN = 'pt';
+-- Run a Geoserver 2.0 NG WMS query
+SELECT 'Geoserver3', "id",substr(encode(asBinary(force_2d("pt"),'XDR'),'base64'),0,16) as "pt" FROM "public"."wmstest" WHERE "pt" && GeomFromText('POLYGON ((-6.58216065979069 -0.7685569763184591, -6.58216065979069 0.911225433349509, -3.050569931030911 0.911225433349509, -3.050569931030911 -0.7685569763184591, -6.58216065979069 -0.7685569763184591))', 4326);
+-- Run a Geoserver 2.0 NG KML query
+SELECT 'Geoserver4', count(*) FROM "public"."wmstest" WHERE "pt" && GeomFromText('POLYGON ((-1.504017942347938 24.0332272532341, -1.504017942347938 25.99364254836741, 1.736833353559741 25.99364254836741, 1.736833353559741 24.0332272532341, -1.504017942347938 24.0332272532341))', 4326);
+SELECT 'Geoserver5', "id",substr(encode(asBinary(force_2d("pt"),'XDR'),'base64'),0,16) as "pt" FROM "public"."wmstest" WHERE "pt" && GeomFromText('POLYGON ((-1.504017942347938 24.0332272532341, -1.504017942347938 25.99364254836741, 1.736833353559741 25.99364254836741, 1.736833353559741 24.0332272532341, -1.504017942347938 24.0332272532341))', 4326);
+SELECT 'Geoserver6', "id",substr(encode(asBinary(force_2d("pt"),'XDR'),'base64'),0,16) as "pt" FROM "public"."wmstest" WHERE "pt" && GeomFromText('POLYGON ((-1.507182836191598 24.031312785172446, -1.507182836191598 25.995557016429064, 1.7399982474034008 25.995557016429064, 1.7399982474034008 24.031312785172446, -1.507182836191598 24.031312785172446))', 4326);
+
+-- MapServer 5.4 tests
+select 'MapServer1', attname from pg_attribute, pg_constraint, pg_class where pg_constraint.conrelid = pg_class.oid and pg_class.oid = pg_attribute.attrelid and pg_constraint.contype = 'p' and pg_constraint.conkey[1] = pg_attribute.attnum and pg_class.relname = 'wmstest' and pg_table_is_visible(pg_class.oid) and pg_constraint.conkey[2] is null;
+select 'MapServer2', "id",substr(encode(AsBinary(force_collection(force_2d("pt")),'NDR'),'base64'),0,16) as geom,"id" from wmstest where pt && GeomFromText('POLYGON((-98.5 32,-98.5 39,-91.5 39,-91.5 32,-98.5 32))',find_srid('','wmstest','pt'));
+
+-- MapServer 5.6 tests
+select * from wmstest where false limit 0;
+select 'MapServer3', attname from pg_attribute, pg_constraint, pg_class where pg_constraint.conrelid = pg_class.oid and pg_class.oid = pg_attribute.attrelid and pg_constraint.contype = 'p' and pg_constraint.conkey[1] = pg_attribute.attnum and pg_class.relname = 'wmstest' and pg_table_is_visible(pg_class.oid) and pg_constraint.conkey[2] is null;
+select 'MapServer4', "id",substr(encode(AsBinary(force_collection(force_2d("pt")),'NDR'),'hex'),0,16) as geom,"id" from wmstest where pt && GeomFromText('POLYGON((-98.5 32,-98.5 39,-91.5 39,-91.5 32,-98.5 32))',find_srid('','wmstest','pt'));
+
+-- Drop the data table
+SELECT 'Removing the data table...';
+DROP TABLE wmstest;
+DELETE FROM geometry_columns WHERE f_table_name = 'wmstest' AND f_table_schema = 'public';
+SELECT 'Done.';
+
+-- test #1869 ST_AsBinary is not unique --
+SELECT 1869 As ticket_id, ST_AsText(ST_AsBinary('POINT(1 2)'));
+
+DELETE FROM spatial_ref_sys WHERE SRID = '4326';
+
+\i 00-regress-install/share/contrib/postgis/uninstall_legacy.sql
diff --git a/regress/sfcgal/legacy_expected b/regress/sfcgal/legacy_expected
new file mode 100644 (file)
index 0000000..d6f34e4
--- /dev/null
@@ -0,0 +1,22 @@
+Starting up MapServer/Geoserver tests...
+Setting up the data table...
+public.wmstest.pt SRID:4326 TYPE:POLYGON DIMS:2 
+ALTER TABLE
+Running Geoserver 2.0 NG tests...
+Geoserver1|POLYGON
+Geoserver2|4326
+Geoserver3|-500|AAAAAAMAAAABAAA
+Geoserver4|1
+Geoserver5|25|AAAAAAMAAAABAAA
+Geoserver6|25|AAAAAAMAAAABAAA
+MapServer1|id
+MapServer2|-9465|AQcAAAABAAAAAQM|-9465
+MapServer2|-9460|AQcAAAABAAAAAQM|-9460
+MapServer3|id
+MapServer4|-9465|010700000001000|-9465
+MapServer4|-9460|010700000001000|-9460
+Removing the data table...
+Done.
+1869|POINT(1 2)
+BEGIN
+COMMIT
diff --git a/regress/sfcgal/measures.sql b/regress/sfcgal/measures.sql
new file mode 100644 (file)
index 0000000..69b3a79
--- /dev/null
@@ -0,0 +1,264 @@
+SET postgis.backend = 'sfcgal';
+
+select '113', ST_area2d('MULTIPOLYGON( ((0 0, 10 0, 10 10, 0 10, 0 0)),( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5) ) ,( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7, 5 7, 5 5),(1 1,2 1, 2 2, 1 2, 1 1) ) )'::GEOMETRY) as value;
+
+select '114', ST_perimeter2d('MULTIPOLYGON( ((0 0, 10 0, 10 10, 0 10, 0 0)),( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5) ) ,( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7, 5 7, 5 5),(1 1,2 1, 2 2, 1 2, 1 1) ) )'::GEOMETRY) as value;
+
+select '115', ST_3DPerimeter('MULTIPOLYGON( ((0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0)),( (0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0),(5 5 0, 7 5 0, 7 7  0, 5 7 0, 5 5 0) ) ,( (0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1, 5 7 1, 5 5 1),(1 1 1,2 1 1, 2 2 1, 1 2 1, 1 1 1) ) )'::GEOMETRY) as value;
+
+
+select '116', ST_length2d('MULTILINESTRING((0 0, 1 1),(0 0, 1 1, 2 2) )'::GEOMETRY) as value;
+select '117', ST_3dlength('MULTILINESTRING((0 0, 1 1),(0 0, 1 1, 2 2) )'::GEOMETRY) as value;
+select '118', ST_3dlength('MULTILINESTRING((0 0 0, 1 1 1),(0 0 0, 1 1 1, 2 2 2) )'::GEOMETRY) as value;
+
+select '134', ST_Distance('POINT(1 2)', 'POINT(1 2)');
+select '135', ST_Distance('POINT(5 0)', 'POINT(10 12)');
+
+select '136', ST_Distance('POINT(0 0)', ST_translate('POINT(0 0)', 5, 12, 0));
+
+
+-- postgis-users/2006-May/012174.html
+select 'dist', ST_Distance(a,b), ST_Distance(b,a) from (
+       select 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry as a,
+               'POLYGON((11 0, 11 10, 20 10, 20 0, 11 0),
+                       (15 5, 15 8, 17 8, 17 5, 15 5))'::geometry as b
+       ) as foo;
+
+--#1502
+SELECT '#1502', ST_Dwithin(a,b,0.0)  from 
+(SELECT 'LINESTRING(-97364 -97364, 9736.4 9736.4)'::geometry a, 'POINT(0 0)'::geometry b ) foo;
+
+--st_shortestline
+
+select 'st_shortestline_134', st_astext(st_shortestline('POINT(1 2)', 'POINT(1 2)'));
+select 'st_shortestline_135', st_astext(st_shortestline('POINT(5 0)', 'POINT(10 12)'));
+
+select 'st_shortestline_136', st_astext(st_shortestline('POINT(0 0)', ST_translate('POINT(0 0)', 5, 12, 0)));
+
+-- postgis-users/2006-May/012174.html
+select 'st_shortestline_dist', st_astext(st_shortestline(a,b)), st_astext(st_shortestline(b,a)) from (
+       select 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry as a,
+               'POLYGON((11 0, 12 10, 20 10, 20 0, 11 0),
+                       (15 5, 15 8, 17 8, 17 5, 15 5))'::geometry as b
+       ) as foo;
+
+
+--st_maxdistance
+
+select 'st_maxdistance_134', st_maxdistance('POINT(1 2)', 'POINT(1 2)');
+select 'st_maxdistance_135', st_maxdistance('POINT(5 0)', 'POINT(10 12)');
+
+select 'st_maxdistance_136', st_maxdistance('POINT(0 0)', ST_translate('POINT(0 0)', 5, 12, 0));
+
+-- postgis-users/2006-May/012174.html
+select 'st_maxdistance_dist', st_maxdistance(a,b), st_maxdistance(b,a) from (
+       select 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry as a,
+               'POLYGON((11 0, 11 10, 20 10, 20 0, 11 0),
+                       (15 5, 15 8, 17 8, 17 5, 15 5))'::geometry as b
+       ) as foo;
+
+
+
+--st_longestline
+
+select 'st_longestline_134', st_astext(st_longestline('POINT(1 2)', 'POINT(1 2)'));
+select 'st_longestline_135', st_astext(st_longestline('POINT(5 0)', 'POINT(10 12)'));
+
+select 'st_longestline_136', st_astext(st_longestline('POINT(0 0)', ST_translate('POINT(0 0)', 5, 12, 0)));
+
+-- postgis-users/2006-May/012174.html
+select 'st_longestline_dist', st_astext(st_longestline(a,b)), st_astext(st_longestline(b,a)) from (
+       select 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry as a,
+               'POLYGON((11 0, 11 10, 20 10, 20 0, 11 0),
+                       (15 5, 15 8, 17 8, 17 5, 15 5))'::geometry as b
+       ) as foo;
+
+select 'distancetest1',                
+       ST_Distance(a, b),
+       st_maxdistance(a, b),
+       st_astext(st_shortestline(a,b)),
+       st_astext(st_shortestline(b,a)),
+       st_astext(st_longestline(a,b)),
+       st_astext(st_longestline(b,a)) from (
+select 
+       ST_GeomFromText('MULTILINESTRING((17 16, 16 17, 17 18, 17 17, 17 16), (28 35,29 39, 30 35))') as a,
+       ST_GeomFromText('MULTIPOLYGON(((-1 -1, -1 25, 25 25, 25 -1, -1 -1), (14 14,14 19,19 19,19 14,14 14)),((33 35,33 40, 35 40, 35 35, 33 35)))') as b
+) as foo;
+
+select  'distancetest2',
+       ST_Distance(a, b),
+       st_maxdistance(a, b),
+       round(st_x(st_startpoint(st_shortestline(a,b)))::numeric, 10),
+       round(st_y(st_startpoint(st_shortestline(a,b)))::numeric, 10),
+       round(st_x(st_endpoint(st_shortestline(a,b)))::numeric, 10),
+       round(st_y(st_endpoint(st_shortestline(a,b)))::numeric, 10),    
+       st_astext(st_longestline(a,b)),
+       st_astext(st_longestline(b,a)) from (
+select 
+       ST_GeomFromText('LINESTRING(-40 -20 , 4 2)') as a,
+       ST_GeomFromText('LINESTRING(-10 20, 1 -2)') as b
+) as foo;
+
+select 'distancepoly1',                
+       ST_Distance(a, b),
+       st_maxdistance(a, b),
+       st_astext(st_shortestline(a,b)),
+       st_astext(st_shortestline(b,a)),
+       st_astext(st_longestline(a,b)),
+       st_astext(st_longestline(b,a)) from (
+select 
+       ST_GeomFromText('MULTIPOLYGON(((17 16, 16 17, 17 18, 17 17, 17 16)), ((28 35,29 39, 30 35, 28 35)))') as a,
+       ST_GeomFromText('MULTIPOLYGON(((-1 -1, -1 25, 25 25, 25 -1, -1 -1), (14 14,14 19,19 19,19 14,14 14)),((33 35,33 40, 35 40, 35 35, 33 35)))') as b
+) as foo;
+
+select 'distancepoly2',                
+               ST_Distance(a, b),
+                       st_maxdistance(a, b),
+                               st_astext(st_shortestline(a,b)),
+                                       st_astext(st_shortestline(b,a)),
+                                               st_astext(st_longestline(a,b)),
+                                                       st_astext(st_longestline(b,a)) from (
+       select ST_GeomFromText('POLYGON((17 14, 16 17, 17 18, 17 17, 17 14))') as a,
+                       ST_GeomFromText('POLYGON((-1 -1, -1 25, 25 25, 25 -1, -1 -1), (14 14,14 19,19 19,19 14,14 14))') as b
+       ) as foo;
+
+
+
+select 'distancepoly3',                
+               ST_Distance(a, b),
+                       st_maxdistance(a, b),
+                               st_astext(st_shortestline(a,b)),
+                                       st_astext(st_shortestline(b,a)),
+                                               st_astext(st_longestline(a,b)),
+                                                       st_astext(st_longestline(b,a)) from (
+       select ST_GeomFromText('POLYGON((17 16, 16 17, 17 19, 17 17, 17 16))') as a,
+                       ST_GeomFromText('POLYGON((-1 -1, -1 25, 25 25, 25 -1, -1 -1), (14 14,14 19,19 19,19 14,14 14))') as b
+       ) as foo;
+
+
+select 'distancepoly4',                
+               ST_Distance(a, b),
+                       st_maxdistance(a, b),
+                               st_astext(st_shortestline(a,b)),
+                                       st_astext(st_shortestline(b,a)),
+                                               st_astext(st_longestline(a,b)),
+                                                       st_astext(st_longestline(b,a)) from (
+       select ST_GeomFromText('POLYGON((17 16, 16 17, 16 20, 18 20, 18 17, 17 16))') as a,
+                       ST_GeomFromText('POLYGON((-1 -1, -1 25, 25 25, 25 -1, -1 -1), (14 14,14 19,19 19,19 14,14 14))') as b
+       ) as foo;
+
+
+
+select 'distancepoly5',                
+               ST_Distance(a, b),
+                       st_maxdistance(a, b),
+                               st_astext(st_shortestline(a,b)),
+                                       st_astext(st_shortestline(b,a)),
+                                               st_astext(st_longestline(a,b)),
+                                                       st_astext(st_longestline(b,a)) from (
+       select ST_GeomFromText('POLYGON((17 12, 16 17, 17 18, 17 17, 17 12))') as a,
+                       ST_GeomFromText('POLYGON((-1 -1, -1 25, 25 25, 25 -1, -1 -1), (14 14,14 19,19 19,19 14,14 14))') as b
+       ) as foo;
+
+
+
+
+select 'distancepoly6',                
+               ST_Distance(a, b),
+                       st_maxdistance(a, b),
+                               st_astext(st_shortestline(a,b)),
+                                       st_astext(st_shortestline(b,a)),
+                                               st_astext(st_longestline(a,b)),
+                                                       st_astext(st_longestline(b,a)) from (
+       select ST_GeomFromText('POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))') as a,
+                       ST_GeomFromText('POLYGON((-1 -1, -1 25, 25 25, 25 -1, -1 -1), (14 14,14 19,19 19,19 14,14 14))') as b
+       ) as foo;
+
+--3D Distance functions
+
+
+SELECT '3dDistancetest1',
+       ST_3DDistance(a,b),
+               ST_3DMaxDistance(a,b),
+                       ST_3DDWithin(a,b,5),
+                               ST_3DDFullyWithin(a,b,5),
+                                       ST_ASEWKT(ST_3DShortestline(a,b)),
+                                               ST_ASEWKT(ST_3DClosestpoint(a,b)),
+                                                       ST_ASEWKT(ST_3DLongestline(a,b)) FROM (
+       SELECT 'POINT(1 1 1)'::geometry as a, 'POINT(3 2 7)'::geometry as b
+       ) as foo;
+       
+       
+SELECT '3dDistancetest2',
+       ST_3DDistance(a,b),
+               ST_3DMaxDistance(a,b),
+                       ST_3DDWithin(a,b,5),
+                               ST_3DDFullyWithin(a,b,5),
+                                       ST_ASEWKT(ST_3DShortestline(a,b)),
+                                               ST_ASEWKT(ST_3DClosestpoint(a,b)),
+                                                       ST_ASEWKT(ST_3DLongestline(a,b)) FROM (
+       SELECT 'POINT(1 1 1)'::geometry as a, 'LINESTRING(0 0 0, 2 2 2)'::geometry as b
+       ) as foo;
+       
+       
+SELECT '3dDistancetest3',
+       ST_3DDistance(a,b),
+               ST_3DMaxDistance(a,b),
+                       ST_3DDWithin(a,b,5),
+                               ST_3DDFullyWithin(a,b,5),
+                                       ST_ASEWKT(ST_SnapToGrid(ST_3DShortestline(a,b), 1e-14)),
+                                               ST_ASEWKT(ST_3DClosestpoint(a,b)),
+                                                       ST_ASEWKT(ST_3DLongestline(a,b)) FROM (
+       SELECT 'POINT(1 1 1)'::geometry as a, 'LINESTRING(5 2 6, -3 -2 4)'::geometry as b
+       ) as foo;
+       
+       
+SELECT '3dDistancetest4',
+       ST_3DDistance(a,b),
+               ST_3DMaxDistance(a,b),
+                       ST_3DDWithin(a,b,5),
+                               ST_3DDFullyWithin(a,b,5),
+                                       ST_ASEWKT(ST_3DShortestline(a,b)),
+                                               ST_ASEWKT(ST_3DClosestpoint(a,b)),
+                                                       ST_ASEWKT(ST_3DLongestline(a,b)) FROM (
+       SELECT  'LINESTRING(1 1 3, 5 7 8)'::geometry  as a, 'POINT(1 1 1)'::geometry as b
+       ) as foo;
+       
+       SELECT '3dDistancetest5',
+       ST_3DDistance(a,b),
+               ST_3DMaxDistance(a,b),
+                       ST_3DDWithin(a,b,5),
+                               ST_3DDFullyWithin(a,b,5),
+                                       ST_ASEWKT(ST_3DShortestline(a,b)),
+                                               ST_ASEWKT(ST_3DClosestpoint(a,b)),
+                                                       ST_ASEWKT(ST_3DLongestline(a,b)) FROM (
+       SELECT  'LINESTRING(1 0 5, 11 0 5)'::geometry  as a, 'LINESTRING(5 2 0, 5 2 10, 5 0 13)'::geometry as b
+       ) as foo;
+
+SELECT '3dDistancetest6',
+       ST_3DDistance(a,b) FROM (
+       SELECT 'LINESTRING(1 1 1 , 2 2 2)'::geometry as a, 'POLYGON((0 0 0, 2 2 2, 3 3 0, 0 0 0))'::geometry as b) as foo;      
+
+-- Area of an empty polygon
+select 'emptyPolyArea', st_area('POLYGON EMPTY');
+
+-- Area of an empty linestring
+select 'emptyLineArea', st_area('LINESTRING EMPTY');
+
+-- Area of an empty point
+select 'emptyPointArea', st_area('POINT EMPTY');
+
+-- Area of an empty multipolygon
+select 'emptyMultiPolyArea', st_area('MULTIPOLYGON EMPTY');
+
+-- Area of an empty multilinestring
+select 'emptyMultiLineArea', st_area('MULTILINESTRING EMPTY');
+
+-- Area of an empty multilipoint
+select 'emptyMultiPointArea', st_area('MULTIPOINT EMPTY');
+
+-- Area of an empty collection
+select 'emptyCollectionArea', st_area('GEOMETRYCOLLECTION EMPTY');
+
+-- 
+select 'spheroidLength1', round(st_length_spheroid('MULTILINESTRING((-118.584 38.374,-118.583 38.5),(-71.05957 42.3589 , -71.061 43))'::geometry,'SPHEROID["GRS_1980",6378137,298.257222101]'::spheroid)::numeric,5);
diff --git a/regress/sfcgal/measures_expected b/regress/sfcgal/measures_expected
new file mode 100644 (file)
index 0000000..f945b15
--- /dev/null
@@ -0,0 +1,45 @@
+113|291
+114|140
+115|140
+116|4.24264068711929
+117|4.24264068711929
+118|5.19615242270663
+134|0
+135|13
+136|13
+dist|1|1
+#1502|t
+st_shortestline_134|LINESTRING(1 2,1 2)
+st_shortestline_135|LINESTRING(5 0,10 12)
+st_shortestline_136|LINESTRING(0 0,5 12)
+st_shortestline_dist|LINESTRING(10 0,11 0)|LINESTRING(11 0,10 0)
+st_maxdistance_134|0
+st_maxdistance_135|13
+st_maxdistance_136|13
+st_maxdistance_dist|22.3606797749979|22.3606797749979
+st_longestline_134|LINESTRING(1 2,1 2)
+st_longestline_135|LINESTRING(5 0,10 12)
+st_longestline_136|LINESTRING(0 0,5 12)
+st_longestline_dist|LINESTRING(0 0,20 10)|LINESTRING(20 10,0 0)
+distancetest1|1|50|LINESTRING(17 18,17 19)|LINESTRING(17 19,17 18)|LINESTRING(29 39,-1 -1)|LINESTRING(-1 -1,29 39)
+distancetest2|0|50|0.0000000000|0.0000000000|0.0000000000|0.0000000000|LINESTRING(-40 -20,-10 20)|LINESTRING(-10 20,-40 -20)
+distancepoly1|1|50|LINESTRING(17 18,17 19)|LINESTRING(17 19,17 18)|LINESTRING(29 39,-1 -1)|LINESTRING(-1 -1,29 39)
+distancepoly2|0|26.1725046566048|LINESTRING(17 14,17 14)|LINESTRING(17 14,17 14)|LINESTRING(17 18,-1 -1)|LINESTRING(-1 -1,17 18)
+distancepoly3|0|26.9072480941474|LINESTRING(17 19,17 19)|LINESTRING(17 19,17 19)|LINESTRING(17 19,-1 -1)|LINESTRING(-1 -1,17 19)
+distancepoly4|0|28.3196045170126|LINESTRING(16 19,16 19)|LINESTRING(16 19,16 19)|LINESTRING(18 20,-1 -1)|LINESTRING(-1 -1,18 20)
+distancepoly5|0|26.1725046566048|LINESTRING(17 12,17 12)|LINESTRING(17 12,17 12)|LINESTRING(17 18,-1 -1)|LINESTRING(-1 -1,17 18)
+distancepoly6|0|32.5269119345812|LINESTRING(2 2,2 2)|LINESTRING(2 2,2 2)|LINESTRING(2 2,25 25)|LINESTRING(25 25,2 2)
+3dDistancetest1|6.40312423743285|6.40312423743285|f|f|LINESTRING(1 1 1,3 2 7)|POINT(1 1 1)|LINESTRING(1 1 1,3 2 7)
+3dDistancetest2|0|1.73205080756888|t|t|LINESTRING(1 1 1,1 1 1)|POINT(1 1 1)|LINESTRING(1 1 1,0 0 0)
+3dDistancetest3|4.09994192757944|6.48074069840786|t|f|LINESTRING(1 1 1,0.61904761904762 -0.19047619047619 4.90476190476191)|POINT(1 1 1)|LINESTRING(1 1 1,5 2 6)
+3dDistancetest4|2|10.0498756211209|t|f|LINESTRING(1 1 3,1 1 1)|POINT(1 1 3)|LINESTRING(5 7 8,1 1 1)
+3dDistancetest5|2|10|t|f|LINESTRING(5 0 5,5 2 5)|POINT(5 0 5)|LINESTRING(11 0 5,5 0 13)
+3dDistancetest6|0
+emptyPolyArea|0
+emptyLineArea|0
+emptyPointArea|0
+emptyMultiPolyArea|0
+emptyMultiLineArea|0
+emptyMultiPointArea|0
+emptyCollectionArea|0
+spheroidLength1|85204.52077
diff --git a/regress/sfcgal/regress.sql b/regress/sfcgal/regress.sql
new file mode 100644 (file)
index 0000000..969a528
--- /dev/null
@@ -0,0 +1,286 @@
+SET postgis.backend = 'sfcgal';
+--- regression test for postGIS
+
+
+
+--- assume datatypes already defined
+
+
+
+--- basic datatypes (correct)
+
+select '1',ST_asewkt('POINT( 1 2 )'::GEOMETRY) as geom;
+select '2',ST_asewkt('POINT( 1 2 3)'::GEOMETRY) as geom;
+
+select '3',ST_asewkt('LINESTRING( 0 0, 1 1, 2 2, 3 3 , 4 4)'::GEOMETRY) as geom;
+select '4',ST_asewkt('LINESTRING( 0 0 0 , 1 1 1 , 2 2 2 , 3 3 3, 4 4 4)'::GEOMETRY) as geom;
+select '5',ST_asewkt('LINESTRING( 1 2 3 , 4 5 6 , 7 8 9 , 10 11 12, 13 14 15)'::GEOMETRY) as geom;
+
+select '6',ST_asewkt('POLYGON( (0 0, 10 0, 10 10, 0 10, 0 0) )'::GEOMETRY) as geom;
+select '7',ST_asewkt('POLYGON( (0 0 1 , 10 0 1, 10 10 1, 0 10 1, 0 0 1) )'::GEOMETRY) as geom;
+select '8',ST_asewkt('POLYGON( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5) )'::GEOMETRY) as geom;
+select '9',ST_asewkt('POLYGON( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5),(1 1,2 1, 2 2, 1 2, 1 1) )'::GEOMETRY) as geom;
+select '10',ST_asewkt('POLYGON( (0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1 , 5 7 1, 5 5 1) )'::GEOMETRY) as geom;
+select '11',ST_asewkt('POLYGON( (0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1, 5 7 1, 5 5 1),(1 1 1,2 1 1, 2 2 1, 1 2 1, 1 1 1) )'::GEOMETRY) as geom;
+
+select '12',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 ))'::GEOMETRY);
+select '13',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 3))'::GEOMETRY);
+select '14',ST_asewkt('GEOMETRYCOLLECTION(LINESTRING( 0 0, 1 1, 2 2, 3 3 , 4 4))'::GEOMETRY);
+select '15',ST_asewkt('GEOMETRYCOLLECTION(LINESTRING( 1 2 3 , 4 5 6 , 7 8 9 , 10 11 12, 13 14 15))'::GEOMETRY);
+select '16',ST_asewkt('GEOMETRYCOLLECTION(POLYGON( (0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1 , 5 7 1, 5 5 1) ))'::GEOMETRY);
+select '17',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 0),POINT( 1 2 3) )'::GEOMETRY);
+select '18',ST_asewkt('GEOMETRYCOLLECTION(LINESTRING( 0 0 0, 1 1 0, 2 2 0, 3 3 0, 4 4 0),POINT( 1 2 3) )'::GEOMETRY);
+select '19',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 ),LINESTRING( 0 0, 1 1, 2 2, 3 3 , 4 4) )'::GEOMETRY);
+select '20',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 0 ),POINT( 1 2 3),LINESTRING( 1 2 3 , 4 5 6 , 7 8 9 , 10 11 12, 13 14 15) )'::GEOMETRY);
+select '21',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 0 ),POINT( 1 2 3),LINESTRING( 1 2 3 , 4 5 6 , 7 8 9 , 10 11 12, 13 14 15),POLYGON( (0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0) ) )'::GEOMETRY);
+select '22',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 0),POINT( 1 2 3),POLYGON( (0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1, 5 7 1, 5 5 1),(1 1 1,2 1 1, 2 2 1, 1 2 1, 1 1 1) ) )'::GEOMETRY);
+
+select '23',ST_asewkt('MULTIPOINT( 1 2)'::GEOMETRY) as geom;
+select '24',ST_asewkt('MULTIPOINT( 1 2 3)'::GEOMETRY) as geom;
+select '25',ST_asewkt('MULTIPOINT( 1 2, 3 4, 5 6)'::GEOMETRY) as geom;
+select '26',ST_asewkt('MULTIPOINT( 1 2 3, 5 6 7, 8 9 10, 11 12 13)'::GEOMETRY) as geom;
+select '27',ST_asewkt('MULTIPOINT( 1 2 0, 1 2 3, 4 5 0, 6 7 8)'::GEOMETRY) as geom;
+select '28',ST_asewkt('MULTIPOINT( 1 2 3,4 5 0)'::GEOMETRY) as geom;
+
+select '29',ST_asewkt('MULTILINESTRING( (0 0, 1 1, 2 2, 3 3 , 4 4) )'::GEOMETRY) as geom;
+select '30',ST_asewkt('MULTILINESTRING( (0 0, 1 1, 2 2, 3 3 , 4 4),(0 0, 1 1, 2 2, 3 3 , 4 4))'::GEOMETRY) as geom;
+select '31',ST_asewkt('MULTILINESTRING( (0 0 0, 1 1 0, 2 2 0, 3 3 0, 4 4 0),(0 0 0, 1 1 0, 2 2 0, 3 3 0, 4 4 0),(1 2 3 , 4 5 6 , 7 8 9 , 10 11 12, 13 14 15) )'::GEOMETRY) as geom;
+select '32',ST_asewkt('MULTILINESTRING( (1 2 3 , 4 5 6 , 7 8 9 , 10 11 12, 13 14 15),(0 0 0, 1 1 0, 2 2 0, 3 3 0, 4 4 0),(0 0 0, 1 1 0, 2 2 0, 3 3 0 , 4 4 0))'::GEOMETRY) as geom;
+
+select '33',ST_asewkt('MULTIPOLYGON( ((0 0, 10 0, 10 10, 0 10, 0 0)) )'::GEOMETRY) as geom;
+select '34',ST_asewkt('MULTIPOLYGON( ((0 0, 10 0, 10 10, 0 10, 0 0)),( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5) ) )'::GEOMETRY) as geom;
+select '35',ST_asewkt('MULTIPOLYGON( ((0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0)),( (0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0),(5 5 0, 7 5 0, 7 7 0, 5 7 0, 5 5 0) ) ,( (0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1, 5 7 1, 5 5 1),(1 1 1,2 1 1, 2 2 1, 1 2 1, 1 1 1) ) )'::GEOMETRY) as geom;
+
+
+select '36',ST_asewkt('GEOMETRYCOLLECTION(MULTIPOINT( 1 2))'::GEOMETRY);
+select '37',ST_asewkt('GEOMETRYCOLLECTION(MULTIPOINT( 1 2 3))'::GEOMETRY);
+select '38',ST_asewkt('GEOMETRYCOLLECTION(MULTIPOINT( 1 2 3, 5 6 7, 8 9 10, 11 12 13))'::GEOMETRY);
+select '39',ST_asewkt('GEOMETRYCOLLECTION(MULTILINESTRING( (0 0, 1 1, 2 2, 3 3 , 4 4) ))'::GEOMETRY);
+select '40',ST_asewkt('GEOMETRYCOLLECTION(MULTILINESTRING( (1 2 3 , 4 5 6 , 7 8 9 , 10 11 12, 13 14 15),(0 0 0, 1 1 0, 2 2 0, 3 3 0, 4 4 0),(0 0 0, 1 1 0, 2 2 0, 3 3 0, 4 4 0)))'::GEOMETRY);
+select '41',ST_asewkt('GEOMETRYCOLLECTION(MULTIPOLYGON( ((0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0)),( (0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0),(5 5 0, 7 5 0, 7 7 0, 5 7 0, 5 5 0) ) ,( (0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1, 5 7 1, 5 5 1),(1 1 1,2 1 1, 2 2 1, 1 2 1, 1 1 1) ) ))'::GEOMETRY);
+select '42',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 0),MULTIPOINT( 1 2 3))'::GEOMETRY);
+select '43',ST_asewkt('GEOMETRYCOLLECTION(MULTIPOINT( 1 2 0, 3 4 0, 5 6 0),POINT( 1 2 3))'::GEOMETRY);
+select '44',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 3),MULTILINESTRING( (0 0 0, 1 1 0, 2 2 0, 3 3 0 , 4 4 0) ))'::GEOMETRY);
+select '45',ST_asewkt('GEOMETRYCOLLECTION(MULTILINESTRING( (0 0 0, 1 1 0, 2 2 0, 3 3 0 , 4 4 0) ),POINT( 1 2 3))'::GEOMETRY);
+select '46',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 3), MULTIPOLYGON( ((0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0)),( (0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0),(5 5 0, 7 5 0, 7 7 0, 5 7 0, 5 5 0) ) ,( (0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1, 5 7 1, 5 5 1),(1 1 1,2 1 1, 2 2 1, 1 2 1, 1 1 1) ) ))'::GEOMETRY);
+select '47',ST_asewkt('GEOMETRYCOLLECTION(MULTIPOLYGON( ((0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0)),( (0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0),(5 5 0, 7 5 0, 7 7 0, 5 7 0, 5 5 0) ) ,( (0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1, 5 7 1, 5 5 1),(1 1 1,2 1 1, 2 2 1, 1 2 1, 1 1 1) ) ),MULTILINESTRING( (0 0 0, 1 1 0, 2 2 0, 3 3 0, 4 4 0),(0 0 0, 1 1 0, 2 2 0, 3 3 0, 4 4 0),(1 2 3 , 4 5 6 , 7 8 9 , 10 11 12, 13 14 15) ),MULTIPOINT( 1 2 3, 5 6 7, 8 9 10, 11 12 13))'::GEOMETRY);
+
+select '48',ST_asewkt('MULTIPOINT( -1 -2 -3, 5.4 6.6 7.77, -5.4 -6.6 -7.77, 1e6 1e-6 -1e6, -1.3e-6 -1.4e-5 0)'::GEOMETRY) as geom;
+
+select '49', ST_asewkt('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(1 1) ))'::GEOMETRY) as geom;
+--- basic datatype (incorrect)
+
+select '50', 'POINT()'::GEOMETRY as geom;
+select '51', 'POINT(1)'::GEOMETRY as geom;
+select '52', 'POINT(,)'::GEOMETRY as geom;
+select '53', 'MULTIPOINT(,)'::GEOMETRY as geom;
+select '54', 'POINT(a b)'::GEOMETRY as geom;
+select '55', 'MULTIPOINT()'::GEOMETRY as geom;
+select '56', ST_asewkt('POLYGON( (0 0, 10 0, 10 10, 0 10) )'::GEOMETRY);
+select '57', ST_asewkt('POLYGON( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7) )'::GEOMETRY);
+select '58', ST_asewkt('MULTILINESTRING((0 0, 1 1),(0 0, 1 1, 2 2,) )'::GEOMETRY);
+
+
+--- funny results
+
+select '59',ST_asewkt('POINT(1 2 3, 4 5 6)'::GEOMETRY);
+select '60',ST_asewkt('POINT(1 2 3 4 5 6 7)'::GEOMETRY);
+select '61',ST_asewkt('LINESTRING(1 1)'::GEOMETRY);
+select '62',regexp_replace(ST_asewkt('POINT( 1e700 0)'::GEOMETRY), E'(Infinity|1\.#INF)', 'inf');
+select '63',regexp_replace(ST_asewkt('POINT( -1e700 0)'::GEOMETRY), E'(Infinity|1\.#INF)', 'inf');
+--select '62',ST_asewkt('POINT( 1e700 0)'::GEOMETRY);
+--select '63',ST_asewkt('POINT( -1e700 0)'::GEOMETRY);
+select '64',ST_asewkt('MULTIPOINT(1 1, 2 2'::GEOMETRY);
+
+
+--- is_same() testing
+
+select '65','POINT(1 1)'::GEOMETRY ~= 'POINT(1 1)'::GEOMETRY as bool;
+select '65a',ST_OrderingEquals('POINT(1 1)'::GEOMETRY,'POINT(1 1)'::GEOMETRY) as bool;
+select '66','POINT(1 1 0)'::GEOMETRY ~= 'POINT(1 1)'::GEOMETRY as bool;
+select '66a',ST_OrderingEquals('POINT(1 1 0)'::GEOMETRY,'POINT(1 1)'::GEOMETRY) as bool;
+select '67','POINT(1 1 0)'::GEOMETRY ~= 'POINT(1 1 0)'::GEOMETRY as bool;
+select '67a',ST_OrderingEquals('POINT(1 1 0)'::GEOMETRY,'POINT(1 1 0)'::GEOMETRY) as bool;
+
+select '68','MULTIPOINT(1 1,2 2)'::GEOMETRY ~= 'MULTIPOINT(1 1,2 2)'::GEOMETRY as bool;
+select '68a',ST_OrderingEquals('MULTIPOINT(1 1,2 2)'::GEOMETRY,'MULTIPOINT(1 1,2 2)'::GEOMETRY) as bool;
+select '69','MULTIPOINT(2 2, 1 1)'::GEOMETRY ~= 'MULTIPOINT(1 1,2 2)'::GEOMETRY as bool;
+select '69a',ST_OrderingEquals('MULTIPOINT(2 2, 1 1)'::GEOMETRY,'MULTIPOINT(1 1,2 2)'::GEOMETRY) as bool;
+
+select '70','GEOMETRYCOLLECTION(POINT( 1 2 3),POINT(4 5 6))'::GEOMETRY ~= 'GEOMETRYCOLLECTION(POINT( 4 5 6),POINT(1 2 3))'::GEOMETRY as bool;
+select '70a',ST_OrderingEquals('GEOMETRYCOLLECTION(POINT( 1 2 3),POINT(4 5 6))'::GEOMETRY,'GEOMETRYCOLLECTION(POINT( 4 5 6),POINT(1 2 3))'::GEOMETRY) as bool;
+select '71','MULTIPOINT(4 5 6, 1 2 3)'::GEOMETRY ~= 'GEOMETRYCOLLECTION(POINT( 4 5 6),POINT(1 2 3))'::GEOMETRY as bool;
+select '71a',ST_OrderingEquals('MULTIPOINT(4 5 6, 1 2 3)'::GEOMETRY,'GEOMETRYCOLLECTION(POINT( 4 5 6),POINT(1 2 3))'::GEOMETRY) as bool;
+select '72','MULTIPOINT(1 2 3, 4 5 6)'::GEOMETRY ~= 'GEOMETRYCOLLECTION(POINT( 4 5 6),POINT(1 2 3))'::GEOMETRY as bool;
+select '72a',ST_OrderingEquals('MULTIPOINT(1 2 3, 4 5 6)'::GEOMETRY,'GEOMETRYCOLLECTION(POINT( 4 5 6),POINT(1 2 3))'::GEOMETRY) as bool;
+select '73','MULTIPOINT(1 2 3, 4 5 6)'::GEOMETRY ~= 'GEOMETRYCOLLECTION(MULTIPOINT(1 2 3, 4 5 6))'::GEOMETRY as bool;
+select '73a',ST_OrderingEquals('MULTIPOINT(1 2 3, 4 5 6)'::GEOMETRY,'GEOMETRYCOLLECTION(MULTIPOINT(1 2 3, 4 5 6))'::GEOMETRY) as bool;
+
+
+select '74','LINESTRING(1 1,2 2)'::GEOMETRY ~= 'POINT(1 1)'::GEOMETRY as bool;
+select '74a',ST_OrderingEquals('LINESTRING(1 1,2 2)'::GEOMETRY,'POINT(1 1)'::GEOMETRY) as bool;
+select '75','LINESTRING(1 1, 2 2)'::GEOMETRY ~= 'LINESTRING(2 2, 1 1)'::GEOMETRY as bool;
+select '75a',ST_OrderingEquals('LINESTRING(1 1, 2 2)'::GEOMETRY,'LINESTRING(2 2, 1 1)'::GEOMETRY) as bool;
+select '76','LINESTRING(1 1, 2 2)'::GEOMETRY ~= 'LINESTRING(1 1, 2 2, 3 3)'::GEOMETRY as bool;
+select '76a',ST_OrderingEquals('LINESTRING(1 1, 2 2)'::GEOMETRY,'LINESTRING(1 1, 2 2, 3 3)'::GEOMETRY) as bool;
+
+--- operator testing (testing is on the BOUNDING BOX (2d), not the actual geometries)
+
+select '77','POINT(1 1)'::GEOMETRY &< 'POINT(1 1)'::GEOMETRY as bool;
+select '78','POINT(1 1)'::GEOMETRY &< 'POINT(2 1)'::GEOMETRY as bool;
+select '79','POINT(2 1)'::GEOMETRY &< 'POINT(1 1)'::GEOMETRY as bool;
+
+select '80','POINT(1 1)'::GEOMETRY << 'POINT(1 1)'::GEOMETRY as bool;
+select '81','POINT(1 1)'::GEOMETRY << 'POINT(2 1)'::GEOMETRY as bool;
+select '82','POINT(2 1)'::GEOMETRY << 'POINT(1 1)'::GEOMETRY as bool;
+
+
+select '83','POINT(1 1)'::GEOMETRY &> 'POINT(1 1)'::GEOMETRY as bool;
+select '84','POINT(1 1)'::GEOMETRY &> 'POINT(2 1)'::GEOMETRY as bool;
+select '85','POINT(2 1)'::GEOMETRY &> 'POINT(1 1)'::GEOMETRY as bool;
+
+select '86','POINT(1 1)'::GEOMETRY >> 'POINT(1 1)'::GEOMETRY as bool;
+select '87','POINT(1 1)'::GEOMETRY >> 'POINT(2 1)'::GEOMETRY as bool;
+select '88','POINT(2 1)'::GEOMETRY >> 'POINT(1 1)'::GEOMETRY as bool;
+
+-- overlap
+
+select '89','POINT(1 1)'::GEOMETRY && 'POINT(1 1)'::GEOMETRY as bool;
+select '90','POINT(1 1)'::GEOMETRY && 'POINT(2 2)'::GEOMETRY as bool;
+select '91','MULTIPOINT(0 0, 1 1)'::GEOMETRY && 'MULTIPOINT(1 1, 2 2)'::GEOMETRY as bool;
+select '92','MULTIPOINT(0 0, 1 1)'::GEOMETRY && 'MULTIPOINT(1.0001 1, 2 2)'::GEOMETRY as bool;
+select '93','MULTIPOINT(0 0, 1 1)'::GEOMETRY && 'MULTIPOINT(1 1.0001, 2 2)'::GEOMETRY as bool;
+select '94','MULTIPOINT(0 0, 1 1)'::GEOMETRY && 'MULTIPOINT(1 0, 2 2)'::GEOMETRY as bool;
+select '95','MULTIPOINT(0 0, 1 1)'::GEOMETRY && 'MULTIPOINT(1.0001 0, 2 2)'::GEOMETRY as bool;
+
+select '96','MULTIPOINT(0 0, 1 1)'::GEOMETRY && 'MULTIPOINT(0 1, 1 2)'::GEOMETRY as bool;
+select '97','MULTIPOINT(0 0, 1 1)'::GEOMETRY && 'MULTIPOINT(0 1.0001, 1 2)'::GEOMETRY as bool;
+
+--- contains 
+
+select '98','MULTIPOINT(0 0, 10 10)'::GEOMETRY ~ 'MULTIPOINT(5 5, 7 7)'::GEOMETRY as bool;
+select '99','MULTIPOINT(5 5, 7 7)'::GEOMETRY ~ 'MULTIPOINT(0 0, 10 10)'::GEOMETRY as bool;
+select '100','MULTIPOINT(0 0, 7 7)'::GEOMETRY ~ 'MULTIPOINT(0 0, 10 10)'::GEOMETRY as bool;
+select '101','MULTIPOINT(-0.0001 0, 7 7)'::GEOMETRY ~ 'MULTIPOINT(0 0, 10 10)'::GEOMETRY as bool;
+
+--- contained by 
+
+select '102','MULTIPOINT(0 0, 10 10)'::GEOMETRY @ 'MULTIPOINT(5 5, 7 7)'::GEOMETRY as bool;
+select '103','MULTIPOINT(5 5, 7 7)'::GEOMETRY @ 'MULTIPOINT(0 0, 10 10)'::GEOMETRY as bool;
+select '104','MULTIPOINT(0 0, 7 7)'::GEOMETRY @ 'MULTIPOINT(0 0, 10 10)'::GEOMETRY as bool;
+select '105','MULTIPOINT(-0.0001 0, 7 7)'::GEOMETRY @ 'MULTIPOINT(0 0, 10 10)'::GEOMETRY as bool;
+
+
+
+--- function testing
+--- conversion function
+
+select '106',box3d('MULTIPOINT(0 0, 7 7)'::GEOMETRY) as bvol;
+
+-- box3d only type is only used for indexing -- NEVER use one yourself
+select '107',ST_AsEWKT(geometry('BOX3D(0 0 0, 7 7 7 )'::BOX3D));
+
+--- debug function testing
+
+select '108',ST_NPoints('MULTIPOINT(0 0, 7 7)'::GEOMETRY) as value;
+select '109',ST_NPoints('GEOMETRYCOLLECTION(POINT(1 1), LINESTRING( 1 1 , 2 2, 3 3))'::GEOMETRY) as value;
+
+select '110', ST_NRings('MULTIPOLYGON( ((0 0, 10 0, 10 10, 0 10, 0 0)),( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5) ) ,( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7, 5 7, 5 5),(1 1,2 1, 2 2, 1 2, 1 1) ) )'::GEOMETRY) as value;
+
+select '111', ST_mem_size(PostGIS_DropBBOX('MULTIPOLYGON( ((0 0, 10 0, 10 10, 0 10, 0 0)),( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5) ) ,( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7, 5 7, 5 5),(1 1,2 1, 2 2, 1 2, 1 1) ) )'::GEOMETRY)) as value;
+
+select '112',ST_NumGeometries('GEOMETRYCOLLECTION(POINT(1 1), LINESTRING( 1 1 , 2 2, 3 3),MULTIPOINT(1 1, 2 2))'::GEOMETRY) as value;
+
+---selection
+
+
+
+--- TOAST testing
+
+-- create a table with data that will be TOASTed (even after compression)
+create table TEST(a GEOMETRY, b GEOMETRY);
+\i regress_biginsert.sql
+
+
+---test basic ops on this 
+
+select '121',box3d(a) as box3d_a, box3d(b) as box3d_b from TEST;
+
+select '122',a <<b from TEST;
+select '123',a &<b from TEST;
+select '124',a >>b from TEST;
+select '125',a &>b from TEST;
+
+select '126',a ~= b from TEST;
+select '127',a @ b from TEST;
+select '128',a ~ b from TEST; 
+
+select '129', ST_mem_size(PostGIS_DropBBOX(a)), ST_mem_size(PostGIS_DropBBOX(b)) from TEST;
+
+select '131', ST_X('POINT(1 2)');
+select '132', ST_Y('POINT(1 2)');
+select '133', ST_Z('POINT(1 2)');
+select '133a', ST_Z('POINT(1 2 3)');
+select '133b', ST_Z('POINTM(1 2 3)');
+select '133c', ST_M('POINT(1 2)');
+select '133d', ST_M('POINTM(1 2 4)');
+select '133e', ST_M('POINT(1 2 4)');
+
+select '137', box3d('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY)'::geometry);
+select '138', box3d('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY, POINT(0 0))'::geometry);
+
+select '139', ST_AsEWKT(ST_multi(ST_setsrid('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY, POINT(0 0))'::geometry, 2)));
+select '140', ST_AsEWKT(ST_multi(ST_setsrid('POINT(2 2)'::geometry, 3)));
+select '141', ST_AsEWKT(ST_multi(ST_setsrid('LINESTRING(2 2, 3 3)'::geometry, 4)));
+select '142', ST_AsEWKT(ST_multi(ST_setsrid('LINESTRING(2 2, 3 3)'::geometry, 5)));
+select '143', ST_AsEWKT(ST_multi(ST_setsrid('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))'::geometry, 6)));
+select '143c1', ST_AsEWKT(ST_multi('CIRCULARSTRING(0 0, 1 1, 2 2)'::geometry));
+select '144', ST_AsEWKT(ST_force_3dm('POINT(1 2 3)'));
+select '145', ST_AsEWKT(ST_force_3dz('POINTM(1 2 3)'));
+select '146', ST_AsEWKT(ST_force_4d('POINTM(1 2 3)'));
+select '147', ST_AsEWKT(ST_force_4d('POINT(1 2 3)'));
+
+select '148', ST_AsText(ST_segmentize('LINESTRING(0 0, 10 0)'::geometry, 5));
+
+select '149', ST_AsText(ST_segmentize('GEOMETRYCOLLECTION EMPTY'::geometry, 0.5));
+
+select '150', ST_AsEWKT(ST_force_collection(ST_setsrid('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))'::geometry, 6)));
+
+select '151', ST_MakeEnvelope(0, 0, 1, 1, 4326);
+select '152', ST_SRID(ST_MakeEnvelope(0, 0, 1, 1, 4326));
+select '152.1', ST_SRID(ST_MakeEnvelope(0, 0, 1, 1)) = ST_SRID('POINT(0 0)'::geometry);
+select '152.2', ST_SRID(ST_SetSRID(ST_MakeEnvelope(0, 0, 1, 1), 4326));
+
+select '153', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(POINT(0 0))',1));
+select '154', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(0 0)))',1));
+select '155', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(0 0), POINT(1 1)))',1));
+select '156', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)))',1));
+select '157', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)))',2));
+select '158', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)),LINESTRING(2 2, 3 3))',2));
+select '159', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)),LINESTRING(2 2, 3 3))',3));
+select '160', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)),LINESTRING(2 2, 3 3))',1));
+select '161', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), GEOMETRYCOLLECTION(POINT(1 1))),LINESTRING(2 2, 3 3))',2));
+select '162', ST_MakeLine(ST_GeomFromText('POINT(-11.1111111 40)'),ST_GeomFromText('LINESTRING(-11.1111111 70,70 -11.1111111)')) As result;
+select '163', ST_AsEWKT('POLYGON((0 0 0, 1 0 0, 1 1 0, 0 1 0, 0 0 0))');
+select '164', ST_AsEWKT('POLYGON((0 0 0, 1 0 0, 1 1 0, 0 1 0, 0 0 1))');
+select '165', ST_AsEWKT('POLYGON((0 0 0, 1 0 0, 1 1 0, 0 1 0, 0 0.1 1))');
+select '166', ST_AsText('POINT EMPTY');
+select '167', ST_AsText('LINESTRING EMPTY');
+select '168', ST_AsText('POLYGON EMPTY');
+select '169', ST_AsText('CIRCULARSTRING EMPTY');
+select '170', ST_AsText('COMPOUNDCURVE EMPTY');
+select '171', ST_AsText('CURVEPOLYGON EMPTY');
+select '172', ST_AsText('MULTIPOINT EMPTY');
+select '173', ST_AsText('MULTILINESTRING EMPTY');
+select '174', ST_AsText('MULTIPOLYGON EMPTY');
+select '175', ST_AsText('TRIANGLE EMPTY');
+select '176', ST_AsText('TIN EMPTY');
+select '177', ST_AsText('POLYHEDRALSURFACE EMPTY');
+select '178', ST_AsText('MULTISURFACE EMPTY');
+select '179', ST_AsText('MULTICURVE EMPTY');
+select '180', ST_AsText('GEOMETRYCOLLECTION EMPTY');
+select '181', ST_AsText('GEOMETRYCOLLECTION(TRIANGLE EMPTY,TIN EMPTY)');
+
+
+-- Drop test table
+DROP table test;
diff --git a/regress/sfcgal/regress_expected b/regress/sfcgal/regress_expected
new file mode 100644 (file)
index 0000000..6c409ad
--- /dev/null
@@ -0,0 +1,189 @@
+1|POINT(1 2)
+2|POINT(1 2 3)
+3|LINESTRING(0 0,1 1,2 2,3 3,4 4)
+4|LINESTRING(0 0 0,1 1 1,2 2 2,3 3 3,4 4 4)
+5|LINESTRING(1 2 3,4 5 6,7 8 9,10 11 12,13 14 15)
+6|POLYGON((0 0,10 0,10 10,0 10,0 0))
+7|POLYGON((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1))
+8|POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5))
+9|POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5),(1 1,2 1,2 2,1 2,1 1))
+10|POLYGON((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1))
+11|POLYGON((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1),(1 1 1,2 1 1,2 2 1,1 2 1,1 1 1))
+12|GEOMETRYCOLLECTION(POINT(1 2))
+13|GEOMETRYCOLLECTION(POINT(1 2 3))
+14|GEOMETRYCOLLECTION(LINESTRING(0 0,1 1,2 2,3 3,4 4))
+15|GEOMETRYCOLLECTION(LINESTRING(1 2 3,4 5 6,7 8 9,10 11 12,13 14 15))
+16|GEOMETRYCOLLECTION(POLYGON((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1)))
+17|GEOMETRYCOLLECTION(POINT(1 2 0),POINT(1 2 3))
+18|GEOMETRYCOLLECTION(LINESTRING(0 0 0,1 1 0,2 2 0,3 3 0,4 4 0),POINT(1 2 3))
+19|GEOMETRYCOLLECTION(POINT(1 2),LINESTRING(0 0,1 1,2 2,3 3,4 4))
+20|GEOMETRYCOLLECTION(POINT(1 2 0),POINT(1 2 3),LINESTRING(1 2 3,4 5 6,7 8 9,10 11 12,13 14 15))
+21|GEOMETRYCOLLECTION(POINT(1 2 0),POINT(1 2 3),LINESTRING(1 2 3,4 5 6,7 8 9,10 11 12,13 14 15),POLYGON((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0)))
+22|GEOMETRYCOLLECTION(POINT(1 2 0),POINT(1 2 3),POLYGON((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1),(1 1 1,2 1 1,2 2 1,1 2 1,1 1 1)))
+23|MULTIPOINT(1 2)
+24|MULTIPOINT(1 2 3)
+25|MULTIPOINT(1 2,3 4,5 6)
+26|MULTIPOINT(1 2 3,5 6 7,8 9 10,11 12 13)
+27|MULTIPOINT(1 2 0,1 2 3,4 5 0,6 7 8)
+28|MULTIPOINT(1 2 3,4 5 0)
+29|MULTILINESTRING((0 0,1 1,2 2,3 3,4 4))
+30|MULTILINESTRING((0 0,1 1,2 2,3 3,4 4),(0 0,1 1,2 2,3 3,4 4))
+31|MULTILINESTRING((0 0 0,1 1 0,2 2 0,3 3 0,4 4 0),(0 0 0,1 1 0,2 2 0,3 3 0,4 4 0),(1 2 3,4 5 6,7 8 9,10 11 12,13 14 15))
+32|MULTILINESTRING((1 2 3,4 5 6,7 8 9,10 11 12,13 14 15),(0 0 0,1 1 0,2 2 0,3 3 0,4 4 0),(0 0 0,1 1 0,2 2 0,3 3 0,4 4 0))
+33|MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0)))
+34|MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0)),((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5)))
+35|MULTIPOLYGON(((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0)),((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0),(5 5 0,7 5 0,7 7 0,5 7 0,5 5 0)),((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1),(1 1 1,2 1 1,2 2 1,1 2 1,1 1 1)))
+36|GEOMETRYCOLLECTION(MULTIPOINT(1 2))
+37|GEOMETRYCOLLECTION(MULTIPOINT(1 2 3))
+38|GEOMETRYCOLLECTION(MULTIPOINT(1 2 3,5 6 7,8 9 10,11 12 13))
+39|GEOMETRYCOLLECTION(MULTILINESTRING((0 0,1 1,2 2,3 3,4 4)))
+40|GEOMETRYCOLLECTION(MULTILINESTRING((1 2 3,4 5 6,7 8 9,10 11 12,13 14 15),(0 0 0,1 1 0,2 2 0,3 3 0,4 4 0),(0 0 0,1 1 0,2 2 0,3 3 0,4 4 0)))
+41|GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0)),((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0),(5 5 0,7 5 0,7 7 0,5 7 0,5 5 0)),((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1),(1 1 1,2 1 1,2 2 1,1 2 1,1 1 1))))
+42|GEOMETRYCOLLECTION(POINT(1 2 0),MULTIPOINT(1 2 3))
+43|GEOMETRYCOLLECTION(MULTIPOINT(1 2 0,3 4 0,5 6 0),POINT(1 2 3))
+44|GEOMETRYCOLLECTION(POINT(1 2 3),MULTILINESTRING((0 0 0,1 1 0,2 2 0,3 3 0,4 4 0)))
+45|GEOMETRYCOLLECTION(MULTILINESTRING((0 0 0,1 1 0,2 2 0,3 3 0,4 4 0)),POINT(1 2 3))
+46|GEOMETRYCOLLECTION(POINT(1 2 3),MULTIPOLYGON(((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0)),((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0),(5 5 0,7 5 0,7 7 0,5 7 0,5 5 0)),((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1),(1 1 1,2 1 1,2 2 1,1 2 1,1 1 1))))
+47|GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0)),((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0),(5 5 0,7 5 0,7 7 0,5 7 0,5 5 0)),((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1),(1 1 1,2 1 1,2 2 1,1 2 1,1 1 1))),MULTILINESTRING((0 0 0,1 1 0,2 2 0,3 3 0,4 4 0),(0 0 0,1 1 0,2 2 0,3 3 0,4 4 0),(1 2 3,4 5 6,7 8 9,10 11 12,13 14 15)),MULTIPOINT(1 2 3,5 6 7,8 9 10,11 12 13))
+48|MULTIPOINT(-1 -2 -3,5.4 6.6 7.77,-5.4 -6.6 -7.77,1000000 1e-6 -1000000,-1.3e-6 -1.4e-5 0)
+49|GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(1 1)))
+ERROR:  parse error - invalid geometry at character 14
+ERROR:  parse error - invalid geometry at character 14
+ERROR:  parse error - invalid geometry at character 14
+ERROR:  parse error - invalid geometry at character 14
+ERROR:  parse error - invalid geometry at character 14
+ERROR:  parse error - invalid geometry at character 14
+ERROR:  geometry contains non-closed rings at character 24
+ERROR:  geometry contains non-closed rings at character 24
+ERROR:  parse error - invalid geometry at character 24
+ERROR:  geometry has too many points at character 23
+ERROR:  parse error - invalid geometry at character 23
+ERROR:  geometry requires more points at character 23
+62|POINT(inf 0)
+63|POINT(-inf 0)
+ERROR:  parse error - invalid geometry at character 23
+65|t
+65a|t
+66|t
+66a|f
+67|t
+67a|t
+68|t
+68a|t
+69|t
+69a|f
+70|t
+70a|f
+71|t
+71a|f
+72|t
+72a|f
+73|t
+73a|f
+74|f
+74a|f
+75|t
+75a|f
+76|f
+76a|f
+77|t
+78|t
+79|f
+80|f
+81|t
+82|f
+83|t
+84|f
+85|t
+86|f
+87|f
+88|t
+89|t
+90|f
+91|t
+92|f
+93|f
+94|t
+95|f
+96|t
+97|f
+98|t
+99|f
+100|f
+101|f
+102|f
+103|t
+104|t
+105|f
+106|BOX3D(0 0 0,7 7 0)
+107|POLYGON((0 0,0 7,7 7,7 0,0 0))
+108|2
+109|4
+110|6
+111|552
+112|3
+121|BOX3D(1.19894826 1.20265412 0,999.932129 999.692932 0)|BOX3D(1.40486765 1.3484304 0,999.857666 999.936401 0)
+122|f
+123|f
+124|f
+125|f
+126|f
+127|f
+128|f
+129|48016|48016
+131|1
+132|2
+133|
+133a|3
+133b|
+133c|
+133d|4
+133e|
+137|
+138|BOX3D(0 0 0,0 0 0)
+139|SRID=2;GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY,POINT(0 0))
+140|SRID=3;MULTIPOINT(2 2)
+141|SRID=4;MULTILINESTRING((2 2,3 3))
+142|SRID=5;MULTILINESTRING((2 2,3 3))
+143|SRID=6;MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)))
+143c1|MULTICURVE(CIRCULARSTRING(0 0,1 1,2 2))
+144|POINTM(1 2 0)
+145|POINT(1 2 0)
+146|POINT(1 2 0 3)
+147|POINT(1 2 3 0)
+148|LINESTRING(0 0,5 0,10 0)
+149|GEOMETRYCOLLECTION EMPTY
+150|SRID=6;GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0)))
+151|0103000020E61000000100000005000000000000000000000000000000000000000000000000000000000000000000F03F000000000000F03F000000000000F03F000000000000F03F000000000000000000000000000000000000000000000000
+152|4326
+152.1|t
+152.2|4326
+153|MULTIPOINT(0 0)
+154|MULTIPOINT(0 0)
+155|MULTIPOINT(0 0,1 1)
+156|MULTIPOINT(1 1)
+157|MULTILINESTRING((0 0,1 1))
+158|MULTILINESTRING((0 0,1 1),(2 2,3 3))
+159|MULTIPOLYGON EMPTY
+160|MULTIPOINT(1 1)
+161|MULTILINESTRING((0 0,1 1),(2 2,3 3))
+162|010200000003000000F771D98DE33826C00000000000004440F771D98DE33826C000000000008051400000000000805140F771D98DE33826C0
+163|POLYGON((0 0 0,1 0 0,1 1 0,0 1 0,0 0 0))
+164|POLYGON((0 0 0,1 0 0,1 1 0,0 1 0,0 0 1))
+ERROR:  geometry contains non-closed rings
+166|POINT EMPTY
+167|LINESTRING EMPTY
+168|POLYGON EMPTY
+169|CIRCULARSTRING EMPTY
+170|COMPOUNDCURVE EMPTY
+171|CURVEPOLYGON EMPTY
+172|MULTIPOINT EMPTY
+173|MULTILINESTRING EMPTY
+174|MULTIPOLYGON EMPTY
+175|TRIANGLE EMPTY
+176|TIN EMPTY
+177|POLYHEDRALSURFACE EMPTY
+178|MULTISURFACE EMPTY
+179|MULTICURVE EMPTY
+180|GEOMETRYCOLLECTION EMPTY
+181|GEOMETRYCOLLECTION(TRIANGLE EMPTY,TIN EMPTY)
diff --git a/regress/sfcgal/regress_ogc.sql b/regress/sfcgal/regress_ogc.sql
new file mode 100644 (file)
index 0000000..8203f66
--- /dev/null
@@ -0,0 +1,153 @@
+---
+--- SFCGAL backend tests based on GEOS/JTS implemented functions
+---
+---
+
+SET postgis.backend = 'sfcgal';
+
+-- Repeat all tests with new function names.
+SELECT 'buffer', ST_astext(ST_SnapToGrid(ST_buffer('POINT(0 0)', 1, 2), 1.0e-6));
+
+SELECT 'geomunion', ST_astext(ST_union('POINT(0 0)', 'POINT(1 1)'));
+SELECT 'convexhull', ST_asewkt(ST_convexhull('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0),(2 2, 2 4, 4 4, 4 2, 2 2))'));
+SELECT 'relate', ST_relate('POINT(0 0)', 'LINESTRING(0 0, 1 1)');
+SELECT 'relate', ST_relate('POINT(0 0)', 'LINESTRING(0 0, 1 1)', 'F0FFFF*02');
+SELECT 'relate', ST_relate('POINT(0 0)', 'LINESTRING(0 0, 1 1)', 'F0FFF0*02');
+SELECT 'disjoint', ST_disjoint('POINT(0 0)', 'LINESTRING(0 0, 1 1)');
+SELECT 'touches', ST_touches('LINESTRING(0 10, 0 -10)', 'LINESTRING(0 0, 1 1)');
+SELECT 'intersects', ST_intersects('LINESTRING(0 10, 0 -10)', 'LINESTRING(0 0, 1 1)');
+SELECT 'crosses', ST_crosses('LINESTRING(0 10, 0 -10)', 'LINESTRING(0 0, 1 1)');
+SELECT 'crosses', ST_crosses('LINESTRING(0 10, 0 -10)', 'LINESTRING(-4 0, 1 1)');
+-- PIP - point within polygon
+SELECT 'within100', ST_within('POINT(5 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point on vertex of polygon
+SELECT 'within101', ST_within('POINT(0 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point outside polygon
+SELECT 'within102', ST_within('POINT(-1 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point on edge of polygon
+SELECT 'within103', ST_within('POINT(0 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point in line with polygon edge
+SELECT 'within104', ST_within('POINT(0 12)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point vertically aligned with polygon vertex 
+SELECT 'within105', ST_within(ST_GeomFromText('POINT(521513 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631));
+-- PIP - repeated vertex 
+SELECT 'within106', ST_within(ST_GeomFromText('POINT(521513 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631));
+-- PIP - point within polygon
+SELECT 'disjoint100', ST_disjoint('POINT(5 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point on polygon vertex
+SELECT 'disjoint101', ST_disjoint('POINT(0 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point outside polygon
+SELECT 'disjoint102', ST_disjoint('POINT(-1 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point on polygon edge
+SELECT 'disjoint103', ST_disjoint('POINT(0 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point in line with polygon edge
+SELECT 'disjoint104', ST_disjoint('POINT(0 12)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point vertically aligned with polygon vertex 
+SELECT 'disjoint105', ST_disjoint(ST_GeomFromText('POINT(521513 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631));
+-- PIP - repeated vertex 
+SELECT 'disjoint106', ST_disjoint(ST_GeomFromText('POINT(521543 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631));
+-- PIP - point within polygon
+SELECT 'disjoint150', ST_disjoint('POINT(5 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point on polygon vertex
+SELECT 'disjoint151', ST_disjoint('POINT(0 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point outside polygon
+SELECT 'disjoint152', ST_disjoint('POINT(-1 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point on polygon edge
+SELECT 'disjoint153', ST_disjoint('POINT(0 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point in line with polygon edge
+SELECT 'disjoint154', ST_disjoint('POINT(0 12)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point vertically aligned with polygon vertex 
+SELECT 'disjoint155', ST_disjoint(ST_GeomFromText('POINT(521513 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631));
+-- PIP - repeated vertex
+SELECT 'disjoint156', ST_disjoint(ST_GeomFromText('POINT(521543 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631));
+-- PIP - point within polygon
+SELECT 'intersects100', ST_intersects('POINT(5 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point on polygon vertex
+SELECT 'intersects101', ST_intersects('POINT(0 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point outside polygon
+SELECT 'intersects102', ST_intersects('POINT(-1 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point on polygon edge
+SELECT 'intersects103', ST_intersects('POINT(0 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point in line with polygon edge
+SELECT 'intersects104', ST_intersects('POINT(0 12)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point vertically aligned with polygon vertex 
+SELECT 'intersects105', ST_intersects(ST_GeomFromText('POINT(521513 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631));
+-- PIP - repeated vertex
+SELECT 'intersects106', ST_intersects(ST_GeomFromText('POINT(521543 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631));
+-- PIP - point within polygon
+SELECT 'intersects150', ST_intersects('POINT(5 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point on polygon vertex
+SELECT 'intersects151', ST_intersects('POINT(0 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point outside polygon
+SELECT 'intersects152', ST_intersects('POINT(-1 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point on polygon edge
+SELECT 'intersects153', ST_intersects('POINT(0 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point in line with polygon edge
+SELECT 'intersects154', ST_intersects('POINT(0 12)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+-- PIP - point vertically aligned with polygon vertex 
+SELECT 'intersects155', ST_intersects(ST_GeomFromText('POINT(521513 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631));
+-- PIP - repeated vertex
+SELECT 'intersects156', ST_intersects(ST_GeomFromText('POINT(521543 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631));
+-- PIP - point within polygon
+SELECT 'contains100', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)');
+-- PIP - point on vertex of polygon
+SELECT 'contains101', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 0)');
+-- PIP - point outside polygon
+SELECT 'contains102', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(-1 0)');
+-- PIP - point on edge of polygon
+SELECT 'contains103', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 5)');
+-- PIP - point in line with polygon edge
+SELECT 'contains104', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 12)');
+-- PIP - point vertically aligned with polygon vertex 
+SELECT 'contains105', ST_contains(ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631), ST_GeomFromText('POINT(521513 5377804)', 32631));
+-- PIP - repeated vertex 
+SELECT 'contains106', ST_contains(ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631), ST_GeomFromText('POINT(521513 5377804)', 32631));
+-- moved here from regress.sql
+select 'within119', ST_within('LINESTRING(-1 -1, -1 101, 101 101, 101 -1)'::GEOMETRY,'BOX3D(0 0, 100 100)'::BOX3D);
+select 'within120', ST_within('LINESTRING(-1 -1, -1 100, 101 100, 101 -1)'::GEOMETRY,'BOX3D(0 0, 100 100)'::BOX3D);
+SELECT 'contains110', ST_Contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'LINESTRING(1 10, 9 10, 9 8)');
+SELECT 'contains111', ST_Contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'LINESTRING(1 10, 10 10, 10 8)');
+SELECT 'within130', ST_Within('LINESTRING(1 10, 9 10, 9 8)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+SELECT 'within131', ST_Within('LINESTRING(1 10, 10 10, 10 8)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+SELECT 'overlaps', ST_overlaps('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))','POINT(5 5)');
+SELECT 'isvalid', ST_isvalid('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
+SELECT 'isvalid', ST_isvalid('POLYGON((0 0, 0 10, 10 10, -5 10, 10 0, 0 0))');
+SELECT 'isvalid', ST_isvalid('GEOMETRYCOLLECTION EMPTY');
+SELECT 'intersection', ST_astext(ST_intersection('LINESTRING(0 10, 0 -10)', 'LINESTRING(0 0, 1 1)'));
+SELECT 'difference', ST_astext(ST_difference('LINESTRING(0 10, 0 -10)'::GEOMETRY, 'LINESTRING(0 2, 0 -2)'::GEOMETRY));
+SELECT 'boundary', ST_astext(ST_boundary('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0),(2 2, 2 4, 4 4, 4 2, 2 2))'));
+SELECT 'symdifference', ST_astext(ST_symdifference('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0),(2 2, 2 4, 4 4, 4 2, 2 2))', 'LINESTRING(0 0, 20 20)'));
+SELECT 'issimple', ST_issimple('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0),(2 2, 2 4, 4 4, 4 2, 2 2))');
+SELECT 'equals', ST_equals('LINESTRING(0 0, 1 1)', 'LINESTRING(1 1, 0 0)');
+WITH inp AS ( SELECT
+ 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0),(2 2, 2 4, 4 4, 4 2, 2 2))'
+::geometry as g )
+SELECT 'pointonsurface', ST_Contains(g, ST_pointonsurface(g)) from inp;
+SELECT 'centroid', ST_astext(ST_centroid('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0),(2 2, 2 4, 4 4, 4 2, 2 2))'));
+SELECT 'exteriorring', ST_astext(ST_exteriorring(ST_PolygonFromText('POLYGON((52 18,66 23,73 9,48 6,52 18),(59 18,67 18,67 13,59 13,59 18))')));
+SELECT 'polygonize_garray', ST_astext(ST_polygonize('{0102000000020000000000000000000000000000000000000000000000000024400000000000000000:0102000000020000000000000000002440000000000000000000000000000000000000000000000000:0102000000020000000000000000002440000000000000244000000000000000000000000000000000:0102000000020000000000000000002440000000000000244000000000000024400000000000000000:0102000000020000000000000000002440000000000000244000000000000000000000000000002440:0102000000020000000000000000000000000000000000244000000000000000000000000000002440:0102000000020000000000000000000000000000000000244000000000000024400000000000002440:0102000000020000000000000000000000000000000000244000000000000000000000000000000000:0102000000020000000000000000000000000000000000244000000000000024400000000000000000}'::geometry[]));
+
+SELECT 'polygonize_garray', ST_astext(ST_geometryn(ST_polygonize('{LINESTRING(0 0, 10 0):LINESTRING(10 0, 10 10):LINESTRING(10 10, 0 10):LINESTRING(0 10, 0 0)}'::geometry[]), 1));
+
+select 'linemerge149', ST_asewkt(ST_linemerge('GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), LINESTRING(4 4, 1 1), LINESTRING(-5 -5, 0 0))'::geometry));
+
+--- postgis-devel/2005-December/001784.html
+select 'intersects', ST_intersects(
+   ST_polygonfromtext('POLYGON((0.0 0.0,1.0 0.0,1.0 1.0,1.0 0.0,0.0 0.0))'),
+      ST_polygonfromtext('POLYGON((0.0 2.0,1.0 2.0,1.0 3.0,0.0 3.0,0.0 2.0))')
+      );
+
+select 'ST_GeometryN', ST_asewkt(ST_GeometryN('LINESTRING(0 0, 1 1)'::geometry, 1));
+select 'ST_NumGeometries', ST_NumGeometries('LINESTRING(0 0, 1 1)'::geometry);
+select 'ST_Union1', ST_AsText(ST_Union(ARRAY['POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))'::geometry, 'POLYGON((0.5 0.5, 1.5 0.5, 1.5 1.5, 0.5 1.5, 0.5 0.5))'::geometry]));
+select 'ST_StartPoint1',ST_AsText(ST_StartPoint('LINESTRING(0 0, 1 1, 2 2)'));
+select 'ST_EndPoint1', ST_AsText(ST_Endpoint('LINESTRING(0 0, 1 1, 2 2)'));
+select 'ST_PointN1', ST_AsText(ST_PointN('LINESTRING(0 0, 1 1, 2 2)',2));
+select 'ST_PointN2', ST_AsText(ST_PointN('LINESTRING(0 0, 1 1, 2 2)',3));
+select 'ST_PointN3',  ST_AsText(ST_PointN('LINESTRING(0 0, 1 1, 2 2)',4));
+select 'ST_PointN4', ST_AsText(ST_PointN('LINESTRING(0 0, 1 1, 2 2)',0));
+select 'ST_PointN5', ST_AsText(ST_PointN('LINESTRING(0 0, 1 1, 2 2)',1));
+select 'ST_PointN6', ST_AsText(ST_PointN('POLYGON((0 0, 1 1, 0 1, 0 0))',1));
+
+-- issues with EMPTY --
+select 'ST_Buffer(empty)', ST_AsText(ST_Buffer('POLYGON EMPTY', 0.5));
diff --git a/regress/sfcgal/regress_ogc_expected b/regress/sfcgal/regress_ogc_expected
new file mode 100644 (file)
index 0000000..cd05535
--- /dev/null
@@ -0,0 +1,89 @@
+buffer|POLYGON((1 0,0.707107 -0.707107,0 -1,-0.707107 -0.707107,-1 0,-0.707107 0.707107,0 1,0.707107 0.707107,1 0))
+geomunion|MULTIPOINT(0 0,1 1)
+convexhull|POLYGON((0 0,0 10,10 10,10 0,0 0))
+relate|F0FFFF102
+relate|t
+relate|f
+disjoint|f
+touches|t
+intersects|t
+crosses|f
+crosses|t
+within100|t
+within101|f
+within102|f
+within103|f
+within104|f
+within105|t
+within106|t
+disjoint100|f
+disjoint101|f
+disjoint102|t
+disjoint103|f
+disjoint104|t
+disjoint105|f
+disjoint106|t
+disjoint150|f
+disjoint151|f
+disjoint152|t
+disjoint153|f
+disjoint154|t
+disjoint155|f
+disjoint156|t
+intersects100|t
+intersects101|t
+intersects102|f
+intersects103|t
+intersects104|f
+intersects105|t
+intersects106|f
+intersects150|t
+intersects151|t
+intersects152|f
+intersects153|t
+intersects154|f
+intersects155|t
+intersects156|f
+contains100|t
+contains101|f
+contains102|f
+contains103|f
+contains104|f
+contains105|t
+contains106|t
+within119|f
+within120|f
+contains110|t
+contains111|f
+within130|t
+within131|f
+overlaps|f
+isvalid|t
+NOTICE:  Self-intersection
+isvalid|f
+isvalid|t
+intersection|POINT(-0 -0)
+difference|MULTILINESTRING((0 10,0 2),(0 -2,0 -10))
+boundary|MULTILINESTRING((0 0,0 10,10 10,10 0,0 0),(2 2,2 4,4 4,4 2,2 2))
+symdifference|GEOMETRYCOLLECTION(LINESTRING(2 2,4 4),LINESTRING(10 10,20 20),POLYGON((0 0,0 10,10 10,10 0,0 0),(4 4,2 4,2 2,4 2,4 4)))
+issimple|t
+equals|t
+pointonsurface|t
+centroid|POINT(5.08333333333333 5.08333333333333)
+exteriorring|LINESTRING(52 18,66 23,73 9,48 6,52 18)
+polygonize_garray|GEOMETRYCOLLECTION EMPTY
+polygonize_garray|POLYGON((10 0,0 0,0 10,10 10,10 0))
+linemerge149|LINESTRING(-5 -5,0 0,1 1,4 4)
+intersects|f
+ST_GeometryN|LINESTRING(0 0,1 1)
+ST_NumGeometries|1
+ST_Union1|POLYGON((0 0,0 1,0.5 1,0.5 1.5,1.5 1.5,1.5 0.5,1 0.5,1 0,0 0))
+ST_StartPoint1|POINT(0 0)
+ST_EndPoint1|POINT(2 2)
+ST_PointN1|POINT(1 1)
+ST_PointN2|POINT(2 2)
+ST_PointN3|
+ST_PointN4|
+ST_PointN5|POINT(0 0)
+ST_PointN6|
+ST_Buffer(empty)|POLYGON EMPTY
diff --git a/regress/sfcgal/regress_ogc_prep.sql b/regress/sfcgal/regress_ogc_prep.sql
new file mode 100644 (file)
index 0000000..a4e53ec
--- /dev/null
@@ -0,0 +1,300 @@
+---
+--- 9DIM Tests based on GEOS/JTS ones
+---
+---
+
+SET postgis.backend = 'sfcgal';
+
+SELECT c, ST_Intersects(ply, pt) FROM 
+( VALUES 
+-- PIP - point within polygon (no cache)
+('intersects099', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), 
+-- PIP - point within polygon
+('intersects100', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), 
+-- PIP - point on polygon vertex
+('intersects101', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 0)'), 
+-- PIP - point outside polygon
+('intersects102', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(-1 0)'),
+-- PIP - point on polygon edge
+('intersects103', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 5)'),
+-- PIP - point in line with polygon edge
+('intersects104', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 12)')
+) AS v(c,ply,pt);
+
+SELECT c, ST_Contains(ply, pt) FROM 
+( VALUES 
+-- PIP - point within polygon (no cache)
+('contains099', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), 
+-- PIP - point within polygon
+('contains100', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), 
+-- PIP - point on polygon vertex
+('contains101', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 0)'), 
+-- PIP - point outside polygon
+('contains102', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(-1 0)'),
+-- PIP - point on polygon edge
+('contains103', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 5)'),
+-- PIP - point in line with polygon edge
+('contains104', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 12)')
+) AS v(c,ply,pt);
+
+SELECT c, ST_Covers(ply, pt) FROM 
+( VALUES 
+-- PIP - point within polygon (no cache)
+('covers099', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), 
+-- PIP - point within polygon
+('covers100', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), 
+-- PIP - point on polygon vertex
+('covers101', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 0)'), 
+-- PIP - point outside polygon
+('covers102', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(-1 0)'),
+-- PIP - point on polygon edge
+('covers103', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 5)'),
+-- PIP - point in line with polygon edge
+('covers104', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 12)')
+) AS v(c,ply,pt);
+
+SELECT c, ST_ContainsProperly(ply, pt) FROM 
+( VALUES 
+-- PIP - point within polygon (no cache)
+('containsproperly099', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), 
+-- PIP - point within polygon
+('containsproperly100', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), 
+-- PIP - point on polygon vertex
+('containsproperly101', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 0)'), 
+-- PIP - point outside polygon
+('containsproperly102', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(-1 0)'),
+-- PIP - point on polygon edge
+('containsproperly103', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 5)'),
+-- PIP - point in line with polygon edge
+('containsproperly104', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 12)')
+) AS v(c,ply,pt);
+
+
+-- PIP - point vertically aligned with polygon vertex, poly first
+SELECT 'intersects105', ST_Intersects(p, ST_GeomFromText('POINT(521513 5377804)', 32631)) FROM 
+( VALUES 
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) 
+) AS v(p);
+-- PIP - point vertically aligned with polygon vertex, point first
+SELECT 'intersects106', ST_Intersects(ST_GeomFromText('POINT(521513 5377804)', 32631), p) FROM 
+( VALUES 
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) 
+) AS v(p);
+-- PIP - repeated vertex, poly first
+SELECT 'intersects107', ST_Intersects(p, ST_GeomFromText('POINT(521543 5377804)', 32631)) FROM 
+( VALUES 
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631))
+) AS v(p);
+-- PIP - repeated vertex, point first
+SELECT 'intersects108', ST_Intersects(ST_GeomFromText('POINT(521543 5377804)', 32631), p) FROM 
+( VALUES 
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631))
+) AS v(p);
+
+
+-- PIP - point vertically aligned with polygon vertex, poly first
+SELECT 'contains105', ST_Contains(p, ST_GeomFromText('POINT(521513 5377804)', 32631)) FROM 
+( VALUES 
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) 
+) AS v(p);
+-- PIP - point vertically aligned with polygon vertex, point first
+SELECT 'contains106', ST_Contains(ST_GeomFromText('POINT(521513 5377804)', 32631), p) FROM 
+( VALUES 
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) 
+) AS v(p);
+-- PIP - repeated vertex, poly first
+SELECT 'contains107', ST_Contains(p, ST_GeomFromText('POINT(521543 5377804)', 32631)) FROM 
+( VALUES 
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631))
+) AS v(p);
+-- PIP - repeated vertex, point first
+SELECT 'contains108', ST_Contains(ST_GeomFromText('POINT(521543 5377804)', 32631), p) FROM 
+( VALUES 
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631))
+) AS v(p);
+
+-- PIP - point vertically aligned with polygon vertex, poly first
+SELECT 'containsproperly105', ST_ContainsProperly(p, ST_GeomFromText('POINT(521513 5377804)', 32631)) FROM 
+( VALUES 
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) 
+) AS v(p);
+-- PIP - point vertically aligned with polygon vertex, point first
+SELECT 'containsproperly106', ST_ContainsProperly(ST_GeomFromText('POINT(521513 5377804)', 32631), p) FROM 
+( VALUES 
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) 
+) AS v(p);
+-- PIP - repeated vertex, poly first
+SELECT 'containsproperly107', ST_ContainsProperly(p, ST_GeomFromText('POINT(521543 5377804)', 32631)) FROM 
+( VALUES 
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631))
+) AS v(p);
+-- PIP - repeated vertex, point first
+SELECT 'containsproperly108', ST_ContainsProperly(ST_GeomFromText('POINT(521543 5377804)', 32631), p) FROM 
+( VALUES 
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631))
+) AS v(p);
+
+-- PIP - point vertically aligned with polygon vertex, poly first
+SELECT 'covers105', ST_Covers(p, ST_GeomFromText('POINT(521513 5377804)', 32631)) FROM 
+( VALUES 
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) 
+) AS v(p);
+-- PIP - point vertically aligned with polygon vertex, point first
+SELECT 'covers106', ST_Covers(ST_GeomFromText('POINT(521513 5377804)', 32631), p) FROM 
+( VALUES 
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) 
+) AS v(p);
+-- PIP - repeated vertex, poly first
+SELECT 'covers107', ST_Covers(p, ST_GeomFromText('POINT(521543 5377804)', 32631)) FROM 
+( VALUES 
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631))
+) AS v(p);
+-- PIP - repeated vertex, point first
+SELECT 'covers108', ST_Covers(ST_GeomFromText('POINT(521543 5377804)', 32631), p) FROM 
+( VALUES 
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)),
+       (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631))
+) AS v(p);
+
+
+SELECT c, ST_Intersects(p1, p2) AS intersects_p1p2, ST_Intersects(p2, p1) AS intersects_p2p1 FROM
+( VALUES
+('intersects200', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), 
+('intersects201', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), 
+('intersects202', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))'),
+('intersects203', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((-5 -5, 5 -5, 5 5, -5 5, -5 -5))'), 
+('intersects204', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((-2 -2, -2 -3, -3 -3, -3 -2, -2 -2))'),
+('intersects205', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), 
+('intersects206', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), 
+('intersects207', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))'),
+('intersects208', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((-5 -5, 5 -5, 5 5, -5 5, -5 -5))'), 
+('intersects209', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((-2 -2, -2 -3, -3 -3, -3 -2, -2 -2))')
+) AS v(c,p1,p2);
+
+SELECT c, ST_Contains(p1, p2) AS contains_p1p2, ST_Contains(p2, p1) AS contains_p2p1 FROM
+( VALUES
+('contains200', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), 
+('contains201', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), 
+('contains202', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))'),
+('contains203', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((-5 -5, 5 -5, 5 5, -5 5, -5 -5))'), 
+('contains204', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((-2 -2, -2 -3, -3 -3, -3 -2, -2 -2))'),
+('contains205', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), 
+('contains206', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), 
+('contains207', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))'),
+('contains208', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((-5 -5, 5 -5, 5 5, -5 5, -5 -5))'), 
+('contains209', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((-2 -2, -2 -3, -3 -3, -3 -2, -2 -2))')
+) AS v(c,p1,p2);
+
+SELECT c, ST_ContainsProperly(p1, p2) AS containsproperly_p1p2, ST_ContainsProperly(p2, p1) AS containsproperly_p2p1 FROM
+( VALUES
+('containsproperly200', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), 
+('containsproperly201', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), 
+('containsproperly202', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))'),
+('containsproperly203', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((-5 -5, 5 -5, 5 5, -5 5, -5 -5))'), 
+('containsproperly204', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((-2 -2, -2 -3, -3 -3, -3 -2, -2 -2))'),
+('containsproperly205', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), 
+('containsproperly206', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), 
+('containsproperly207', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))'),
+('containsproperly208', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((-5 -5, 5 -5, 5 5, -5 5, -5 -5))'), 
+('containsproperly209', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((-2 -2, -2 -3, -3 -3, -3 -2, -2 -2))')
+) AS v(c,p1,p2);
+
+SELECT c, ST_Covers(p1, p2) AS covers_p1p2, ST_Covers(p2, p1) AS covers_p2p1 FROM
+( VALUES
+('covers200', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), 
+('covers201', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), 
+('covers202', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))'),
+('covers203', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((-5 -5, 5 -5, 5 5, -5 5, -5 -5))'), 
+('covers204', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((-2 -2, -2 -3, -3 -3, -3 -2, -2 -2))'),
+('covers205', 'POLYGON((0 0, 0 10, 10 10, 11 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), 
+('covers206', 'POLYGON((0 0, 0 10, 10 10, 11 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), 
+('covers207', 'POLYGON((0 0, 0 10, 10 10, 11 0, 0 0))', 'POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))'),
+('covers208', 'POLYGON((0 0, 0 10, 10 10, 11 0, 0 0))', 'POLYGON((-5 -5, 5 -5, 5 5, -5 5, -5 -5))'), 
+('covers209', 'POLYGON((0 0, 0 10, 10 10, 11 0, 0 0))', 'POLYGON((-2 -2, -2 -3, -3 -3, -3 -2, -2 -2))')
+) AS v(c,p1,p2);
+
+-- UNEXPECTED GEOMETRY TYPES --
+
+SELECT c, ST_Contains(p1, p2) AS contains_p1p2, ST_Contains(p2, p1) AS contains_p2p1, 
+          ST_Covers(p1, p2) AS covers_p1p2, ST_Covers(p2, p1) AS covers_p2p1,
+          ST_Intersects(p1, p2) AS intersects_p1p2, ST_Intersects(p2, p1) AS intersects_p2p1,
+          ST_ContainsProperly(p1, p2) AS containsproper_p1p2, ST_ContainsProperly(p2, p1) AS containsproper_p2p1 
+          FROM
+( VALUES
+('types100', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), 
+('types101', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), 
+('types102', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), 
+('types103', 'LINESTRING(0 0, 0 10, 10 10, 10 0)', 'POINT(5 5)'), 
+('types104', 'LINESTRING(0 0, 0 10, 10 10, 10 0)', 'POINT(5 5)'), 
+('types105', 'LINESTRING(0 0, 0 10, 10 10, 10 0)', 'POINT(5 5)'), 
+('types106', 'POINT(5 5)', 'POINT(5 5)'), 
+('types107', 'POINT(5 5)', 'POINT(5 5)'), 
+('types108', 'POINT(5 5)', 'POINT(5 5)'), 
+('types109', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'), 
+('types110', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'), 
+('types111', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'), 
+('types112', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'LINESTRING(0 0, 0 10, 10 10, 10 0)'), 
+('types113', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'LINESTRING(0 0, 0 10, 10 10, 10 0)'), 
+('types114', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'LINESTRING(0 0, 0 10, 10 10, 10 0)') 
+) AS v(c,p1,p2);
+
+
+SELECT 'intersects310', ST_intersects('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', p) FROM ( VALUES 
+('LINESTRING(1 10, 9 10, 9 8)'),('LINESTRING(1 10, 9 10, 9 8)'),('LINESTRING(1 10, 9 10, 9 8)')
+) AS v(p);
+SELECT 'intersects311', ST_intersects('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', p) FROM ( VALUES 
+('LINESTRING(1 10, 10 10, 10 8)'),('LINESTRING(1 10, 10 10, 10 8)'),('LINESTRING(1 10, 10 10, 10 8)')
+) AS v(p);
+
+SELECT 'contains310', ST_Contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', p) FROM ( VALUES 
+('LINESTRING(1 10, 9 10, 9 8)'),('LINESTRING(1 10, 9 10, 9 8)'),('LINESTRING(1 10, 9 10, 9 8)')
+) AS v(p);
+SELECT 'contains311', ST_Contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', p) FROM ( VALUES 
+('LINESTRING(1 10, 10 10, 10 8)'),('LINESTRING(1 10, 10 10, 10 8)'),('LINESTRING(1 10, 10 10, 10 8)')
+) AS v(p);
+
+SELECT 'containsproperly310', ST_ContainsProperly('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', p) FROM ( VALUES 
+('LINESTRING(1 10, 9 10, 9 8)'),('LINESTRING(1 10, 9 10, 9 8)'),('LINESTRING(1 10, 9 10, 9 8)')
+) AS v(p);
+SELECT 'containsproperly311', ST_ContainsProperly('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', p) FROM ( VALUES 
+('LINESTRING(1 10, 10 10, 10 8)'),('LINESTRING(1 10, 10 10, 10 8)'),('LINESTRING(1 10, 10 10, 10 8)')
+) AS v(p);
+
+SELECT 'covers310', ST_Covers('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', p) FROM ( VALUES 
+('LINESTRING(1 10, 9 10, 9 8)'),('LINESTRING(1 10, 9 10, 9 8)'),('LINESTRING(1 10, 9 10, 9 8)')
+) AS v(p);
+SELECT 'covers311', ST_Covers('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', p) FROM ( VALUES 
+('LINESTRING(1 10, 10 10, 10 8)'),('LINESTRING(1 10, 10 10, 10 8)'),('LINESTRING(1 10, 10 10, 10 8)')
+) AS v(p);
+
diff --git a/regress/sfcgal/regress_ogc_prep_expected b/regress/sfcgal/regress_ogc_prep_expected
new file mode 100644 (file)
index 0000000..4600388
--- /dev/null
@@ -0,0 +1,151 @@
+intersects099|t
+intersects100|t
+intersects101|t
+intersects102|f
+intersects103|t
+intersects104|f
+contains099|t
+contains100|t
+contains101|f
+contains102|f
+contains103|f
+contains104|f
+covers099|t
+covers100|t
+covers101|t
+covers102|f
+covers103|t
+covers104|f
+containsproperly099|t
+containsproperly100|t
+containsproperly101|f
+containsproperly102|f
+containsproperly103|f
+containsproperly104|f
+intersects105|t
+intersects105|t
+intersects105|t
+intersects106|t
+intersects106|t
+intersects106|t
+intersects107|f
+intersects107|f
+intersects107|f
+intersects108|f
+intersects108|f
+intersects108|f
+contains105|t
+contains105|t
+contains105|t
+contains106|f
+contains106|f
+contains106|f
+contains107|f
+contains107|f
+contains107|f
+contains108|f
+contains108|f
+contains108|f
+containsproperly105|t
+containsproperly105|t
+containsproperly105|t
+containsproperly106|f
+containsproperly106|f
+containsproperly106|f
+containsproperly107|f
+containsproperly107|f
+containsproperly107|f
+containsproperly108|f
+containsproperly108|f
+containsproperly108|f
+covers105|t
+covers105|t
+covers105|t
+covers106|f
+covers106|f
+covers106|f
+covers107|f
+covers107|f
+covers107|f
+covers108|f
+covers108|f
+covers108|f
+intersects200|t|t
+intersects201|t|t
+intersects202|t|t
+intersects203|t|t
+intersects204|f|f
+intersects205|t|t
+intersects206|t|t
+intersects207|t|t
+intersects208|t|t
+intersects209|f|f
+contains200|t|f
+contains201|t|f
+contains202|t|f
+contains203|f|f
+contains204|f|f
+contains205|t|f
+contains206|t|f
+contains207|t|f
+contains208|f|f
+contains209|f|f
+containsproperly200|t|f
+containsproperly201|t|f
+containsproperly202|f|f
+containsproperly203|f|f
+containsproperly204|f|f
+containsproperly205|t|f
+containsproperly206|t|f
+containsproperly207|f|f
+containsproperly208|f|f
+containsproperly209|f|f
+covers200|t|f
+covers201|t|f
+covers202|t|f
+covers203|f|f
+covers204|f|f
+covers205|t|f
+covers206|t|f
+covers207|t|f
+covers208|f|f
+covers209|f|f
+types100|t|f|t|f|t|t|t|f
+types101|t|f|t|f|t|t|t|f
+types102|t|f|t|f|t|t|t|f
+types103|f|f|f|f|f|f|f|f
+types104|f|f|f|f|f|f|f|f
+types105|f|f|f|f|f|f|f|f
+types106|t|t|t|t|t|t|t|t
+types107|t|t|t|t|t|t|t|t
+types108|t|t|t|t|t|t|t|t
+types109|t|t|t|t|t|t|f|f
+types110|t|t|t|t|t|t|f|f
+types111|t|t|t|t|t|t|f|f
+types112|f|f|t|f|t|t|f|f
+types113|f|f|t|f|t|t|f|f
+types114|f|f|t|f|t|t|f|f
+intersects310|t
+intersects310|t
+intersects310|t
+intersects311|t
+intersects311|t
+intersects311|t
+contains310|t
+contains310|t
+contains310|t
+contains311|f
+contains311|f
+contains311|f
+containsproperly310|f
+containsproperly310|f
+containsproperly310|f
+containsproperly311|f
+containsproperly311|f
+containsproperly311|f
+covers310|t
+covers310|t
+covers310|t
+covers311|t
+covers311|t
+covers311|t
diff --git a/regress/sfcgal/tickets.sql b/regress/sfcgal/tickets.sql
new file mode 100644 (file)
index 0000000..d3f7c3b
--- /dev/null
@@ -0,0 +1,826 @@
+--
+-- Regression tests that were filed as cases in bug tickets,
+-- referenced by bug number for historical interest.
+--
+
+SET postgis.backend = 'sfcgal';
+
+-- NOTE: some tests _require_ spatial_ref_sys entries.
+-- In particular, the GML output ones want auth_name and auth_srid too,
+-- so we provide one for EPSG:4326
+DELETE FROM spatial_ref_sys;
+INSERT INTO spatial_ref_sys ( srid, proj4text ) VALUES ( 32611, '+proj=utm +zone=11 +ellps=WGS84 +datum=WGS84 +units=m +no_defs' );
+INSERT INTO spatial_ref_sys ( auth_name, auth_srid, srid, proj4text ) VALUES ( 'EPSG', 4326, 4326, '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs' );
+INSERT INTO spatial_ref_sys ( srid, proj4text ) VALUES ( 32602, '+proj=utm +zone=2 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ' );
+INSERT INTO spatial_ref_sys ( srid, proj4text ) VALUES ( 32702, '+proj=utm +zone=2 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ' );
+INSERT INTO spatial_ref_sys ( srid, proj4text ) VALUES ( 3395, '+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ' );
+
+INSERT INTO spatial_ref_sys (srid,proj4text) VALUES (32707,'+proj=utm +zone=7 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ');
+
+
+-- #2 --
+SELECT '#2', ST_AsText(ST_Union(g)) FROM
+( VALUES 
+('SRID=4326;MULTIPOLYGON(((1 1,1 2,2 2,2 1,1 1)))'), 
+('SRID=4326;MULTIPOLYGON(((2 1,3 1,3 2,2 2,2 1)))')
+) AS v(g);
+
+-- #11 --
+SELECT '#11', round(ST_Distance (a.g, ST_Intersection(b.g, a.g))) AS distance 
+FROM (SELECT '01020000000200000050E8303FC2E85141B017CFC05A825541000000E0C0E85141000000205C825541'::geometry AS g) a, 
+        (SELECT 'LINESTRING(4694792.35840419 5638508.89950758,4694793.20840419 5638506.34950758)'::geometry AS g) b;
+       
+-- #21 --
+SELECT '#21', ST_AsEWKT(ST_Locate_Along_Measure(g, 4566)) FROM
+( VALUES 
+(ST_GeomFromEWKT('SRID=31293;LINESTRINGM( 6193.76 5337404.95 4519, 6220.13 5337367.145 4566, 6240.889 5337337.383 4603 )'))
+) AS v(g);
+
+-- #22 --
+SELECT ST_Within(g, 'POLYGON((0 0,10 0,20 10,10 20,0 20,-10 10,0 0))') FROM 
+(VALUES 
+('POLYGON((4 9,6 9,6 11,4 11,4 9))')
+) AS v(g);
+
+-- #33 --
+CREATE TABLE road_pg (ID INTEGER, NAME VARCHAR(32));
+SELECT '#33', AddGeometryColumn( '', 'public', 'road_pg','roads_geom', 330000, 'POINT', 2 );
+DROP TABLE road_pg;
+
+-- #44 -- 
+SELECT '#44', ST_Relate(g1, g2, 'T12101212'), ST_Relate(g1, g2, 't12101212') FROM 
+(VALUES 
+('POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))', 'POLYGON((1 1, 3 1, 3 3, 1 3, 1 1))')
+) AS v(g1, g2);
+
+-- #58 --
+SELECT '#58', round(ST_xmin(g)),round(ST_ymin(g)),round(ST_xmax(g)),round(ST_ymax(g)) FROM (SELECT ST_Envelope('CIRCULARSTRING(220268.439465645 150415.359530563,220227.333322076 150505.561285879,220227.353105332 150406.434743975)') as g)  AS foo;
+
+-- #65 --
+SELECT '#65', ST_AsGML(ST_GeometryFromText('CURVEPOLYGON(CIRCULARSTRING(4 2,3 -1.0,1 -1,-1.0 4,4 2))'));
+
+-- #66 --
+SELECT '#66', ST_AsText((ST_Dump(ST_GeomFromEWKT('CIRCULARSTRING(0 0,1 1,2 2)'))).geom);
+
+-- #68 --
+SELECT '#68a', ST_AsText(ST_Shift_Longitude(ST_GeomFromText('MULTIPOINT(1 3, 4 5)')));
+SELECT '#68b', ST_AsText(ST_Shift_Longitude(ST_GeomFromText('CIRCULARSTRING(1 3, 4 5, 6 7)')));
+
+-- #69 --
+SELECT '#69', ST_AsText(ST_Translate(ST_GeomFromText('CIRCULARSTRING(220268 150415,220227 150505,220227 150406)'),1,2));
+
+-- #70 --
+SELECT '#70', ST_NPoints(ST_LinetoCurve(ST_Buffer('POINT(1 2)',3)));
+
+-- #73 --
+SELECT '#73', ST_AsText(ST_Force_Collection(ST_GeomFromEWKT('CIRCULARSTRING(1 1, 2 3, 4 5, 6 7, 5 6)')));
+
+-- #80 --
+SELECT '#80', ST_AsText(ST_Multi('MULTILINESTRING((0 0,1 1))'));
+
+-- #83 --
+SELECT '#83', ST_AsText(ST_Multi(ST_GeomFromText('CIRCULARSTRING(220268 150415,220227 150505,220227 150406)')));
+
+-- #85 --
+SELECT '#85', ST_Distance(ST_GeomFromText('CIRCULARSTRING(220268 150415,220227 150505,220227 150406)'), ST_Point(220268, 150415));
+
+-- #112 --
+SELECT '#112', ST_AsText(ST_CurveToLine('GEOMETRYCOLLECTION(POINT(-10 50))'::geometry));
+
+-- #113 --
+SELECT '#113', ST_Locate_Along_Measure('LINESTRING(0 0 0, 1 1 1)', 0.5);
+
+-- #116 --
+SELECT '#116', ST_AsText('010300000000000000');
+
+-- #122 --
+SELECT '#122', ST_AsText(ST_SnapToGrid(ST_GeomFromText('CIRCULARSTRING(220268 150415,220227 150505,220227 150406)'), 0.1));
+
+-- #124 --
+SELECT '#124a', ST_AsText(ST_GeomFromEWKT('COMPOUNDCURVE(CIRCULARSTRING(0 0,1 1,1 0),(1 0,30 5),CIRCULARSTRING(30 5,34 56,67 89))'));
+SELECT '#124b', ST_AsText(ST_GeomFromEWKT('COMPOUNDCURVE(CIRCULARSTRING(0 0,1 1,1 0),(1 0,30 6),CIRCULARSTRING(30 5,34 56,67 89))'));
+
+-- #145 --
+SELECT '#145a', ST_Buffer(ST_GeomFromText('LINESTRING(-116.93414544665981 34.16033385105459,-116.87777514700957 34.10831080544884,-116.86972224705954 34.086748622072776,-116.9327074288116 34.08458099517253,-117.00216369088065 34.130329331330216,-117.00216369088065 34.130329331330216)', 4326), 0);
+SELECT '#145b', ST_Area(ST_Buffer(ST_GeomFromText('LINESTRING(-116.93414544665981 34.16033385105459,-116.87777514700957 34.10831080544884,-116.86972224705954 34.086748622072776,-116.9327074288116 34.08458099517253,-117.00216369088065 34.130329331330216,-117.00216369088065 34.130329331330216)', 4326), 0));
+
+-- #146 --
+SELECT '#146', ST_Distance(g1,g2), ST_Dwithin(g1,g2,0.01), ST_AsEWKT(g2) FROM (SELECT ST_geomFromEWKT('LINESTRING(1 2, 2 4)') As g1, ST_Collect(ST_GeomFromEWKT('LINESTRING(0 0, -1 -1)'), ST_GeomFromEWKT('MULTIPOINT(1 2,2 3)')) As g2) As foo;
+
+-- #156 --
+SELECT '#156', ST_AsEWKT('0106000000010000000103000000010000000700000024213D12AA7BFD40945FF42576511941676A32F9017BFD40B1D67BEA7E511941C3E3C640DB7DFD4026CE38F4EE531941C91289C5A7EFD40017B8518E3531941646F1599AB7DFD409627F1F0AE521941355EBA49547CFD407B14AEC74652194123213D12AA7BFD40945FF42576511941');
+
+-- #157 --
+SELECT 
+       '#157',
+       ST_GeometryType(g) As newname, 
+       GeometryType(g) as oldname 
+FROM ( VALUES 
+       (ST_GeomFromText('POLYGON((-0.25 -1.25,-0.25 1.25,2.5 1.25,2.5 -1.25,-0.25 -1.25), (2.25 0,1.25 1,1.25 -1,2.25 0),(1 -1,1 1,0 0,1 -1))') ),
+       ( ST_Point(1,2) ), 
+       ( ST_Buffer(ST_Point(1,2), 3) ), 
+       ( ST_LineToCurve(ST_Buffer(ST_Point(1,2), 3)) ) , 
+       ( ST_LineToCurve(ST_Boundary(ST_Buffer(ST_Point(1,2), 3))) )
+       ) AS v(g);
+
+
+-- #168 --
+SELECT '#168', ST_NPoints(g), ST_AsText(g), ST_isValidReason(g)
+FROM ( VALUES
+('01060000C00100000001030000C00100000003000000E3D9107E234F5041A3DB66BC97A30F4122ACEF440DAF9440FFFFFFFFFFFFEFFFE3D9107E234F5041A3DB66BC97A30F4122ACEF440DAF9440FFFFFFFFFFFFEFFFE3D9107E234F5041A3DB66BC97A30F4122ACEF440DAF9440FFFFFFFFFFFFEFFF'::geometry)
+) AS v(g);
+
+-- #175 --
+SELECT '#175', ST_AsEWKT(ST_GeomFromEWKT('SRID=26915;POINT(482020 4984378.)'));
+
+-- #178 --
+SELECT '#178a', ST_XMin(ST_MakeBox2D(ST_Point(5, 5), ST_Point(0, 0)));
+SELECT '#178b', ST_XMax(ST_MakeBox2D(ST_Point(5, 5), ST_Point(0, 0)));
+
+-- #179 --
+SELECT '#179a', ST_MakeLine(ARRAY[NULL,NULL,NULL,NULL]);
+SELECT '#179b', ST_MakeLine(ARRAY[NULL,NULL,NULL,NULL]);
+
+-- #183 --
+SELECT '#183', ST_AsText(ST_SnapToGrid(ST_LineToCurve(ST_LineMerge(ST_Collect(ST_CurveToLine(ST_GeomFromEWKT('CIRCULARSTRING(0 0, 1 1, 1 0)')),ST_GeomFromEWKT('LINESTRING(1 0, 0 1)') ))), 1E-10));
+
+-- #210 --
+SELECT '#210a', ST_Union(ARRAY[NULL,NULL,NULL,NULL]) ;
+SELECT '#210b', ST_MakeLine(ARRAY[NULL,NULL,NULL,NULL]) ;
+
+-- #213 --
+SELECT '#213', round(ST_Perimeter(ST_CurveToLine(ST_GeomFromEWKT('CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0,2 0, 2 1, 2 3, 4 3),(4 3, 4 5, 1 4, 0 0)))'))));
+
+-- #234 --
+SELECT '#234', ST_AsText(ST_GeomFromText('COMPOUNDCURVE( (0 0,1 1) )'));
+
+-- #239 --
+--SELECT '#239', ST_AsSVG('010700002031BF0D0000000000');
+
+-- #241 --
+CREATE TABLE c ( the_geom GEOMETRY);
+INSERT INTO c SELECT ST_MakeLine(ST_Point(-10,40),ST_Point(40,-10)) As the_geom;
+INSERT INTO c SELECT ST_MakeLine(ST_Point(-10,40),ST_Point(40,-10)) As the_geom;
+SELECT '#241', sum(ST_LineCrossingDirection(the_geom, ST_GeomFromText('LINESTRING(1 2,3 4)'))) FROM c;
+DROP TABLE c;
+
+-- #254 --
+SELECT '#254', ST_Segmentize(ST_GeomFromText('GEOMETRYCOLLECTION EMPTY'), 0.5);
+
+-- #259 --
+SELECT '#259', ST_Distance(ST_GeographyFromText('SRID=4326;POLYGON EMPTY'), ST_GeographyFromText('SRID=4326;POINT(1 2)'));
+
+-- #260 --
+SELECT '#260', round(ST_Distance(ST_GeographyFromText('SRID=4326;POINT(-10 40)'), ST_GeographyFromText('SRID=4326;POINT(-10 55)')));
+
+-- #261 --
+SELECT '#261', ST_Distance(ST_GeographyFromText('SRID=4326;POINT(-71.0325022849392 42.3793285830812)'),ST_GeographyFromText('SRID=4326;POLYGON((-71.0325022849392 42.3793285830812,-71.0325745928559 42.3793012556699,-71.0326708728343 42.3794450989722,-71.0326045866257 42.3794706688942,-71.0325022849392 42.3793285830812))'));
+
+-- #262 --
+SELECT '#262', ST_AsText(pt.the_geog) As wkt_pt, ST_Covers(poly.the_geog, pt.the_geog) As geog,
+       ST_Covers(
+               ST_Transform(CAST(poly.the_geog As geometry),32611), 
+               ST_Transform(CAST(pt.the_geog As geometry),32611)) As utm,
+       ST_Covers(
+               CAST(poly.the_geog As geometry), 
+               CAST(pt.the_geog As geometry)
+       ) As pca
+FROM (SELECT ST_GeographyFromText('SRID=4326;POLYGON((-119.5434 34.9438,-119.5437 34.9445,-119.5452 34.9442,-119.5434 34.9438))') As the_geog) 
+       As poly
+    CROSS JOIN 
+       (VALUES
+               ( ST_GeographyFromText('SRID=4326;POINT(-119.5434 34.9438)') ) ,
+               ( ST_GeographyFromText('SRID=4326;POINT(-119.5452 34.9442)') ) ,
+               ( ST_GeographyFromText('SRID=4326;POINT(-119.5434 34.9438)') ),
+               ( ST_GeographyFromText('SRID=4326;POINT(-119.5438 34.9443)')  )
+       )
+       As pt(the_geog);
+
+-- #263 --
+SELECT '#263', ST_AsEWKT(geometry(geography(pt.the_geom))) As wkt,
+       ST_Covers(
+               ST_Transform(poly.the_geom,32611), 
+               ST_Transform(pt.the_geom,32611)) As utm,
+       ST_Covers(
+               poly.the_geom, 
+               pt.the_geom)
+        As pca,
+       ST_Covers(geometry(geography(poly.the_geom)),
+               geometry(geography(pt.the_geom))) As gm_to_gg_gm_pca
+       
+FROM (SELECT ST_GeomFromEWKT('SRID=4326;POLYGON((-119.5434 34.9438,-119.5437 34.9445,-119.5452 34.9442,-119.5434 34.9438))') As the_geom) 
+       As poly
+    CROSS JOIN 
+       (VALUES
+               ( ST_GeomFromEWKT('SRID=4326;POINT(-119.5434 34.9438)') ) ,
+               ( ST_GeomFromEWKT('SRID=4326;POINT(-119.5452 34.9442)') ) ,
+               ( ST_GeomFromEWKT('SRID=4326;POINT(-119.5434 34.9438)') ),
+               ( ST_GeomFromEWKT('SRID=4326;POINT(-119.5438 34.9443)')  )
+       )
+       As pt(the_geom);
+
+-- #271 --
+SELECT '#271', ST_Covers(
+'POLYGON((-9.123456789 50,51 -11.123456789,-10.123456789 50,-9.123456789 50))'::geography,
+'POINT(-10.123456789 50)'::geography
+);
+
+-- #272 --
+SELECT '#272', ST_LineCrossingDirection(foo.line1, foo.line2) As l1_cross_l2 ,
+    ST_LineCrossingDirection(foo.line2, foo.line1) As l2_cross_l1
+FROM (SELECT
+    ST_GeomFromText('LINESTRING(25 169,89 114,40 70,86 43)') As line1, ST_GeomFromText('LINESTRING(2.99 90.16,71 74,20 140,171 154)') As line2 ) As foo;
+
+-- #277 --
+SELECT '#277', ST_AsGML(2, ST_GeomFromText('POINT(1 1e308)'));
+
+-- #299 --
+SELECT '#299', round(ST_Y(geometry(ST_Intersection(ST_GeographyFromText('POINT(1.2456 2)'), ST_GeographyFromText('POINT(1.2456 2)'))))); 
+
+-- #304 --
+
+SELECT '#304';
+
+CREATE OR REPLACE FUNCTION utmzone(geometry)
+  RETURNS integer AS
+$BODY$
+DECLARE
+    geomgeog geometry;
+    zone int;
+    pref int;
+
+BEGIN
+    geomgeog:= ST_Transform($1,4326);
+
+    IF (ST_Y(geomgeog))>0 THEN
+       pref:=32600;
+    ELSE
+       pref:=32700;
+    END IF;
+
+    zone:=floor((ST_X(geomgeog)+180)/6)+1;
+    IF ( zone > 60 ) THEN zone := 60; END IF;
+
+    RETURN zone+pref;
+END;
+$BODY$ LANGUAGE 'plpgsql' IMMUTABLE
+  COST 100;
+
+CREATE TABLE utm_dots ( the_geog geography, utm_srid integer);
+INSERT INTO utm_dots SELECT geography(ST_SetSRID(ST_Point(i*10,j*10),4326)) As the_geog, utmzone(ST_SetSRID(ST_Point(i*10,j*10),4326)) As utm_srid FROM generate_series(-17,17) As i CROSS JOIN generate_series(-8,8) As j;
+
+SELECT ST_AsText(the_geog) as the_pt, 
+       utm_srid,
+       ST_Area(ST_Buffer(the_geog,10)) As the_area, 
+       ST_Area(geography(ST_Transform(ST_Buffer(ST_Transform(geometry(the_geog),utm_srid),10),4326))) As geog_utm_area
+FROM utm_dots 
+WHERE ST_Area(ST_Buffer(the_geog,10)) NOT between 307 and 315
+LIMIT 10;
+
+SELECT '#304.a', Count(*) FROM utm_dots WHERE ST_DWithin(the_geog, 'POINT(0 0)'::geography, 3000000);
+
+CREATE INDEX utm_dots_gix ON utm_dots USING GIST (the_geog);
+SELECT '#304.b', Count(*) FROM utm_dots WHERE ST_DWithin(the_geog, 'POINT(0 0)'::geography, 300000);
+
+DROP FUNCTION utmzone(geometry);
+DROP TABLE utm_dots;
+
+-- #408 --
+SELECT '#408', substring(st_isvalidreason('0105000020E0670000010000000102000020E06700000100000016DA52BA62A04141FFF3AD290B735241') from E'.*\\[');
+SELECT '#408.1', st_isvalid('01050000000100000001020000000100000000000000000000000000000000000000');
+SELECT '#408.2', st_isvalidreason('01020000000100000000000000000000000000000000000000');
+SELECT '#408.3', st_isvalid('0106000020BB0B000001000000010300000005000000D6000000000000C0F1A138410AD7A3103190524114AE4721F7A138410000000030905241713D0A57FAA1384185EB51982C9052417B14AE87FAA13841000000402A905241AE47E13AFBA1384114AE474128905241EC51B81EFDA138413D0AD7632690524152B81E85FFA13841D7A3707D2590524152B81E4500A23841713D0A072590524100000000FFA13841713D0AF724905241CDCCCCCCFFA13841CDCCCC0C249052419A99991901A238419A999919249052411F85EBD101A23841D7A3704D23905241E17A14AE02A23841A4703D3A2290524185EB51F808A23841000000D021905241E17A14EE0BA238413333335321905241666666A615A23841B81E85AB1F905241713D0AD710A23841B81E858B1E905241666666260CA2384114AE4731209052410AD7A37009A23841CDCCCCEC20905241AE47E13A06A23841EC51B87E219052419A9999D903A23841EC51B80E21905241EC51B8DE08A238418FC2F5681F905241666666660EA23841A4703D9A1D9052413D0AD7A30FA2384114AE47A11C9052413333333311A23841000000101C90524148E17A1414A23841333333931A905241EC51B81E1AA23841EC51B89E1890524185EB51381CA23841D7A370BD17905241295C8FC220A2384185EB51C816905241C3F528DC2BA238418FC2F5E814905241E17A14EE2EA23841EC51B8FE13905241AE47E1FA2BA23841EC51B8EE119052415C8FC2F52BA2384185EB51C810905241333333332EA2384114AE4701109052417B14AEC73BA238410AD7A3300D905241CDCCCCCC43A238417B14AE870B905241CDCCCC4C45A23841A4703D3A0B9052413D0AD7A34DA238411F85EB810A905241295C8F8250A23841CDCCCCBC09905241000000C053A238410AD7A36009905241A4703D0A5CA2384114AE4751099052418FC2F5A866A23841A4703D4A0A9052410000008069A2384114AE47B10A9052415C8FC2B573A23841B81E851B0D905241AE47E1FA76A23841666666C60D9052417B14AE077BA238411F85EB510E905241AE47E1FA7FA23841666666E60E9052415C8FC2358DA23841000000F010905241EC51B85E95A2384148E17A14119052417B14AE4795A23841CDCCCCCC1090524114AE47E18CA2384185EB51F80F90524148E17AD480A2384114AE47A10E9052413D0AD76383A23841713D0AF70C9052417B14AEC784A23841A4703D8A0C9052410000000086A23841A4703D0A0B9052411F85EB9187A23841B81E851B09905241F6285CCF86A2384100000010099052417B14AE4787A2384185EB51180890524114AE472186A23841CDCCCCFC079052410AD7A3B086A23841C3F5280C07905241333333B385A23841CDCCCC0C07905241000000407EA2384152B81E15079052419A9999197BA23841A4703D2A079052416666666673A2384114AE47710790524114AE47A16EA238413D0AD7F30690524114AE472170A238418FC2F5D8059052413D0AD72372A2384185EB511806905241A4703DCA71A23841D7A3707D05905241EC51B8DE7EA238411F85EBD104905241E17A14AE76A23841333333E30390524185EB51B875A23841713D0A47029052415C8FC2F576A23841D7A3703D029052419A99999976A2384114AE475101905241333333B378A23841EC51B83E019052410AD7A3307CA238410AD7A320019052418FC2F52885A23841295C8FD20090524148E17A9483A238416666664600905241295C8FC276A238411F85EB9100905241CDCCCC4C76A2384100000070FF8F5241AE47E13A76A2384133333343FF8F52417B14AE0783A23841D7A370FDFE8F5241E17A14AE81A23841C3F5283CFE8F52415C8FC2357DA2384114AE47A1FE8F5241CDCCCC8C7BA238415C8FC275FD8F524148E17AD47FA238417B14AE17FD8F5241000000807EA238413D0AD7A3FC8F5241713D0AD776A2384133333363FD8F5241CDCCCC8C73A2384152B81EF5FD8F5241E17A14AE70A2384114AE4711FE8F524185EB51B870A23841B81E852BFF8F524152B81E056CA2384114AE4731FF8F5241B81E856B6BA2384152B81E25FE8F5241AE47E13A69A23841E17A142EFE8F52419A99995962A238415C8FC275FE8F52415C8FC27562A238411F85EB710090524114AE47A15BA23841EC51B86E00905241EC51B85E5BA238419A9999E902905241295C8F025BA238417B14AE8704905241A4703D8A54A23841713D0A7704905241C3F5285C51A2384148E17A44049052418FC2F5E84CA23841A4703D4A049052410AD7A3304CA2384148E17A94049052419A9999994CA238413D0AD7F305905241AE47E1FA49A2384114AE471106905241EC51B85E49A23841AE47E1FA07905241AE47E13A43A238415C8FC255099052416666662644A23841D7A3707D0A9052415C8FC2F53FA23841CDCCCC2C0B90524185EB517839A2384185EB51380C90524152B81E4532A23841D7A370DD099052419A9999592FA2384152B81E4509905241D7A3707D2AA23841B81E857B089052415C8FC27526A238416666667608905241EC51B81E26A238417B14AE7707905241295C8F0226A23841F6285C1F07905241666666A61CA23841CDCCCC6C07905241713D0A1716A23841B81E856B07905241B81E85EB15A2384100000040079052411F85EB1108A2384114AE4741079052415C8FC23505A2384148E17AC40790524152B81E0506A23841EC51B84E09905241713D0A5707A23841AE47E10A0A905241EC51B81E12A2384152B81EA50890524152B81E4521A23841F6285CDF0890524148E17A1427A23841EC51B80E099052415C8FC2B52AA2384185EB5168099052413D0AD7E32FA23841CDCCCC3C0A9052413D0AD7A331A23841333333930A90524185EB51F833A238410AD7A3B00B9052411F85EB5135A23841EC51B8AE0B90524185EB513836A23841333333530D9052410000004030A238415C8FC2B50E905241000000802FA238415C8FC2750E9052410000008028A238419A9999B90E905241F6285C0F28A23841333333630E90524114AE47E123A23841333333730E905241D7A3707D23A2384152B81E750E9052410000008023A2384185EB51E80E905241D7A370BD1EA23841713D0A170F9052419A9999991EA23841333333830F9052419A9999991CA238411F85EB810F90524152B81E450EA2384152B81E750F9052417B14AE470AA23841EC51B89E0F905241B81E85EB05A238410AD7A3F00F905241D7A3707DFFA138417B14AEF71090524185EB51F8FDA138413D0AD72311905241295C8F02FAA13841EC51B83E11905241713D0A17EFA13841E17A145E129052417B14AE87CBA1384152B81E05179052418FC2F528C0A13841D7A3709D17905241D7A370BDC0A13841F6285C5F18905241295C8F82CBA138419A9999F917905241AE47E1BAD7A138415C8FC255169052411F85EB91E0A13841000000401590524114AE47A1E2A1384185EB5108159052415C8FC235ECA13841C3F5286C13905241C3F528DCF4A13841000000701290524152B81E45F5A138415C8FC2A51290524100000040F6A13841CDCCCC7C129052417B14AE47FBA138410000000012905241EC51B85E00A2384185EB51A8119052413D0AD7A305A238419A99990911905241EC51B81E0AA238411F85EB611090524148E17A940EA23841A4703D0A1090524152B81E0514A2384152B81EE50F905241F6285CCF15A238410AD7A3E00F9052417B14AEC718A23841CDCCCCDC0F9052419A9999191AA238415C8FC2E50F905241EC51B81E20A238415C8FC2E50F90524148E17A1420A23841333333C30F9052417B14AE8729A23841713D0AA70F905241000000002AA238413D0AD733119052411F85EB9129A23841C3F528EC12905241E17A142E28A238419A999919149052418FC2F5A825A23841CDCCCC1C15905241C3F5285C21A2384114AE473116905241F6285C4F1BA2384152B81E4517905241D7A3707D1AA2384148E17A1417905241C3F5285C19A23841D7A3702D179052413333333318A23841B81E85CB17905241000000C017A2384185EB5108189052413D0AD72310A238419A9999F91790524148E17A5410A2384148E17AD41690524148E17AD40DA2384152B81ED516905241B81E85AB09A23841F6285C1F179052418FC2F5A809A2384185EB51C8179052418FC2F56808A238417B14AEC7179052410000008008A2384185EB515818905241AE47E1BA16A23841F6285C6F189052410AD7A33017A23841C3F5289C18905241000000C012A23841AE47E10A1A9052411F85EB5110A238413D0AD7131B905241000000800DA238415C8FC2451C90524148E17A140DA23841A4703D4A1C9052413D0AD7230BA2384148E17A141E905241295C8F4205A23841295C8F421E905241F6285C4F00A238419A9999691E905241C3F5289CFDA13841AE47E16A1E905241D7A370FDFDA1384114AE47711F90524185EB51F801A23841B81E855B1F905241A4703D0A05A23841CDCCCCAC1F905241E17A14AE02A23841EC51B89E20905241295C8F82FFA138419A9999E9219052419A999919FEA1384185EB5188239052410AD7A330FAA13841E17A14DE25905241C3F5281CF9A13841F6285CFF26905241AE47E13AF8A138415C8FC2E527905241CDCCCC8CF7A1384185EB51B82890524185EB51F8F7A138413333334329905241C3F5281CF6A138418FC2F5182C905241A4703D4AF5A13841EC51B8BE2C905241CDCCCC0CF4A13841713D0AF72E90524185EB5138F3A13841000000502F905241000000C0F1A138410AD7A3103190524111000000CDCCCC4C6AA23841713D0A170A905241CDCCCC4C6FA238411F85EB710790524148E17A947AA2384114AE47410890524185EB51387BA23841D7A370ED07905241666666267BA23841713D0A7707905241EC51B85E7EA2384114AE476107905241E17A14AE7EA2384114AE473108905241713D0A5785A23841CDCCCCBC089052410AD7A33083A23841F6285C9F0B9052413333337382A23841666666460C90524148E17AD481A23841333333D30C90524114AE472181A23841333333730D905241AE47E1BA7FA23841CDCCCC3C0E9052418FC2F56876A238415C8FC2050D90524185EB513872A238418FC2F5D80B90524185EB513870A23841EC51B82E0B905241CDCCCC4C6AA23841713D0A170A90524113000000A4703DCA6BA238415C8FC295FF8F5241B81E856B74A238410AD7A380FF8F5241EC51B89E74A23841E17A149E00905241AE47E1BA74A23841F6285C4F019052419A99995974A23841295C8F520290524148E17AD473A2384114AE47B10390524152B81EC572A2384114AE4701059052417B14AE476DA23841AE47E1DA04905241F6285C8F6DA23841333333A303905241000000006CA2384152B81E9503905241EC51B81E69A23841A4703D7A039052410AD7A3B068A23841B81E85AB049052415C8FC2F55CA23841CDCCCC8C0490524152B81E455DA238411F85EB0103905241333333B35DA23841AE47E1DA00905241EC51B85E67A23841C3F528FC009052410AD7A3B067A23841CDCCCCCCFF8F524185EB51B86BA23841333333C3FF8F5241A4703DCA6BA238415C8FC295FF8F5241020000003D0AD7A346A238413D0AD7E3099052413D0AD7A346A238413D0AD7E309905241100000007B14AEC74DA238410AD7A3B008905241EC51B85E4EA23841B81E850B079052413D0AD7234FA23841C3F528DC0490524185EB51385CA23841EC51B8EE04905241B81E852B60A23841A4703DDA049052410000008066A23841A4703DFA049052411F85EB116AA23841CDCCCC0C05905241CDCCCC8C6EA23841A4703D5A05905241A4703D0A6CA238417B14AE37079052411F85EBD16AA23841A4703DCA07905241AE47E1FA68A23841E17A14FE08905241295C8F0268A238410AD7A320099052419A99999963A23841AE47E10A099052415C8FC2B55AA23841333333C30890524114AE476156A23841CDCCCCBC089052417B14AEC74DA238410AD7A3B008905241');
+SELECT '#408.4', st_isvalidreason('0106000020BB0B000001000000010300000005000000D6000000000000C0F1A138410AD7A3103190524114AE4721F7A138410000000030905241713D0A57FAA1384185EB51982C9052417B14AE87FAA13841000000402A905241AE47E13AFBA1384114AE474128905241EC51B81EFDA138413D0AD7632690524152B81E85FFA13841D7A3707D2590524152B81E4500A23841713D0A072590524100000000FFA13841713D0AF724905241CDCCCCCCFFA13841CDCCCC0C249052419A99991901A238419A999919249052411F85EBD101A23841D7A3704D23905241E17A14AE02A23841A4703D3A2290524185EB51F808A23841000000D021905241E17A14EE0BA238413333335321905241666666A615A23841B81E85AB1F905241713D0AD710A23841B81E858B1E905241666666260CA2384114AE4731209052410AD7A37009A23841CDCCCCEC20905241AE47E13A06A23841EC51B87E219052419A9999D903A23841EC51B80E21905241EC51B8DE08A238418FC2F5681F905241666666660EA23841A4703D9A1D9052413D0AD7A30FA2384114AE47A11C9052413333333311A23841000000101C90524148E17A1414A23841333333931A905241EC51B81E1AA23841EC51B89E1890524185EB51381CA23841D7A370BD17905241295C8FC220A2384185EB51C816905241C3F528DC2BA238418FC2F5E814905241E17A14EE2EA23841EC51B8FE13905241AE47E1FA2BA23841EC51B8EE119052415C8FC2F52BA2384185EB51C810905241333333332EA2384114AE4701109052417B14AEC73BA238410AD7A3300D905241CDCCCCCC43A238417B14AE870B905241CDCCCC4C45A23841A4703D3A0B9052413D0AD7A34DA238411F85EB810A905241295C8F8250A23841CDCCCCBC09905241000000C053A238410AD7A36009905241A4703D0A5CA2384114AE4751099052418FC2F5A866A23841A4703D4A0A9052410000008069A2384114AE47B10A9052415C8FC2B573A23841B81E851B0D905241AE47E1FA76A23841666666C60D9052417B14AE077BA238411F85EB510E905241AE47E1FA7FA23841666666E60E9052415C8FC2358DA23841000000F010905241EC51B85E95A2384148E17A14119052417B14AE4795A23841CDCCCCCC1090524114AE47E18CA2384185EB51F80F90524148E17AD480A2384114AE47A10E9052413D0AD76383A23841713D0AF70C9052417B14AEC784A23841A4703D8A0C9052410000000086A23841A4703D0A0B9052411F85EB9187A23841B81E851B09905241F6285CCF86A2384100000010099052417B14AE4787A2384185EB51180890524114AE472186A23841CDCCCCFC079052410AD7A3B086A23841C3F5280C07905241333333B385A23841CDCCCC0C07905241000000407EA2384152B81E15079052419A9999197BA23841A4703D2A079052416666666673A2384114AE47710790524114AE47A16EA238413D0AD7F30690524114AE472170A238418FC2F5D8059052413D0AD72372A2384185EB511806905241A4703DCA71A23841D7A3707D05905241EC51B8DE7EA238411F85EBD104905241E17A14AE76A23841333333E30390524185EB51B875A23841713D0A47029052415C8FC2F576A23841D7A3703D029052419A99999976A2384114AE475101905241333333B378A23841EC51B83E019052410AD7A3307CA238410AD7A320019052418FC2F52885A23841295C8FD20090524148E17A9483A238416666664600905241295C8FC276A238411F85EB9100905241CDCCCC4C76A2384100000070FF8F5241AE47E13A76A2384133333343FF8F52417B14AE0783A23841D7A370FDFE8F5241E17A14AE81A23841C3F5283CFE8F52415C8FC2357DA2384114AE47A1FE8F5241CDCCCC8C7BA238415C8FC275FD8F524148E17AD47FA238417B14AE17FD8F5241000000807EA238413D0AD7A3FC8F5241713D0AD776A2384133333363FD8F5241CDCCCC8C73A2384152B81EF5FD8F5241E17A14AE70A2384114AE4711FE8F524185EB51B870A23841B81E852BFF8F524152B81E056CA2384114AE4731FF8F5241B81E856B6BA2384152B81E25FE8F5241AE47E13A69A23841E17A142EFE8F52419A99995962A238415C8FC275FE8F52415C8FC27562A238411F85EB710090524114AE47A15BA23841EC51B86E00905241EC51B85E5BA238419A9999E902905241295C8F025BA238417B14AE8704905241A4703D8A54A23841713D0A7704905241C3F5285C51A2384148E17A44049052418FC2F5E84CA23841A4703D4A049052410AD7A3304CA2384148E17A94049052419A9999994CA238413D0AD7F305905241AE47E1FA49A2384114AE471106905241EC51B85E49A23841AE47E1FA07905241AE47E13A43A238415C8FC255099052416666662644A23841D7A3707D0A9052415C8FC2F53FA23841CDCCCC2C0B90524185EB517839A2384185EB51380C90524152B81E4532A23841D7A370DD099052419A9999592FA2384152B81E4509905241D7A3707D2AA23841B81E857B089052415C8FC27526A238416666667608905241EC51B81E26A238417B14AE7707905241295C8F0226A23841F6285C1F07905241666666A61CA23841CDCCCC6C07905241713D0A1716A23841B81E856B07905241B81E85EB15A2384100000040079052411F85EB1108A2384114AE4741079052415C8FC23505A2384148E17AC40790524152B81E0506A23841EC51B84E09905241713D0A5707A23841AE47E10A0A905241EC51B81E12A2384152B81EA50890524152B81E4521A23841F6285CDF0890524148E17A1427A23841EC51B80E099052415C8FC2B52AA2384185EB5168099052413D0AD7E32FA23841CDCCCC3C0A9052413D0AD7A331A23841333333930A90524185EB51F833A238410AD7A3B00B9052411F85EB5135A23841EC51B8AE0B90524185EB513836A23841333333530D9052410000004030A238415C8FC2B50E905241000000802FA238415C8FC2750E9052410000008028A238419A9999B90E905241F6285C0F28A23841333333630E90524114AE47E123A23841333333730E905241D7A3707D23A2384152B81E750E9052410000008023A2384185EB51E80E905241D7A370BD1EA23841713D0A170F9052419A9999991EA23841333333830F9052419A9999991CA238411F85EB810F90524152B81E450EA2384152B81E750F9052417B14AE470AA23841EC51B89E0F905241B81E85EB05A238410AD7A3F00F905241D7A3707DFFA138417B14AEF71090524185EB51F8FDA138413D0AD72311905241295C8F02FAA13841EC51B83E11905241713D0A17EFA13841E17A145E129052417B14AE87CBA1384152B81E05179052418FC2F528C0A13841D7A3709D17905241D7A370BDC0A13841F6285C5F18905241295C8F82CBA138419A9999F917905241AE47E1BAD7A138415C8FC255169052411F85EB91E0A13841000000401590524114AE47A1E2A1384185EB5108159052415C8FC235ECA13841C3F5286C13905241C3F528DCF4A13841000000701290524152B81E45F5A138415C8FC2A51290524100000040F6A13841CDCCCC7C129052417B14AE47FBA138410000000012905241EC51B85E00A2384185EB51A8119052413D0AD7A305A238419A99990911905241EC51B81E0AA238411F85EB611090524148E17A940EA23841A4703D0A1090524152B81E0514A2384152B81EE50F905241F6285CCF15A238410AD7A3E00F9052417B14AEC718A23841CDCCCCDC0F9052419A9999191AA238415C8FC2E50F905241EC51B81E20A238415C8FC2E50F90524148E17A1420A23841333333C30F9052417B14AE8729A23841713D0AA70F905241000000002AA238413D0AD733119052411F85EB9129A23841C3F528EC12905241E17A142E28A238419A999919149052418FC2F5A825A23841CDCCCC1C15905241C3F5285C21A2384114AE473116905241F6285C4F1BA2384152B81E4517905241D7A3707D1AA2384148E17A1417905241C3F5285C19A23841D7A3702D179052413333333318A23841B81E85CB17905241000000C017A2384185EB5108189052413D0AD72310A238419A9999F91790524148E17A5410A2384148E17AD41690524148E17AD40DA2384152B81ED516905241B81E85AB09A23841F6285C1F179052418FC2F5A809A2384185EB51C8179052418FC2F56808A238417B14AEC7179052410000008008A2384185EB515818905241AE47E1BA16A23841F6285C6F189052410AD7A33017A23841C3F5289C18905241000000C012A23841AE47E10A1A9052411F85EB5110A238413D0AD7131B905241000000800DA238415C8FC2451C90524148E17A140DA23841A4703D4A1C9052413D0AD7230BA2384148E17A141E905241295C8F4205A23841295C8F421E905241F6285C4F00A238419A9999691E905241C3F5289CFDA13841AE47E16A1E905241D7A370FDFDA1384114AE47711F90524185EB51F801A23841B81E855B1F905241A4703D0A05A23841CDCCCCAC1F905241E17A14AE02A23841EC51B89E20905241295C8F82FFA138419A9999E9219052419A999919FEA1384185EB5188239052410AD7A330FAA13841E17A14DE25905241C3F5281CF9A13841F6285CFF26905241AE47E13AF8A138415C8FC2E527905241CDCCCC8CF7A1384185EB51B82890524185EB51F8F7A138413333334329905241C3F5281CF6A138418FC2F5182C905241A4703D4AF5A13841EC51B8BE2C905241CDCCCC0CF4A13841713D0AF72E90524185EB5138F3A13841000000502F905241000000C0F1A138410AD7A3103190524111000000CDCCCC4C6AA23841713D0A170A905241CDCCCC4C6FA238411F85EB710790524148E17A947AA2384114AE47410890524185EB51387BA23841D7A370ED07905241666666267BA23841713D0A7707905241EC51B85E7EA2384114AE476107905241E17A14AE7EA2384114AE473108905241713D0A5785A23841CDCCCCBC089052410AD7A33083A23841F6285C9F0B9052413333337382A23841666666460C90524148E17AD481A23841333333D30C90524114AE472181A23841333333730D905241AE47E1BA7FA23841CDCCCC3C0E9052418FC2F56876A238415C8FC2050D90524185EB513872A238418FC2F5D80B90524185EB513870A23841EC51B82E0B905241CDCCCC4C6AA23841713D0A170A90524113000000A4703DCA6BA238415C8FC295FF8F5241B81E856B74A238410AD7A380FF8F5241EC51B89E74A23841E17A149E00905241AE47E1BA74A23841F6285C4F019052419A99995974A23841295C8F520290524148E17AD473A2384114AE47B10390524152B81EC572A2384114AE4701059052417B14AE476DA23841AE47E1DA04905241F6285C8F6DA23841333333A303905241000000006CA2384152B81E9503905241EC51B81E69A23841A4703D7A039052410AD7A3B068A23841B81E85AB049052415C8FC2F55CA23841CDCCCC8C0490524152B81E455DA238411F85EB0103905241333333B35DA23841AE47E1DA00905241EC51B85E67A23841C3F528FC009052410AD7A3B067A23841CDCCCCCCFF8F524185EB51B86BA23841333333C3FF8F5241A4703DCA6BA238415C8FC295FF8F5241020000003D0AD7A346A238413D0AD7E3099052413D0AD7A346A238413D0AD7E309905241100000007B14AEC74DA238410AD7A3B008905241EC51B85E4EA23841B81E850B079052413D0AD7234FA23841C3F528DC0490524185EB51385CA23841EC51B8EE04905241B81E852B60A23841A4703DDA049052410000008066A23841A4703DFA049052411F85EB116AA23841CDCCCC0C05905241CDCCCC8C6EA23841A4703D5A05905241A4703D0A6CA238417B14AE37079052411F85EBD16AA23841A4703DCA07905241AE47E1FA68A23841E17A14FE08905241295C8F0268A238410AD7A320099052419A99999963A23841AE47E10A099052415C8FC2B55AA23841333333C30890524114AE476156A23841CDCCCCBC089052417B14AEC74DA238410AD7A3B008905241');
+
+-- #457 --
+SELECT '#457.1', st_astext(st_collectionExtract('POINT(0 0)', 1));
+SELECT '#457.2', st_astext(st_collectionExtract('POINT(0 0)', 2));
+SELECT '#457.3', st_astext(st_collectionExtract('POINT(0 0)', 3));
+SELECT '#457.4', st_astext(st_collectionExtract('LINESTRING(0 0, 1 1)', 1));
+SELECT '#457.5', st_astext(st_collectionExtract('LINESTRING(0 0, 1 1)', 2));
+SELECT '#457.6', st_astext(st_collectionExtract('LINESTRING(0 0, 1 1)', 3));
+SELECT '#457.7', st_astext(st_collectionExtract('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))', 1));
+SELECT '#457.8', st_astext(st_collectionExtract('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))', 2));
+SELECT '#457.9', st_astext(st_collectionExtract('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))', 3));
+
+-- #835 --
+SELECT '#835.1', st_astext(st_collectionExtract('POLYGON EMPTY', 1));
+SELECT '#835.2', st_astext(st_collectionExtract('POLYGON EMPTY', 2));
+SELECT '#835.3', st_astext(st_collectionExtract('POLYGON EMPTY', 3));
+SELECT '#835.4', st_astext(st_collectionExtract('LINESTRING EMPTY', 1));
+SELECT '#835.5', st_astext(st_collectionExtract('LINESTRING EMPTY', 2));
+SELECT '#835.6', st_astext(st_collectionExtract('LINESTRING EMPTY', 3));
+SELECT '#835.7', st_astext(st_collectionExtract('POINT EMPTY', 1));
+SELECT '#835.8', st_astext(st_collectionExtract('POINT EMPTY', 2));
+SELECT '#835.9', st_astext(st_collectionExtract('POINT EMPTY', 3));
+SELECT '#835.10', st_astext(st_collectionExtract('GEOMETRYCOLLECTION EMPTY', 1));
+SELECT '#835.11', st_astext(st_collectionExtract('GEOMETRYCOLLECTION EMPTY', 2));
+SELECT '#835.12', st_astext(st_collectionExtract('GEOMETRYCOLLECTION EMPTY', 3));
+
+-- #650 --
+SELECT '#650', ST_AsText(ST_Collect(ARRAY[ST_MakePoint(0,0), ST_MakePoint(1,1), null, ST_MakePoint(2,2)]));
+
+-- #662 --
+--SELECT '#662', ST_MakePolygon(ST_AddPoint(ST_AddPoint(ST_MakeLine(ST_SetSRID(ST_MakePointM(i+m,j,m),4326),ST_SetSRID(ST_MakePointM(j+m,i-m,m),4326)),ST_SetSRID(ST_MakePointM(i,j,m),4326)),ST_SetSRID(ST_MakePointM(i+m,j,m),4326))) As the_geom FROM generate_series(-10,50,20) As i CROSS JOIN generate_series(50,70, 20) As j CROSS JOIN generate_series(1,2) As m ORDER BY i, j, m, i*j*m LIMIT 1;
+
+-- #667 --
+SELECT '#667', ST_AsEWKT(ST_LineToCurve(ST_Buffer(ST_SetSRID(ST_Point(i,j),4326), j))) As the_geom FROM generate_series(-10,50,10) As i CROSS JOIN generate_series(40,70, 20) As j ORDER BY i, j, i*j LIMIT 1;
+
+-- #677 --
+SELECT '#677',round(ST_Distance_Spheroid(ST_GeomFromEWKT('MULTIPOLYGON(((-10 40,-10 55,-10 70,5 40,-10 40)))'), ST_GeomFromEWKT('MULTIPOINT(20 40,20 55,20 70,35 40,35 55,35 70,50 40,50 55,50 70)'), 'SPHEROID["GRS_1980",6378137,298.257222101]')) As result;
+
+-- #680 --
+SELECT '#680', encode(ST_AsBinary(geography(foo1.the_geom)),'hex') As result FROM ((SELECT ST_SetSRID(ST_MakePointM(i,j,m),4326) As the_geom FROM generate_series(-10,50,10) As i CROSS JOIN generate_series(50,70, 20) AS j CROSS JOIN generate_series(1,2) As m ORDER BY i, j, i*j*m)) As foo1 LIMIT 1;
+
+-- #681 --
+SELECT '#681a', ST_AsGML(ST_GeomFromText('POINT EMPTY', 4326));
+SELECT '#681b', ST_AsGML(ST_GeomFromText('POLYGON EMPTY', 4326));
+SELECT '#681c', ST_AsGML(ST_GeomFromText('LINESTRING EMPTY', 4326));
+SELECT '#681d', ST_AsGML(ST_GeomFromText('MULTIPOINT EMPTY', 4326));
+SELECT '#681e', ST_AsGML(ST_GeomFromText('MULTILINESTRING EMPTY', 4326));
+SELECT '#681f', ST_AsGML(ST_GeomFromText('MULTIPOLYGON EMPTY', 4326));
+SELECT '#681g', ST_AsGML(ST_GeomFromText('GEOMETRYCOLLECTION EMPTY', 4326));
+
+
+-- #682 --
+SELECT '#682', ST_Buffer(ST_GeomFromText('POLYGON EMPTY',4326) , 0.5);
+
+-- #683 --
+SELECT '#683', ST_BuildArea(ST_GeomFromText('POINT EMPTY',4326));
+
+-- #684,#2109 --
+SELECT '#684,#2109', ST_AsEWKT(ST_Centroid(ST_GeomFromText('POLYGON EMPTY',4326)));
+SELECT '#2109', ST_AsEWKT(ST_Centroid(ST_GeomFromText('MULTILINESTRING ZM EMPTY',3395)));
+
+-- #685 --
+SELECT '#685', ST_ConvexHull(ST_GeomFromText('POLYGON EMPTY',4326));
+
+-- #686 --
+SELECT '#686', ST_COLLECT(ST_GeomFromText('POLYGON EMPTY',4326),ST_GeomFromText('TRIANGLE EMPTY',4326));
+
+-- #687 --
+SELECT '#687', ST_DFullyWithin(ST_GeomFromText('LINESTRING(-10 50,50 -10)',4326), ST_GeomFromText('POLYGON EMPTY',4326),5);
+
+-- #689 --
+SELECT '#689', ST_CoveredBy(ST_GeomFromText('POLYGON EMPTY'), ST_GeomFromText('LINESTRING(-10 50,50 -10)'));
+
+-- #690 --
+SELECT '#690';
+SELECT ST_MakeLine(ST_GeomFromText('POINT(-11.1111111 40)'), ST_GeomFromText('LINESTRING(-11.1111111 70,70 -11.1111111)')) As result;
+
+-- #693 --
+SELECT '#693a', ST_GeomFromEWKT('SRID=4326;POLYGONM((-71.1319 42.2503 1,-71.132 42.2502 3,-71.1323 42.2504 -2,-71.1322 42.2505 1,-71.1319 42.2503 0))');
+SELECT '#693b', ST_GeomFromEWKT('SRID=4326;POLYGONM((-71.1319 42.2512 0,-71.1318 42.2511 20,-71.1317 42.2511 -20,-71.1317 42.251 5,-71.1317 42.2509 4,-71.132 42.2511 6,-71.1319 42.2512 30))');
+
+-- #694 --
+SELECT '#694';
+SELECT ST_MakePolygon('POINT(1 2)'::geometry);
+
+-- #695 --
+SELECT '#695';
+SELECT ST_RemovePoint('POINT(-11.1111111 40)'::geometry, 1);
+
+-- #696 --
+SELECT '#696',ST_Segmentize(ST_GeomFromEWKT('PolyhedralSurface( ((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)), ((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)), ((0 0 0, 1 0 0, 1 0 1, 0 0 1, 0 0 0)), ((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)), ((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)), ((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)) )'), 0.5);
+
+-- #720 --
+SELECT '#720', ST_AsText(ST_SnapTogrid(ST_Transform(ST_GeomFromText('MULTIPOINT(-10 40,-10 55,-10 70,5 40,5 55,5 70,20 40,20 55,20 70,35 40,35 55,35 70,50 40,50 55,50 70)',4326), 3395), 0.01));
+
+-- #723 --
+SELECT '#723',
+ ST_SnapToGrid( ST_Intersection(a.geog, b.geog)::geometry, 0.00001)
+FROM (VALUES (ST_GeogFromText('SRID=4326;POINT(-11.1111111 40)') ), (ST_GeogFromText('SRID=4326;POINT(-11.1111111 55)') ) ) As  a(geog) CROSS JOIN ( VALUES (ST_GeogFromText('SRID=4326;POINT(-11.1111111 40)') ), (ST_GeogFromText('SRID=4326;POINT(-11.1111111 55)') )) As b(geog);
+
+-- #729 --
+--SELECT '#729',ST_MakeLine(foo1.the_geom) As result FROM ((SELECT ST_GeomFromText('POINT EMPTY',4326) As the_geom UNION ALL SELECT ST_GeomFromText('MULTIPOINT EMPTY',4326) As the_geom UNION ALL SELECT ST_GeomFromText('MULTIPOLYGON EMPTY',4326) As the_geom UNION ALL SELECT ST_GeomFromText('LINESTRING EMPTY',4326) As the_geom UNION ALL SELECT ST_GeomFromText('MULTILINESTRING EMPTY',4326) As the_geom ) ) As foo1;
+
+-- #804
+SELECT '#804', ST_AsGML(3, 'SRID=4326;POINT(0 0)'::geometry, 0, 1);
+
+
+-- #845
+SELECT '#845', ST_Intersects('POINT(169.69960846592 -46.5061209281002)'::geometry, 'POLYGON((169.699607857174 -46.5061218662,169.699607857174 -46.5061195965597,169.699608806526 -46.5061195965597,169.699608806526 -46.5061218662,169.699607857174 -46.5061218662))'::geometry);
+
+-- #834
+SELECT '#834', ST_AsEWKT(ST_Intersection('LINESTRING(0 0,0 10,10 10,10 0)', 'LINESTRING(10 10 4,10 0 5,0 0 5)'));
+
+-- #884 --
+CREATE TABLE foo (id integer, the_geom geometry);
+INSERT INTO foo VALUES (1, st_geomfromtext('MULTIPOLYGON(((-113.6 35.4,-113.6 35.8,-113.2 35.8,-113.2 35.4,-113.6 35.4),(-113.5 35.5,-113.3 35.5,-113.3 35.7,-113.5 35.7,-113.5 35.5)))'));
+INSERT INTO foo VALUES (2, st_geomfromtext('MULTIPOLYGON(((-113.7 35.3,-113.7 35.9,-113.1 35.9,-113.1 35.3,-113.7 35.3),(-113.6 35.4,-113.2 35.4,-113.2 35.8,-113.6 35.8,-113.6 35.4)),((-113.5 35.5,-113.5 35.7,-113.3 35.7,-113.3 35.5,-113.5 35.5)))'));
+
+select '#884', id, ST_Within(
+ST_GeomFromText('POINT (-113.4 35.6)'), the_geom
+) from foo;
+
+select '#938', 'POLYGON EMPTY'::geometry::box2d;
+
+DROP TABLE foo;
+
+-- #668 --
+select '#668',box2d('CIRCULARSTRING(10 2,12 2,14 2)'::geometry) as b;
+
+-- #711 --
+select '#711', ST_GeoHash(ST_GeomFromText('POLYGON EMPTY',4326));
+
+-- #712 --
+SELECT '#712',ST_IsValid(ST_GeomFromText('POLYGON EMPTY',4326));
+
+-- #756
+WITH inp AS ( SELECT 'LINESTRING(0 0, 1 1)'::geometry as s,
+                     'LINESTRING EMPTY'::geometry as e      )
+ SELECT '#756.1', ST_Equals(s, st_multi(s)),
+                  ST_Equals(s, st_collect(s, e))
+ FROM inp;
+
+
+-- #1023 --
+select '#1023', 'POINT(10 4)'::geometry = 'POINT(10 4)'::geometry;
+select '#1023.a', 'POINT(10 4)'::geometry = 'POINT(10 5)'::geometry;
+select '#1023.b', postgis_addbbox('POINT(10 4)'::geometry) = 'POINT(10 4)'::geometry;
+
+-- #1069 --
+select '#1060', ST_Relate(ST_GeomFromText('POINT EMPTY',4326), ST_GeomFromText('POINT EMPTY',4326)) As result;
+
+-- #1273 --
+WITH p AS ( SELECT 'POINT(832694.188 816254.625)'::geometry as g ) 
+SELECT '#1273', st_equals(p.g, postgis_addbbox(p.g)) from p;
+
+-- Another for #1273 --
+WITH p AS ( SELECT 'MULTIPOINT((832694.188 816254.625))'::geometry as g ) 
+SELECT '#1273.1', st_equals(p.g, postgis_dropbbox(p.g)) from p;
+
+-- #877, #818
+create table t(g geometry);
+select '#877.1', ST_EstimatedExtent('t','g');
+analyze t;
+select '#877.2', ST_EstimatedExtent('public', 't','g');
+select '#877.2.deprecated', ST_Estimated_Extent('public', 't','g');
+insert into t(g) values ('LINESTRING(-10 -50, 20 30)');
+
+-- #877.3
+with e as ( select ST_EstimatedExtent('t','g') as e )
+select '#877.3', round(st_xmin(e.e)::numeric, 5), round(st_xmax(e.e)::numeric, 5),
+round(st_ymin(e.e)::numeric, 5), round(st_ymax(e.e)::numeric, 5) from e;
+
+-- #877.4
+analyze t;
+with e as ( select ST_EstimatedExtent('t','g') as e )
+select '#877.4', round(st_xmin(e.e)::numeric, 5), round(st_xmax(e.e)::numeric, 5),
+round(st_ymin(e.e)::numeric, 5), round(st_ymax(e.e)::numeric, 5) from e;
+
+-- #877.5
+truncate t;
+with e as ( select ST_EstimatedExtent('t','g') as e )
+select '#877.5', round(st_xmin(e.e)::numeric, 5), round(st_xmax(e.e)::numeric, 5),
+round(st_ymin(e.e)::numeric, 5), round(st_ymax(e.e)::numeric, 5) from e;
+drop table t;
+
+-- #1292
+SELECT '#1292', ST_AsText(ST_SnapToGrid(ST_GeomFromText(
+       'GEOMETRYCOLLECTION(POINT(180 90),POLYGON((140 50,150 50,180 50,140 50),(140 60,150 60,180 60,140 60)))'
+       , 4326), 0.00001)::geography);
+
+-- #1292.1
+SELECT '#1292.1', ST_AsText(ST_GeomFromText('POINT(180.00000000001 95)')::geography),
+       ST_AsText(ST_GeomFromText('POINT(185 90.00000000001)')::geography);
+
+-- #1320
+SELECT '<#1320>';
+CREATE TABLE A ( geom geometry(MultiPolygon, 4326),
+                 geog geography(MultiPolygon, 4326) );
+-- Valid inserts
+INSERT INTO a(geog) VALUES('SRID=4326;MULTIPOLYGON (((0 0, 10 0, 10 10, 0 0)))'::geography);
+INSERT INTO a(geom) VALUES('SRID=4326;MULTIPOLYGON (((0 0, 10 0, 10 10, 0 0)))'::geometry);
+SELECT '#1320.geog.1', geometrytype(geog::geometry), st_srid(geog::geometry) FROM a where geog is not null;
+SELECT '#1320.geom.1', geometrytype(geom), st_srid(geom) FROM a where geom is not null;
+-- Type mismatches is not allowed
+INSERT INTO a(geog) VALUES('SRID=4326;POLYGON ((0 0, 10 0, 10 10, 0 0))'::geography);
+INSERT INTO a(geom) VALUES('SRID=4326;POLYGON ((0 0, 10 0, 10 10, 0 0))'::geometry);
+SELECT '#1320.geog.2', geometrytype(geog::geometry), st_srid(geog::geometry) FROM a where geog is not null;
+SELECT '#1320.geom.2', geometrytype(geom), st_srid(geom) FROM a where geom is not null;
+-- Even if it's a trigger changing the type
+CREATE OR REPLACE FUNCTION triga() RETURNS trigger AS
+$$ BEGIN
+       NEW.geom = ST_GeometryN(New.geom,1);
+       NEW.geog = ST_GeometryN(New.geog::geometry,1)::geography;
+       RETURN NEW;
+END; $$ language plpgsql VOLATILE;
+CREATE TRIGGER triga_before
+  BEFORE INSERT ON a FOR EACH ROW
+  EXECUTE PROCEDURE triga();
+INSERT INTO a(geog) VALUES('SRID=4326;MULTIPOLYGON (((0 0, 10 0, 10 10, 0 0)))'::geography);
+INSERT INTO a(geom) VALUES('SRID=4326;MULTIPOLYGON (((0 0, 10 0, 10 10, 0 0)))'::geometry);
+SELECT '#1320.geog.3', geometrytype(geog::geometry), st_srid(geog::geometry) FROM a where geog is not null;
+SELECT '#1320.geom.3', geometrytype(geom), st_srid(geom) FROM a where geom is not null;
+DROP TABLE A;
+DROP FUNCTION triga();
+SELECT '</#1320>';
+
+-- st_AsText POLYGON((0 0,10 0,10 10,0 0))
+
+
+-- #1344
+select '#1344', octet_length(ST_AsEWKB(st_makeline(g))) FROM ( values ('POINT(0 0)'::geometry ) ) as foo(g);
+
+-- #1385
+SELECT '#1385', ST_Extent(g) FROM ( select null::geometry as g ) as foo; 
+
+-- #657
+SELECT '#657.1',Round(ST_X(ST_Project('POINT(175 10)'::geography, 2000000, 3.1415/2)::GEOMETRY)::numeric,2);
+SELECT '#657.2',Round(ST_Distance(ST_Project('POINT(10 10)'::geography, 10, 0), 'POINT(10 10)'::geography)::numeric,2);
+SELECT '#657.3',ST_DWithin(ST_Project('POINT(10 10)'::geography, 2000, pi()/2), 'POINT(10 10)'::geography, 2000);
+
+-- #1305
+SELECT '#1305.1',ST_AsText(ST_Project('POINT(10 10)'::geography, 0, 0));
+WITH pts AS ( SELECT 'POINT(0 45)'::geography AS s, 'POINT(45 45)'::geography AS e ) 
+SELECT '#1305.2',abs(ST_Distance(e, ST_Project(s, ST_Distance(s, e), ST_Azimuth(s, e)))) < 0.001 FROM pts;
+SELECT '#1305.3',ST_Azimuth('POINT(0 45)'::geography, 'POINT(0 45)'::geography) IS NULL;
+
+-- #1445
+SELECT '01060000400200000001040000400100000001010000400000000000000000000000000000000000000000000000000101000040000000000000F03F000000000000F03F000000000000F03F'::geometry;
+SELECT '01050000400200000001040000400100000001010000400000000000000000000000000000000000000000000000000101000040000000000000F03F000000000000F03F000000000000F03F'::geometry;
+SELECT '01040000400200000001040000400100000001010000400000000000000000000000000000000000000000000000000101000040000000000000F03F000000000000F03F000000000000F03F'::geometry;
+SELECT '01090000400200000001040000400100000001010000400000000000000000000000000000000000000000000000000101000040000000000000F03F000000000000F03F000000000000F03F'::geometry;
+SELECT '010B0000400200000001040000400100000001010000400000000000000000000000000000000000000000000000000101000040000000000000F03F000000000000F03F000000000000F03F'::geometry;
+SELECT '010C0000400200000001040000400100000001010000400000000000000000000000000000000000000000000000000101000040000000000000F03F000000000000F03F000000000000F03F'::geometry;
+
+
+-- #1453
+SELECT '#1453.1', ST_OrderingEquals('POINT EMPTY', 'POINT EMPTY');
+SELECT '#1453.2', ST_OrderingEquals('POINT EMPTY', 'POINT Z EMPTY');
+
+-- #1454
+with inp as ( select 'MULTILINESTRING((0 0, 2 0))'::geometry as g )
+SELECT '#1454', st_orderingequals(g,g) from inp;
+
+-- #1414
+SELECT '#1414', st_astext(st_force_3dz('CURVEPOLYGON EMPTY'));
+
+-- #1478
+SELECT '#1478', 'SRID=1;POINT EMPTY'::geometry::text::geometry;
+
+-- #745 
+SELECT '#745', ST_AsEWKT(ST_Split('POLYGON((-72 42 1,-70 43 1,-71 41 1,-72 42 1))',
+                                  'LINESTRING(-10 40 1,-9 41 1)'));
+
+-- #1450
+SELECT '#1450', GeometryType('POINT(0 0)'::geography), GeometryType('POLYGON EMPTY'::geography);
+
+-- #1482
+select '#1482', ST_Srid('POINT(0 0)'::geography(point, 0)::geometry);
+
+-- #852
+CREATE TABLE cacheable (id int, g geometry);
+COPY cacheable FROM STDIN;
+1      POINT(0.5 0.5000000000001)
+2      POINT(0.5 0.5000000000001)
+\.
+select '#852.1', id, -- first run is not cached, consequent are cached
+  st_intersects(g, 'POLYGON((0 0, 10 10, 1 0, 0 0))'::geometry),
+  st_intersects(g, 'POLYGON((0 0, 1 1, 1 0, 0 0))'::geometry) from cacheable;
+UPDATE cacheable SET g = 'POINT(0.5 0.5)';
+-- New select, new cache
+select '#852.2', id, -- first run is not cached, consequent are cached
+  st_intersects(g, 'POLYGON((0 0, 10 10, 1 0, 0 0))'::geometry),
+  st_intersects(g, 'POLYGON((0 0, 1 1, 1 0, 0 0))'::geometry) from cacheable;
+DROP TABLE cacheable;
+
+-- #1489
+with inp AS ( SELECT
+       st_multi('POINT EMPTY'::geometry) as mp,
+       st_multi('LINESTRING EMPTY'::geometry) as ml, 
+       st_multi('POLYGON EMPTY'::geometry) as ma,
+       st_multi('GEOMETRYCOLLECTION EMPTY'::geometry) as mm
+) select '#1489',
+       st_astext(mp), st_numgeometries(mp),
+       st_astext(ml), st_numgeometries(ml),
+       st_astext(ma), st_numgeometries(ma),
+       st_astext(mm), st_numgeometries(mm)
+FROM inp;
+
+-- #1150
+insert into spatial_ref_sys (srid, proj4text) values (500001,NULL);
+insert into spatial_ref_sys (srid, proj4text) values (500002, '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs');
+select '#1150', st_astext(st_transform('SRID=500002;POINT(0 0)',500001));
+
+-- #1038
+select '#1038', ST_AsSVG('POLYGON EMPTY'::geometry);
+
+-- #1042
+select '#1042',round((st_ymax(st_minimumboundingcircle('LINESTRING(-1 -1, 1 1)')) * st_xmax(st_minimumboundingcircle('LINESTRING(-1 -1, 1 1)')))::numeric,0);
+
+-- #1170 --
+SELECT '#1170', ST_Y(ST_Intersection( ST_GeogFromText( 'POINT(0 90)'), ST_GeogFromText( 'POINT(0 90)' ))::geometry);
+
+-- #1264 --
+SELECT '#1264', ST_DWithin('POLYGON((-10 -10, -10 10, 10 10, 10 -10, -10 -10))'::geography, 'POINT(0 0)'::geography, 0);
+
+-- #1398
+select '#1398a', st_astext(st_snaptogrid(st_project('POINT(-120 45)'::geography, 100000, radians(45))::geometry,0.000001));
+select '#1398b', st_astext(st_snaptogrid(st_project('POINT(20 85)'::geography, 2000000, radians(0.1))::geometry,0.000001));
+
+-- #1543
+with inp as ( select 
+'0105000000020000000102000000040000000000000000000000000000000000000000000000000024400000000000000000000000000000244000000000000024400000000000000000000000000000000001020000000100000000000000000000000000000000000000'
+::geometry as g )
+select '#1543', st_astext(g), st_astext(st_buildarea(g)) from inp;
+
+-- #1578
+with inp as (
+ select ST_Collect('POLYGON EMPTY', 'POLYGON EMPTY') as mp,
+        'POINT(0 0)'::geometry as p
+)
+select '#1578', _st_within(p, mp), _st_intersects(p, mp) FROM inp;
+
+-- #1580
+select '#1580.1', ST_Summary(ST_Transform('SRID=4326;POINT(0 0)'::geometry, 3395));
+select '#1580.2', ST_Transform('SRID=4326;POINT(180 90)'::geometry, 3395); -- fails
+select '#1580.3', ST_Summary(ST_Transform('SRID=4326;POINT(0 0)'::geometry, 3395));
+
+-- #1596 --
+CREATE TABLE road_pg (ID INTEGER, NAME VARCHAR(32));
+SELECT '#1596.1', AddGeometryColumn( 'road_pg','roads_geom', 3395, 'POINT', 2 );
+SELECT '#1596.2', UpdateGeometrySRID( 'road_pg','roads_geom', 330000);
+SELECT '#1596.3', srid FROM geometry_columns
+  WHERE f_table_name = 'road_pg' AND f_geometry_column = 'roads_geom';
+SELECT '#1596.4', UpdateGeometrySRID( 'road_pg','roads_geom', 999000);
+SELECT '#1596.5', srid FROM geometry_columns
+  WHERE f_table_name = 'road_pg' AND f_geometry_column = 'roads_geom';
+SELECT '#1596.6', UpdateGeometrySRID( 'road_pg','roads_geom', -1);
+SELECT '#1596.7', srid FROM geometry_columns
+  WHERE f_table_name = 'road_pg' AND f_geometry_column = 'roads_geom';
+DROP TABLE road_pg;
+
+-- #1596
+WITH inp AS ( SELECT
+ 'POLYGON((-176 -22,-176 -21,-175 -21,-175 -22,-176 -22))'::geography as a,
+ 'POINT(-176 -22)'::geography as p
+) SELECT '#1596', ST_Summary(ST_Intersection(a,p)) FROM inp;
+
+-- #1695
+SELECT '#1695', ST_AsEWKT(ST_SnapToGrid('MULTIPOLYGON(((0 0, 10 0, 10 10, 0 10, 0 0)))'::geometry, 20));
+
+-- #1697 --
+CREATE TABLE eg(g geography, gm geometry);
+CREATE INDEX egi on eg using gist (g);
+CREATE INDEX egind on eg using gist (gm gist_geometry_ops_nd);
+INSERT INTO eg (g, gm)
+ select 'POINT EMPTY'::geography,
+        'POINT EMPTY'::geometry
+ from generate_series(1,1024);
+SELECT '#1697.1', count(*) FROM eg WHERE g && 'POINT(0 0)'::geography;
+SELECT '#1697.2', count(*) FROM eg WHERE gm && 'POINT(0 0)'::geometry;
+SELECT '#1697.3', count(*) FROM eg WHERE gm ~= 'POINT EMPTY'::geometry;
+DROP TABLE eg;
+
+-- #1734 --
+create table eg (g geography);
+create index egi on eg using gist (g);
+INSERT INTO eg(g) VALUES (NULL);
+INSERT INTO eg (g) VALUES ('POINT(0 0)'::geography);
+INSERT INTO eg (g) select 'POINT(0 0)'::geography
+       FROM generate_series(1,1024);
+SELECT '#1734.1', count(*) FROM eg;
+DROP table eg;
+
+-- #1755 --
+select '#1755', st_geographyFromText('SRID=4326;Point(85 35 0)');
+
+-- #1776 --
+with inp as ( SELECT 
+ 'POLYGON EMPTY'::geometry as A,
+ 'POLYGON((0 0, 10 0, 10 10, 0 0))'::geometry as B )
+SELECT '#1776',
+ ST_AsText(ST_SymDifference(A,B)), ST_AsText(ST_SymDifference(B, A))
+FROM inp;
+
+-- #1780 --
+SELECT '#1780',ST_GeoHash('POINT(4 4)'::geometry) = ST_GeoHash('POINT(4 4)'::geography);
+
+-- #1791 --
+with inp as ( SELECT
+ '010100000000000000004065C0041AD965BE5554C0'::geometry as a,
+ '010100000001000000004065C0041AD965BE5554C0'::geometry as b
+) SELECT '#1791', round(ST_Azimuth(a,b)*10)/10 from inp;
+
+
+-- #1799 --
+SELECT '#1799', ST_Segmentize('LINESTRING(0 0, 10 0)'::geometry, 0);
+
+-- #1936 --
+select st_astext(st_geomfromgml(
+    '<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2" 
+    gml:id="HPA.15449990010" srsName="urn:ogc:def:crs:EPSG::4326" 
+    srsDimension="2">
+    <gml:exterior>
+    <gml:Ring>
+    <gml:curveMember>
+    <gml:LineString gml:id="HPA.15449990010.1">
+    <gml:posList>711540.35 1070163.61 711523.82 1070166.54 711521.30 1070164.14 711519.52 1070162.44 711518.57 1070164.62 712154.47 1070824.94</gml:posList>
+    </gml:LineString>
+    </gml:curveMember>
+    <gml:curveMember>
+    <gml:Curve gml:id="HPA.15449990010.2">
+    <gml:segments><gml:ArcString>
+    <gml:posList>712154.47 1070824.94 712154.98 1070826.04 712154.41 1070827.22</gml:posList>
+    </gml:ArcString>
+    </gml:segments>
+    </gml:Curve>
+    </gml:curveMember>
+    <gml:curveMember>
+    <gml:LineString gml:id="HPA.15449990010.3">
+    <gml:posList>712154.41 1070827.22 712160.31 1070837.07 712160.92 1070835.36 712207.89 1071007.95</gml:posList>
+    </gml:LineString>
+    </gml:curveMember>
+    <gml:curveMember>
+    <gml:Curve gml:id="HPA.15449990010.4"><gml:segments><gml:ArcString><gml:posList>712207.89 1071007.95 712207.48 1071005.59 712208.38 1071001.28</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember><gml:curveMember><gml:LineString gml:id="HPA.15449990010.5"><gml:posList>712208.38 1071001.28 712228.74 1070949.67 712233.98 1070936.15 712124.93 1070788.72</gml:posList></gml:LineString></gml:curveMember><gml:curveMember><gml:Curve gml:id="HPA.15449990010.6"><gml:segments><gml:ArcString><gml:posList>712124.93 1070788.72 712124.28 1070785.87 712124.63 1070783.38</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember><gml:curveMember><gml:LineString gml:id="HPA.15449990010.7"><gml:posList>712124.63 1070783.38 712141.04 1070764.12 712146.60 1070757.01 711540.35 1070163.61</gml:posList></gml:LineString></gml:curveMember></gml:Ring></gml:exterior>
+    <gml:interior>
+    <gml:LinearRing>
+    <gml:posList>713061.62 1070354.46 713053.59 1070335.12 713049.58 1070315.92 713049.65 1070298.33 713061.62 1070354.46</gml:posList>
+    </gml:LinearRing>
+    </gml:interior>
+    </gml:Polygon>'));
+
+-- #1957 --
+SELECT '#1957', ST_Distance(ST_Makeline(ARRAY['POINT(1 0)'::geometry]), 'POINT(0 0)'::geometry);
+
+-- #1978 --
+SELECT '#1978', round(ST_Length(ST_GeomFromText('CIRCULARSTRING(0 0,1 0,0 0)',0))::numeric,4);
+
+-- #1996 --
+SELECT '#1996', ST_AsGeoJSON(ST_GeomFromText('POINT EMPTY'));
+
+-- #2001 --
+SELECT '#2001', ST_AsText(ST_CurveToLine(ST_GeomFromText('CURVEPOLYGON((0 0, 0 1, 1 1, 0 0))'), 2));
+
+-- #2028 --
+SELECT '#2028', ST_AsText(ST_Multi('TRIANGLE((0 0, 0 1, 1 1, 0 0))'));
+
+
+-- #2035 START ------------------------------------------------------------
+
+-- Simple geographic table, with single point.
+CREATE TABLE "city" (
+    "id" integer,
+    "name" varchar(30) NOT NULL,
+    "point" geometry(POINT,4326) NOT NULL
+);
+CREATE INDEX "city_point_id" ON "city" USING GIST ( "point" );
+
+-- Initial data, with points around the world.
+INSERT INTO "city" (id, name, point) VALUES (1, 'Houston', 'SRID=4326;POINT(-95.363151 29.763374)');
+INSERT INTO "city" (id, name, point) VALUES (2, 'Dallas', 'SRID=4326;POINT(-95.363151 29.763374)');
+INSERT INTO "city" (id, name, point) VALUES (3, 'Oklahoma City', 'SRID=4326;POINT(-97.521157 34.464642)');
+INSERT INTO "city" (id, name, point) VALUES (4, 'Wellington', 'SRID=4326;POINT(174.783117 -41.315268)');
+INSERT INTO "city" (id, name, point) VALUES (5, 'Pueblo', 'SRID=4326;POINT(-104.609252 38.255001)');
+INSERT INTO "city" (id, name, point) VALUES (6, 'Lawrence', 'SRID=4326;POINT(-95.23506 38.971823)');
+INSERT INTO "city" (id, name, point) VALUES (7, 'Chicago', 'SRID=4326;POINT(-87.650175 41.850385)');
+INSERT INTO "city" (id, name, point) VALUES (8, 'Victoria', 'SRID=4326;POINT(-123.305196 48.462611)');
+
+-- This query, or COUNT(*), does not return anything; should return 6 cities,
+-- excluding Pueblo and Victoria.  The Polygon is a simple approximation of
+-- Colorado.
+SELECT '#2035a', Count(*) FROM "city"
+  WHERE "city"."point" >> ST_GeomFromEWKT('SRID=4326;POLYGON ((-109.060253 36.992426, -109.060253 41.003444, -102.041524 41.003444, -102.041524 36.992426, -109.060253 36.992426))');
+
+-- However, when a LIMIT is placed on statement, the query suddenly works.
+SELECT '#2035b', Count(*) FROM "city"
+  WHERE "city"."point" >> ST_GeomFromEWKT('SRID=4326;POLYGON ((-109.060253 36.992426, -109.060253 41.003444, -102.041524 41.003444, -102.041524 36.992426, -109.060253 36.992426))') LIMIT 6;
+
+DROP TABLE "city";
+-- #2035 END --------------------------------------------------------------
+
+
+-- #2084 --
+SELECT '#2048', num, ST_Within('POINT(-54.394 56.522)', "the_geom"), ST_CoveredBy('POINT(-54.394 56.522)', "the_geom")
+FROM ( VALUES
+(1, '0103000000010000000E00000051C6F7C5A5324BC02EB69F8CF13F4C40F12EA4C343364BC0326AA2CF47434C402BC1A8A44E364BC02A50E10852434C407F2990D959364BC0A0D1730B5D434C404102452C62364BC0ECF335CB65434C400903232F6B364BC0F635E84B6F434C40BD0CC51D6F364BC0D2805EB873434C40B9E6E26F7B364BC0F20B93A982434C40D9FAAF73D3344BC0FE84D04197444C40BD5C8AABCA344BC0CED05CA791444C4023F2237EC5344BC02A84F23E8E444C40BDCDD8077B324BC0C60FB90F01434C409FD1702E65324BC04EF1915C17404C4051C6F7C5A5324BC02EB69F8CF13F4C40'::geometry), 
+(2, '0103000000010000001C00000003F25650F73B4BC098477F523E3E4C40C9A6A344CE3C4BC0C69698653E3E4C40BDD0E979373E4BC0081FA0FB723E4C400FD252793B3E4BC01A137F14753E4C40537170E998414BC070D3BCE314414C4023FC51D499474BC0D4D100DE024F4C40638C47A984454BC024130D52F0504C40B9442DCDAD404BC03A29E96168554C40C7108DEE20404BC07C7C26FBE7554C40195D6BEF533F4BC0E20391459A564C40239FE40E9B344BC08C1ADB6B41514C40132D3F7095314BC0BA2ADF33124F4C409DB91457952D4BC02C7B681F2B4C4C4089DC60A8C32C4BC07C5C3810924B4C40D7ED409DF22A4BC0F64389963C4A4C405D1EF818AC2A4BC00EC84274084A4C401B48A46DFC294BC0B271A8DF85494C40E78AA6B393294BC01ED0EFFB37494C4081C64B3789294BC0DC5BE7DF2E494C409B23329287294BC0F0D6974E2D494C40CD22D5D687294BC0844316D72C494C40F5229D4FE2294BC002F19825AB484C40A3D0BD5AE9294BC06C0776A9A2484C409FD1702E65324BC04EF1915C17404C409F860AA7BD324BC0162CA390E33F4C40539A5C1C23334BC0FE86B04EB03F4C4081511DFF90334BC088FF36D4873F4C4003F25650F73B4BC098477F523E3E4C40'::geometry), 
+(3, '010300000001000000100000008D57CD101A214BC0AECDD34E072C4C400DBB72E6EC274BC0A8088D60E32C4C40CF8FD7E6734E4BC0B22695BE4A324C40BFA74213934F4BC020BE505D4C354C4057CD4BEE454E4BC0BA6CF3940F3D4C40E7BDC5FD263E4BC09A4B297D5B484C4073A46A86701C4BC0B287F08D93364C4045501F86701C4BC05EBDB78D93364C40A37DB6586D1C4BC0841E7D2891364C409FBF445F6D1C4BC01E225C5690364C40D1BA97726D1C4BC06E2AF7EA8D364C4019B60C9B751C4BC0D2FD702575364C40FDE4394B5E1F4BC08C40F231CC2F4C402343DF40F51F4BC022008E3D7B2E4C400BB57B45F9204BC0908CE2EA3A2C4C408D57CD101A214BC0AECDD34E072C4C40'::geometry) 
+) AS f(num, the_geom);
+
+-- #2112 -- Start
+SELECT '#2112a', ST_3DDistance(a,b), ST_ASEWKT(ST_3DShortestLine(a,b))
+FROM (SELECT 'POLYGON((1 1 1, 5 1 1,5 5 1, 1 5 1,1 1 1))'::geometry as a, 'LINESTRING(0 0 2, 0 0 0,5 5 2)'::geometry as b
+     ) as foo;
+
+SELECT '#2112b', ST_3DDistance(a,b), ST_ASEWKT(ST_3DShortestLine(a,b)) 
+FROM (SELECT 'POLYGON((1 1 1, 5 1 1,5 5 1, 1 5 1,1 1 1))'::geometry as a, 'LINESTRING(1 0 2, 1 0 0,5 5 -1)'::geometry as b
+     ) as foo;
+-- 2112 -- End
+
+SELECT '#2108', ST_AsEWKT(ST_LineInterpolatePoint('SRID=3395;LINESTRING M EMPTY'::geometry, 0.5));
+SELECT '#2117', ST_AsEWKT(ST_PointOnSurface('SRID=3395;MULTIPOLYGON M EMPTY'::geometry));
+
+SELECT '#2110.1', 'POINT(0 0)'::geometry = 'POINT EMPTY'::geometry;
+SELECT '#2110.2', 'POINT EMPTY'::geometry = 'POINT EMPTY'::geometry;
+SELECT '#2110.3', 'POINT(0 0)'::geometry = 'POINT(0 0)'::geometry;
+
+
+SELECT '#2145',
+round(ST_Length(St_Segmentize(ST_GeographyFromText('LINESTRING(-89.3000030518 28.2000007629,-89.1999969482 89.1999969482,-89.1999969482 89.1999969482)'), 10000))::numeric,0);
+
+
+-- Clean up
+DELETE FROM spatial_ref_sys;
diff --git a/regress/sfcgal/tickets_expected b/regress/sfcgal/tickets_expected
new file mode 100644 (file)
index 0000000..fbdaf4f
--- /dev/null
@@ -0,0 +1,245 @@
+#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
+#44|t|t
+#58|220187|150406|220289|150507
+ERROR:  lwgeom_to_gml2: 'CurvePolygon' geometry type not supported
+#66|CIRCULARSTRING(0 0,1 1,2 2)
+#68a|MULTIPOINT(1 3,4 5)
+ERROR:  lwgeom_longitude_shift: unsupported geom type: CircularString
+#69|CIRCULARSTRING(220269 150417,220228 150507,220228 150408)
+#70|3
+#73|GEOMETRYCOLLECTION(CIRCULARSTRING(1 1,2 3,4 5,6 7,5 6))
+#80|MULTILINESTRING((0 0,1 1))
+#83|MULTICURVE(CIRCULARSTRING(220268 150415,220227 150505,220227 150406))
+ERROR:  LWGEOM2SFCGAL: Unknown geometry type !
+#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)
+#124a|COMPOUNDCURVE(CIRCULARSTRING(0 0,1 1,1 0),(1 0,30 5),CIRCULARSTRING(30 5,34 56,67 89))
+ERROR:  incontinuous compound curve
+#145a|0103000020E610000000000000
+#145b|0
+#146|0|t|GEOMETRYCOLLECTION(LINESTRING(0 0,-1 -1),MULTIPOINT(1 2,2 3))
+ERROR:  Invalid hex string, length (267) has to be a multiple of two!
+#157|ST_Polygon|POLYGON
+#157|ST_Point|POINT
+#157|ST_Polygon|POLYGON
+#157|ST_CurvePolygon|CURVEPOLYGON
+#157|ST_CircularString|CIRCULARSTRING
+#168|3|MULTIPOLYGON ZM (((4275341.96977851 259186.966993061 1323.76295828331 -1.79769313486232e+308,4275341.96977851 259186.966993061 1323.76295828331 -1.79769313486232e+308,4275341.96977851 259186.966993061 1323.76295828331 -1.79769313486232e+308)))|IllegalArgumentException: Invalid number of points in LinearRing found 3 - must be 0 or >= 4
+#175|SRID=26915;POINT(482020 4984378)
+#178a|0
+#178b|5
+NOTICE:  No points or linestrings in input array
+#179a|
+NOTICE:  No points or linestrings in input array
+#179b|
+#183|CIRCULARSTRING(0 0,0.5 1.2071067812,0 1)
+#210a|
+NOTICE:  No points or linestrings in input array
+#210b|
+#213|17
+#234|COMPOUNDCURVE((0 0,1 1))
+#241|0
+#254|010700000000000000
+#259|
+#260|1667701
+#261|0
+#262|POINT(-119.5434 34.9438)|t|t|t
+#262|POINT(-119.5452 34.9442)|t|t|t
+#262|POINT(-119.5434 34.9438)|t|t|t
+#262|POINT(-119.5438 34.9443)|t|t|t
+#263|SRID=4326;POINT(-119.5434 34.9438)|t|t|t
+#263|SRID=4326;POINT(-119.5452 34.9442)|t|t|t
+#263|SRID=4326;POINT(-119.5434 34.9438)|t|t|t
+#263|SRID=4326;POINT(-119.5438 34.9443)|t|t|t
+#271|t
+#272|-2|2
+#277|<gml:Point><gml:coordinates>1,1e+308</gml:coordinates></gml:Point>
+#299|2
+#304
+#304.a|21
+#304.b|1
+#408|Too few points in geometry component[
+NOTICE:  Too few points in geometry component at or near point 0 0
+#408.1|f
+#408.2|Too few points in geometry component[0 0]
+NOTICE:  IllegalArgumentException: Invalid number of points in LinearRing found 2 - must be 0 or >= 4
+#408.3|f
+#408.4|IllegalArgumentException: Invalid number of points in LinearRing found 2 - must be 0 or >= 4
+#457.1|POINT(0 0)
+#457.2|LINESTRING EMPTY
+#457.3|POLYGON EMPTY
+#457.4|POINT EMPTY
+#457.5|LINESTRING(0 0,1 1)
+#457.6|POLYGON EMPTY
+#457.7|POINT EMPTY
+#457.8|LINESTRING EMPTY
+#457.9|POLYGON((0 0,1 0,1 1,0 1,0 0))
+#835.1|POINT EMPTY
+#835.2|LINESTRING EMPTY
+#835.3|POLYGON EMPTY
+#835.4|POINT EMPTY
+#835.5|LINESTRING EMPTY
+#835.6|POLYGON EMPTY
+#835.7|POINT EMPTY
+#835.8|LINESTRING EMPTY
+#835.9|POLYGON EMPTY
+#835.10|MULTIPOINT EMPTY
+#835.11|MULTILINESTRING EMPTY
+#835.12|MULTIPOLYGON EMPTY
+#650|MULTIPOINT(0 0,1 1,2 2)
+#667|SRID=4326;CURVEPOLYGON(CIRCULARSTRING(30 40,-49.2314112161292 32.1963871193548,30 40))
+#677|1121395
+#680|01d107000000000000000024c000000000000049400000000000000040
+#681a|
+#681b|
+#681c|
+#681d|
+#681e|
+#681f|
+#681g|
+#682|0103000020E610000000000000
+#683|0103000020E610000000000000
+#684,#2109|SRID=4326;POINT EMPTY
+#2109|SRID=3395;POINT EMPTY
+#685|0103000020E610000000000000
+#686|0107000020E610000000000000
+#687|f
+#689|f
+#690
+010200000003000000F771D98DE33826C00000000000004440F771D98DE33826C000000000008051400000000000805140F771D98DE33826C0
+#693a|0103000060E61000000100000005000000EA95B20C71C851C02B1895D409204540000000000000F03F9CC420B072C851C0C7BAB88D062045400000000000000840B1506B9A77C851C08E75711B0D20454000000000000000C0FF21FDF675C851C0F2D24D6210204540000000000000F03FEA95B20C71C851C02B1895D4092045400000000000000000
+#693b|0103000060E61000000100000007000000EA95B20C71C851C0AA605452272045400000000000000000386744696FC851C04703780B2420454000000000000034408638D6C56DC851C04703780B2420454000000000000034C08638D6C56DC851C0E3A59BC42020454000000000000014408638D6C56DC851C08048BF7D1D20454000000000000010409CC420B072C851C04703780B242045400000000000001840EA95B20C71C851C0AA605452272045400000000000003E40
+#694
+ERROR:  Shell is not a line
+#695
+ERROR:  First argument must be a LINESTRING
+#696|010F000080060000000103000080010000000500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F03F0000000000000000000000000000F03F000000000000F03F0000000000000000000000000000F03F0000000000000000000000000000000000000000000000000000000000000000010300008001000000050000000000000000000000000000000000000000000000000000000000000000000000000000000000F03F0000000000000000000000000000F03F000000000000F03F0000000000000000000000000000F03F0000000000000000000000000000000000000000000000000000000000000000000000000000000001030000800100000005000000000000000000000000000000000000000000000000000000000000000000F03F00000000000000000000000000000000000000000000F03F0000000000000000000000000000F03F00000000000000000000000000000000000000000000F03F00000000000000000000000000000000000000000000000001030000800100000005000000000000000000F03F000000000000F03F0000000000000000000000000000F03F000000000000F03F000000000000F03F000000000000F03F0000000000000000000000000000F03F000000000000F03F00000000000000000000000000000000000000000000F03F000000000000F03F0000000000000000010300008001000000050000000000000000000000000000000000F03F00000000000000000000000000000000000000000000F03F000000000000F03F000000000000F03F000000000000F03F000000000000F03F000000000000F03F000000000000F03F00000000000000000000000000000000000000000000F03F00000000000000000103000080010000000500000000000000000000000000000000000000000000000000F03F000000000000F03F0000000000000000000000000000F03F000000000000F03F000000000000F03F000000000000F03F0000000000000000000000000000F03F000000000000F03F00000000000000000000000000000000000000000000F03F
+#720|MULTIPOINT(-1113194.91 4838471.4,-1113194.91 7326837.72,-1113194.91 11028513.63,556597.45 4838471.4,556597.45 7326837.72,556597.45 11028513.63,2226389.82 4838471.4,2226389.82 7326837.72,2226389.82 11028513.63,3896182.18 4838471.4,3896182.18 7326837.72,3896182.18 11028513.63,5565974.54 4838471.4,5565974.54 7326837.72,5565974.54 11028513.63)
+#723|0101000020E61000006284F068E33826C00000000000004440
+#723|0107000020E610000000000000
+#723|0107000020E610000000000000
+#723|0101000020E61000006284F068E33826C00100000000804B40
+#804|<gml:Point srsName="urn:ogc:def:crs:EPSG::4326"><gml:pos srsDimension="2">0 0</gml:pos></gml:Point>
+#845|t
+#834|GEOMETRYCOLLECTION(POINT(0 0),LINESTRING(10 0,10 10))
+#884|1|f
+#884|2|t
+#938|
+#668|BOX(10 2,14 2)
+#711|
+#712|t
+#756.1|t|t
+#1023|t
+#1023.a|f
+#1023.b|t
+#1060|FFFFFFFF2
+#1273|t
+#1273.1|t
+ERROR:  stats for "t.g" do not exist
+ERROR:  stats for "t.g" do not exist
+WARNING:  ST_Estimated_Extent signature was deprecated in 2.1.0. Please use ST_EstimatedExtent
+ERROR:  stats for "t.g" do not exist
+ERROR:  stats for "t.g" do not exist
+#877.4|-10.15000|20.15000|-50.40000|30.40000
+#877.5|-10.15000|20.15000|-50.40000|30.40000
+#1292|GEOMETRYCOLLECTION(POINT(180 90),POLYGON((140 50,150 50,180 50,140 50),(140 60,150 60,180 60,140 60)))
+NOTICE:  Coordinate values were coerced into range [-180 -90, 180 90] for GEOGRAPHY
+NOTICE:  Coordinate values were coerced into range [-180 -90, 180 90] for GEOGRAPHY
+#1292.1|POINT(180 85)|POINT(-175 90)
+<#1320>
+#1320.geog.1|MULTIPOLYGON|4326
+#1320.geom.1|MULTIPOLYGON|4326
+ERROR:  Geometry type (Polygon) does not match column type (MultiPolygon)
+ERROR:  Geometry type (Polygon) does not match column type (MultiPolygon)
+#1320.geog.2|MULTIPOLYGON|4326
+#1320.geom.2|MULTIPOLYGON|4326
+ERROR:  Geometry type (Polygon) does not match column type (MultiPolygon)
+ERROR:  Geometry type (Polygon) does not match column type (MultiPolygon)
+#1320.geog.3|MULTIPOLYGON|4326
+#1320.geom.3|MULTIPOLYGON|4326
+</#1320>
+#1344|25
+#1385|
+#657.1|-166.78
+#657.2|10.00
+#657.3|t
+#1305.1|POINT(10 10)
+#1305.2|t
+#1305.3|t
+ERROR:  MultiPolygon cannot contain MultiPoint element at character 8
+ERROR:  MultiLineString cannot contain MultiPoint element at character 8
+ERROR:  MultiPoint cannot contain MultiPoint element at character 8
+ERROR:  CompoundCurve cannot contain MultiPoint element at character 8
+ERROR:  MultiCurve cannot contain MultiPoint element at character 8
+ERROR:  MultiSurface cannot contain MultiPoint element at character 8
+#1453.1|t
+#1453.2|f
+#1454|t
+#1414|CURVEPOLYGON Z EMPTY
+#1478|01040000200100000000000000
+#745|GEOMETRYCOLLECTION(POLYGON((-72 42 1,-70 43 1,-71 41 1,-72 42 1)))
+#1450|POINT|POLYGON
+#1482|4326
+#852.1|1|f|f
+#852.1|2|f|f
+#852.2|1|t|t
+#852.2|2|t|t
+#1489|MULTIPOINT EMPTY|0|MULTILINESTRING EMPTY|0|MULTIPOLYGON EMPTY|0|GEOMETRYCOLLECTION EMPTY|0
+ERROR:  AddToPROJ4SRSCache: could not parse proj4 string '' 
+#1038|
+#1042|2
+#1170|90
+#1264|t
+#1398a|POINT(-119.093153 45.632669)
+#1398b|POINT(-160.137654 77.091608)
+#1543|MULTILINESTRING((0 0,10 0,10 10,0 0),(0 0))|POLYGON((0 0,10 10,10 0,0 0))
+#1578|f|f
+#1580.1|Point[BS]
+ERROR:  transform: couldn't project point (180 90 0): tolerance condition error (-20)
+#1580.3|Point[BS]
+#1596.1|public.road_pg.roads_geom SRID:3395 TYPE:POINT DIMS:2 
+ERROR:  invalid SRID: 330000 not found in spatial_ref_sys
+#1596.3|3395
+ERROR:  invalid SRID: 999000 not found in spatial_ref_sys
+#1596.5|3395
+NOTICE:  SRID value -1 converted to the officially unknown SRID value 0
+#1596.6|public.road_pg.roads_geom SRID changed to 0
+#1596.7|0
+#1596|Point[BGS]
+#1695|MULTIPOLYGON EMPTY
+#1697.1|0
+#1697.2|0
+#1697.3|1024
+#1734.1|1026
+#1755|01010000A0E6100000000000000040554000000000008041400000000000000000
+#1776|POLYGON((0 0,10 0,10 10,0 0))|POLYGON((0 0,10 0,10 10,0 0))
+#1780|t
+#1791|4.7
+ERROR:  ST_Segmentize: invalid max_distance 0 (must be >= 0)
+ERROR:  invalid GML representation
+#1957|inf
+#1978|3.1413
+#1996|{"type":"Point","coordinates":[]}
+#2001|POLYGON((0 0,0 1,1 1,0 0))
+#2028|TIN(((0 0,0 1,1 1,0 0)))
+#2035a|6
+#2035b|6
+#2048|1|f|f
+#2048|2|t|t
+#2048|3|f|f
+#2112a|0|LINESTRING(2.5 2.5 1,2.5 2.5 1)
+#2112b|1|LINESTRING(1 1 1,1 0 1)
+#2108|SRID=3395;POINTM EMPTY
+#2117|SRID=3395;POINTM EMPTY
+#2110.1|f
+#2110.2|t
+#2110.3|t
+#2145|6792004
diff --git a/regress/sfcgal/wmsservers.sql b/regress/sfcgal/wmsservers.sql
new file mode 100644 (file)
index 0000000..290f456
--- /dev/null
@@ -0,0 +1,39 @@
+SET postgis.backend = 'sfcgal';
+SET client_min_messages TO warning;
+
+SELECT 'Starting up MapServer/Geoserver tests...';
+-- Set up the data table
+SELECT 'Setting up the data table...';
+CREATE TABLE public.wmstest ( id INTEGER, pt GEOMETRY(Polygon,4326) );
+INSERT INTO wmstest SELECT lon * 100 + lat AS id, st_setsrid(st_buffer(st_makepoint(lon, lat),1.0),4326) AS pt
+FROM (select lon, generate_series(-80,80, 5) AS lat FROM (SELECT generate_series(-175, 175, 5) AS lon) AS sq1) AS sq2;
+--INSERT INTO geometry_columns (f_table_catalog, f_table_schema, f_table_name, f_geometry_column, coord_dimension, srid, type) VALUES ('', 'public','wmstest','pt',2,4326,'POLYGON');
+ALTER TABLE wmstest add PRIMARY KEY ( id );
+CREATE INDEX wmstest_geomidx ON wmstest using gist ( pt );
+
+-- Geoserver 2.0 NG tests
+SELECT 'Running Geoserver 2.0 NG tests...';
+-- Run a Geoserver 2.0 NG metadata query
+SELECT 'Geoserver1', upper(TYPE) As TYPE FROM GEOMETRY_COLUMNS WHERE F_TABLE_SCHEMA = 'public' AND F_TABLE_NAME = 'wmstest' AND F_GEOMETRY_COLUMN = 'pt';
+SELECT 'Geoserver2', SRID FROM GEOMETRY_COLUMNS WHERE F_TABLE_SCHEMA = 'public' AND F_TABLE_NAME = 'wmstest' AND F_GEOMETRY_COLUMN = 'pt';
+-- Run a Geoserver 2.0 NG WMS query
+SELECT 'Geoserver3', "id",substr(encode(ST_AsBinary(ST_Force_2d("pt"),'XDR'),'base64'),0,16) as "pt" FROM "public"."wmstest" WHERE "pt" && ST_GeomFromText('POLYGON ((-6.58216065979069 -0.7685569763184591, -6.58216065979069 0.911225433349509, -3.050569931030911 0.911225433349509, -3.050569931030911 -0.7685569763184591, -6.58216065979069 -0.7685569763184591))', 4326);
+-- Run a Geoserver 2.0 NG KML query
+SELECT 'Geoserver4', count(*) FROM "public"."wmstest" WHERE "pt" && ST_GeomFromText('POLYGON ((-1.504017942347938 24.0332272532341, -1.504017942347938 25.99364254836741, 1.736833353559741 25.99364254836741, 1.736833353559741 24.0332272532341, -1.504017942347938 24.0332272532341))', 4326);
+SELECT 'Geoserver5', "id",substr(encode(ST_AsBinary(ST_Force_2d("pt"),'XDR'),'base64'),0,16) as "pt" FROM "public"."wmstest" WHERE "pt" && ST_GeomFromText('POLYGON ((-1.504017942347938 24.0332272532341, -1.504017942347938 25.99364254836741, 1.736833353559741 25.99364254836741, 1.736833353559741 24.0332272532341, -1.504017942347938 24.0332272532341))', 4326);
+SELECT 'Geoserver6', "id",substr(encode(ST_AsBinary(ST_Force_2d("pt"),'XDR'),'base64'),0,16) as "pt" FROM "public"."wmstest" WHERE "pt" && ST_GeomFromText('POLYGON ((-1.507182836191598 24.031312785172446, -1.507182836191598 25.995557016429064, 1.7399982474034008 25.995557016429064, 1.7399982474034008 24.031312785172446, -1.507182836191598 24.031312785172446))', 4326);
+
+-- MapServer 5.4 tests
+select 'MapServer1', attname from pg_attribute, pg_constraint, pg_class where pg_constraint.conrelid = pg_class.oid and pg_class.oid = pg_attribute.attrelid and pg_constraint.contype = 'p' and pg_constraint.conkey[1] = pg_attribute.attnum and pg_class.relname = 'wmstest' and pg_table_is_visible(pg_class.oid) and pg_constraint.conkey[2] is null;
+select 'MapServer2', "id",substr(encode(ST_AsBinary(ST_Force_collection(ST_Force_2d("pt")),'NDR'),'base64'),0,16) as geom,"id" from wmstest where pt && ST_GeomFromText('POLYGON((-98.5 32,-98.5 39,-91.5 39,-91.5 32,-98.5 32))',find_srid('','wmstest','pt'));
+
+-- MapServer 5.6 tests
+select * from wmstest where false limit 0;
+select 'MapServer3', attname from pg_attribute, pg_constraint, pg_class where pg_constraint.conrelid = pg_class.oid and pg_class.oid = pg_attribute.attrelid and pg_constraint.contype = 'p' and pg_constraint.conkey[1] = pg_attribute.attnum and pg_class.relname = 'wmstest' and pg_table_is_visible(pg_class.oid) and pg_constraint.conkey[2] is null;
+select 'MapServer4', "id",substr(encode(ST_AsBinary(ST_Force_collection(ST_Force_2d("pt")),'NDR'),'hex'),0,16) as geom,"id" from wmstest where pt && ST_GeomFromText('POLYGON((-98.5 32,-98.5 39,-91.5 39,-91.5 32,-98.5 32))',find_srid('','wmstest','pt'));
+
+-- Drop the data table
+SELECT 'Removing the data table...';
+DROP TABLE wmstest;
+--DELETE FROM geometry_columns WHERE f_table_name = 'wmstest' AND f_table_schema = 'public';
+SELECT 'Done.';
diff --git a/regress/sfcgal/wmsservers_expected b/regress/sfcgal/wmsservers_expected
new file mode 100644 (file)
index 0000000..d2702ad
--- /dev/null
@@ -0,0 +1,18 @@
+Starting up MapServer/Geoserver tests...
+Setting up the data table...
+ALTER TABLE
+Running Geoserver 2.0 NG tests...
+Geoserver1|POLYGON
+Geoserver2|4326
+Geoserver3|-500|AAAAAAMAAAABAAA
+Geoserver4|1
+Geoserver5|25|AAAAAAMAAAABAAA
+Geoserver6|25|AAAAAAMAAAABAAA
+MapServer1|id
+MapServer2|-9465|AQcAAAABAAAAAQM|-9465
+MapServer2|-9460|AQcAAAABAAAAAQM|-9460
+MapServer3|id
+MapServer4|-9465|010700000001000|-9465
+MapServer4|-9460|010700000001000|-9460
+Removing the data table...
+Done.