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 ===========================================================================
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])
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
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}])
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}])
installation.xml \
introduction.xml \
performance_tips.xml \
- postgis.xml \
+ postgis.xml \
reference_accessor.xml \
reference_constructor.xml \
reference_editor.xml \
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 > $@
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
<!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>
&reference_output;
&reference_operator;
&reference_measure;
+ &reference_sfcgal;
&reference_processing;
&reference_lrs;
&reference_transaction;
<!-- 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>
<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>
<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>
- ST_Intersects(g1, g2 ) --> 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>
<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>
</important>
<para>Performed by the GEOS module</para>
+ <para>&sfcgal_enhanced;</para>
<para>Availability: 1.5 support for geography data type was introduced.</para>
--- /dev/null
+<?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>
<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,'
', ' '), '	', ' '))"/>\r
</xsl:variable>\r
--- /dev/null
+<?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) > 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 >= 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[ ]]>\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) > 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="'&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, '
')">\r
+ <xsl:value-of select="substring-before($text, '
')"/>\r
+ <![CDATA[<br/>]]>\r
+ <xsl:call-template name="break">\r
+ <xsl:with-param \r
+ name="text" \r
+ select="substring-after($text, '
')"\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) > 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()<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
--- /dev/null
+<?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,'
', ' '), '	', ' '))"/>\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) > 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()<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) > 0">args: </xsl:if>\r
+ <xsl:for-each select="paramdef">\r
+ <xsl:choose>\r
+ <xsl:when test="count(parameter) > 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()<last()"><xsl:text>, </xsl:text></xsl:if>\r
+ </xsl:for-each>\r
+ <xsl:if test="count(paramdef/parameter) > 0"> - </xsl:if>\r
+ </xsl:for-each> \r
+ </xsl:template>\r
+\r
+</xsl:stylesheet>\r
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)
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 $<
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 \
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
--- /dev/null
+/**********************************************************************
+ * $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};
--- /dev/null
+/**********************************************************************
+ *
+ * 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};
+
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;
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
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
}
}
+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)
{
--- /dev/null
+/**********************************************************************
+ *
+ * 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;
+}
--- /dev/null
+/**********************************************************************
+ *
+ * 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);
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 \
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 \
# 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
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
--- /dev/null
+/**********************************************************************
+ *
+ * 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);
+}
--- /dev/null
+/**********************************************************************
+ *
+ * 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
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);
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
*/
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);
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);
}
-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;
}
-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;
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);
--- /dev/null
+/**********************************************************************
+ *
+ * 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);
+}
--- /dev/null
+/**********************************************************************
+ *
+ * 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);
-- 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
-- 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;
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
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;
svnver text;
projver text;
geosver text;
+ sfcgalver text;
+ cgalver text;
gdalver text;
libxmlver text;
dbproc text;
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;
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;
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;
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;
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
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;
-- 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
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);
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;
#include "lwgeom_log.h"
#include "lwgeom_pg.h"
#include "geos_c.h"
+#include "lwgeom_backend_api.h"
/*
* This is required for builds against pgsql
/* install PostgreSQL handlers */
pg_install_lwgeom_handlers();
+
+ /* initialize geometry backend */
+ lwgeom_init_backend();
}
/*
--- /dev/null
+---------------------------------------------------------------------------
+--
+-- 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;
--- /dev/null
+---------------------------------------------------------------------------
+--
+-- 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;
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
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
--- /dev/null
+---
+--- 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 = '';
--- /dev/null
+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
OPT_UPGRADE=no
OPT_WITH_TOPO=no
OPT_WITH_RASTER=no
+OPT_WITH_SFCGAL=no
OPT_EXPECT=no
OPT_EXTENSIONS=no
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
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
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
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;
'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
}
-
###################################################################
# Uninstall postgis (serves as an uninstall test)
##################################################################
--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
};
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;
}
{
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;
--- /dev/null
+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
--- /dev/null
+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;
--- /dev/null
+ST_ConcaveHull MultiPolygon 0.95|t|t
+ST_ConcaveHull Lines 0.80|t|t
+ST_ConcaveHull Lines 0.80 holes|t|t
--- /dev/null
+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;
--- /dev/null
+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
--- /dev/null
+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;
+
--- /dev/null
+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
--- /dev/null
+--
+-- 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
--- /dev/null
+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
--- /dev/null
+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);
--- /dev/null
+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
--- /dev/null
+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;
--- /dev/null
+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)
--- /dev/null
+---
+--- 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));
--- /dev/null
+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
--- /dev/null
+---
+--- 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);
+
--- /dev/null
+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
--- /dev/null
+--
+-- 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;
--- /dev/null
+#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
--- /dev/null
+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.';
--- /dev/null
+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.