From 927028f23cee30f3247cdb9698a6ef19db7a722d Mon Sep 17 00:00:00 2001 From: Olivier Courtin Date: Thu, 9 May 2013 19:38:17 +0000 Subject: [PATCH] Add SFCGAL support cf #2254. Include SFCGAL support, postgis backend handling (GEOS/SFCGAL). Regress tests, documentation prototypes and also additional force_sfs function. git-svn-id: http://svn.osgeo.org/postgis/trunk@11389 b70326c6-7e19-0410-871a-916f4a2858ee --- configure.ac | 53 +- doc/Makefile.in | 13 +- doc/postgis.xml | 8 + doc/reference.xml | 1 + doc/reference_measure.xml | 5 + doc/reference_processing.xml | 1 + doc/reference_sfcgal.xml | 238 +++++++ doc/xsl/postgis_comments.sql.xsl | 2 +- doc/xsl/sfcgal_cheatsheet.html.xsl | 234 +++++++ doc/xsl/sfcgal_comments.sql.xsl | 102 +++ liblwgeom/Makefile.in | 7 +- liblwgeom/cunit/Makefile.in | 7 + liblwgeom/cunit/cu_force_sfs.c | 175 +++++ liblwgeom/cunit/cu_sfcgal.c | 100 +++ liblwgeom/cunit/cu_tester.c | 6 + liblwgeom/liblwgeom.h.in | 6 + liblwgeom/lwgeom.c | 53 ++ liblwgeom/lwgeom_sfcgal.c | 565 ++++++++++++++++ liblwgeom/lwgeom_sfcgal.h | 36 + postgis/Makefile.in | 40 +- postgis/lwgeom_backend_api.c | 189 ++++++ postgis/lwgeom_backend_api.h | 19 + postgis/lwgeom_functions_basic.c | 22 + postgis/lwgeom_geos.c | 12 +- postgis/lwgeom_geos.h | 5 + postgis/lwgeom_sfcgal.c | 531 +++++++++++++++ postgis/lwgeom_sfcgal.h | 39 ++ postgis/postgis.sql.in | 45 +- postgis/postgis_module.c | 4 + postgis/sfcgal.sql.in | 70 ++ postgis/uninstall_sfcgal.sql.in | 36 + regress/Makefile.in | 20 + regress/regress_sfcgal.sql | 27 + regress/regress_sfcgal_expected | 14 + regress/run_test | 23 + regress/run_test.pl | 18 +- regress/sfcgal/README | 75 ++ regress/sfcgal/concave_hull.sql | 44 ++ regress/sfcgal/concave_hull_expected | 3 + regress/sfcgal/empty.sql | 147 ++++ regress/sfcgal/empty_expected | 55 ++ regress/sfcgal/geography.sql | 79 +++ regress/sfcgal/geography_expected | 22 + regress/sfcgal/legacy.sql | 58 ++ regress/sfcgal/legacy_expected | 22 + regress/sfcgal/measures.sql | 264 ++++++++ regress/sfcgal/measures_expected | 45 ++ regress/sfcgal/regress.sql | 286 ++++++++ regress/sfcgal/regress_expected | 189 ++++++ regress/sfcgal/regress_ogc.sql | 153 +++++ regress/sfcgal/regress_ogc_expected | 89 +++ regress/sfcgal/regress_ogc_prep.sql | 300 ++++++++ regress/sfcgal/regress_ogc_prep_expected | 151 +++++ regress/sfcgal/tickets.sql | 826 +++++++++++++++++++++++ regress/sfcgal/tickets_expected | 245 +++++++ regress/sfcgal/wmsservers.sql | 39 ++ regress/sfcgal/wmsservers_expected | 18 + 57 files changed, 5806 insertions(+), 30 deletions(-) create mode 100644 doc/reference_sfcgal.xml create mode 100644 doc/xsl/sfcgal_cheatsheet.html.xsl create mode 100644 doc/xsl/sfcgal_comments.sql.xsl create mode 100644 liblwgeom/cunit/cu_force_sfs.c create mode 100644 liblwgeom/cunit/cu_sfcgal.c create mode 100644 liblwgeom/lwgeom_sfcgal.c create mode 100644 liblwgeom/lwgeom_sfcgal.h create mode 100644 postgis/lwgeom_backend_api.c create mode 100644 postgis/lwgeom_backend_api.h create mode 100644 postgis/lwgeom_sfcgal.c create mode 100644 postgis/lwgeom_sfcgal.h create mode 100644 postgis/sfcgal.sql.in create mode 100644 postgis/uninstall_sfcgal.sql.in create mode 100644 regress/regress_sfcgal.sql create mode 100644 regress/regress_sfcgal_expected create mode 100644 regress/sfcgal/README create mode 100644 regress/sfcgal/concave_hull.sql create mode 100644 regress/sfcgal/concave_hull_expected create mode 100644 regress/sfcgal/empty.sql create mode 100644 regress/sfcgal/empty_expected create mode 100644 regress/sfcgal/geography.sql create mode 100644 regress/sfcgal/geography_expected create mode 100644 regress/sfcgal/legacy.sql create mode 100644 regress/sfcgal/legacy_expected create mode 100644 regress/sfcgal/measures.sql create mode 100644 regress/sfcgal/measures_expected create mode 100644 regress/sfcgal/regress.sql create mode 100644 regress/sfcgal/regress_expected create mode 100644 regress/sfcgal/regress_ogc.sql create mode 100644 regress/sfcgal/regress_ogc_expected create mode 100644 regress/sfcgal/regress_ogc_prep.sql create mode 100644 regress/sfcgal/regress_ogc_prep_expected create mode 100644 regress/sfcgal/tickets.sql create mode 100644 regress/sfcgal/tickets_expected create mode 100644 regress/sfcgal/wmsservers.sql create mode 100644 regress/sfcgal/wmsservers_expected diff --git a/configure.ac b/configure.ac index 4e1defe33..80d31b505 100644 --- a/configure.ac +++ b/configure.ac @@ -609,6 +609,45 @@ AC_DEFINE_UNQUOTED([POSTGIS_GEOS_VERSION], [$POSTGIS_GEOS_VERSION], [GEOS librar AC_SUBST([POSTGIS_GEOS_VERSION]) +dnl =========================================================================== +dnl SFCGAL library support +dnl =========================================================================== + +AC_ARG_WITH([sfcgal], + [AS_HELP_STRING([--with-sfcgal=PATH], [Add SFCGAL support. ARG allows to specify an alternate PATH to sfcgal-config])], + [SFCGAL_CONFIG="$withval"], + [AC_PATH_PROG([SFCGAL_CONFIG], [sfcgal-config], [])]) + +HAVE_SFCGAL="no" + +if test "x$with_sfcgal" != "xno"; then + if test -x "$SFCGAL_CONFIG"; then + SFCGAL_VERSION=`$SFCGAL_CONFIG --version` + SFCGAL_LDFLAGS=`$SFCGAL_CONFIG --libs` + SFCGAL_CPPFLAGS=`$SFCGAL_CONFIG --cflags`" -DHAVE_SFCGAL" + + SFCGAL_STATIC=`$SFCGAL_CONFIG --static` + if test "x$SFCGAL_STATIC" = "xON"; then + AC_MSG_WARN([The SFCGAL version found is not installed as a dynamic library.]) + else + SFCGAL="sfcgal" + HAVE_SFCGAL="yes" + fi + + else + if test "x$with_sfcgal" != "x"; then + AC_MSG_ERROR([sfcgal-config cannot be found. Please install sfcgal]) + fi + fi +fi + +AC_SUBST([SFCGAL_VERSION]) +AC_SUBST([SFCGAL_CPPFLAGS]) +AC_SUBST([SFCGAL_LDFLAGS]) +AC_SUBST([SFCGAL_OBJS]) +AC_SUBST([SFCGAL]) +AC_SUBST([HAVE_SFCGAL]) + dnl =========================================================================== dnl Detect gettext dnl =========================================================================== @@ -854,10 +893,10 @@ dnl Always enable use of ANALYZE statistics by default AC_DEFINE_UNQUOTED([POSTGIS_USE_STATS], [1], [Enable use of ANALYZE statistics]) -CPPFLAGS="$PGSQL_CPPFLAGS $GEOS_CPPFLAGS $PROJ_CPPFLAGS $XML2_CPPFLAGS" +CPPFLAGS="$PGSQL_CPPFLAGS $GEOS_CPPFLAGS $PROJ_CPPFLAGS $XML2_CPPFLAGS $SFCGAL_CPPFLAGS" dnl AC_MSG_RESULT([CPPFLAGS: $CPPFLAGS]) -SHLIB_LINK="$PGSQL_LDFLAGS $GEOS_LDFLAGS $PROJ_LDFLAGS -lgeos_c -lproj $JSON_LDFLAGS $XML2_LDFLAGS" +SHLIB_LINK="$PGSQL_LDFLAGS $GEOS_LDFLAGS $PROJ_LDFLAGS -lgeos_c -lproj $JSON_LDFLAGS $XML2_LDFLAGS $SFCGAL_LDFLAGS" AC_SUBST([SHLIB_LINK]) dnl AC_MSG_RESULT([SHLIB_LINK: $SHLIB_LINK]) @@ -1092,6 +1131,7 @@ else RT_MAKEFILE_LIST="raster/Makefile" fi + dnl =========================================================================== dnl See if we have the requirements for building the extensions, namely dnl PostgreSQL 9.1 or better and the xlstproc tool for generating the commends @@ -1164,6 +1204,10 @@ if test "x$RASTER" = "xraster"; then AC_MSG_RESULT([ GDAL config: ${GDAL_CONFIG}]) AC_MSG_RESULT([ GDAL version: ${GDAL_FULL_VERSION}]) fi +if test "x$SFCGAL" = "xsfcgal"; then + AC_MSG_RESULT([ SFCGAL config: ${SFCGAL_CONFIG}]) + AC_MSG_RESULT([ SFCGAL version: ${SFCGAL_VERSION}]) +fi AC_MSG_RESULT([ PostgreSQL config: ${PG_CONFIG}]) AC_MSG_RESULT([ PostgreSQL version: ${PGSQL_FULL_VERSION}]) AC_MSG_RESULT([ PROJ4 version: ${POSTGIS_PROJ_VERSION}]) @@ -1185,6 +1229,11 @@ if test "x$TOPOLOGY" = "xtopology"; then else AC_MSG_RESULT([ PostGIS Topology: disabled]) fi +if test "x$SFCGAL" = "xsfcgal"; then + AC_MSG_RESULT([ SFCGAL support: enabled]) +else + AC_MSG_RESULT([ SFCGAL support: disabled]) +fi AC_MSG_RESULT() AC_MSG_RESULT([ -------- Documentation Generation -------- ]) AC_MSG_RESULT([ xsltproc: ${XSLTPROC}]) diff --git a/doc/Makefile.in b/doc/Makefile.in index a107ce385..d7719c838 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -108,7 +108,7 @@ XML_SOURCES = \ installation.xml \ introduction.xml \ performance_tips.xml \ - postgis.xml \ + postgis.xml \ reference_accessor.xml \ reference_constructor.xml \ reference_editor.xml \ @@ -181,6 +181,12 @@ topology_comments.sql: ./xsl/topology_comments.sql.xsl $(XML_INPUTS) topology_cheatsheet.html: ./xsl/topology_cheatsheet.html.xsl $(XML_INPUTS) $(XSLTPROC) --novalid ./xsl/topology_cheatsheet.html.xsl postgis-out.xml > $@ +sfcgal_comments.sql: ./xsl/sfcgal_comments.sql.xsl $(XML_INPUTS) + $(XSLTPROC) --novalid ./xsl/sfcgal_comments.sql.xsl postgis-out.xml > $@ + +sfcgal_cheatsheet.html: ./xsl/sfcgal_cheatsheet.html.xsl $(XML_INPUTS) + $(XSLTPROC) --novalid ./xsl/sfcgal_cheatsheet.html.xsl postgis-out.xml > $@ + tiger_geocoder_comments.sql: ./xsl/tiger_geocoder_comments.sql.xsl $(XML_INPUTS) $(XSLTPROC) --novalid ./xsl/tiger_geocoder_comments.sql.xsl postgis-out.xml > $@ @@ -280,16 +286,17 @@ maintainer-clean: clean images-clean ifeq ($(XSLTPROC),) comments: requirements_not_met_xsltproc else -comments: postgis_comments.sql raster_comments.sql topology_comments.sql tiger_geocoder_comments.sql +comments: postgis_comments.sql raster_comments.sql topology_comments.sql sfcgal_comments.sql tiger_geocoder_comments.sql endif -cheatsheets: postgis_cheatsheet.html raster_cheatsheet.html topology_cheatsheet.html tiger_geocoder_cheatsheet.html +cheatsheets: postgis_cheatsheet.html raster_cheatsheet.html topology_cheatsheet.html sfcgal_cheatsheet.html tiger_geocoder_cheatsheet.html ifeq ($(XSLTPROC),) comments-install: if test -e postgis_comments.sql -a \ -e raster_comments.sql -a \ -e topology_comments.sql -a \ + -e sfcgal_comments.sql -a \ -e tiger_geocoder_comments.sql; then \ $(MAKE) -f Makefile.comments install; \ fi diff --git a/doc/postgis.xml b/doc/postgis.xml index 9956debb4..65d0de01d 100644 --- a/doc/postgis.xml +++ b/doc/postgis.xml @@ -32,6 +32,7 @@ + @@ -59,6 +60,13 @@ This method implements the SQL/MM specification."> + + + + + This method is also provided by SFCGAL backend."> + diff --git a/doc/reference.xml b/doc/reference.xml index 72cccd2ea..5d1449775 100644 --- a/doc/reference.xml +++ b/doc/reference.xml @@ -24,6 +24,7 @@ &reference_output; &reference_operator; &reference_measure; + &reference_sfcgal; &reference_processing; &reference_lrs; &reference_transaction; diff --git a/doc/reference_measure.xml b/doc/reference_measure.xml index bb527513c..d9e0dde8e 100644 --- a/doc/reference_measure.xml +++ b/doc/reference_measure.xml @@ -127,6 +127,7 @@ SELECT ST_AsEWKT(ST_3DClosestPoint(line,pt)) AS cp3d_line_pt, &P_support; &sqlmm_compliant; SQL-MM ? + &sfcgal_enhanced; Availability: 2.0.0 @@ -661,6 +662,7 @@ SELECT ST_AsEWKT(ST_3DShortestLine(line,pt)) AS shl3d_line_pt, &P_support; 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. + &sfcgal_enhanced; @@ -1971,6 +1973,7 @@ SELECT ST_Disjoint('POINT(0 0)'::geometry, 'LINESTRING ( 0 0, 0 2 )'::geometry); &sfs_compliant; &sqlmm_compliant; SQL-MM 3: 5.1.23 &curve_support; + &sfcgal_enhanced; Availability: 1.5.0 geography support was introduced in 1.5. Speed improvements for planar to better handle large or many vertex geometries Enhanced: 2.1.0 improved speed for geography. See Making Geography faster for details. @@ -2643,6 +2646,7 @@ SELECT ST_Equals(ST_Reverse(ST_GeomFromText('LINESTRING(0 0, 10 10)')), - ST_Intersects(g1, g2 ) --> Not (ST_Disjoint(g1, g2 )) &sqlmm_compliant; SQL-MM 3: 5.1.27 + &sfcgal_enhanced; Geometry Examples @@ -2708,6 +2712,7 @@ t &sfs_compliant; s2.1.5.1 &sqlmm_compliant; SQL-MM 3: 7.1.2, 9.3.4 Availability: 1.5.0 geography support was introduced in 1.5. + &sfcgal_enhanced; diff --git a/doc/reference_processing.xml b/doc/reference_processing.xml index bd50c4509..f52200fb3 100644 --- a/doc/reference_processing.xml +++ b/doc/reference_processing.xml @@ -1611,6 +1611,7 @@ POINT(2 1) Performed by the GEOS module + &sfcgal_enhanced; Availability: 1.5 support for geography data type was introduced. diff --git a/doc/reference_sfcgal.xml b/doc/reference_sfcgal.xml new file mode 100644 index 000000000..7a8d412c4 --- /dev/null +++ b/doc/reference_sfcgal.xml @@ -0,0 +1,238 @@ + + + + Using SFCGAL Advanced 2D/3D functions + + TODO Introduction part + + + TODO Install part + + + + + ST_Extrude + + Extrude a surface to a related volume + + + + + + geometry ST_Extrude + geometry geom + float x + float y + float z + + + + + + Description + + Availability + &Z_support; + &P_support; + &T_support; + + + + + + + + ST_MakeSolid + + Make a Solid from a Geometry + + + + + + geometry ST_MakeSolid + geometry geom + + + + + + Description + + Availability + &Z_support; + &P_support; + &T_support; + + + + + + + + ST_StraightSkeleton + + Compute a straight skeleton from a geometry + + + + + + geometry ST_StraightSkeleton + geometry geom + + + + + + Description + + Availability + &Z_support; + &P_support; + &T_support; + + + + + + + + ST_IsPlanar + + Check if a surface is or not planar + + + + + + boolean ST_IsPlanar + geometry geom + + + + + + Description + + Availability + &Z_support; + &P_support; + &T_support; + + + + + + + + ST_Orientation + + Determine surface orientation + + + + + + integer ST_Orientation + geometry geom + + + + + + Description + + Availability + &Z_support; + &P_support; + &T_support; + + + + + + + + ST_ForceLHR + + Force LHR orientation + + + + + + geometry ST_ForceLHR + geometry geom + + + + + + Description + + Availability + &Z_support; + &P_support; + &T_support; + + + + + + + ST_Minkowski + + Perform Minkowski sum + + + + + + geometry ST_Minkowski + geometry geom1 + geometry geom2 + + + + + + Description + + Availability + &Z_support; + &P_support; + &T_support; + + + + + + + + ST_Tesselate + + Perform surface Tesselation + + + + + + geometry ST_Tesselate + geometry geom + + + + + + Description + + Availability + &Z_support; + &P_support; + &T_support; + + + + + diff --git a/doc/xsl/postgis_comments.sql.xsl b/doc/xsl/postgis_comments.sql.xsl index 60630c08b..82b36c800 100644 --- a/doc/xsl/postgis_comments.sql.xsl +++ b/doc/xsl/postgis_comments.sql.xsl @@ -18,7 +18,7 @@ ' - + diff --git a/doc/xsl/sfcgal_cheatsheet.html.xsl b/doc/xsl/sfcgal_cheatsheet.html.xsl new file mode 100644 index 000000000..c7883ef4f --- /dev/null +++ b/doc/xsl/sfcgal_cheatsheet.html.xsl @@ -0,0 +1,234 @@ + + + + + 2.1 + Availability: + Enhanced: + false + true + http://postgis.net/docs/manual-dev/ + + PostGIS SFCGAL Cheat Sheet + +

PostGIS ]]> ]]> + + ]]> + + + ]]> + + + + ]]> + ]]> + ]]> + + + + + ]]> + ]]> + + + + + + + class="evenrowoddrow" ]]>.html]]>]]>]]>1 ]]> + + 2 ]]> + mm ]]> + G ]]> + g3.4 ]]> + 3D ]]> + + + () + + + + + +
    ]]>]]>]]> + ]]> + ]]> + + + + + + + + + ]]> + Examples + + + + ]]> + + + + + + + + + + + + + + + + + + class="evenrowoddrow"]]> + ]]>
    ]]>]]> +
    + ]]> +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + ]]> + + + + + + + + + + + + + + + + + + + + , + + + + + + + diff --git a/doc/xsl/sfcgal_comments.sql.xsl b/doc/xsl/sfcgal_comments.sql.xsl new file mode 100644 index 000000000..28cfe9764 --- /dev/null +++ b/doc/xsl/sfcgal_comments.sql.xsl @@ -0,0 +1,102 @@ + + + + + + + + + + + + ' + + + + + + + + + + + + + + +COMMENT ON AGGREGATEFUNCTION ( +geometry, +) IS ' '; + + + + + + + + + + + + + + + + + + + + + + + + + + ' + + + + '' + + + + + + + + + + + + + + args: + + + + + + + + + , + + - + + + + diff --git a/liblwgeom/Makefile.in b/liblwgeom/Makefile.in index f88fee4cd..3cc6256fd 100644 --- a/liblwgeom/Makefile.in +++ b/liblwgeom/Makefile.in @@ -91,6 +91,12 @@ SA_OBJS = \ NM_OBJS = \ lwspheroid.o +ifeq (@SFCGAL@,sfcgal) +CFLAGS += @SFCGAL_CPPFLAGS@ +LDFLAGS += @SFCGAL_LDFLAGS@ +SA_OBJS += lwgeom_sfcgal.o +endif + LT_SA_OBJS = $(SA_OBJS:.o=.lo) LT_NM_OBJS = $(NM_OBJS:.o=.lo) LT_OBJS = $(LT_SA_OBJS) $(LT_NM_OBJS) @@ -157,7 +163,6 @@ $(LT_NM_OBJS): %.lo: %.c parser: $(YACC) -o'lwin_wkt_parse.c' -d lwin_wkt_parse.y $(LEX) -i lwin_wkt_lex.l - # $(YACC) --debug --verbose -o'$@' -d $< # $(YACC) -o'$@' -d $^ # $(LEX) -i $< diff --git a/liblwgeom/cunit/Makefile.in b/liblwgeom/cunit/Makefile.in index e5723aeb1..edac6093d 100644 --- a/liblwgeom/cunit/Makefile.in +++ b/liblwgeom/cunit/Makefile.in @@ -38,6 +38,7 @@ OBJS= \ cu_stringbuffer.o \ cu_triangulate.o \ cu_homogenize.o \ + cu_force_sfs.o \ cu_out_wkt.o \ cu_out_wkb.o \ cu_out_gml.o \ @@ -51,6 +52,12 @@ OBJS= \ cu_in_wkt.o \ cu_tester.o +ifeq (@SFCGAL@,sfcgal) +CXXFLAGS += @SFCGAL_CPPFLAGS@ +LDFLAGS += @SFCGAL_LDFLAGS@ +OBJS += cu_sfcgal.o +endif + # If we couldn't find the cunit library then display a helpful message ifeq ($(CUNIT_LDFLAGS),) all: requirements_not_met_cunit diff --git a/liblwgeom/cunit/cu_force_sfs.c b/liblwgeom/cunit/cu_force_sfs.c new file mode 100644 index 000000000..f329921b4 --- /dev/null +++ b/liblwgeom/cunit/cu_force_sfs.c @@ -0,0 +1,175 @@ +/********************************************************************** + * $Id:$ + * + * PostGIS - Spatial Types for PostgreSQL + * http://postgis.refractions.net + * Copyright 2013 Olivier Courtin + * + * 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 +#include +#include +#include "CUnit/Basic.h" + +#include "liblwgeom_internal.h" +#include "cu_tester.h" + +static void do_geom_test(char * in, char * out) +{ + LWGEOM *g, *h; + char *tmp; + + g = lwgeom_from_wkt(in, LW_PARSER_CHECK_NONE); + h = lwgeom_force_sfs(g); + tmp = lwgeom_to_ewkt(h); + if (strcmp(tmp, out)) + fprintf(stderr, "\nIn: %s\nOut: %s\nExp: %s\n", + in, tmp, out); + CU_ASSERT_STRING_EQUAL(tmp, out); + lwfree(tmp); + lwgeom_free(g); + lwgeom_free(h); +} + + +static void do_type_test(char * in, int type) +{ + LWGEOM *g, *h; + + g = lwgeom_from_wkt(in, LW_PARSER_CHECK_NONE); + h = lwgeom_force_sfs(g); + if(h->type != type) + fprintf(stderr, "\nIn: %s\nOut: %s\nExp: %s\n", + in, lwtype_name(h->type), lwtype_name(type)); + CU_ASSERT_EQUAL(h->type, type); + lwgeom_free(g); + lwgeom_free(h); +} + + +static void test_sqlmm(void) +{ + do_type_test("CIRCULARSTRING(-1 0,0 1,0 -1)", + LINETYPE); + + do_type_test("COMPOUNDCURVE(CIRCULARSTRING(-1 0,0 1,0 -1),(0 -1,-1 -1))", + LINETYPE); + + do_type_test("COMPOUNDCURVE((-3 -3,-1 0),CIRCULARSTRING(-1 0,0 1,0 -1),(0 -1,0 -1.5,0 -2),CIRCULARSTRING(0 -2,-1 -3,1 -3),(1 -3,5 5))", + LINETYPE); + + do_type_test("COMPOUNDCURVE(CIRCULARSTRING(-1 0,0 1,0 -1),CIRCULARSTRING(0 -1,-1 -2,1 -2))", + LINETYPE); + + do_type_test("CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING (0 0 2,1 1 2,1 0 2),(1 0 2,0 1 2),(0 1 2, 0 0 2)))", + POLYGONTYPE); + + do_type_test("CURVEPOLYGON (COMPOUNDCURVE (CIRCULARSTRING (0 0 2 5,1 1 2 6,1 0 2 5), (1 0 2 3,0 1 2 2), (0 1 2 2,30 1 2 2), CIRCULARSTRING (30 1 2 2,12 1 2 6,1 10 2 5, 1 10 3 5, 0 0 2 5)))", + POLYGONTYPE); + + do_type_test("MULTISURFACE (CURVEPOLYGON (CIRCULARSTRING (-2 0, -1 -1, 0 0, 1 -1, 2 0, 0 2, -2 0), (-1 0, 0 0.5, 1 0, 0 1, -1 0)), ((7 8, 10 10, 6 14, 4 11, 7 8)))", + MULTIPOLYGONTYPE); + +} + +static void test_sfs_12(void) +{ + do_geom_test("TRIANGLE((1 2,3 4,5 6,1 2))", + "POLYGON((1 2,3 4,5 6,1 2))"); + + do_geom_test("GEOMETRYCOLLECTION(TRIANGLE((1 2,3 4,5 6,1 2)))", + "GEOMETRYCOLLECTION(POLYGON((1 2,3 4,5 6,1 2)))"); + + do_geom_test("GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(TRIANGLE((1 2,3 4,5 6,1 2))))", + "GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POLYGON((1 2,3 4,5 6,1 2))))"); + + + do_geom_test("TIN(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))", + "MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))"); + + do_geom_test("GEOMETRYCOLLECTION(TIN(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8))))", + "GEOMETRYCOLLECTION(MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8))))"); + + do_geom_test("GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(TIN(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))))", + "GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))))"); + + + do_geom_test("POLYHEDRALSURFACE(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))", + "MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))"); + + do_geom_test("GEOMETRYCOLLECTION(POLYHEDRALSURFACE(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8))))", + "GEOMETRYCOLLECTION(MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8))))"); + + do_geom_test("GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POLYHEDRALSURFACE(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))))", + "GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))))"); + +} + +static void test_sfs_11(void) +{ + do_geom_test("POINT(1 2)", + "POINT(1 2)"); + + do_geom_test("LINESTRING(1 2,3 4)", + "LINESTRING(1 2,3 4)"); + + do_geom_test("POLYGON((1 2,3 4,5 6,1 2))", + "POLYGON((1 2,3 4,5 6,1 2))"); + + do_geom_test("POLYGON((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8))", + "POLYGON((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8))"); + + do_geom_test("MULTIPOINT(1 2,3 4)", + "MULTIPOINT(1 2,3 4)"); + + do_geom_test("MULTILINESTRING((1 2,3 4),(5 6,7 8))", + "MULTILINESTRING((1 2,3 4),(5 6,7 8))"); + + do_geom_test("MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))", + "MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))"); + + do_geom_test("MULTIPOLYGON(((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8)),((13 14,15 16,17 18,13 14)))", + "MULTIPOLYGON(((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8)),((13 14,15 16,17 18,13 14)))"); + + do_geom_test("GEOMETRYCOLLECTION(POINT(1 2),LINESTRING(3 4,5 6))", + "GEOMETRYCOLLECTION(POINT(1 2),LINESTRING(3 4,5 6))"); + + do_geom_test("GEOMETRYCOLLECTION EMPTY", + "GEOMETRYCOLLECTION EMPTY"); + + /* SRID */ + do_geom_test("SRID=4326;GEOMETRYCOLLECTION EMPTY", + "SRID=4326;GEOMETRYCOLLECTION EMPTY"); + + do_geom_test("SRID=4326;POINT(1 2)", + "SRID=4326;POINT(1 2)"); + + + /* 3D and 4D */ + /* SFS 1.2 is only 2D but we choose here to keep 3D and 4D, + and let the user use force_2d if he want/need it */ + do_geom_test("POINT(1 2 3)", + "POINT(1 2 3)"); + + do_geom_test("POINTM(1 2 3)", + "POINTM(1 2 3)"); + + do_geom_test("POINT(1 2 3 4)", + "POINT(1 2 3 4)"); +} + +/* +** Used by test harness to register the tests in this file. +*/ +CU_TestInfo force_sfs_tests[] = +{ + PG_TEST(test_sfs_11), + PG_TEST(test_sfs_12), + PG_TEST(test_sqlmm), + CU_TEST_INFO_NULL +}; +CU_SuiteInfo force_sfs_suite = {"force_sfs", NULL, NULL, force_sfs_tests}; diff --git a/liblwgeom/cunit/cu_sfcgal.c b/liblwgeom/cunit/cu_sfcgal.c new file mode 100644 index 000000000..5ed921cff --- /dev/null +++ b/liblwgeom/cunit/cu_sfcgal.c @@ -0,0 +1,100 @@ +/********************************************************************** + * + * PostGIS - Spatial Types for PostgreSQL + * http://postgis.refractions.net + * + * + * This is free software; you can redistribute and/or modify it under + * the terms of the GNU General Public Licence. See the COPYING file. + * + **********************************************************************/ + +#include +#include +#include +#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}; + diff --git a/liblwgeom/cunit/cu_tester.c b/liblwgeom/cunit/cu_tester.c index 4c0c01a94..9145d3f06 100644 --- a/liblwgeom/cunit/cu_tester.c +++ b/liblwgeom/cunit/cu_tester.c @@ -38,9 +38,11 @@ extern CU_SuiteInfo libgeom_suite; extern CU_SuiteInfo split_suite; extern CU_SuiteInfo geodetic_suite; extern CU_SuiteInfo geos_suite; +extern CU_SuiteInfo sfcgal_suite; extern CU_SuiteInfo tree_suite; extern CU_SuiteInfo triangulate_suite; extern CU_SuiteInfo homogenize_suite; +extern CU_SuiteInfo force_sfs_suite; extern CU_SuiteInfo in_geojson_suite; extern CU_SuiteInfo stringbuffer_suite; extern CU_SuiteInfo surface_suite; @@ -76,11 +78,15 @@ int main(int argc, char *argv[]) split_suite, geodetic_suite, geos_suite, +#if HAVE_SFCGAL + sfcgal_suite, +#endif tree_suite, triangulate_suite, stringbuffer_suite, surface_suite, homogenize_suite, + force_sfs_suite, #if HAVE_JSON in_geojson_suite, #endif diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in index fb20b5f8d..886f63246 100644 --- a/liblwgeom/liblwgeom.h.in +++ b/liblwgeom/liblwgeom.h.in @@ -873,6 +873,12 @@ extern LWGEOM* lwgeom_force_4d(const LWGEOM *geom); extern LWGEOM* lwgeom_simplify(const LWGEOM *igeom, double dist); +/* + * Force to use SFS 1.1 geometry type + * (rather than SFS 1.2 and/or SQL/MM) + */ +extern LWGEOM* lwgeom_force_sfs(LWGEOM *geom); + /*-------------------------------------------------------- * all the base types (point/line/polygon) will have a diff --git a/liblwgeom/lwgeom.c b/liblwgeom/lwgeom.c index a30ea0c23..cdabd1beb 100644 --- a/liblwgeom/lwgeom.c +++ b/liblwgeom/lwgeom.c @@ -705,6 +705,59 @@ lwgeom_force_dims(const LWGEOM *geom, int hasz, int hasm) } } +LWGEOM* +lwgeom_force_sfs(LWGEOM *geom) +{ + LWCOLLECTION *col; + int i; + LWGEOM *g; + + + switch(geom->type) + { + /* SQL/MM types */ + case CIRCSTRINGTYPE: + case COMPOUNDTYPE: + case CURVEPOLYTYPE: + case MULTICURVETYPE: + case MULTISURFACETYPE: + return lwgeom_segmentize(geom, 32); + + /* SFS 1.2 types */ + case TRIANGLETYPE: + g = lwpoly_as_lwgeom(lwpoly_from_lwlines((LWLINE*)geom, 0, NULL)); + lwgeom_free(geom); + return g; + + case TINTYPE: + col = (LWCOLLECTION*) geom; + for ( i = 0; i < col->ngeoms; i++ ) + { + g = lwpoly_as_lwgeom(lwpoly_from_lwlines((LWLINE*)col->geoms[i], 0, NULL)); + lwgeom_free(col->geoms[i]); + col->geoms[i] = g; + } + + col->type = MULTIPOLYGONTYPE; + return lwmpoly_as_lwgeom((LWMPOLY*)geom); + + case POLYHEDRALSURFACETYPE: + geom->type = MULTIPOLYGONTYPE; + return (LWGEOM *)geom; + + /* Collection */ + case COLLECTIONTYPE: + col = (LWCOLLECTION*)geom; + for ( i = 0; i < col->ngeoms; i++ ) + col->geoms[i] = lwgeom_force_sfs((LWGEOM*)col->geoms[i]); + + return lwcollection_as_lwgeom((LWCOLLECTION*)geom); + + default: + return (LWGEOM *)geom; + } +} + int32_t lwgeom_get_srid(const LWGEOM *geom) { diff --git a/liblwgeom/lwgeom_sfcgal.c b/liblwgeom/lwgeom_sfcgal.c new file mode 100644 index 000000000..57a56fcfd --- /dev/null +++ b/liblwgeom/lwgeom_sfcgal.c @@ -0,0 +1,565 @@ +/********************************************************************** + * + * PostGIS - Spatial Types for PostgreSQL + * http://postgis.refractions.net + * + * Wrapper around SFCGAL for 3D functions + * + * Copyright 2012-2013 Oslandia + * + * 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 +#include "lwgeom_sfcgal.h" + +static int SFCGAL_type_to_lwgeom_type(sfcgal_geometry_type_t type); +static POINTARRAY* ptarray_from_SFCGAL(const sfcgal_geometry_t* geom, int force3D); +static sfcgal_geometry_t* ptarray_to_SFCGAL(const POINTARRAY* pa, int type); + + + +/* Return SFCGAL version string */ +const char* +lwgeom_sfcgal_version() +{ + const char *version = sfcgal_version(); + return version; +} + + +/* + * Mapping between SFCGAL and PostGIS types + * + * Throw an error if type is unsupported + */ +static int +SFCGAL_type_to_lwgeom_type(sfcgal_geometry_type_t type) +{ + switch (type) + { + case SFCGAL_TYPE_POINT: + return POINTTYPE; + + case SFCGAL_TYPE_LINESTRING: + return LINETYPE; + + case SFCGAL_TYPE_POLYGON: + return POLYGONTYPE; + + case SFCGAL_TYPE_MULTIPOINT: + return MULTIPOINTTYPE; + + case SFCGAL_TYPE_MULTILINESTRING: + return MULTILINETYPE; + + case SFCGAL_TYPE_MULTIPOLYGON: + return MULTIPOLYGONTYPE; + + case SFCGAL_TYPE_MULTISOLID: + return COLLECTIONTYPE; /* Nota: PolyhedralSurface closed inside + aim is to use true solid type as soon + as available in OGC SFS */ + + case SFCGAL_TYPE_GEOMETRYCOLLECTION: + return COLLECTIONTYPE; + +#if 0 + case SFCGAL_TYPE_CIRCULARSTRING: + return CIRCSTRINGTYPE; + + case SFCGAL_TYPE_COMPOUNDCURVE: + return COMPOUNDTYPE; + + case SFCGAL_TYPE_CURVEPOLYGON: + return CURVEPOLYTYPE; + + case SFCGAL_TYPE_MULTICURVE: + return MULTICURVETYPE; + + case SFCGAL_TYPE_MULTISURFACE: + return MULTISURFACETYPE; +#endif + + case SFCGAL_TYPE_POLYHEDRALSURFACE: + return POLYHEDRALSURFACETYPE; + + case SFCGAL_TYPE_TRIANGULATEDSURFACE: + return TINTYPE; + + case SFCGAL_TYPE_TRIANGLE: + return TRIANGLETYPE; + + default: + lwerror("SFCGAL_type_to_lwgeom_type: Unknown Type"); + return 0; + } +} + + +/* + * Return a PostGIS pointarray from a simple SFCGAL geometry: + * POINT, LINESTRING or TRIANGLE + * + * Trought an error on others types + */ +static POINTARRAY* +ptarray_from_SFCGAL(const sfcgal_geometry_t* geom, int want3d) +{ + POINT4D point; + uint32_t i, npoints; + POINTARRAY* pa = NULL; + + assert(geom); + + switch (sfcgal_geometry_type_id(geom)) + { + case SFCGAL_TYPE_POINT: + { + pa = ptarray_construct(want3d, 0, 1); + point.x = sfcgal_point_x(geom); + point.y = sfcgal_point_y(geom); + + if (sfcgal_geometry_is_3d(geom)) + point.z = sfcgal_point_z(geom); + else if (want3d) + point.z = 0.0; + + ptarray_set_point4d(pa, 0, &point); + } + break; + + case SFCGAL_TYPE_LINESTRING: + { + npoints = sfcgal_linestring_num_points(geom); + pa = ptarray_construct(want3d, 0, npoints); + + for (i = 0; i < npoints; i++) + { + const sfcgal_geometry_t* pt = sfcgal_linestring_point_n(geom, i); + point.x = sfcgal_point_x(pt); + point.y = sfcgal_point_y(pt); + + if (sfcgal_geometry_is_3d(geom)) + point.z = sfcgal_point_z(pt); + else if (want3d) + point.z = 0.0; + + ptarray_set_point4d(pa, i, &point); + } + } + break; + + case SFCGAL_TYPE_TRIANGLE: + { + pa = ptarray_construct(want3d, 0, 4); + + for (i = 0; i < 4; i++) + { + const sfcgal_geometry_t* pt = sfcgal_triangle_vertex(geom, (i%3)); + point.x = sfcgal_point_x(pt); + point.y = sfcgal_point_y(pt); + + if ( sfcgal_geometry_is_3d(geom)) + point.z = sfcgal_point_z(pt); + else if (want3d) + point.z = 0.0; + + ptarray_set_point4d(pa, i, &point); + } + } + break; + + /* Other types should not be called directly ... */ + default: + lwerror("ptarray_from_SFCGAL: Unknown Type"); + break; + } + return pa; +} + + +/* + * Convert a PostGIS pointarray to SFCGAL structure + * + * Used for simple LWGEOM geometry POINT, LINESTRING, TRIANGLE + * and POLYGON rings + */ +static sfcgal_geometry_t* +ptarray_to_SFCGAL(const POINTARRAY* pa, int type) +{ + POINT3DZ point; + int is_3d; + uint32_t i; + + assert(pa); + + is_3d = FLAGS_GET_Z(pa->flags) != 0; + + switch (type) + { + case POINTTYPE: + { + getPoint3dz_p(pa, 0, &point); + if (is_3d) return sfcgal_point_create_from_xyz(point.x, point.y, point.z); + else return sfcgal_point_create_from_xy(point.x, point.y); + } + break; + + case LINETYPE: + { + sfcgal_geometry_t* line = sfcgal_linestring_create(); + + for (i = 0; i < pa->npoints; i++) + { + getPoint3dz_p(pa, i, &point); + if (is_3d) + { + sfcgal_linestring_add_point(line, + sfcgal_point_create_from_xyz(point.x, point.y, point.z)); + } + else + { + sfcgal_linestring_add_point(line, + sfcgal_point_create_from_xy(point.x, point.y)); + } + } + + return line; + } + break; + + case TRIANGLETYPE: + { + sfcgal_geometry_t* triangle = sfcgal_triangle_create(); + + getPoint3dz_p(pa, 0, &point); + if (is_3d) sfcgal_triangle_set_vertex_from_xyz(triangle, 0, point.x, point.y, point.z); + else sfcgal_triangle_set_vertex_from_xy (triangle, 0, point.x, point.y); + + getPoint3dz_p(pa, 1, &point); + if (is_3d) sfcgal_triangle_set_vertex_from_xyz(triangle, 1, point.x, point.y, point.z); + else sfcgal_triangle_set_vertex_from_xy (triangle, 1, point.x, point.y); + + getPoint3dz_p(pa, 2, &point); + if (is_3d) sfcgal_triangle_set_vertex_from_xyz(triangle, 2, point.x, point.y, point.z); + else sfcgal_triangle_set_vertex_from_xy (triangle, 2, point.x, point.y); + + return triangle; + } + break; + + /* Other SFCGAL types should not be called directly ... */ + default: + lwerror("ptarray_from_SFCGAL: Unknown Type"); + return NULL; + } +} + + +/* + * Convert a SFCGAL structure to PostGIS LWGEOM + * + * Throws an error on unsupported type + */ +LWGEOM* +SFCGAL2LWGEOM(const sfcgal_geometry_t* geom, int force3D, int srid) +{ + uint32_t ngeoms, nshells; + uint32_t i, j, k; + int want3d; + + assert(geom); + + want3d = force3D || sfcgal_geometry_is_3d(geom); + + switch (sfcgal_geometry_type_id(geom)) + { + case SFCGAL_TYPE_POINT: + { + if (sfcgal_geometry_is_empty(geom)) + return (LWGEOM*) lwpoint_construct_empty(srid, want3d, 0); + + POINTARRAY* pa = ptarray_from_SFCGAL(geom, want3d); + return (LWGEOM*) lwpoint_construct(srid, NULL, pa); + } + + case SFCGAL_TYPE_LINESTRING: + { + if (sfcgal_geometry_is_empty(geom)) + return (LWGEOM*) lwline_construct_empty(srid, want3d, 0); + + POINTARRAY* pa = ptarray_from_SFCGAL(geom, want3d); + return (LWGEOM*) lwline_construct(srid, NULL, pa); + } + + case SFCGAL_TYPE_TRIANGLE: + { + if (sfcgal_geometry_is_empty(geom)) + return (LWGEOM*) lwtriangle_construct_empty(srid, want3d, 0); + + POINTARRAY* pa = ptarray_from_SFCGAL(geom, want3d); + return (LWGEOM*) lwtriangle_construct(srid, NULL, pa); + } + + case SFCGAL_TYPE_POLYGON: + { + if (sfcgal_geometry_is_empty(geom)) + return (LWGEOM*) lwpoly_construct_empty(srid, want3d, 0); + + uint32_t nrings = sfcgal_polygon_num_interior_rings(geom) + 1; + POINTARRAY** pa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*) * nrings); + + pa[0] = ptarray_from_SFCGAL(sfcgal_polygon_exterior_ring(geom), want3d); + for (i = 1; i < nrings; i++) + pa[i] = ptarray_from_SFCGAL(sfcgal_polygon_interior_ring_n(geom, i-1), want3d); + + return (LWGEOM*) lwpoly_construct(srid, NULL, nrings, pa); + } + + case SFCGAL_TYPE_MULTIPOINT: + case SFCGAL_TYPE_MULTILINESTRING: + case SFCGAL_TYPE_MULTIPOLYGON: + case SFCGAL_TYPE_MULTISOLID: + case SFCGAL_TYPE_GEOMETRYCOLLECTION: + { + ngeoms = sfcgal_geometry_collection_num_geometries(geom); + LWGEOM** geoms = NULL; + if (ngeoms) + { + geoms = (LWGEOM**) lwalloc(sizeof(LWGEOM*) * ngeoms); + for (i = 0; i < ngeoms; i++) + { + const sfcgal_geometry_t* g = sfcgal_geometry_collection_geometry_n(geom, i); + geoms[i] = SFCGAL2LWGEOM(g, 0, srid); + } + geoms = (LWGEOM**) lwrealloc(geoms, sizeof(LWGEOM*) * ngeoms); + } + return (LWGEOM*) lwcollection_construct(SFCGAL_type_to_lwgeom_type( + sfcgal_geometry_type_id(geom)), srid, NULL, ngeoms, geoms); + } + +#if 0 + case SFCGAL_TYPE_CIRCULARSTRING: + case SFCGAL_TYPE_COMPOUNDCURVE: + case SFCGAL_TYPE_CURVEPOLYGON: + case SFCGAL_TYPE_MULTICURVE: + case SFCGAL_TYPE_MULTISURFACE: + case SFCGAL_TYPE_CURVE: + case SFCGAL_TYPE_SURFACE: + + /* TODO curve types handling */ +#endif + + case SFCGAL_TYPE_POLYHEDRALSURFACE: + { + ngeoms = sfcgal_polyhedral_surface_num_polygons(geom); + + LWGEOM** geoms = NULL; + if (ngeoms) + { + geoms = (LWGEOM**) lwalloc(sizeof(LWGEOM*) * ngeoms); + for (i = 0; i < ngeoms; i++) + { + const sfcgal_geometry_t* g = sfcgal_polyhedral_surface_polygon_n( geom, i ); + geoms[i] = SFCGAL2LWGEOM(g, 0, srid); + } + } + return (LWGEOM*)lwcollection_construct(POLYHEDRALSURFACETYPE, srid, NULL, ngeoms, geoms); + } + + /* Solid is map as a closed PolyhedralSurface (for now) */ + case SFCGAL_TYPE_SOLID: + { + nshells = sfcgal_solid_num_shells(geom); + + for (ngeoms = 0, i = 0; i < nshells; i++) + ngeoms += sfcgal_polyhedral_surface_num_polygons(sfcgal_solid_shell_n(geom, i)); + + LWGEOM** geoms = 0; + if (ngeoms) + { + geoms = (LWGEOM**) lwalloc( sizeof(LWGEOM*) * ngeoms); + for (i = 0, k =0 ; i < nshells; i++) + { + const sfcgal_geometry_t* shell = sfcgal_solid_shell_n(geom, i); + ngeoms = sfcgal_polyhedral_surface_num_polygons(shell); + + for (j = 0; j < ngeoms; j++) + { + const sfcgal_geometry_t* g = sfcgal_polyhedral_surface_polygon_n(shell, j); + geoms[k] = SFCGAL2LWGEOM(g, 1, srid); + k++; + } + } + } + LWGEOM* rgeom = (LWGEOM*) lwcollection_construct(POLYHEDRALSURFACETYPE, srid, NULL, ngeoms, geoms); + if (ngeoms) FLAGS_SET_SOLID( rgeom->flags, 1); + return rgeom; + } + + case SFCGAL_TYPE_TRIANGULATEDSURFACE: + { + ngeoms = sfcgal_triangulated_surface_num_triangles(geom); + LWGEOM** geoms = NULL; + if (ngeoms) + { + geoms = (LWGEOM**) lwalloc(sizeof(LWGEOM*) * ngeoms); + for (i = 0; i < ngeoms; i++) + { + const sfcgal_geometry_t* g = sfcgal_triangulated_surface_triangle_n(geom, i); + geoms[i] = SFCGAL2LWGEOM(g, 0, srid); + } + } + return (LWGEOM*) lwcollection_construct(TINTYPE, srid, NULL, ngeoms, geoms); + } + + default: + lwerror("SFCGAL2LWGEOM: Unknown Type"); + return NULL; + } +} + + +sfcgal_geometry_t* +LWGEOM2SFCGAL(const LWGEOM* geom) +{ + uint32_t i; + sfcgal_geometry_t* ret_geom = NULL; + + assert(geom); + + switch (geom->type) + { + case POINTTYPE: + { + const LWPOINT* lwp = (const LWPOINT*) geom; + if (lwgeom_is_empty(geom)) return sfcgal_point_create(); + + return ptarray_to_SFCGAL(lwp->point, POINTTYPE); + } + break; + + case LINETYPE: + { + const LWLINE* line = (const LWLINE*) geom; + if (lwgeom_is_empty(geom)) return sfcgal_linestring_create(); + + return ptarray_to_SFCGAL(line->points, LINETYPE); + } + break; + + case TRIANGLETYPE: + { + const LWTRIANGLE* triangle = (const LWTRIANGLE*) geom; + if (lwgeom_is_empty(geom)) return sfcgal_triangle_create(); + return ptarray_to_SFCGAL(triangle->points, TRIANGLETYPE); + } + break; + + case POLYGONTYPE: + { + const LWPOLY* poly = (const LWPOLY*) geom; + uint32_t nrings = poly->nrings - 1; + + if (lwgeom_is_empty(geom)) return sfcgal_polygon_create(); + + sfcgal_geometry_t* exterior_ring = ptarray_to_SFCGAL(poly->rings[0], LINETYPE); + ret_geom = sfcgal_polygon_create_from_exterior_ring(exterior_ring); + + for (i = 0; i < nrings; i++) + { + sfcgal_geometry_t* ring = ptarray_to_SFCGAL(poly->rings[i + 1], LINETYPE); + sfcgal_polygon_add_interior_ring(ret_geom, ring); + } + return ret_geom; + } + break; + + case MULTIPOINTTYPE: + case MULTILINETYPE: + case MULTIPOLYGONTYPE: + case COLLECTIONTYPE: + { + if (geom->type == MULTIPOINTTYPE) ret_geom = sfcgal_multi_point_create(); + else if (geom->type == MULTILINETYPE) ret_geom = sfcgal_multi_linestring_create(); + else if (geom->type == MULTIPOLYGONTYPE) ret_geom = sfcgal_multi_polygon_create(); + else ret_geom = sfcgal_geometry_collection_create(); + + const LWCOLLECTION* lwc = (const LWCOLLECTION*)geom; + for (i = 0; i < lwc->ngeoms; i++) + { + sfcgal_geometry_t* g = LWGEOM2SFCGAL(lwc->geoms[i]); + sfcgal_geometry_collection_add_geometry(ret_geom, g); + } + + return ret_geom; + } + break; + + case POLYHEDRALSURFACETYPE: + { + const LWPSURFACE* lwp = (const LWPSURFACE*) geom; + ret_geom = sfcgal_polyhedral_surface_create(); + + for (i = 0; i < lwp->ngeoms; i++) + { + sfcgal_geometry_t* g = LWGEOM2SFCGAL((const LWGEOM*) lwp->geoms[i]); + sfcgal_polyhedral_surface_add_polygon(ret_geom, g); + } + /* We treat polyhedral surface as the only exterior shell, + since we can't distinguish exterior from interior shells ... */ + if (FLAGS_GET_SOLID(lwp->flags)) + { + return sfcgal_solid_create_from_exterior_shell(ret_geom); + } + + return ret_geom; + } + break; + + case TINTYPE: + { + const LWTIN* lwp = (const LWTIN*) geom; + ret_geom = sfcgal_triangulated_surface_create(); + + for (i = 0; i < lwp->ngeoms; i++) + { + sfcgal_geometry_t* g = LWGEOM2SFCGAL((const LWGEOM*) lwp->geoms[i]); + sfcgal_triangulated_surface_add_triangle(ret_geom, g); + } + + return ret_geom; + } + break; + + default: + lwerror("LWGEOM2SFCGAL: Unknown geometry type !"); + return NULL; + } +} + + +/* + * No Operation SFCGAL function, used (only) for cunit tests + * Take a PostGIS geometry, send it to SFCGAL and return it unchanged (in theory) + */ +LWGEOM* lwgeom_sfcgal_noop(const LWGEOM* geom_in) +{ + sfcgal_geometry_t* converted; + + assert(geom_in); + + converted = LWGEOM2SFCGAL(geom_in); + assert(converted); + + LWGEOM* geom_out = SFCGAL2LWGEOM(converted, 0, SRID_UNKNOWN); + sfcgal_geometry_delete(converted); + + /* copy SRID (SFCGAL does not store the SRID) */ + geom_out->srid = geom_in->srid; + return geom_out; +} diff --git a/liblwgeom/lwgeom_sfcgal.h b/liblwgeom/lwgeom_sfcgal.h new file mode 100644 index 000000000..6316b691a --- /dev/null +++ b/liblwgeom/lwgeom_sfcgal.h @@ -0,0 +1,36 @@ +/********************************************************************** + * + * PostGIS - Spatial Types for PostgreSQL + * http://postgis.refractions.net + * + * Wrapper around SFCGAL for 3D functions + * + * Copyright 2012-2013 Oslandia + * + * 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 + + +/* 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); diff --git a/postgis/Makefile.in b/postgis/Makefile.in index c0976fd5b..da2487946 100644 --- a/postgis/Makefile.in +++ b/postgis/Makefile.in @@ -15,15 +15,30 @@ MODULE_big=postgis-@POSTGIS_MAJOR_VERSION@.@POSTGIS_MINOR_VERSION@ MODULEDIR=contrib/$(MODULE_big) # Files to be copied to the contrib/ directory -DATA_built=postgis.sql uninstall_postgis.sql postgis_upgrade_20_21.sql postgis_upgrade_21_minor.sql legacy.sql uninstall_legacy.sql legacy_minimal.sql legacy_gist.sql +SQL_built=postgis.sql uninstall_postgis.sql postgis_upgrade_20_21.sql postgis_upgrade_21_minor.sql legacy.sql uninstall_legacy.sql legacy_minimal.sql legacy_gist.sql uninstall_sfcgal.sql DATA=../spatial_ref_sys.sql +# SQL objects (files requiring pre-processing) +SQL_objs=postgis.sql legacy.sql legacy_minimal.sql + +GEOM_BACKEND_OBJ = lwgeom_geos.o +SFCGAL_BACKEND_OBJ = lwgeom_sfcgal.o + +ifeq (@SFCGAL@,sfcgal) +DATA_built=$(SQL_built) sfcgal.sql +SQL_OBJS=$(SQL_objs) sfcgal.sql +BACKEND_OBJ=$(GEOM_BACKEND_OBJ) $(SFCGAL_BACKEND_OBJ) +else +BACKEND_OBJ=$(GEOM_BACKEND_OBJ) +DATA_built=$(SQL_built) +SQL_OBJS=$(SQL_objs) +endif + + + # SQL preprocessor SQLPP = @SQLPP@ -# SQL objects (files requiring pre-processing) -SQL_OBJS=postgis.sql legacy.sql legacy_minimal.sql - # PostgreSQL objects PG_OBJS= \ postgis_module.o \ @@ -36,7 +51,8 @@ PG_OBJS= \ lwgeom_btree.o \ lwgeom_box.o \ lwgeom_box3d.o \ - lwgeom_geos.o \ + $(BACKEND_OBJ) \ + lwgeom_backend_api.o \ lwgeom_geos_prepared.o \ lwgeom_geos_clean.o \ lwgeom_geos_relatematch.o \ @@ -73,13 +89,20 @@ OBJS=$(PG_OBJS) # to an existing liblwgeom.so in the PostgreSQL $libdir supplied by an # older version of PostGIS, rather than with the static liblwgeom.a # supplied with newer versions of PostGIS -PG_CPPFLAGS += @CPPFLAGS@ -I../liblwgeom -I../libpgcommon -SHLIB_LINK_F = ../libpgcommon/libpgcommon.a ../liblwgeom/.libs/liblwgeom.a @SHLIB_LINK@ +PG_CPPFLAGS += @CPPFLAGS@ -I../liblwgeom -I../libpgcommon -fPIC +SHLIB_LINK_F = ../libpgcommon/libpgcommon.a ../liblwgeom/.libs/liblwgeom.a @SHLIB_LINK@ + +# Add SFCGAL Flags if defined +ifeq (@SFCGAL@,sfcgal) +PG_CPPFLAGS += @SFCGAL_CPPFLAGS@ +SHLIB_LINK_F += @SFCGAL_LDFLAGS@ +endif # Extra files to remove during 'make clean' EXTRA_CLEAN=$(SQL_OBJS) \ uninstall_postgis.sql \ uninstall_legacy.sql \ + uninstall_sfcgal.sql \ postgis_upgrade_20_21.sql.in \ postgis_upgrade_20_21.sql \ postgis_upgrade_21_minor.sql @@ -165,5 +188,8 @@ uninstall_postgis.sql: postgis.sql ../utils/create_undef.pl uninstall_legacy.sql: legacy.sql ../utils/create_undef.pl $(PERL) ../utils/create_undef.pl $< $(POSTGIS_PGSQL_VERSION) > $@ +uninstall_sfcgal.sql: sfcgal.sql ../utils/create_undef.pl + $(PERL) ../utils/create_undef.pl $< $(POSTGIS_PGSQL_VERSION) > $@ + distclean: clean rm -f Makefile diff --git a/postgis/lwgeom_backend_api.c b/postgis/lwgeom_backend_api.c new file mode 100644 index 000000000..cf4f71634 --- /dev/null +++ b/postgis/lwgeom_backend_api.c @@ -0,0 +1,189 @@ +/********************************************************************** + * + * PostGIS - Spatial Types for PostgreSQL + * http://postgis.refractions.net + * + * Wrapper around external librairies functions (GEOS/CGAL...) + * + * Copyright 2012-2013 Oslandia + * + * This is free software; you can redistribute and/or modify it under + * the terms of the GNU General Public Licence. See the COPYING file. + * + **********************************************************************/ + +#include "postgres.h" +#include "fmgr.h" +#include "../liblwgeom/liblwgeom.h" + +/* for custom variables */ +#include "utils/guc.h" + +#include "../postgis_config.h" +#include "lwgeom_backend_api.h" +#include "lwgeom_geos.h" +#include "lwgeom_sfcgal.h" + +Datum intersects(PG_FUNCTION_ARGS); +Datum intersects3d(PG_FUNCTION_ARGS); +Datum intersection(PG_FUNCTION_ARGS); +Datum area(PG_FUNCTION_ARGS); +Datum distance(PG_FUNCTION_ARGS); +Datum distance3d(PG_FUNCTION_ARGS); + +Datum intersects3d_dwithin(PG_FUNCTION_ARGS); +Datum postgis_sfcgal_version(PG_FUNCTION_ARGS); + + +struct lwgeom_backend_definition +{ + const char* name; + Datum (*intersects_fn) (PG_FUNCTION_ARGS); + Datum (*intersects3d_fn) (PG_FUNCTION_ARGS); + Datum (*intersection_fn) (PG_FUNCTION_ARGS); + Datum (*area_fn) (PG_FUNCTION_ARGS); + Datum (*distance_fn) (PG_FUNCTION_ARGS); + Datum (*distance3d_fn) (PG_FUNCTION_ARGS); +}; + +#if HAVE_SFCGAL +#define LWGEOM_NUM_BACKENDS 2 +#else +#define LWGEOM_NUM_BACKENDS 1 +#endif + +struct lwgeom_backend_definition lwgeom_backends[LWGEOM_NUM_BACKENDS] = { + { .name = "geos", + .intersects_fn = geos_intersects, + .intersects3d_fn = intersects3d_dwithin, + .intersection_fn = geos_intersection, + .area_fn = LWGEOM_area_polygon, + .distance_fn = LWGEOM_mindistance2d, + .distance3d_fn = LWGEOM_mindistance3d + }, +#if HAVE_SFCGAL + { .name = "sfcgal", + .intersects_fn = sfcgal_intersects, + .intersects3d_fn = sfcgal_intersects3D, + .intersection_fn = sfcgal_intersection, + .area_fn = sfcgal_area, + .distance_fn = sfcgal_distance, + .distance3d_fn = sfcgal_distance3D + } +#endif +}; + + +/* Geometry Backend */ +char* lwgeom_backend_name; +struct lwgeom_backend_definition* lwgeom_backend = &lwgeom_backends[0]; + +void lwgeom_backend_switch( const char* newvalue, void* extra ) +{ + int i; + + if (!newvalue) { return; } + + for ( i = 0; i < LWGEOM_NUM_BACKENDS; ++i ) { + if ( !strcmp(lwgeom_backends[i].name, newvalue) ) { + lwgeom_backend = &lwgeom_backends[i]; + return; + } + } + lwerror("Can't find %s geometry backend", newvalue ); +} + +void lwgeom_init_backend() +{ + DefineCustomStringVariable( "postgis.backend", /* name */ + "Sets the PostGIS Geometry Backend.", /* short_desc */ + "Sets the PostGIS Geometry Backend (allowed values are 'geos' or 'sfcgal')", /* long_desc */ + &lwgeom_backend_name, /* valueAddr */ + (char *)lwgeom_backends[0].name, /* bootValue */ + PGC_USERSET, /* GucContext context */ + 0, /* int flags */ +#if POSTGIS_PGSQL_VERSION >= 91 + NULL, /* GucStringCheckHook check_hook */ +#endif + lwgeom_backend_switch, /* GucStringAssignHook assign_hook */ + NULL /* GucShowHook show_hook */ + ); +} + +PG_FUNCTION_INFO_V1(intersects); +Datum intersects(PG_FUNCTION_ARGS) +{ + return (*lwgeom_backend->intersects_fn)( fcinfo ); +} + +PG_FUNCTION_INFO_V1(intersection); +Datum intersection(PG_FUNCTION_ARGS) +{ + return (*lwgeom_backend->intersection_fn)( fcinfo ); +} + +PG_FUNCTION_INFO_V1(area); +Datum area(PG_FUNCTION_ARGS) +{ + return (*lwgeom_backend->area_fn)( fcinfo ); +} + +PG_FUNCTION_INFO_V1(distance); +Datum distance(PG_FUNCTION_ARGS) +{ + return (*lwgeom_backend->distance_fn)( fcinfo ); +} + +PG_FUNCTION_INFO_V1(distance3d); +Datum distance3d(PG_FUNCTION_ARGS) +{ + return (*lwgeom_backend->distance3d_fn)( fcinfo ); +} + +PG_FUNCTION_INFO_V1(intersects3d); +Datum intersects3d(PG_FUNCTION_ARGS) +{ + return (*lwgeom_backend->intersects3d_fn)( fcinfo ); +} + + + +/* intersects3d through dwithin + * used by the 'geos' backend + */ +PG_FUNCTION_INFO_V1(intersects3d_dwithin); +Datum intersects3d_dwithin(PG_FUNCTION_ARGS) +{ + double mindist; + GSERIALIZED *geom1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + GSERIALIZED *geom2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); + LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1); + LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2); + + if (lwgeom1->srid != lwgeom2->srid) + { + elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n"); + PG_RETURN_NULL(); + } + + mindist = lwgeom_mindistance3d_tolerance(lwgeom1,lwgeom2,0.0); + + PG_FREE_IF_COPY(geom1, 0); + PG_FREE_IF_COPY(geom2, 1); + /*empty geometries cases should be right handled since return from underlying + functions should be MAXFLOAT which causes false as answer*/ + PG_RETURN_BOOL(0.0 == mindist); +} + + +PG_FUNCTION_INFO_V1(postgis_sfcgal_version); +Datum postgis_sfcgal_version(PG_FUNCTION_ARGS) +{ +#if HAVE_SFCGAL + const char *ver = lwgeom_sfcgal_version(); + text *result = cstring2text(ver); +#else + text *result = NULL; +#endif + PG_RETURN_POINTER(result); +} diff --git a/postgis/lwgeom_backend_api.h b/postgis/lwgeom_backend_api.h new file mode 100644 index 000000000..3ce7719b8 --- /dev/null +++ b/postgis/lwgeom_backend_api.h @@ -0,0 +1,19 @@ +/********************************************************************** + * + * PostGIS - Spatial Types for PostgreSQL + * http://postgis.refractions.net + * + * Wrapper around external librairies functions (GEOS/CGAL...) + * + * Copyright 2012-2013 Oslandia + * + * 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 diff --git a/postgis/lwgeom_functions_basic.c b/postgis/lwgeom_functions_basic.c index a74a453a2..a2f4a636d 100644 --- a/postgis/lwgeom_functions_basic.c +++ b/postgis/lwgeom_functions_basic.c @@ -69,6 +69,7 @@ Datum LWGEOM_isempty(PG_FUNCTION_ARGS); Datum LWGEOM_segmentize2d(PG_FUNCTION_ARGS); Datum LWGEOM_reverse(PG_FUNCTION_ARGS); Datum LWGEOM_force_clockwise_poly(PG_FUNCTION_ARGS); +Datum LWGEOM_force_sfs(PG_FUNCTION_ARGS); Datum LWGEOM_noop(PG_FUNCTION_ARGS); Datum LWGEOM_zmflag(PG_FUNCTION_ARGS); Datum LWGEOM_hasz(PG_FUNCTION_ARGS); @@ -508,6 +509,27 @@ Datum LWGEOM_force_multi(PG_FUNCTION_ARGS) PG_RETURN_POINTER(result); } +/** transform input geometry to a SFS 1.1 geometry type compliant */ +PG_FUNCTION_INFO_V1(LWGEOM_force_sfs); +Datum LWGEOM_force_sfs(PG_FUNCTION_ARGS) +{ + GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + GSERIALIZED *result; + LWGEOM *lwgeom; + LWGEOM *ogeom; + + POSTGIS_DEBUG(2, "LWGEOM_force_sfs called"); + + lwgeom = lwgeom_from_gserialized(geom); + ogeom = lwgeom_force_sfs(lwgeom); + + result = geometry_serialize(ogeom); + + PG_FREE_IF_COPY(geom, 0); + + PG_RETURN_POINTER(result); +} + /** Returns the point in first input geometry that is closest to the second input geometry in 2d */ diff --git a/postgis/lwgeom_geos.c b/postgis/lwgeom_geos.c index f342385f3..474248fc6 100644 --- a/postgis/lwgeom_geos.c +++ b/postgis/lwgeom_geos.c @@ -41,7 +41,7 @@ Datum relate_full(PG_FUNCTION_ARGS); Datum relate_pattern(PG_FUNCTION_ARGS); Datum disjoint(PG_FUNCTION_ARGS); Datum touches(PG_FUNCTION_ARGS); -Datum intersects(PG_FUNCTION_ARGS); +Datum geos_intersects(PG_FUNCTION_ARGS); Datum crosses(PG_FUNCTION_ARGS); Datum contains(PG_FUNCTION_ARGS); Datum containsproperly(PG_FUNCTION_ARGS); @@ -51,7 +51,7 @@ Datum isvalid(PG_FUNCTION_ARGS); Datum isvalidreason(PG_FUNCTION_ARGS); Datum isvaliddetail(PG_FUNCTION_ARGS); Datum buffer(PG_FUNCTION_ARGS); -Datum intersection(PG_FUNCTION_ARGS); +Datum geos_intersection(PG_FUNCTION_ARGS); Datum convexhull(PG_FUNCTION_ARGS); Datum topologypreservesimplify(PG_FUNCTION_ARGS); Datum difference(PG_FUNCTION_ARGS); @@ -1443,8 +1443,8 @@ Datum ST_OffsetCurve(PG_FUNCTION_ARGS) } -PG_FUNCTION_INFO_V1(intersection); -Datum intersection(PG_FUNCTION_ARGS) +PG_FUNCTION_INFO_V1(geos_intersection); +Datum geos_intersection(PG_FUNCTION_ARGS) { GSERIALIZED *geom1; GSERIALIZED *geom2; @@ -2554,8 +2554,8 @@ Datum crosses(PG_FUNCTION_ARGS) } -PG_FUNCTION_INFO_V1(intersects); -Datum intersects(PG_FUNCTION_ARGS) +PG_FUNCTION_INFO_V1(geos_intersects); +Datum geos_intersects(PG_FUNCTION_ARGS) { GSERIALIZED *geom1; GSERIALIZED *geom2; diff --git a/postgis/lwgeom_geos.h b/postgis/lwgeom_geos.h index c59135f6a..87487d94d 100644 --- a/postgis/lwgeom_geos.h +++ b/postgis/lwgeom_geos.h @@ -23,6 +23,11 @@ GSERIALIZED *GEOS2POSTGIS(GEOSGeom geom, char want3d); GEOSGeometry * POSTGIS2GEOS(GSERIALIZED *g); +Datum geos_intersects(PG_FUNCTION_ARGS); +Datum geos_intersection(PG_FUNCTION_ARGS); +Datum LWGEOM_area_polygon(PG_FUNCTION_ARGS); +Datum LWGEOM_mindistance2d(PG_FUNCTION_ARGS); +Datum LWGEOM_mindistance3d(PG_FUNCTION_ARGS); void errorIfGeometryCollection(GSERIALIZED *g1, GSERIALIZED *g2); diff --git a/postgis/lwgeom_sfcgal.c b/postgis/lwgeom_sfcgal.c new file mode 100644 index 000000000..38e86e05f --- /dev/null +++ b/postgis/lwgeom_sfcgal.c @@ -0,0 +1,531 @@ +/********************************************************************** + * + * PostGIS - Spatial Types for PostgreSQL + * http://postgis.refractions.net + * + * Wrapper around SFCGAL for 3D functions + * + * Copyright 2012-2013 Oslandia + * + * This is free software; you can redistribute and/or modify it under + * the terms of the GNU General Public Licence. See the COPYING file. + * + **********************************************************************/ + +#include "postgres.h" +#include "fmgr.h" +#include "../liblwgeom/liblwgeom.h" + +#include "lwgeom_sfcgal.h" + + + +Datum sfcgal_from_ewkt(PG_FUNCTION_ARGS); +Datum sfcgal_distance(PG_FUNCTION_ARGS); +Datum sfcgal_distance3D(PG_FUNCTION_ARGS); +Datum sfcgal_area(PG_FUNCTION_ARGS); +Datum sfcgal_area3D(PG_FUNCTION_ARGS); +Datum sfcgal_intersects(PG_FUNCTION_ARGS); +Datum sfcgal_intersects3D(PG_FUNCTION_ARGS); +Datum sfcgal_intersection(PG_FUNCTION_ARGS); +Datum sfcgal_intersection3D(PG_FUNCTION_ARGS); +Datum sfcgal_extrude(PG_FUNCTION_ARGS); +Datum sfcgal_straight_skeleton(PG_FUNCTION_ARGS); +Datum sfcgal_is_planar(PG_FUNCTION_ARGS); +Datum sfcgal_orientation(PG_FUNCTION_ARGS); +Datum sfcgal_force_lhr(PG_FUNCTION_ARGS); +Datum sfcgal_triangulate(PG_FUNCTION_ARGS); +Datum sfcgal_tesselate(PG_FUNCTION_ARGS); +Datum sfcgal_minkowski_sum(PG_FUNCTION_ARGS); + + +GSERIALIZED *geometry_serialize(LWGEOM *lwgeom); +char* text2cstring(const text *textptr); + +static int __sfcgal_init = 0; + +void sfcgal_postgis_init(void) +{ + if ( ! __sfcgal_init ) { + sfcgal_init(); + sfcgal_set_error_handlers((sfcgal_error_handler_t) lwnotice, (sfcgal_error_handler_t) lwerror); + sfcgal_set_alloc_handlers(lwalloc, lwfree); + __sfcgal_init = 1; + } +} + + +/* Conversion from GSERIALIZED* to SFCGAL::Geometry */ +sfcgal_geometry_t* POSTGIS2SFCGALGeometry(GSERIALIZED *pglwgeom) +{ + sfcgal_geometry_t* g; + LWGEOM *lwgeom = lwgeom_from_gserialized(pglwgeom); + + if (! lwgeom) + { + lwerror("POSTGIS2SFCGALGeometry: Unable to deserialize input"); + } + g = LWGEOM2SFCGAL(lwgeom); + lwgeom_free(lwgeom); + + return g; +} + + +/* Conversion from GSERIALIZED* to SFCGAL::PreparedGeometry */ +sfcgal_prepared_geometry_t* POSTGIS2SFCGALPreparedGeometry(GSERIALIZED *pglwgeom) +{ + sfcgal_geometry_t* g; + LWGEOM *lwgeom = lwgeom_from_gserialized(pglwgeom); + + if (!lwgeom) + { + lwerror("POSTGIS2SFCGALPreparedGeometry: Unable to deserialize input"); + } + g = LWGEOM2SFCGAL(lwgeom); + + lwgeom_free(lwgeom); + + return sfcgal_prepared_geometry_create_from_geometry(g, gserialized_get_srid(pglwgeom)); +} + + +/* Conversion from SFCGAL::Geometry to GSERIALIZED */ +GSERIALIZED* SFCGALGeometry2POSTGIS(const sfcgal_geometry_t* geom, int force3D, int SRID) +{ + GSERIALIZED *result; + LWGEOM* lwgeom = SFCGAL2LWGEOM(geom, force3D, SRID); + + if (lwgeom_needs_bbox(lwgeom) == LW_TRUE) + lwgeom_add_bbox(lwgeom); + + result = geometry_serialize(lwgeom); + lwgeom_free(lwgeom); + + return result; +} + + +/* Conversion from SFCGAL::PreparedGeometry to GSERIALIZED */ +GSERIALIZED* SFCGALPreparedGeometry2POSTGIS(const sfcgal_prepared_geometry_t* geom, int force3D) +{ + return SFCGALGeometry2POSTGIS(sfcgal_prepared_geometry_geometry(geom), + force3D, sfcgal_prepared_geometry_srid(geom)); +} + + +/* Conversion from EWKT to GSERIALIZED */ +PG_FUNCTION_INFO_V1(sfcgal_from_ewkt); +Datum sfcgal_from_ewkt(PG_FUNCTION_ARGS) +{ + GSERIALIZED* result; + sfcgal_prepared_geometry_t* g; + text *wkttext = PG_GETARG_TEXT_P(0); + char *cstring = text2cstring(wkttext); + + sfcgal_postgis_init(); + + g = sfcgal_io_read_ewkt( cstring, strlen(cstring) ); + + result = SFCGALPreparedGeometry2POSTGIS( g, 0 ); + sfcgal_prepared_geometry_delete( g ); + PG_RETURN_POINTER(result); +} + + +PG_FUNCTION_INFO_V1(sfcgal_area); +Datum sfcgal_area(PG_FUNCTION_ARGS) + { + GSERIALIZED *input; + sfcgal_geometry_t *geom; + double result; + + sfcgal_postgis_init(); + + input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + geom = POSTGIS2SFCGALGeometry(input); + + result = sfcgal_geometry_area(geom); + sfcgal_geometry_delete(geom); + + PG_FREE_IF_COPY(input, 0); + + PG_RETURN_FLOAT8(result); +} + + +PG_FUNCTION_INFO_V1(sfcgal_area3D); +Datum sfcgal_area3D(PG_FUNCTION_ARGS) + { + GSERIALIZED *input; + sfcgal_geometry_t *geom; + double result; + + sfcgal_postgis_init(); + + input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + geom = POSTGIS2SFCGALGeometry(input); + + result = sfcgal_geometry_area_3d(geom); + sfcgal_geometry_delete(geom); + + PG_FREE_IF_COPY(input, 0); + + PG_RETURN_FLOAT8(result); +} + + +PG_FUNCTION_INFO_V1(sfcgal_is_planar); +Datum sfcgal_is_planar(PG_FUNCTION_ARGS) +{ + GSERIALIZED *input; + sfcgal_geometry_t *geom; + int result; + + sfcgal_postgis_init(); + + input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + geom = POSTGIS2SFCGALGeometry(input); + + result = sfcgal_geometry_is_planar(geom); + sfcgal_geometry_delete(geom); + + PG_FREE_IF_COPY(input, 0); + + PG_RETURN_BOOL(result); +} + + +PG_FUNCTION_INFO_V1(sfcgal_orientation); +Datum sfcgal_orientation(PG_FUNCTION_ARGS) +{ + GSERIALIZED *input; + sfcgal_geometry_t *geom; + int result; + + sfcgal_postgis_init(); + + input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + geom = POSTGIS2SFCGALGeometry(input); + + result = sfcgal_geometry_orientation(geom); + sfcgal_geometry_delete(geom); + + PG_FREE_IF_COPY(input, 0); + + PG_RETURN_INT32(result); +} + + +PG_FUNCTION_INFO_V1(sfcgal_intersects); +Datum sfcgal_intersects(PG_FUNCTION_ARGS) +{ + GSERIALIZED *input0, *input1; + sfcgal_geometry_t *geom0, *geom1; + int result; + + sfcgal_postgis_init(); + + input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); + geom0 = POSTGIS2SFCGALGeometry(input0); + PG_FREE_IF_COPY(input0, 0); + geom1 = POSTGIS2SFCGALGeometry(input1); + PG_FREE_IF_COPY(input1, 1); + + result = sfcgal_geometry_intersects(geom0, geom1); + sfcgal_geometry_delete(geom0); + sfcgal_geometry_delete(geom1); + + PG_RETURN_BOOL(result); +} + + +PG_FUNCTION_INFO_V1(sfcgal_intersects3D); +Datum sfcgal_intersects3D(PG_FUNCTION_ARGS) +{ + GSERIALIZED *input0, *input1; + sfcgal_geometry_t *geom0, *geom1; + int result; + + sfcgal_postgis_init(); + + input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); + geom0 = POSTGIS2SFCGALGeometry(input0); + PG_FREE_IF_COPY(input0, 0); + geom1 = POSTGIS2SFCGALGeometry(input1); + PG_FREE_IF_COPY(input1, 1); + + result = sfcgal_geometry_intersects_3d(geom0, geom1); + sfcgal_geometry_delete(geom0); + sfcgal_geometry_delete(geom1); + + PG_RETURN_BOOL(result); +} + + +PG_FUNCTION_INFO_V1(sfcgal_distance); +Datum sfcgal_distance(PG_FUNCTION_ARGS) +{ + GSERIALIZED *input0, *input1; + sfcgal_geometry_t *geom0, *geom1; + double result; + + sfcgal_postgis_init(); + + input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); + geom0 = POSTGIS2SFCGALGeometry(input0); + PG_FREE_IF_COPY(input0, 0); + geom1 = POSTGIS2SFCGALGeometry(input1); + PG_FREE_IF_COPY(input1, 1); + + result = sfcgal_geometry_distance(geom0, geom1); + sfcgal_geometry_delete(geom0); + sfcgal_geometry_delete(geom1); + + PG_RETURN_FLOAT8(result); +} + + +PG_FUNCTION_INFO_V1(sfcgal_distance3D); +Datum sfcgal_distance3D(PG_FUNCTION_ARGS) +{ + GSERIALIZED *input0, *input1; + sfcgal_geometry_t *geom0, *geom1; + double result; + + sfcgal_postgis_init(); + + input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); + geom0 = POSTGIS2SFCGALGeometry(input0); + PG_FREE_IF_COPY(input0, 0); + geom1 = POSTGIS2SFCGALGeometry(input1); + PG_FREE_IF_COPY(input1, 1); + + result = sfcgal_geometry_distance_3d(geom0, geom1); + sfcgal_geometry_delete(geom0); + sfcgal_geometry_delete(geom1); + + PG_RETURN_FLOAT8(result); +} + + +PG_FUNCTION_INFO_V1(sfcgal_tesselate); +Datum sfcgal_tesselate(PG_FUNCTION_ARGS) +{ + GSERIALIZED *input, *output; + sfcgal_geometry_t *geom; + sfcgal_geometry_t *result; + srid_t srid; + + sfcgal_postgis_init(); + + input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + srid = gserialized_get_srid(input); + geom = POSTGIS2SFCGALGeometry(input); + PG_FREE_IF_COPY(input, 0); + + result = sfcgal_geometry_tesselate(geom); + sfcgal_geometry_delete(geom); + + output = SFCGALGeometry2POSTGIS(result, 0, srid); + sfcgal_geometry_delete(result); + + PG_RETURN_POINTER(output); +} + + +PG_FUNCTION_INFO_V1(sfcgal_triangulate); +Datum sfcgal_triangulate(PG_FUNCTION_ARGS) +{ + GSERIALIZED *input, *output; + sfcgal_geometry_t *geom; + sfcgal_geometry_t *result; + srid_t srid; + + sfcgal_postgis_init(); + + input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + srid = gserialized_get_srid(input); + geom = POSTGIS2SFCGALGeometry(input); + PG_FREE_IF_COPY(input, 0); + + result = sfcgal_geometry_triangulate_2dz(geom); + sfcgal_geometry_delete(geom); + + output = SFCGALGeometry2POSTGIS(result, 0, srid); + sfcgal_geometry_delete(result); + + PG_RETURN_POINTER(output); +} + + +PG_FUNCTION_INFO_V1(sfcgal_force_lhr); +Datum sfcgal_force_lhr(PG_FUNCTION_ARGS) +{ + GSERIALIZED *input, *output; + sfcgal_geometry_t *geom; + sfcgal_geometry_t *result; + srid_t srid; + + sfcgal_postgis_init(); + + input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + srid = gserialized_get_srid(input); + geom = POSTGIS2SFCGALGeometry(input); + PG_FREE_IF_COPY(input, 0); + + result = sfcgal_geometry_force_lhr(geom); + sfcgal_geometry_delete(geom); + + output = SFCGALGeometry2POSTGIS(result, 0, srid); + sfcgal_geometry_delete(result); + + PG_RETURN_POINTER(output); +} + + +PG_FUNCTION_INFO_V1(sfcgal_straight_skeleton); +Datum sfcgal_straight_skeleton(PG_FUNCTION_ARGS) +{ + GSERIALIZED *input, *output; + sfcgal_geometry_t *geom; + sfcgal_geometry_t *result; + srid_t srid; + + sfcgal_postgis_init(); + + input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + srid = gserialized_get_srid(input); + geom = POSTGIS2SFCGALGeometry(input); + PG_FREE_IF_COPY(input, 0); + + result = sfcgal_geometry_straight_skeleton(geom); + sfcgal_geometry_delete(geom); + + output = SFCGALGeometry2POSTGIS(result, 0, srid); + sfcgal_geometry_delete(result); + + PG_RETURN_POINTER(output); +} + + +PG_FUNCTION_INFO_V1(sfcgal_intersection); +Datum sfcgal_intersection(PG_FUNCTION_ARGS) +{ + GSERIALIZED *input0, *input1, *output; + sfcgal_geometry_t *geom0, *geom1; + sfcgal_geometry_t *result; + srid_t srid; + + sfcgal_postgis_init(); + + input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + srid = gserialized_get_srid(input0); + input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); + geom0 = POSTGIS2SFCGALGeometry(input0); + PG_FREE_IF_COPY(input0, 0); + geom1 = POSTGIS2SFCGALGeometry(input1); + PG_FREE_IF_COPY(input1, 1); + + result = sfcgal_geometry_intersection(geom0, geom1); + sfcgal_geometry_delete(geom0); + sfcgal_geometry_delete(geom1); + + output = SFCGALGeometry2POSTGIS(result, 0, srid); + sfcgal_geometry_delete(result); + + PG_RETURN_POINTER(output); +} + + +PG_FUNCTION_INFO_V1(sfcgal_intersection3D); +Datum sfcgal_intersection3D(PG_FUNCTION_ARGS) +{ + GSERIALIZED *input0, *input1, *output; + sfcgal_geometry_t *geom0, *geom1; + sfcgal_geometry_t *result; + srid_t srid; + + sfcgal_postgis_init(); + + input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + srid = gserialized_get_srid(input0); + input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); + geom0 = POSTGIS2SFCGALGeometry(input0); + PG_FREE_IF_COPY(input0, 0); + geom1 = POSTGIS2SFCGALGeometry(input1); + PG_FREE_IF_COPY(input1, 1); + + result = sfcgal_geometry_intersection_3d(geom0, geom1); + sfcgal_geometry_delete(geom0); + sfcgal_geometry_delete(geom1); + + output = SFCGALGeometry2POSTGIS(result, 0, srid); + sfcgal_geometry_delete(result); + + PG_RETURN_POINTER(output); +} + + +PG_FUNCTION_INFO_V1(sfcgal_minkowski_sum); +Datum sfcgal_minkowski_sum(PG_FUNCTION_ARGS) +{ + GSERIALIZED *input0, *input1, *output; + sfcgal_geometry_t *geom0, *geom1; + sfcgal_geometry_t *result; + srid_t srid; + + sfcgal_postgis_init(); + + input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + srid = gserialized_get_srid(input0); + input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); + geom0 = POSTGIS2SFCGALGeometry(input0); + PG_FREE_IF_COPY(input0, 0); + geom1 = POSTGIS2SFCGALGeometry(input1); + PG_FREE_IF_COPY(input1, 1); + + result = sfcgal_geometry_minkowski_sum(geom0, geom1); + sfcgal_geometry_delete(geom0); + sfcgal_geometry_delete(geom1); + + output = SFCGALGeometry2POSTGIS(result, 0, srid); + sfcgal_geometry_delete(result); + + PG_RETURN_POINTER(output); +} + + +PG_FUNCTION_INFO_V1(sfcgal_extrude); +Datum sfcgal_extrude(PG_FUNCTION_ARGS) +{ + GSERIALIZED *input, *output; + sfcgal_geometry_t *geom; + sfcgal_geometry_t *result; + double dx, dy, dz; + srid_t srid; + + sfcgal_postgis_init(); + + input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + srid = gserialized_get_srid(input); + + geom = POSTGIS2SFCGALGeometry(input); + PG_FREE_IF_COPY(input, 0); + + dx = PG_GETARG_FLOAT8(1); + dy = PG_GETARG_FLOAT8(2); + dz = PG_GETARG_FLOAT8(3); + + result = sfcgal_geometry_extrude(geom, dx, dy, dz); + sfcgal_geometry_delete(geom); + + output = SFCGALGeometry2POSTGIS(result, 0, srid); + sfcgal_geometry_delete(result); + + PG_RETURN_POINTER(output); +} diff --git a/postgis/lwgeom_sfcgal.h b/postgis/lwgeom_sfcgal.h new file mode 100644 index 000000000..6f1e3bbfa --- /dev/null +++ b/postgis/lwgeom_sfcgal.h @@ -0,0 +1,39 @@ +/********************************************************************** + * + * PostGIS - Spatial Types for PostgreSQL + * http://postgis.refractions.net + * + * Wrapper around SFCGAL for 3D functions + * + * Copyright 2012-2013 Oslandia + * + * 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); diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in index 1f7374d10..f2f662622 100644 --- a/postgis/postgis.sql.in +++ b/postgis/postgis.sql.in @@ -1134,7 +1134,7 @@ CREATE OR REPLACE FUNCTION ST_area2d(geometry) -- PostGIS equivalent function: area(geometry) CREATE OR REPLACE FUNCTION ST_Area(geometry) RETURNS FLOAT8 - AS 'MODULE_PATHNAME','LWGEOM_area_polygon' + AS 'MODULE_PATHNAME','area' LANGUAGE 'c' IMMUTABLE STRICT; -- Availability: 1.2.2 @@ -1149,7 +1149,7 @@ CREATE OR REPLACE FUNCTION ST_distance_spheroid(geom1 geometry, geom2 geometry,s -- PostGIS equivalent function: distance(geom1 geometry, geom2 geometry) CREATE OR REPLACE FUNCTION ST_Distance(geom1 geometry, geom2 geometry) RETURNS float8 - AS 'MODULE_PATHNAME', 'LWGEOM_mindistance2d' + AS 'MODULE_PATHNAME', 'distance' LANGUAGE 'c' IMMUTABLE STRICT COST 100; @@ -1223,6 +1223,12 @@ CREATE OR REPLACE FUNCTION ST_Multi(geometry) AS 'MODULE_PATHNAME', 'LWGEOM_force_multi' LANGUAGE 'c' IMMUTABLE STRICT; +-- Availability: 2.1.0 +CREATE OR REPLACE FUNCTION ST_force_sfs(geometry) + RETURNS geometry + AS 'MODULE_PATHNAME', 'LWGEOM_force_sfs' + LANGUAGE 'c' IMMUTABLE STRICT; + -- Availability: 1.2.2 CREATE OR REPLACE FUNCTION ST_Expand(box3d,float8) RETURNS box3d @@ -2437,6 +2443,10 @@ CREATE OR REPLACE FUNCTION postgis_geos_version() RETURNS text AS 'MODULE_PATHNAME' LANGUAGE 'c' IMMUTABLE; +CREATE OR REPLACE FUNCTION postgis_sfcgal_version() RETURNS text + AS 'MODULE_PATHNAME' + LANGUAGE 'c' IMMUTABLE; + CREATE OR REPLACE FUNCTION postgis_svn_version() RETURNS text AS 'MODULE_PATHNAME' LANGUAGE 'c' IMMUTABLE; @@ -2460,6 +2470,8 @@ DECLARE svnver text; projver text; geosver text; + sfcgalver text; + cgalver text; gdalver text; libxmlver text; dbproc text; @@ -2481,6 +2493,12 @@ BEGIN gdalver := NULL; RAISE NOTICE 'Function postgis_gdal_version() not found. Is raster support enabled and rtpostgis.sql installed?'; END; + BEGIN + SELECT postgis_sfcgal_version() INTO sfcgalver; + EXCEPTION + WHEN undefined_function THEN + sfcgalver := NULL; + END; SELECT postgis_libxml_version() INTO libxmlver; SELECT postgis_scripts_installed() INTO dbproc; SELECT postgis_scripts_released() INTO relproc; @@ -2521,6 +2539,10 @@ BEGIN fullver = fullver || ' GEOS="' || geosver || '"'; END IF; + IF sfcgalver IS NOT NULL THEN + fullver = fullver || ' SFCGAL="' || sfcgalver || '"'; + END IF; + IF projver IS NOT NULL THEN fullver = fullver || ' PROJ="' || projver || '"'; END IF; @@ -4656,7 +4678,7 @@ CREATE OR REPLACE RULE geometry_columns_delete AS CREATE OR REPLACE FUNCTION ST_3DDistance(geom1 geometry, geom2 geometry) RETURNS float8 - AS 'MODULE_PATHNAME', 'LWGEOM_mindistance3d' + AS 'MODULE_PATHNAME', 'distance3d' LANGUAGE 'c' IMMUTABLE STRICT COST 100; @@ -4707,10 +4729,16 @@ CREATE OR REPLACE FUNCTION ST_3DDFullyWithin(geom1 geometry, geom2 geometry,floa AS 'SELECT $1 && ST_Expand($2,$3) AND $2 && ST_Expand($1,$3) AND _ST_3DDFullyWithin($1, $2, $3)' LANGUAGE 'sql' IMMUTABLE COST 100; + +CREATE OR REPLACE FUNCTION _ST_3DIntersects(geom1 geometry, geom2 geometry) + RETURNS boolean + AS 'MODULE_PATHNAME','intersects3d' + LANGUAGE 'c' IMMUTABLE STRICT + COST 100; CREATE OR REPLACE FUNCTION ST_3DIntersects(geom1 geometry, geom2 geometry) RETURNS boolean - AS 'SELECT $1 && $2 AND _ST_3DDWithin($1, $2, 0.0)' + AS 'SELECT $1 && $2 AND _ST_3DIntersects($1, $2)' LANGUAGE 'sql' IMMUTABLE COST 100; @@ -5086,7 +5114,7 @@ $$ ORDER BY 1, 2 ) As foo ) ); IF ST_IsValid(var_tempgeom) AND ST_GeometryType(var_tempgeom) = 'ST_Polygon' THEN - var_tempgeom := ST_Intersection(var_tempgeom, var_convhull); + var_tempgeom := ST_force_sfs(ST_Intersection(var_tempgeom, var_convhull)); IF param_allow_holes THEN var_param_geom := var_tempgeom; ELSE @@ -5094,7 +5122,7 @@ $$ END IF; return var_param_geom; ELSIF ST_IsValid(var_tempgeom) THEN - var_param_geom := ST_Intersection(var_tempgeom, var_convhull); + var_param_geom := ST_force_sfs(ST_Intersection(var_tempgeom, var_convhull)); END IF; END IF; @@ -5119,7 +5147,7 @@ $$ -- break envelope into 4 triangles about the centroid of the geometry and returned the clipped geometry in each quadrant FOR i in 1 .. 4 LOOP var_geoms[i] := ST_MakePolygon(ST_MakeLine(ARRAY[ST_PointN(var_enline,i), ST_PointN(var_enline,i+1), var_cent, ST_PointN(var_enline,i)])); - var_geoms[i] := ST_Intersection(var_param_geom, ST_Buffer(var_geoms[i],var_buf)); + var_geoms[i] := ST_force_sfs(ST_Intersection(var_param_geom, ST_Buffer(var_geoms[i],var_buf))); IF ST_IsValid(var_geoms[i]) THEN ELSE @@ -5165,7 +5193,7 @@ $$ ELSE var_resultgeom := ST_Buffer(var_resultgeom,var_buf); END IF; - var_resultgeom := ST_Intersection(var_resultgeom, ST_ConvexHull(var_param_geom)); + var_resultgeom := ST_force_sfs(ST_Intersection(var_resultgeom, ST_ConvexHull(var_param_geom))); ELSE -- dimensions are too small to cut var_resultgeom := _ST_ConcaveHull(var_param_geom); @@ -5195,4 +5223,5 @@ CREATE OR REPLACE FUNCTION ST_AsX3D(geom geometry, maxdecimaldigits integer DEFA GRANT SELECT ON TABLE geography_columns TO public; GRANT SELECT ON TABLE geometry_columns TO public; GRANT SELECT ON TABLE spatial_ref_sys TO public; + COMMIT; diff --git a/postgis/postgis_module.c b/postgis/postgis_module.c index 6082df55d..2addefb62 100644 --- a/postgis/postgis_module.c +++ b/postgis/postgis_module.c @@ -21,6 +21,7 @@ #include "lwgeom_log.h" #include "lwgeom_pg.h" #include "geos_c.h" +#include "lwgeom_backend_api.h" /* * This is required for builds against pgsql @@ -94,6 +95,9 @@ _PG_init(void) /* install PostgreSQL handlers */ pg_install_lwgeom_handlers(); + + /* initialize geometry backend */ + lwgeom_init_backend(); } /* diff --git a/postgis/sfcgal.sql.in b/postgis/sfcgal.sql.in new file mode 100644 index 000000000..344cfa9cc --- /dev/null +++ b/postgis/sfcgal.sql.in @@ -0,0 +1,70 @@ +--------------------------------------------------------------------------- +-- +-- PostGIS - SFCGAL functions +-- Copyright 2012-2013 Oslandia +-- +-- This is free software; you can redistribute and/or modify it under +-- the terms of the GNU General Public Licence. See the COPYING file. +-- +--------------------------------------------------------------------------- + + +-- +-- New SFCGAL functions (meaning prototype not already provided by GEOS) +-- + +BEGIN; + +CREATE OR REPLACE FUNCTION postgis_sfcgal_version() RETURNS text + AS 'MODULE_PATHNAME' + LANGUAGE 'c' IMMUTABLE; + +CREATE OR REPLACE FUNCTION ST_3DIntersection(geom1 geometry, geom2 geometry) + RETURNS geometry + AS 'MODULE_PATHNAME','sfcgal_intersection3D' + LANGUAGE 'c' IMMUTABLE STRICT + COST 100; + +CREATE OR REPLACE FUNCTION ST_Tesselate(geometry) + RETURNS geometry + AS 'MODULE_PATHNAME','sfcgal_tesselate' + LANGUAGE 'c' IMMUTABLE STRICT + COST 100; + +CREATE OR REPLACE FUNCTION ST_3DArea(geometry) + RETURNS FLOAT8 + AS 'MODULE_PATHNAME','sfcgal_area3D' + LANGUAGE 'c' IMMUTABLE STRICT + COST 100; + +CREATE OR REPLACE FUNCTION ST_Extrude(geometry, float8, float8, float8) + RETURNS geometry + AS 'MODULE_PATHNAME','sfcgal_extrude' + LANGUAGE 'c' IMMUTABLE STRICT + COST 100; + +CREATE OR REPLACE FUNCTION ST_ForceLHR(geometry) + RETURNS geometry + AS 'MODULE_PATHNAME','sfcgal_force_lhr' + LANGUAGE 'c' IMMUTABLE STRICT + COST 100; + +CREATE OR REPLACE FUNCTION ST_Orientation(geometry) + RETURNS INT4 + AS 'MODULE_PATHNAME','sfcgal_orientation' + LANGUAGE 'c' IMMUTABLE STRICT + COST 100; + +CREATE OR REPLACE FUNCTION ST_Minkowski(geometry, geometry) + RETURNS geometry + AS 'MODULE_PATHNAME','sfcgal_minkowski_sum' + LANGUAGE 'c' IMMUTABLE STRICT + COST 100; + +CREATE OR REPLACE FUNCTION ST_StraightSkeleton(geometry) + RETURNS geometry + AS 'MODULE_PATHNAME','sfcgal_straight_skeleton' + LANGUAGE 'c' IMMUTABLE STRICT + COST 100; + +COMMIT; diff --git a/postgis/uninstall_sfcgal.sql.in b/postgis/uninstall_sfcgal.sql.in new file mode 100644 index 000000000..cb5a2fe44 --- /dev/null +++ b/postgis/uninstall_sfcgal.sql.in @@ -0,0 +1,36 @@ +--------------------------------------------------------------------------- +-- +-- PostGIS - SFCGAL functions +-- Copyright 2012-2013 Oslandia +-- +-- 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; diff --git a/regress/Makefile.in b/regress/Makefile.in index 83304f137..a0d863f4a 100644 --- a/regress/Makefile.in +++ b/regress/Makefile.in @@ -19,6 +19,7 @@ POSTGIS_PGSQL_VERSION=@POSTGIS_PGSQL_VERSION@ POSTGIS_GEOS_VERSION=@POSTGIS_GEOS_VERSION@ POSTGIS_PROJ_VERSION=@POSTGIS_PROJ_VERSION@ HAVE_JSON=@HAVE_JSON@ +HAVE_SFCGAL=@HAVE_SFCGAL@ MINGWBUILD=@MINGWBUILD@ # MingW hack: rather than use PGSQL_BINDIR directly, we change @@ -158,6 +159,25 @@ ifeq ($(HAVE_JSON),yes) in_geojson endif +ifeq ($(HAVE_SFCGAL),yes) + # SFCGAL additionnal backend + TESTS += \ + regress_sfcgal \ + sfcgal/empty.sql \ + sfcgal/geography.sql \ + sfcgal/legacy.sql \ + sfcgal/measures.sql \ + sfcgal/regress_ogc_prep.sql \ + sfcgal/regress_ogc.sql \ + sfcgal/regress.sql \ + sfcgal/tickets.sql \ + sfcgal/concave_hull.sql \ + sfcgal/wmsservers.sql + + RUNTESTFLAGS = --sfcgal +endif + + all install uninstall: distclean: clean diff --git a/regress/regress_sfcgal.sql b/regress/regress_sfcgal.sql new file mode 100644 index 000000000..efda63b40 --- /dev/null +++ b/regress/regress_sfcgal.sql @@ -0,0 +1,27 @@ +--- +--- Regression tests for PostGIS SFCGAL backend +--- + +-- We only care about testing PostGIS prototype here +-- Behaviour is already handled by SFCGAL own tests + +SELECT 'ST_Tesselate', ST_AsText(ST_Tesselate('GEOMETRYCOLLECTION(POINT(4 4),POLYGON((0 0,1 0,1 1,0 1,0 0)))')); +SELECT 'ST_3DArea', ST_3DArea('POLYGON((0 0 0,1 0 0,1 1 0,0 1 0,0 0 0))'); +SELECT 'ST_Extrude_point', ST_AsText(ST_Extrude('POINT(0 0)', 1, 0, 0)); +SELECT 'ST_Extrude_line', ST_AsText(ST_Extrude(ST_Extrude('POINT(0 0)', 1, 0, 0), 0, 1, 0)); +SELECT 'ST_Extrude_surface', ST_AsText(ST_Extrude(ST_Extrude(ST_Extrude('POINT(0 0)', 1, 0, 0), 0, 1, 0), 0, 0, 1)); +SELECT 'ST_ForceLHR', ST_AsText(ST_ForceLHR('POLYGON((0 0,0 1,1 1,1 0,0 0))')); +SELECT 'ST_Orientation_1', ST_Orientation(ST_ForceLHR('POLYGON((0 0,0 1,1 1,1 0,0 0))')); +SELECT 'ST_Orientation_2', ST_Orientation(ST_ForceRHR('POLYGON((0 0,0 1,1 1,1 0,0 0))')); +SELECT 'ST_Minkowski', ST_AsText(ST_Minkowski('LINESTRING(0 0,4 0)','POLYGON((0 0,1 0,1 1,0 1,0 0))')); +SELECT 'ST_StraightSkeleton', ST_AsText(ST_StraightSkeleton('POLYGON((0 0,1 0,1 1,0 1,0 0))')); + +-- Backend switch tests +SET postgis.backend = 'geos'; +SELECT 'intersection_geos', ST_astext(ST_intersection('LINESTRING(0 10, 0 -10)', 'LINESTRING(0 0, 1 1)')); + +SET postgis.backend = 'sfcgal'; +SELECT 'intersection_sfcgal', ST_astext(ST_intersection('LINESTRING(0 10, 0 -10)', 'LINESTRING(0 0, 1 1)')); + +SET postgis.backend = 'foo'; +SET postgis.backend = ''; diff --git a/regress/regress_sfcgal_expected b/regress/regress_sfcgal_expected new file mode 100644 index 000000000..43bd333f3 --- /dev/null +++ b/regress/regress_sfcgal_expected @@ -0,0 +1,14 @@ +ST_Tesselate|GEOMETRYCOLLECTION(POINT(4 4),TIN(((0 1,1 0,1 1,0 1)),((0 1,0 0,1 0,0 1)))) +ST_3DArea|1 +ST_Extrude_point|LINESTRING Z (0 0 0,1 0 0) +ST_Extrude_line|POLYHEDRALSURFACE Z (((0 0 0,1 0 0,1 1 0,0 1 0,0 0 0))) +ST_Extrude_surface|POLYHEDRALSURFACE Z (((1 1 0,1 0 0,0 1 0,1 1 0)),((0 1 1,1 0 1,1 1 1,0 1 1)),((1 0 0,0 0 0,0 1 0,1 0 0)),((0 1 1,0 0 1,1 0 1,0 1 1)),((1 0 0,1 1 0,1 1 1,1 0 1,1 0 0)),((1 1 0,0 1 0,0 1 1,1 1 1,1 1 0)),((0 1 0,0 0 0,0 0 1,0 1 1,0 1 0)),((0 0 0,1 0 0,1 0 1,0 0 1,0 0 0))) +ST_ForceLHR|POLYGON((0 0,1 0,1 1,0 1,0 0)) +ST_Orientation_1|-1 +ST_Orientation_2|1 +ST_Minkowski|MULTIPOLYGON(((0 0,1 0,5 0,5 1,4 1,0 1,0 0))) +ST_StraightSkeleton|MULTILINESTRING((0 0,0.5 0.5),(1 0,0.5 0.5),(1 1,0.5 0.5),(0 1,0.5 0.5)) +intersection_geos|POINT(0 0) +intersection_sfcgal|POINT(-0 -0) +ERROR: Can't find foo geometry backend +ERROR: Can't find geometry backend diff --git a/regress/run_test b/regress/run_test index 54b1e7fc9..2b1c9a5a4 100755 --- a/regress/run_test +++ b/regress/run_test @@ -57,6 +57,7 @@ OPT_CREATE=yes OPT_UPGRADE=no OPT_WITH_TOPO=no OPT_WITH_RASTER=no +OPT_WITH_SFCGAL=no OPT_EXPECT=no OPT_EXTENSIONS=no @@ -661,6 +662,23 @@ prepare_spatial () init_db_error "raster comments" fi fi # } + + if test x"$OPT_WITH_SFCGAL" = "xyes"; then # { + SCRIPT=${STAGED_SCRIPTS_DIR}/sfcgal.sql + if test -e ${SCRIPT}; then + echo "Adding sfcgal support" + ${PSQL} ${_psql_opts} -Xf ${SCRIPT} "${DB}" \ + >> ${PGIS_REG_TMPDIR}/regress_log 2>&1 || init_db_error "raster module" + else + echo "${SCRIPT} not found" >&2 + exit 1 + fi + if test -e ${STAGED_SCRIPTS_DIR}/sfcgal_comments.sql; then + ${PSQL} ${_psql_opts} -Xf ${STAGED_SCRIPTS_DIR}/sfcgal_comments.sql \ + "${DB}" >> ${PGIS_REG_TMPDIR}/regress_log 2>&1 || \ + init_db_error "sfcgal comments" + fi + fi # } } # Create the spatial database @@ -848,6 +866,10 @@ while [ -n "$1" ]; do OPT_WITH_RASTER=yes shift continue + elif test "$1" = "--sfcgal"; then + OPT_WITH_SFCGAL=yes + shift + continue elif test "$1" = "--clean"; then OPT_CLEAN=yes shift @@ -866,6 +888,7 @@ if [ -z "$1" ]; then echo " --nodrop do not drop the regression database on exit" >&2 echo " --raster load also raster extension" >&2 echo " --topology load also topology extension" >&2 + echo " --sfcgal use also sfcgal backend" >&2 echo " --clean cleanup test logs on exit" >&2 echo " --expect save obtained output as expected" >&2 exit 1 diff --git a/regress/run_test.pl b/regress/run_test.pl index 40800724d..7ea6ef69f 100755 --- a/regress/run_test.pl +++ b/regress/run_test.pl @@ -47,6 +47,7 @@ my $OPT_NOCREATE = 0; my $OPT_UPGRADE = 0; my $OPT_WITH_TOPO = 0; my $OPT_WITH_RASTER = 0; +my $OPT_WITH_SFCGAL = 0; my $OPT_EXPECT = 0; my $OPT_EXTENSIONS = 0; my $VERBOSE = 0; @@ -59,11 +60,11 @@ GetOptions ( 'nocreate' => \$OPT_NOCREATE, 'topology' => \$OPT_WITH_TOPO, 'raster' => \$OPT_WITH_RASTER, + 'sfcgal' => \$OPT_WITH_SFCGAL, 'expect' => \$OPT_EXPECT, 'extensions' => \$OPT_EXTENSIONS ); - ################################################################## # Set the locale to "C" so error messages match # Save original locale to set back @@ -305,7 +306,6 @@ foreach $TEST (@ARGV) } - ################################################################### # Uninstall postgis (serves as an uninstall test) ################################################################## @@ -365,6 +365,7 @@ Options: --nodrop do not drop the regression database on exit --raster load also raster extension --topology load also topology extension + --sfcgal use also sfcgal backend --clean cleanup test logs on exit --expect save obtained output as expected }; @@ -1036,16 +1037,25 @@ sub prepare_spatial if ( $OPT_WITH_TOPO ) { + print "Loading Topology"; load_sql_file("${STAGED_SCRIPTS_DIR}/topology.sql", 1); load_sql_file("${STAGED_SCRIPTS_DIR}/topology_comments.sql", 0); } if ( $OPT_WITH_RASTER ) { + print "Loading Raster"; load_sql_file("${STAGED_SCRIPTS_DIR}/rtpostgis.sql", 1); load_sql_file("${STAGED_SCRIPTS_DIR}/raster_comments.sql", 0); } + if ( $OPT_WITH_SFCGAL ) + { + print "Loading sfcgal"; + load_sql_file("${STAGED_SCRIPTS_DIR}/sfcgal.sql", 1); + load_sql_file("${STAGED_SCRIPTS_DIR}/sfcgal_comments.sql", 0); + } + return 1; } @@ -1111,6 +1121,10 @@ sub drop_spatial { load_sql_file("${STAGED_SCRIPTS_DIR}/uninstall_rtpostgis.sql"); } + if ( $OPT_WITH_SFCGAL ) + { + load_sql_file("${STAGED_SCRIPTS_DIR}/uninstall_sfcgal.sql"); + } load_sql_file("${STAGED_SCRIPTS_DIR}/uninstall_postgis.sql"); return 1; diff --git a/regress/sfcgal/README b/regress/sfcgal/README new file mode 100644 index 000000000..892c2b003 --- /dev/null +++ b/regress/sfcgal/README @@ -0,0 +1,75 @@ +These regress/sfcgal directory contains several tests closely based on +current regress one. + +Usually they should behave really the same (i.e with both backends) +however some slightly differences beetween GEOS and SFCGAL backends +are listed below: + + +== +sfcgal/ticket +== + +2.OBT: #11|1.31708901596544e-9 +2.EXP: #11|0 + +=> Numerical precision issue + (We slightly modify the unit test to use SQL round) + + +18.OBT: ERROR: LWGEOM2SFCGAL: Unknown geometry type ! +18.EXP: #85|0 + +=> Curves are not (yet) handled by SFCGAL + (To be done in future SFCGAL release) + + + +132.OBT: #834|GEOMETRYCOLLECTION(POINT(0 0),LINESTRING(10 0,10 10)) +132.EXP: #834|GEOMETRYCOLLECTION(POINT(0 0 5),LINESTRING(10 10 5,10 0 5)) + +=> For SFCGAL a 2D Intersection even with both 2D and 3D input data + is assumed as 2D and so set output Z to 0 + + + +228.OBT: #1957|inf +228.EXP: #1957|1 + +=> Initial line is OGC invalid (single point), + so SFCGAL return infinite distance, + which .. also make sense + + + +== +sfcgal/regress_ogc +== + +65.OBT: intersection|POINT(-0 -0) +65.EXP: intersection|POINT(0 0) + +=> No comment, except that the test itself could be sligthly rewrited + + + +== +sfcgal/empty +== + +29.OBT: ST_Intersection(geometry, empty) == geometry|010700000000000000 +29.EXP: ST_Intersection(geometry, empty) == geometry|010300000000000000 + +30.OBT: ST_Intersection(empty, empty) == empty|010700000000000000 +30.EXP: ST_Intersection(empty, empty) == empty|010300000000000000 + +=> SFCGAL don't consider keeping initial geometry type when intersection is null + so a GEOMETRYCOLLECTION(EMPTY) is returned (for both tests) + (maybe could be improved in SFCGAL) + + +33.OBT: ST_Distance(geometry, empty) == NULL|inf +33.EXP: ST_Distance(geometry, empty) == NULL| + +=> SFCGAL returns an infinite distance to an empty geometry instead of null, + which .. also make sense diff --git a/regress/sfcgal/concave_hull.sql b/regress/sfcgal/concave_hull.sql new file mode 100644 index 000000000..82d867ba5 --- /dev/null +++ b/regress/sfcgal/concave_hull.sql @@ -0,0 +1,44 @@ +SET postgis.backend = 'sfcgal'; + +-- $Id: concave_hull.sql 9324 2012-02-27 22:08:12Z pramsey $ +-- Tests to confirm the concave hull area is <= convex hull and +-- covers the original geometry (can't use covers because always gives topo errors with 3.3 +SELECT + 'ST_ConcaveHull MultiPolygon 0.95', ST_Area(ST_Intersection(geom,ST_ConcaveHull( + geom, 0.95) )) = ST_Area(geom) As encloses_geom, + (ST_Area(ST_ConvexHull(geom)) + - ST_Area(ST_ConcaveHull(geom, 0.95))) < (0.95 * ST_Area(ST_ConvexHull(geom) ) ) As reached_target +FROM ST_Union(ST_GeomFromText('POLYGON((175 150, 20 40, + 50 60, 125 100, 175 150))'), + ST_Buffer(ST_GeomFromText('POINT(110 170)'), 20) + ) As geom; + +SELECT + 'ST_ConcaveHull Lines 0.80', ST_Intersection(geom,ST_ConcaveHull( + geom, 0.80) ) = geom As encloses_geom, + (ST_Area(ST_ConvexHull(geom)) + - ST_Area(ST_ConcaveHull(geom, 0.80))) < (0.80 * ST_Area(ST_ConvexHull(geom) ) ) As reached_target + +FROM ST_GeomFromText('MULTILINESTRING((106 164,30 112,74 70,82 112,130 94, + 130 62,122 40,156 32,162 76,172 88), +(132 178,134 148,128 136,96 128,132 108,150 130, +170 142,174 110,156 96,158 90,158 88), +(22 64,66 28,94 38,94 68,114 76,112 30, +132 10,168 18,178 34,186 52,184 74,190 100, +190 122,182 148,178 170,176 184,156 164,146 178, +132 186,92 182,56 158,36 150,62 150,76 128,88 118))') As geom; + +-- test holes vs. no holes - holes should still enclose but have smaller area than no holes -- +SELECT + 'ST_ConcaveHull Lines 0.80 holes', ST_Intersection(geom,ST_ConcaveHull( + geom, 0.80, true) ) = geom As encloses_geom, + ST_Area(ST_ConcaveHull(geom, 0.80, true)) < ST_Area(ST_ConcaveHull(geom, 0.80)) As reached_target + +FROM ST_GeomFromText('MULTILINESTRING((106 164,30 112,74 70,82 112,130 94, + 130 62,122 40,156 32,162 76,172 88), +(132 178,134 148,128 136,96 128,132 108,150 130, +170 142,174 110,156 96,158 90,158 88), +(22 64,66 28,94 38,94 68,114 76,112 30, +132 10,168 18,178 34,186 52,184 74,190 100, +190 122,182 148,178 170,176 184,156 164,146 178, +132 186,92 182,56 158,36 150,62 150,76 128,88 118))') As geom; diff --git a/regress/sfcgal/concave_hull_expected b/regress/sfcgal/concave_hull_expected new file mode 100644 index 000000000..f81537cf1 --- /dev/null +++ b/regress/sfcgal/concave_hull_expected @@ -0,0 +1,3 @@ +ST_ConcaveHull MultiPolygon 0.95|t|t +ST_ConcaveHull Lines 0.80|t|t +ST_ConcaveHull Lines 0.80 holes|t|t diff --git a/regress/sfcgal/empty.sql b/regress/sfcgal/empty.sql new file mode 100644 index 000000000..496070fbc --- /dev/null +++ b/regress/sfcgal/empty.sql @@ -0,0 +1,147 @@ +SET postgis.backend = 'sfcgal'; + +-- ST_SnapToGrid +SELECT 'T1.1', ST_AsEWKT(ST_SnapToGrid('POINT EMPTY', 1)); +SELECT 'T1.2', ST_AsEWKT(ST_SnapToGrid('LINESTRING EMPTY', 1)); +SELECT 'T1.3', ST_AsEWKT(ST_SnapToGrid('SRID=4326;POLYGON EMPTY', 1)); + +-- ST_Buffer +SELECT 'T2.1', ST_AsEWKT(ST_Buffer('SRID=4326;POINT EMPTY', 0)); +SELECT 'T2.2', ST_AsEWKT(ST_Buffer('SRID=4326;LINESTRING EMPTY', 0)); +SELECT 'T2.3', ST_AsEWKT(ST_Buffer('SRID=4326;MULTIPOLYGON EMPTY', 0)); +WITH b as ( SELECT ST_Buffer('SRID=4326;MULTIPOINT EMPTY', 1) as g ) +SELECT 'T2.4', ST_Srid(g), GeometryType(g) from b; + +-- ST_AsGML (output may need some tweaking) +SELECT 'T3.1', ST_AsGML('POINT EMPTY'); +SELECT 'T3.2', ST_AsGML('LINESTRING EMPTY'); +SELECT 'T3.3', ST_AsGML('POLYGON EMPTY'); +SELECT 'T3.4', ST_AsGML('MULTIPOLYGON EMPTY'); +SELECT 'T3.5', ST_AsGML('MULTILINESTRING EMPTY'); +SELECT 'T3.6', ST_AsGML('GEOMETRYCOLLECTION EMPTY'); +SELECT 'T3.7', ST_AsGML(3,'POINT EMPTY'::geometry); +SELECT 'T3.8', ST_AsGML(3,'LINESTRING EMPTY'::geometry); +SELECT 'T3.9', ST_AsGML(3,'POLYGON EMPTY'::geometry); +SELECT 'T3.10', ST_AsGML(3,'MULTIPOLYGON EMPTY'::geometry); +SELECT 'T3.11', ST_AsGML(3,'MULTILINESTRING EMPTY'::geometry); +SELECT 'T3.12', ST_AsGML(3,'GEOMETRYCOLLECTION EMPTY'::geometry); +SELECT 'T3.13', ST_AsGML(3,'POINT EMPTY'::geometry); +SELECT 'T3.14', ST_AsGML(3,'LINESTRING EMPTY'::geometry); +SELECT 'T3.15', ST_AsGML(3,'POLYGON EMPTY'::geometry); +SELECT 'T3.16', ST_AsGML(3,'MULTIPOLYGON EMPTY'::geometry); +SELECT 'T3.17', ST_AsGML(3,'MULTILINESTRING EMPTY'::geometry); +SELECT 'T3.18', ST_AsGML(3,'GEOMETRYCOLLECTION EMPTY'::geometry); + +-- See http://trac.osgeo.org/postgis/wiki/DevWikiEmptyGeometry + +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty, + 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry, + 120 as tolerance + ) SELECT 'ST_Buffer(empty, tolerance) == empty', ST_Buffer(empty, tolerance) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty, + 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry + ) SELECT 'ST_Union(geometry, empty) == geometry', ST_Union(geometry, empty) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty + ) SELECT 'ST_Union(empty, empty) == empty', ST_Union(empty, empty) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty, + 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry + ) SELECT 'ST_Intersection(geometry, empty) == geometry', ST_Intersection(geometry, empty) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty + ) SELECT 'ST_Intersection(empty, empty) == empty', ST_Intersection(empty, empty) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty, + 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry + ) SELECT 'ST_Difference(geometry, empty) == geometry', ST_Difference(geometry, empty) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty, + 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry + ) SELECT 'ST_Difference(empty, geometry) == empty', ST_Difference(empty, geometry) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty, + 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry + ) SELECT 'ST_Distance(geometry, empty) == NULL', ST_Distance(geometry, empty) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty, + 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry, + 120 as tolerance + ) SELECT 'ST_DWithin(geometry, empty, tolerance) == FALSE', ST_DWithin(geometry, empty, tolerance) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty, + 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry + ) SELECT 'ST_Within(geometry, empty) == FALSE', ST_Within(geometry, empty) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty, + 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry + ) SELECT 'ST_Contains(empty, geometry) == FALSE', ST_Contains(empty, geometry) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty, + 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry + ) SELECT 'ST_Within(empty, geometry) == FALSE', ST_Within(empty, geometry) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty + ) SELECT 'ST_Contains(empty, empty) == FALSE', ST_Contains(empty, empty) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty, + 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry + ) SELECT 'ST_Intersects(geometry, empty) == FALSE', ST_Intersects(geometry, empty) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty + ) SELECT 'ST_Intersects(empty, empty) == FALSE', ST_Intersects(empty, empty) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty, + 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry + ) SELECT 'ST_Disjoint(empty, empty) == TRUE', ST_Disjoint(empty, empty) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty, + 'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry + ) SELECT 'ST_Disjoint(geometry, empty) == TRUE', ST_Disjoint(geometry, empty) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty1, + 'POINT Z EMPTY'::geometry as empty2 + ) SELECT 'ST_Equals(empty1, empty2) == TRUE', ST_Equals(empty1, empty2) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty + ) SELECT 'ST_IsSimple(empty) == TRUE', ST_IsSimple(empty) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty + ) SELECT 'ST_IsValid(empty) == TRUE', ST_IsValid(empty) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty + ) SELECT 'ST_NumGeometries(empty) == 0', ST_NumGeometries(empty) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty + ) SELECT 'ST_NRings(empty) == 0', ST_NRings(empty) FROM inp; +WITH inp AS (SELECT + 'LINESTRING EMPTY'::geometry as empty + ) SELECT 'ST_NumPoints(empty) == 0', ST_NumPoints(empty) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty + ) SELECT 'ST_NPoints(empty) == 0', ST_NPoints(empty) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty, + 1 as n + ) SELECT 'ST_GeometryN(empty, n) == empty', ST_GeometryN(empty, n) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty + ) SELECT 'ST_ExteriorRing(empty) == empty', ST_ExteriorRing(empty) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty, + 1 as n + ) SELECT 'ST_InteriorRingN(empty, n) == NULL', ST_InteriorRingN(empty, n) FROM inp; +WITH inp AS (SELECT + 'POLYGON EMPTY'::geometry as empty + ) SELECT 'ST_Area(empty) == 0', ST_Area(empty) FROM inp; +WITH inp AS (SELECT + 'LINESTRING EMPTY'::geometry as empty + ) SELECT 'ST_Length(empty) == 0', ST_Length(empty) FROM inp; + + +-- Operators + +-- same box, see http://trac.osgeo.org/postgis/ticket/1453 +SELECT '~=', 'POINT EMPTY'::geometry ~= 'POINT EMPTY'::geometry; diff --git a/regress/sfcgal/empty_expected b/regress/sfcgal/empty_expected new file mode 100644 index 000000000..4acf5620d --- /dev/null +++ b/regress/sfcgal/empty_expected @@ -0,0 +1,55 @@ +T1.1|POINT EMPTY +T1.2|LINESTRING EMPTY +T1.3|SRID=4326;POLYGON EMPTY +T2.1|SRID=4326;POLYGON EMPTY +T2.2|SRID=4326;POLYGON EMPTY +T2.3|SRID=4326;POLYGON EMPTY +T2.4|4326|POLYGON +T3.1| +T3.2| +T3.3| +T3.4| +T3.5| +T3.6| +T3.7| +T3.8| +T3.9| +T3.10| +T3.11| +T3.12| +T3.13| +T3.14| +T3.15| +T3.16| +T3.17| +T3.18| +ST_Buffer(empty, tolerance) == empty|010300000000000000 +ST_Union(geometry, empty) == geometry|0103000000010000000400000000000000000000000000000000000000000000000000244000000000000000000000000000001440000000000000144000000000000000000000000000000000 +ST_Union(empty, empty) == empty|010300000000000000 +ST_Intersection(geometry, empty) == geometry|010700000000000000 +ST_Intersection(empty, empty) == empty|010700000000000000 +ST_Difference(geometry, empty) == geometry|0103000000010000000400000000000000000000000000000000000000000000000000244000000000000000000000000000001440000000000000144000000000000000000000000000000000 +ST_Difference(empty, geometry) == empty|010300000000000000 +ST_Distance(geometry, empty) == NULL|inf +ST_DWithin(geometry, empty, tolerance) == FALSE|f +ST_Within(geometry, empty) == FALSE|f +ST_Contains(empty, geometry) == FALSE|f +ST_Within(empty, geometry) == FALSE|f +ST_Contains(empty, empty) == FALSE|f +ST_Intersects(geometry, empty) == FALSE|f +ST_Intersects(empty, empty) == FALSE|f +ST_Disjoint(empty, empty) == TRUE|t +ST_Disjoint(geometry, empty) == TRUE|t +ST_Equals(empty1, empty2) == TRUE|t +ST_IsSimple(empty) == TRUE|t +ST_IsValid(empty) == TRUE|t +ST_NumGeometries(empty) == 0|0 +ST_NRings(empty) == 0|0 +ST_NumPoints(empty) == 0|0 +ST_NPoints(empty) == 0|0 +ST_GeometryN(empty, n) == empty|010300000000000000 +ST_ExteriorRing(empty) == empty|010200000000000000 +ST_InteriorRingN(empty, n) == NULL| +ST_Area(empty) == 0|0 +ST_Length(empty) == 0|0 +~=|t diff --git a/regress/sfcgal/geography.sql b/regress/sfcgal/geography.sql new file mode 100644 index 000000000..1fa7db6e8 --- /dev/null +++ b/regress/sfcgal/geography.sql @@ -0,0 +1,79 @@ +SET postgis.backend = 'sfcgal'; + +INSERT INTO spatial_ref_sys (srid, auth_name, auth_srid, srtext, proj4text) +VALUES ( + '4326', + 'EPSG', + '4326', + 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]', + '+proj=longlat +datum=WGS84 +no_defs' +); + +-- Do cached and uncached distance agree? +SELECT c, abs(ST_Distance(ply::geography, pt::geography) - _ST_DistanceUnCached(ply::geography, pt::geography)) < 0.01 FROM +( VALUES +('geog_distance_cached_1a', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), +('geog_distance_cached_1b', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), +('geog_distance_cached_1c', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), +('geog_distance_cached_1e', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), +('geog_distance_cached_1f', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), +('geog_distance_cached_1g', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), +('geog_distance_cached_1h', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)') +) AS u(c,ply,pt); + +-- Does tolerance based distance work cached? Inside tolerance +SELECT c, ST_DWithin(ply::geography, pt::geography, 3000) from +( VALUES +('geog_dithin_cached_1a', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(10.01 5)'), +('geog_dithin_cached_1b', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(10.01 5)'), +('geog_dithin_cached_1c', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(10.01 5)') +) as p(c, ply, pt); + +-- Does tolerance based distance work cached? Outside tolerance +SELECT c, ST_DWithin(ply::geography, pt::geography, 1000) from +( VALUES +('geog_dithin_cached_2a', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(10.01 5)'), +('geog_dithin_cached_2b', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(10.01 5)'), +('geog_dithin_cached_2c', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(10.01 5)') +) as p(c, ply, pt); + +-- Do things work when there's cache coherence on the point side but not the poly side? +SELECT c, ST_DWithin(ply::geography, pt::geography, 3000) from +( VALUES +('geog_dithin_cached_3a', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), +('geog_dithin_cached_3b', 'POLYGON((1 1, 1 10, 10 10, 10 1, 1 1))', 'POINT(5 5)'), +('geog_dithin_cached_3c', 'POLYGON((2 2, 2 10, 10 10, 10 2, 2 2))', 'POINT(5 5)') +) as p(c, ply, pt); + +-- Test a precision case near the south pole that came up during development. +WITH pt AS ( + SELECT point::geography FROM ( VALUES + ('0101000020E61000006C5B94D920EB4CC0A0FD481119B24FC0'), + ('0101000020E610000097A8DE1AD8524CC09C8A54185B1050C0'), + ('0101000020E61000008FC2F5285C4F4CC0E5ED08A7050F50C0'), + ('0101000020E61000008FC2F5285C4F4CC0E5ED08A7050F50C0') ) AS p(point) +), +ply AS ( + SELECT polygon::geography FROM ( VALUES + ('0106000020E610000001000000010300000001000000A10100005036E50AEF8E4FC0E3FC4D2844A443C000000000008046C000000000000047C033333333335346C000000000000047C066666666662646C000000000000047C09999999999F945C000000000000047C0CDCCCCCCCCCC45C000000000000047C00000000000A045C000000000000047C033333333337345C000000000000047C066666666664645C000000000000047C099999999991945C000000000000047C0CDCCCCCCCCEC44C000000000000047C00000000000C044C000000000000047C033333333339344C000000000000047C066666666666644C000000000000047C099999999993944C000000000000047C0CDCCCCCCCC0C44C000000000000047C00000000000E043C000000000000047C03333333333B343C000000000000047C066666666668643C000000000000047C099999999995943C000000000000047C0CDCCCCCCCC2C43C000000000000047C000000000000043C000000000000047C03333333333D342C000000000000047C06666666666A642C000000000000047C099999999997942C000000000000047C0CDCCCCCCCC4C42C000000000000047C000000000002042C000000000000047C03333333333F341C000000000000047C06666666666C641C000000000000047C099999999999941C000000000000047C0CDCCCCCCCC6C41C000000000000047C000000000004041C000000000000047C033333333331341C000000000000047C06666666666E640C000000000000047C09999999999B940C000000000000047C0CDCCCCCCCC8C40C000000000000047C000000000006040C000000000000047C033333333333340C000000000000047C066666666660640C000000000000047C03333333333B33FC000000000000047C09999999999593FC000000000000047C00000000000003FC000000000000047C06666666666A63EC000000000000047C0CCCCCCCCCC4C3EC000000000000047C03333333333F33DC000000000000047C09999999999993DC000000000000047C00000000000403DC000000000000047C06666666666E63CC000000000000047C0CCCCCCCCCC8C3CC000000000000047C03333333333333CC000000000000047C09999999999D93BC000000000000047C00000000000803BC000000000000047C06666666666263BC000000000000047C0CCCCCCCCCCCC3AC000000000000047C03333333333733AC000000000000047C09999999999193AC000000000000047C00000000000C039C000000000000047C066666666666639C000000000000047C0CCCCCCCCCC0C39C000000000000047C03333333333B338C000000000000047C099999999995938C000000000000047C000000000000038C000000000000047C06666666666A637C000000000000047C0CDCCCCCCCC4C37C000000000000047C03333333333F336C000000000000047C099999999999936C000000000000047C000000000004036C000000000000047C06666666666E635C000000000000047C0CDCCCCCCCC8C35C000000000000047C033333333333335C000000000000047C09999999999D934C000000000000047C000000000008034C000000000000047C066666666662634C000000000000047C0CDCCCCCCCCCC33C000000000000047C033333333337333C000000000000047C099999999991933C000000000000047C00000000000C032C000000000000047C066666666666632C000000000000047C0CDCCCCCCCC0C32C000000000000047C03333333333B331C000000000000047C099999999995931C000000000000047C000000000000031C000000000000047C06666666666A630C000000000000047C0CDCCCCCCCC4C30C000000000000047C06666666666E62FC000000000000047C03333333333332FC000000000000047C00000000000802EC000000000000047C0CCCCCCCCCCCC2DC000000000000047C09999999999192DC000000000000047C06666666666662CC000000000000047C03333333333B32BC000000000000047C00000000000002BC000000000000047C0CCCCCCCCCC4C2AC000000000000047C099999999999929C000000000000047C06666666666E628C000000000000047C033333333333328C000000000000047C000000000008027C000000000000047C0CDCCCCCCCCCC26C000000000000047C099999999991926C000000000000047C066666666666625C000000000000047C03333333333B324C000000000000047C000000000000024C000000000000047C000000000000024C03943F5FFFF7F56C000000000008052C03943F5FFFF7F56C000000000008052C00000000000004EC068774831407A52C00000000000004EC0B8ACC266807452C00000000000004EC020240B98C06E52C00000000000004EC0705985CD006952C00000000000004EC0D9D0CDFE406352C00000000000004EC029064834815D52C00000000000004EC0917D9065C15752C00000000000004EC0E1B20A9B015252C00000000000004EC0492A53CC414C52C00000000000004EC09A5FCD01824652C00000000000004EC002D71533C24052C00000000000004EC0520C9068023B52C00000000000004EC0BA83D899423552C00000000000004EC00AB952CF822F52C00000000000004EC072309B00C32952C00000000000004EC0C3651536032452C00000000000004EC02BDD5D67431E52C00000000000004EC09354A698831852C00000000000004EC0E38920CEC31252C00000000000004EC04B0169FF030D52C00000000000004EC09B36E334440752C00000000000004EC003AE2B66840152C00000000000004EC054E3A59BC4FB51C00000000000004EC0BC5AEECC04F651C00000000000004EC00C90680245F051C00000000000004EC07407B13385EA51C00000000000004EC0C43C2B69C5E451C00000000000004EC02DB4739A05DF51C00000000000004EC07DE9EDCF45D951C00000000000004EC0E560360186D351C00000000000004EC03596B036C6CD51C00000000000004EC09D0DF96706C851C00000000000004EC0EE42739D46C251C00000000000004EC056BABBCE86BC51C00000000000004EC0A6EF3504C7B651C00000000000004EC00E677E3507B151C00000000000004EC076DEC66647AB51C00000000000004EC0C613419C87A551C00000000000004EC02E8B89CDC79F51C00000000000004EC07FC00303089A51C00000000000004EC0E7374C34489451C00000000000004EC0376DC669888E51C00000000000004EC09FE40E9BC88851C00000000000004EC0EF1989D0088351C00000000000004EC05791D101497D51C00000000000004EC0A8C64B37897751C00000000000004EC0103E9468C97151C00000000000004EC060730E9E096C51C00000000000004EC0C8EA56CF496651C00000000000004EC01820D1048A6051C00000000000004EC081971936CA5A51C00000000000004EC0D1CC936B0A5551C00000000000004EC03944DC9C4A4F51C00000000000004EC0A1BB24CE8A4951C00000000000004EC0F1F09E03CB4351C00000000000004EC05968E7340B3E51C00000000000004EC0AA9D616A4B3851C00000000000004EC01215AA9B8B3251C00000000000004EC0624A24D1CB2C51C00000000000004EC0CAC16C020C2751C00000000000004EC01AF7E6374C2151C00000000000004EC0826E2F698C1B51C00000000000004EC0D3A3A99ECC1551C00000000000004EC03B1BF2CF0C1051C00000000000004EC08B506C054D0A51C00000000000004EC0F3C7B4368D0451C00000000000004EC043FD2E6CCDFE50C00000000000004EC0AB74779D0DF950C00000000000004EC0FCA9F1D24DF350C00000000000004EC064213A048EED50C00000000000004EC0CC988235CEE750C00000000000004EC01CCEFC6A0EE250C00000000000004EC08445459C4EDC50C00000000000004EC0D47ABFD18ED650C00000000000004EC0C2340C1F11D150C00000000000004EC0C2340C1F11D150C0FE7DC685032D4DC0C2340C1F11D150C0FE7DC685033D4CC0C2340C1F11D150C0713D0AD7A3304CC02AAC545051CB50C0703D0AD7A3304CC07AE1CE8591C550C0703D0AD7A3304CC0E25817B7D1BF50C0703D0AD7A3304CC0328E91EC11BA50C0703D0AD7A3304CC09A05DA1D52B450C0703D0AD7A3304CC0EB3A545392AE50C0703D0AD7A3304CC053B29C84D2A850C0703D0AD7A3304CC0A3E716BA12A350C0703D0AD7A3304CC00B5F5FEB529D50C0703D0AD7A3304CC05B94D920939750C0703D0AD7A3304CC0C30B2252D39150C0703D0AD7A3304CC014419C87138C50C0703D0AD7A3304CC07CB8E4B8538650C0703D0AD7A3304CC0CCED5EEE938050C0703D0AD7A3304CC03465A71FD47A50C0703D0AD7A3304CC0849A2155147550C0703D0AD7A3304CC0EC116A86546F50C0703D0AD7A3304CC03ECBF3E0EE6E50C0713D0AD7A3304CC0FF3EE3C2816E50C0A2EE0390DAB04BC0EC12D55B038550C01630815B77974BC05BCEA5B8AA9A50C0C173EFE1928F4BC0A5315A4755B550C00000000000804BC0014D840D4FD150C01899DB1896744BC05D05E7421B2A51C0B38EF4B3A2754BC0BB0F406A132751C068E89FE062C94AC03D6B1217DB2851C0413F9D3C76564AC09F268E97491D51C01E55A8C9E72D4AC014AE47E17A5051C05E770481DF154AC0DA531795F95E51C0ADA81CEE7E154AC033333333337351C0EACF7EA488084AC0DA835A1DCA8251C019479B994F014AC00473F4F8BDA551C0CB4A9352D0014AC0AD927EB12DFD51C0848FD2B6AB014AC07F11D9AC1FFF51C0D21D1F8887F249C01D4762388D1B52C06AE27899BCCA49C00AD7A3703D1252C08BAF2C87CCA049C0A323B9FC871A52C0ADCE20F4229449C056760B6E351352C0F866E5A8ED8449C024F83A04E91352C0DCDB8882745249C0F1F44A59863252C0DBCD42F1195049C01A97BBE09D4452C0EEEBC039236449C09A31BBDD014C52C0454B79083E6349C0A59421D8826352C004824AA6542849C04BABC6B71C6252C046216EF36B1449C0A4F55C4BED5D52C01CE7DB27EC0549C0D9BBF550916452C058CE39D3DFF648C0DD0E6844445C52C0937D46D8A6E648C098B4F347E26652C0F6FC1F1620C748C0AB37B412845D52C0D9A2BBDA40A948C048E17A14AE5F52C0D52137C30D9448C04B1A48BCE14B52C0BF901F3BB99848C0B26DAC1FF63552C0E4709CCA587B48C0287E8CB96B2652C0912CBBBB296948C0A59421D8822852C0D49AE61DA74048C0C009E0C1AA1452C0106734A8EC2E48C0A8D94D3ADB1452C004560E2DB21948C0687B4F40EE2452C06ECF3D35A8F047C089022269DC1552C0ADAC23FDACCD47C019B2158FE61652C07BC26DC89AB747C009B3BFA2910A52C095E70B6B74B447C01DF2857F47FF51C01D8AA7C3AF9A47C0F1248EE156F651C0E9482EFF219B47C07A45A6327BFE51C0711706D1FF8747C0A5315A4755FD51C000000000008047C0395BE5AE4AFB51C0CD6152D7356547C0182DF64DD0F451C00CC3EC0A226447C0B6CA5D95D5EA51C098E19A96B34A47C06ABC749318FA51C0E51E5C4B121247C0C1920612EFEE51C0780F2B37AC0847C09D2743FA12EA51C0653FE65EBBF546C01563AAAA61F351C0FA8271CBA2CB46C00775368966E151C08208CC9E5FC346C05DEF4806CAD651C03ECB98277C9C46C03760A12042E551C0FFF1B96EA57B46C073A7CF69710152C090A4FF40147346C03D5C1723B70152C0F46C567DAE6646C03505D78198E051C023DF008E985E46C08351499D80D451C037853A51B76646C09C46A4B789C751C0B515FBCBEE4546C09C33A2B437CF51C0BE82D9A95E3446C066E1462550F651C042CB5FC6B93046C09B6B3DE8FEF551C056212FB5EF0D46C075FBF6BFEDEB51C04E36D4DE96FF45C020578FA01DF251C0C967C3ABF6E845C05CA2C4F87AE651C0E5F21FD26FD745C0FD0978E3EEFB51C06CE3F49AC3BE45C09D11A5BDC1F951C00C11267B3AAB45C08A9DDFE643F051C037EE83E27DA645C0A922CB38FCEF51C0CCBE863B729645C008D5BC99070852C0865EDACB118745C088635DDC460952C01B09D91E624E45C01F85EB51B80652C07D96E7C1DD4D45C0A8188CB6CF0152C018135102513E45C00C7D0B46000852C0166646E4602945C06E2585C31C0352C039B0C167901345C0A499DD497AEF51C0BD1358A5991245C023DBF97E6AF251C0BEF15AAE230045C0EE7C3F355EF151C0F6FC1F1620E944C040529F3FC8F851C0BBF7CB82E4D344C0D27E5AFBF1F751C0F6D61B107CB444C0CA9C23938AF751C0B498EEF4A2B544C0624775BC1FF751C035958D13C7B644C0EA8B637FB1F651C040BEE654E8B744C0AADC49E43FF651C0298B1FA206B944C0AD7CCAF3CAF551C043D796E421BA44C0D6E6CDB652F551C0ECBDE6053ABB44C0532E8236D7F451C06B72E6EF4EBC44C07E585A7C58F451C08F13AC8C60BD44C01EB00D92D6F351C0DE7A8EC66EBE44C02712978151F351C01507278879BF44C0F9333455C9F251C0D96153BC80C044C015E364173EF251C08540374E84C144C0703EEAD2AFF151C0B21F3E2984C244C062E9C5921EF151C088F91C3980C344C0313839628AF051C083F6D36978C444C05856C44CF3EF51C0A018B0A76CC544C09366255E59EF51C0A5E04CDF5CC644C0AE9C57A2BCEE51C08AED95FD48C744C0495192251DEE51C09C95C8EF30C844C0760F48F47AED51C0747975A314C944C0739C251BD6EC51C060108206F4C944C061F910A72EEC51C0372E2A07CFCA44C0385F28A584EB51C066820194A5CB44C0E834C122D8EA51C01010F59B77CC44C0DDFF662D29EA51C0149F4C0E45CD44C0DA4EDAD277E951C0E725ACDA0DCE44C0669F0F21C4E851C0FB2B15F1D1CE44C0C53D2E260EE851C0B124E84191CF44C0A41F8FF055E751C09CC2E5BD4BD044C098B9BB8E9BE651C0F042305601D144C076CF6C0FDFE551C017B14CFCB1D144C0B73F898120E551C0192224A25DD244C0F9C924F45FE451C0E5E7043A04D344C0B2D07E769DE351C03EBCA3B6A5D344C047160118D9E251C039E31C0B42D444C095753EE812E251C01B45F52AD9D444C01596F1F64AE151C09D7F1B0A6BD544C0B79BFB5381E051C048EEE89CF7D544C096D2620FB6DF51C0F7A922D87ED644C0AA565139E9DE51C0497FFAB000D744C097B713E21ADE51C0FBDB0F1D7DD744C0BB98171A4BDD51C0FBB27012F4D744C0AC4DEAF179DC51C02D579A8765D844C03173377AA7DB51C0BC4C7A73D1D844C0FB84C7C3D3DA51C0FD106FCD37D944C027707EDFFED951C095D8488D98D944C0C8225ADE28D951C013444AABF3D944C08B1871D151D851C0B40A292049DA44C0ADE4F0C979D751C0529B0EE598DA44C061B91CD9A0D651C07AB398F3E2DA44C0D4EC4B10C7D551C076ECD94527DB44C0F97BE880ECD451C0633E5AD665DB44C0398B6D3C11D451C01F7917A09EDB44C04CE5655435D351C01FB3859ED1DB44C048786ADA58D251C018AE8FCDFEDB44C022D120E07BD151C05831972926DC44C0C89539779ED051C0F25975AF47DC44C0FEFD6EB1C0CF51C091E07A5C63DC44C02B4B83A0E2CE51C0EE54702E79DC44C03D3F3F5604CE51C0F24E962389DC44C0D69270E425CD51C07E95A53A93DC44C0EE6AE85C47CC51C0A93ACF7297DC44C00BCE79D168CB51C0C6ADBCCB95DC44C04F19F8538ACA51C0D7C28F458EDC44C06D7535F6ABC951C09FAFE2E080DC44C0CD4B01CACDC851C04CFEC79E6DDC44C000BC26E1EFC751C0B675CA8054DC44C09F116B4D12C751C029F7EC8835DC44C0DF3A8C2035C651C0DC51AAB910DC44C0F53F3F6C58C551C0FC0BF515E6DB44C073BB2E427CC451C0632137A1B5DB44C0D153F9B3A0C351C0F7B7515F7FDB44C04D3630D3C5C251C0CDC99C5443DB44C0459355B1EBC151C0F8C4E68501DB44C0451CDB5F12C151C0342174F8B9DA44C0DB8320F039C051C062EBFEB16CDA44C079FF717362BF51C0E546B6B819DA44C078CB06FB8BBE51C0F2E43D13C1D944C06DB1FF97B6BD51C0DC71ADC862D944C0F890655BE2BC51C088F88FE0FED844C03BEB27560FBC51C0E13BE36295D844C014711B993DBB51C09706175826D844C04F94F8346DBA51C02E710CC9B1D744C0F31B5A3A9EB951C04B1E15BF37D744C0C6BBBBB9D0B851C0976DF243B8D644C03FAF78C304B851C014A5D46133D644C0F757CA673AB751C01A115A23A9D544C0DADFC6B671B651C0141B8E9319D544C014DF5FC0AAB551C0FE56E8BD84D444C005066194E5B451C0E6874BAEEAD344C049CB6E4222B451C0629B04714BD344C0E91D05DA60B351C03E9CC912A7D244C0051C766AA1B251C04D9CB8A0FDD144C0D3CDE802E4B151C0CD9556284FD144C058E557B228B151C00E448EB79BD044C0C48290876FB051C0DCF3AE5CE3CF44C0ABFD3091B8AF51C0A54B6B2626CF44C034B3A7DD03AF51C06F0BD82364CE44C048D9317B51AE51C0DEC46A649DCD44C0FC56DA77A1AD51C05A8BF8F7D1CC44C032A278E1F3AC51C0709CB4EE01CC44C0A0A2AFC548AC51C0B9002F592DCB44C03F9AEC31A0AB51C03225534854CA44C05A136633FAAA51C0646D66CD76C944C02DD41AD756AA51C050BE06FA94C844C04CD8D029B6A951C0720229E0AEC744C0D34F143818A951C0DEA61792C4C644C075A4360E7DA851C0AF117122D6C544C082844DB8E4A751C0EE1126A4E3C444C0FDF331424FA751C02849782AEDC344C0B6637FB7BCA651C0B58EF8C8F2C244C0A5CE92232DA651C0FE4C8593F4C144C067DD8991A0A551C0EBD8489EF2C044C01010420C17A551C084C3B7FDECBF44C046EE579E90A451C006268FC6E3BE44C0C53D26520DA451C0AAE8D20DD7BD44C0473FC5318DA351C01B04CCE8C6BC44C0E1F1094710A351C0E0BD066DB3BB44C0E85C859B96A251C000E050B09CBA44C05AE0833820A251C0CAEBB7C882B944C0CF8B0C27ADA151C02F4887CC65B844C00B7CE06F3DA151C0B66B46D245B744C02E3F7A1BD1A051C03B02B7F022B644C0813F0D3268A051C0BA0ED33EFDB444C0E43485BB02A051C02C09CBD3D4B344C0FB9C85BFA09F51C0CBF803C7A9B244C0EB396945429F51C0D58A15307CB144C0E1974154E79E51C0FC25C8264CB044C03299D6F28F9E51C0ADFA12C319AF44C03D09A6273C9E51C076101A1DE5AD44C0EF35E3F8EB9D51C084502C4DAEAC44C0F98F766C9F9D51C0A08DC16B75AB44C09EB70C93849D51C08100BE8003AB44C05036E50AEF8E4FC0E3FC4D2844A443C0') + ) as q(polygon) +) +SELECT 'geog_precision_savffir', _ST_DistanceUnCached(pt.point, ply.polygon), ST_Distance(pt.point, ply.polygon) FROM pt, ply; + +-- Test another precision case near the north poly and over the dateline +WITH pt AS ( + SELECT point::geography FROM ( VALUES + ('0101000020E610000000000000004065400000000000804840'), + ('0101000020E610000075C8CD70033965C02176A6D079315040') ) AS p(point) +), +ply AS ( + SELECT polygon::geography FROM ( VALUES + ('0103000020E6100000010000004101000078A1B94E231F65C000000000000051400000000000C063C000000000000052400000000000C063C0000000000000524078A1B94E231F65C0000000000000514078A1B94E231F65C000000000008056400000000000A061C000000000008056400000000000A061C0EF940ED6FF7F56400000000000A061C0DD291DACFF7F56400000000000A061C0CBBE2B82FF7F56400000000000A061C0B9533A58FF7F56400000000000A061C0A8E8482EFF7F56400000000000A061C0967D5704FF7F56400000000000A061C072A774B0FE7F56400000000000A061C04FD1915CFE7F56400000000000A061C02BFBAE08FE7F56400000000000A061C0F6B9DA8AFD7F56400000000000A061C0C178060DFD7F56400000000000A061C079CC4065FC7F56400000000000A061C00F4A9869FB7F56400000000000A061C0A4C7EF6DFA7F56400000000000A061C0040473F4F87F56400000000000A061C052D50451F77F56400000000000A061C07DD0B359F57F56400000000000A061C0611F9DBAF27F56400000000000A061C00F2DB29DEF7F56400000000000A061C0642310AFEB7F56400000000000A061C06102B7EEE67F56400000000000A061C0E1F3C308E17F56400000000000A061C0AFB6627FD97F56400000000000A061C0DDB5847CD07F56400000000000A061C013DA722EC57F56400000000000A061C02C4D4A41B77F56400000000000A061C0CFF753E3A57F56400000000000A061C0B72DCA6C907F56400000000000A061C0776C04E2757F56400000000000A061C093C6681D557F56400000000000A061C05B0D897B2C7F56400000000000A061C01B12F758FA7E56400000000000A061C0B8239C16BC7E56400000000000A061C027FC523F6F7E56400000000000A061C0BD9179E40F7E56400000000000A061C0CFDA6D179A7D56400000000000A061C0F0332E1C087D56400000000000A061C07CB8E4B8537C56400000000000A061C0C53D963E747B56400000000000A061C08E40BCAE5F7A56400000000000A061C07F8CB96B097956400000000000A061C0FE65F7E4617756400000000000A061C0C9073D9B557556400000000000A061C0CDCCCCCCCC7256400000000000A061C07A01F6D1A96F56400000000000A061C053616C21C86B56400000000000A061C009A7052FFA6656400000000000A061C0F0332E1C086156400000000000A061C085471B47AC5956400000000000A061C0752497FF905056400000000000A061C08C84B69C4B4556400000000000A061C02C6519E2583756400000000000A061C02B357BA0152656400000000000A061C055C6BFCFB81056400000000000A061C0F988981249F655400000000000A061C08C321B6492D555400000000000A061C0ADC5A70018AD55400000000000A061C02254A9D9037B55400000000000A061C009E1D1C6113D55400000000000A061C0A0E5797077F054400000000000A061C0FA49B54FC79154400000000000A061C043959A3DD01C54400000000000A061C075EACA67798C53400000000000A061C00EE02D90A0DA52400000000000A061C000000000000052400000000000A061C000000000000052400000000000A061C00100000000004F400000000000A061C01730815B77274E408C45D3D9C99D61C04CAB21718F254E40C0120F289B9861C03EB324404D214E40745E6397A89061C0B9AAECBB221C4E406C3997E2AA8E61C09E465A2A6F274E4068666666667F61C0C9EA56CF49174E40F8D005F52D7661C01FF98381E72A4E408499B67F656261C01B69A9BC1D2D4E40C04351A04F6261C01CD82AC1E2284E40EC7C3F355E6661C0097250C24C0B4E40E8525C55F66161C001E31934F4FF4D406431B1F9B86161C0EDDD1FEF55FF4D407C4963B48E5961C06749809A5AF64D40703D0AD7A35661C0D60451F701F44D4080608E1EBF5561C0F22900C633EC4D40008750A5665561C048C49448A2E74D40205036E50A5461C0C481902C60E24D40283108AC1C4161C0C1E78711C2BB4D40B08009DCBA4061C0CA1F0C3CF7BA4D4010751F80D43E61C0029F1F4608B74D40A47EDE54A43E61C03CFC3559A3B64D405C3D27BD6F3361C00938842A359F4D40E85BE674593161C0F7D1A92B9F8D4D409820EA3E003061C019E76F42217E4D402883A3E4D53061C08833BF9A03744D40605E807D742E61C04E7FF62345744D40182B6A300D2961C06B82A8FB00804D40D0FBC6D79E2561C0C8F484251E844D4044DD0720B52261C0E46BCF2C09884D40DC9DB5DB2E2161C0AF47E17A148A4D40303D6189071F61C02A5C8FC2F58C4D40F8F719170E1C61C02259C0046E914D405031CEDF841A61C0AB2B9FE579944D401C649291B31261C077DB85E63A954D40A07A6B60AB0F61C03E963E7441A14D40247F30F0DC0F61C026E99AC937A34D402054A9D9030F61C04EB9C2BB5CA44D40C051F2EA1C0F61C0CE920035B5A84D409CF9D51C200F61C05B2A6F4738A94D40C86C9049460F61C05D8FC2F528B04D4008D3307C440F61C073BF4351A0BB4D40285C8FC2F50B61C03E61890794B94D40080C59DDEA0B61C030FA0AD28CB94D40D8166536C80B61C04C7155D977B94D400079AF5A990B61C005392861A6B94D40F836FDD98F0B61C0E8A4F78DAFB94D40D03FC1C58A0B61C0DA5A5F24B4B94D4058087250C20961C0650113B875BB4D401C5A643BDF0861C0C32FF5F3A6BE4D407862D68BA10761C0E627D53E1DC34D4020680586AC0761C03A5D16139BC74D40D02C0950530B61C07194BC3AC7CC4D4030EBC5504E0961C0988BF84ECCCE4D40CCAFE600C10861C07411DF8959CF4D40B81457957D0861C0EC8B84B69CCF4D400825CCB4FD0761C0F2EF332E1CD04D40703D0AD7A30761C023F8DF4A76D04D403837A6272C0661C0BD3AC780ECD14D40602D3E05C00261C05F2EE23B31D34D4018601F9DBA0161C057F146E691D34D409820EA3E000161C03AEE940ED6D34D406CB2463D440061C041C1C58A1AD44D4010FC6F253B0061C0C8F484251ED44D402CBCCB457CFE60C038328FFCC1D44D40C0BC00FBE8FB60C065AF777FBCD74D4080BC57AD4CFB60C0C7BFCFB870D84D40102DB29DEFF860C0BB490C022BDB4D40242D95B723F760C0E25D2EE23BDD4D402CE7525C55EF60C00B9DD7D825E64D40CC1E680586EB60C0EE9925016ADE4D400C022B8716E860C0B7B9313D61D94D40CC0182397AE760C0FFB7921D1BD94D40C095ECD808E760C0B1389CF9D5D44D40E47E87A240E560C0079E7B0F97D04D401C5036E50AE560C0013ACC9717D04D40C01C3D7E6FE460C03A2861A6EDCF4D40988F6B43C5E360C05665DF15C1CF4D40148733BF9AE360C0252367614FCF4D40D0A5B8AAECE060C040DEAB5626C84D40D4CA845FEAE060C09AB67F65A5C54D40901EBFB7E9E060C01B2FDD2406C54D40B05582C5E1E060C055E3A59BC4BC4D405014E81379E260C0537E52EDD3B94D40483D44A33BE360C08A07944DB9B64D40E8263108ACDF60C09A7CB3CD8DB14D4080F10C1AFAE060C04052448655AC4D40D8D825AAB7DE60C06B65C22FF5A34D40E874594C6CD660C01D5A643BDF9F4D40F82CCF83BBD560C063D68BA19C984D40B0683A3B19D260C046990D32C9904D407047382D78CF60C0CDE9B298D8904D4078978BF84ECE60C017139B8F6B8B4D4008B64AB038CC60C094DE37BEF6844D40303D618907CD60C069CBB914577D4D40140A117008CA60C0E644BB0A297B4D4054E3A59BC4CA60C0763C66A032764D40044CE0D6DDC960C025404D2D5B734D40A818E76F42C860C0FD6F253B366E4D40A41EA2D11DBF60C067F2CD3637624D40D0A92B9FE5BA60C07732384A5E5D4D4030B610E4A0B660C059FFE7305F4E4D40A0BE654E97B560C02CC1E270E64B4D4044813E9127B560C08A5E46B1DC4A4D40C09F1A2FDDB460C044FF04172B4A4D40DCD26A48DCB460C0284EEE77284A4D4028E3DF675CB360C04A29E8F692464D4048D74CBED9B160C05F9D6340F6424D4098395D1613AC60C09F7B0F971C374D40F00390DAC4AE60C0A80018CFA0314D40F8F719170EAB60C0AC730CC85E234D400C5EF415A4A860C01B4CC3F0111D4D4008E1D1C611A760C03208AC1C5A184D40E422BE13B3A660C08221AB5B3D174D404833164D67A660C0FCC6D79E59164D4070641EF983A560C073DC291DAC134D4020E527D53EA260C06B9F8EC70C004D40B0BAD573D29B60C0DEEA39E97DEB4C40F4D6C056099860C07884D38217D94C4064B48EAA269560C0D869A4A5F2CE4C4054C6BFCFB89160C081ECF5EE8FBF4C405CC47762D68B60C02AE8F692C6AC4C40446E861BF08760C0ADA8C1340C9B4C4060C8EA56CF8B60C096CFF23CB88B4C40D005F52D738160C07E5C1B2AC6854C40AC6EF59CF48360C088BF266BD46F4C40D8EBDD1FEF7B60C026CCB4FD2B674C402883A3E4D57C60C040A9F6E978604C40D03FC1C58A7B60C0448B6CE7FB594C40747632384A7B60C07D96E7C1DD554C40D0747632387B60C03815A930B6544C40F8B31F29227B60C074F4F8BD4D534C40D8868A71FE7A60C0FF7DC68503514C40600CE544BB7A60C0F88DAF3DB34C4C40C8D2872EA87960C046F0BF95EC4C4C40E04F8D976E7860C0A2B94E232D4D4C4054910A630B7860C08642041C424D4C40540E2DB29D7760C03ED00A0C594D4C40808B1535987660C005FF5BC98E4D4C40D09B8A54187560C036EA211ADD4D4C406891ED7C3F7460C019ADA3AA094E4C4050EDD3F1987260C059FFE7305F4E4C40446458C51B6F60C02EEC6987BF464C40280AF4893C6A60C0E46BCF2C09404C40E0AFC91AF56960C03A7AFCDEA63F4C408872A25D856960C0ADA8C1340C3F4C4018B2BAD5736960C043EC4CA1F33E4C4044088F368E6560C0C57762D68B394C40CCCCCCCCCC6260C0A4C7EF6DFA334C4058DDEA39E95E60C0613C8386FE314C4034164D67275E60C0709EEA909B314C40C8F99B50885D60C0FE2B2B4D4A314C40E07A14AE475D60C0D4D9C9E028314C4098F56228275C60C0EAEC647094304C40C0D84290835B60C0F246E6913F304C40981C774A075960C0CA1F0C3CF72E4C40900A630B415860C0B1AC3429052D4C40205ED72FD85760C0E44EE960FD2B4C40DC240681955760C0ECDD1FEF552B4C407C74EACA675760C0E6965643E22A4C40B04B546F0D5760C0CBBE2B82FF294C4034936FB6B95660C05B0D897B2C294C40285C8FC2F55560C0C9CD70033E274C40342905DD5E5560C08CA6B393C1254C4098728577B95460C07923F3C81F244C4044C02154A95460C01D9430D3F6234C40A82688BA0F5460C067834C3272224C4030815B77F35360C044FF04172B224C40E422BE13B35360C0DAEBDD1FEF214C40A47EDE54A45260C038A6272CF1204C403C1405FA445260C0079E7B0F97204C40C8681D554D5160C0B3632310AF1F4C4080F10C1AFA4E60C050AA7D3A1E1F4C405C33F9669B4E60C0DE0720B5891B4C409CC420B0724E60C03641D47D001A4C40C0FF56B2634E60C0B7D617096D194C40B46CAD2F124E60C092442FA358164C402891442FA34D60C0AF64C74620124C4090ED7C3F354B60C023F8DF4A76104C405CE15D2EE24760C0C7850321590C4C400CB08F4E5D4760C07177D66EBB0C4C40E097FA79534360C048FE60E0B90F4C40C8D2872EA84260C0EA263108AC0C4C4098395D16134260C052F2EA1C030A4C40902232ACE24160C029D027F224094C40B87EC16ED84160C094DE37BEF6084C40F00703CFBD4160C0EAB298D87C084C40DC9DB5DB2E4160C0DAEBDD1FEF054C40200C3CF71E4160C09AB67F65A5054C40686AD95A5F4060C067F2CD3637024C40A41EA2D11D4060C0A2629CBF09014C40C4724BAB214060C05D8FC2F528004C40F8B31F29224060C00FA14ACD1E004C409C16BCE82B4060C034F9669B1BFF4B40CC457C27664060C04DC3F01131F94B405C5A0D897B4060C0E6ED08A705F74B40DC0720B5894060C0B72DCA6C90F54B40BCD05CA7914060C0EA60FD9FC3F44B4054F146E6914060C07177D66EBBF44B40601A868F884060C07177D66EBBF44B409CF9D51C204060C07177D66EBBF44B409CF9D51C204060C0F20C1AFA27F44B406414CB2DAD4260C077BE9F1A2FE94B40B8533A58FF4360C06D5B94D920E74B40B05582C5E14460C0CBF8F71917E24B40F82CCF83BB4460C0174D672783DB4B40188BA6B3934360C0AC90F2936AD74B4004DD5ED2184460C00B2E56D460CA4B4044D3D9C9E04260C03AB4C876BEBF4B40EC5F5969524160C0E8FBA9F1D2B94B406414CB2DAD4060C05001309E41AB4B40900A630B413F60C0D205F52D73A64B40E4C281902C3F60C096B7239C16A44B4020020EA14A4360C0F870C971A7984B400035B56CAD4460C00BF4893C49924B40E0F3C308E14460C001E31934F48F4B402866BD18CA4560C0B3632310AF8B4B4048ACC5A7004660C0011DE6CB0B884B401881785DBF4860C07FA4880CAB7C4B40B46CAD2F124B60C0B7F3FDD478754B40480C022B874D60C0A553573ECB6F4B40C0D4CF9B8A4E60C0FF60E0B9F76C4B40889D29745E4F60C0F4716DA8186B4B40DC9DB5DB2E5260C0A96F99D365654B4000D9EBDD1F5460C0D678E92631644B4054AEF02E175560C0A81DFE9AAC614B40182FDD24065460C0E06C73637A5E4B403C3F8C101E5460C055E3A59BC45C4B408043A852B35360C0597380608E5A4B40044CE0D6DD9560C0CDCCCCCCCC544B406866666666DE60C01E03B2D7BB1B4B4000000000000061C00100000000004B400000000000E060C01E03B2D7BB5B4A400000000000F862C0132C0E677E614C4000000000002063C00100000000004C4000000000000064C00100000000C04A40F8B31F2922FA64C03433333333B34940F8B31F29221266C0B0C91AF51011494034333333332366401D03B2D7BB1B49402EE7525C555D64409A99999999D946400000000000E063404A63B48EAA0A494000000000002065400100000000004B40000000000040654003F1BA7EC1564B406766666666466540EACF7EA488684B4000000000008066400100000000004E4068666666668665C03433333333035040E8C6F484251F65C00000000000405040E8C6F484251F65C00000000000C0504078A1B94E231F65C00000000000005140') + ) as q(polygon) +) +SELECT 'geog_precision_pazafir', _ST_DistanceUnCached(pt.point, ply.polygon), ST_Distance(pt.point, ply.polygon) FROM pt, ply; + + +-- Clean up spatial_ref_sys +DELETE FROM spatial_ref_sys WHERE srid = 4326; + diff --git a/regress/sfcgal/geography_expected b/regress/sfcgal/geography_expected new file mode 100644 index 000000000..3359d125d --- /dev/null +++ b/regress/sfcgal/geography_expected @@ -0,0 +1,22 @@ +geog_distance_cached_1a|t +geog_distance_cached_1b|t +geog_distance_cached_1c|t +geog_distance_cached_1e|t +geog_distance_cached_1f|t +geog_distance_cached_1g|t +geog_distance_cached_1h|t +geog_dithin_cached_1a|t +geog_dithin_cached_1b|t +geog_dithin_cached_1c|t +geog_dithin_cached_2a|f +geog_dithin_cached_2b|f +geog_dithin_cached_2c|f +geog_dithin_cached_3a|t +geog_dithin_cached_3b|t +geog_dithin_cached_3c|t +geog_precision_savffir|0|0 +geog_precision_savffir|0|0 +geog_precision_savffir|0|0 +geog_precision_savffir|0|0 +geog_precision_pazafir|0|0 +geog_precision_pazafir|0|0 diff --git a/regress/sfcgal/legacy.sql b/regress/sfcgal/legacy.sql new file mode 100644 index 000000000..db80f9a9a --- /dev/null +++ b/regress/sfcgal/legacy.sql @@ -0,0 +1,58 @@ +-- +-- These tests serve the purpose of ensuring compatibility with +-- old versions of postgis users. +-- +-- Their use rely on loading the legacy.sql script. +-- This file also serves as a testcase for uninstall_legacy.sql +-- + +SET postgis.backend = 'sfcgal'; +SET client_min_messages TO WARNING; + +\i 00-regress-install/share/contrib/postgis/legacy.sql + +INSERT INTO "spatial_ref_sys" ("srid","auth_name","auth_srid","srtext","proj4text") VALUES (4326,'EPSG',4326,'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs '); + +SELECT 'Starting up MapServer/Geoserver tests...'; +-- Set up the data table +SELECT 'Setting up the data table...'; +CREATE TABLE public.wmstest ( id INTEGER ); +SELECT AddGeometryColumn( 'wmstest', 'pt', 4326, 'POLYGON', 2 ); +INSERT INTO wmstest SELECT lon * 100 + lat AS id, st_setsrid(st_buffer(st_makepoint(lon, lat),1.0),4326) AS pt +FROM (select lon, generate_series(-80,80, 5) AS lat FROM (SELECT generate_series(-175, 175, 5) AS lon) AS sq1) AS sq2; +ALTER TABLE wmstest add PRIMARY KEY ( id ); +CREATE INDEX wmstest_geomidx ON wmstest using gist ( pt ); + +-- Geoserver 2.0 NG tests +SELECT 'Running Geoserver 2.0 NG tests...'; +-- Run a Geoserver 2.0 NG metadata query +SELECT 'Geoserver1', TYPE FROM GEOMETRY_COLUMNS WHERE F_TABLE_SCHEMA = 'public' AND F_TABLE_NAME = 'wmstest' AND F_GEOMETRY_COLUMN = 'pt'; +SELECT 'Geoserver2', SRID FROM GEOMETRY_COLUMNS WHERE F_TABLE_SCHEMA = 'public' AND F_TABLE_NAME = 'wmstest' AND F_GEOMETRY_COLUMN = 'pt'; +-- Run a Geoserver 2.0 NG WMS query +SELECT 'Geoserver3', "id",substr(encode(asBinary(force_2d("pt"),'XDR'),'base64'),0,16) as "pt" FROM "public"."wmstest" WHERE "pt" && GeomFromText('POLYGON ((-6.58216065979069 -0.7685569763184591, -6.58216065979069 0.911225433349509, -3.050569931030911 0.911225433349509, -3.050569931030911 -0.7685569763184591, -6.58216065979069 -0.7685569763184591))', 4326); +-- Run a Geoserver 2.0 NG KML query +SELECT 'Geoserver4', count(*) FROM "public"."wmstest" WHERE "pt" && GeomFromText('POLYGON ((-1.504017942347938 24.0332272532341, -1.504017942347938 25.99364254836741, 1.736833353559741 25.99364254836741, 1.736833353559741 24.0332272532341, -1.504017942347938 24.0332272532341))', 4326); +SELECT 'Geoserver5', "id",substr(encode(asBinary(force_2d("pt"),'XDR'),'base64'),0,16) as "pt" FROM "public"."wmstest" WHERE "pt" && GeomFromText('POLYGON ((-1.504017942347938 24.0332272532341, -1.504017942347938 25.99364254836741, 1.736833353559741 25.99364254836741, 1.736833353559741 24.0332272532341, -1.504017942347938 24.0332272532341))', 4326); +SELECT 'Geoserver6', "id",substr(encode(asBinary(force_2d("pt"),'XDR'),'base64'),0,16) as "pt" FROM "public"."wmstest" WHERE "pt" && GeomFromText('POLYGON ((-1.507182836191598 24.031312785172446, -1.507182836191598 25.995557016429064, 1.7399982474034008 25.995557016429064, 1.7399982474034008 24.031312785172446, -1.507182836191598 24.031312785172446))', 4326); + +-- MapServer 5.4 tests +select 'MapServer1', attname from pg_attribute, pg_constraint, pg_class where pg_constraint.conrelid = pg_class.oid and pg_class.oid = pg_attribute.attrelid and pg_constraint.contype = 'p' and pg_constraint.conkey[1] = pg_attribute.attnum and pg_class.relname = 'wmstest' and pg_table_is_visible(pg_class.oid) and pg_constraint.conkey[2] is null; +select 'MapServer2', "id",substr(encode(AsBinary(force_collection(force_2d("pt")),'NDR'),'base64'),0,16) as geom,"id" from wmstest where pt && GeomFromText('POLYGON((-98.5 32,-98.5 39,-91.5 39,-91.5 32,-98.5 32))',find_srid('','wmstest','pt')); + +-- MapServer 5.6 tests +select * from wmstest where false limit 0; +select 'MapServer3', attname from pg_attribute, pg_constraint, pg_class where pg_constraint.conrelid = pg_class.oid and pg_class.oid = pg_attribute.attrelid and pg_constraint.contype = 'p' and pg_constraint.conkey[1] = pg_attribute.attnum and pg_class.relname = 'wmstest' and pg_table_is_visible(pg_class.oid) and pg_constraint.conkey[2] is null; +select 'MapServer4', "id",substr(encode(AsBinary(force_collection(force_2d("pt")),'NDR'),'hex'),0,16) as geom,"id" from wmstest where pt && GeomFromText('POLYGON((-98.5 32,-98.5 39,-91.5 39,-91.5 32,-98.5 32))',find_srid('','wmstest','pt')); + +-- Drop the data table +SELECT 'Removing the data table...'; +DROP TABLE wmstest; +DELETE FROM geometry_columns WHERE f_table_name = 'wmstest' AND f_table_schema = 'public'; +SELECT 'Done.'; + +-- test #1869 ST_AsBinary is not unique -- +SELECT 1869 As ticket_id, ST_AsText(ST_AsBinary('POINT(1 2)')); + +DELETE FROM spatial_ref_sys WHERE SRID = '4326'; + +\i 00-regress-install/share/contrib/postgis/uninstall_legacy.sql diff --git a/regress/sfcgal/legacy_expected b/regress/sfcgal/legacy_expected new file mode 100644 index 000000000..d6f34e48f --- /dev/null +++ b/regress/sfcgal/legacy_expected @@ -0,0 +1,22 @@ +Starting up MapServer/Geoserver tests... +Setting up the data table... +public.wmstest.pt SRID:4326 TYPE:POLYGON DIMS:2 +ALTER TABLE +Running Geoserver 2.0 NG tests... +Geoserver1|POLYGON +Geoserver2|4326 +Geoserver3|-500|AAAAAAMAAAABAAA +Geoserver4|1 +Geoserver5|25|AAAAAAMAAAABAAA +Geoserver6|25|AAAAAAMAAAABAAA +MapServer1|id +MapServer2|-9465|AQcAAAABAAAAAQM|-9465 +MapServer2|-9460|AQcAAAABAAAAAQM|-9460 +MapServer3|id +MapServer4|-9465|010700000001000|-9465 +MapServer4|-9460|010700000001000|-9460 +Removing the data table... +Done. +1869|POINT(1 2) +BEGIN +COMMIT diff --git a/regress/sfcgal/measures.sql b/regress/sfcgal/measures.sql new file mode 100644 index 000000000..69b3a7952 --- /dev/null +++ b/regress/sfcgal/measures.sql @@ -0,0 +1,264 @@ +SET postgis.backend = 'sfcgal'; + +select '113', ST_area2d('MULTIPOLYGON( ((0 0, 10 0, 10 10, 0 10, 0 0)),( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5) ) ,( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7, 5 7, 5 5),(1 1,2 1, 2 2, 1 2, 1 1) ) )'::GEOMETRY) as value; + +select '114', ST_perimeter2d('MULTIPOLYGON( ((0 0, 10 0, 10 10, 0 10, 0 0)),( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5) ) ,( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7, 5 7, 5 5),(1 1,2 1, 2 2, 1 2, 1 1) ) )'::GEOMETRY) as value; + +select '115', ST_3DPerimeter('MULTIPOLYGON( ((0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0)),( (0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0),(5 5 0, 7 5 0, 7 7 0, 5 7 0, 5 5 0) ) ,( (0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1, 5 7 1, 5 5 1),(1 1 1,2 1 1, 2 2 1, 1 2 1, 1 1 1) ) )'::GEOMETRY) as value; + + +select '116', ST_length2d('MULTILINESTRING((0 0, 1 1),(0 0, 1 1, 2 2) )'::GEOMETRY) as value; +select '117', ST_3dlength('MULTILINESTRING((0 0, 1 1),(0 0, 1 1, 2 2) )'::GEOMETRY) as value; +select '118', ST_3dlength('MULTILINESTRING((0 0 0, 1 1 1),(0 0 0, 1 1 1, 2 2 2) )'::GEOMETRY) as value; + +select '134', ST_Distance('POINT(1 2)', 'POINT(1 2)'); +select '135', ST_Distance('POINT(5 0)', 'POINT(10 12)'); + +select '136', ST_Distance('POINT(0 0)', ST_translate('POINT(0 0)', 5, 12, 0)); + + +-- postgis-users/2006-May/012174.html +select 'dist', ST_Distance(a,b), ST_Distance(b,a) from ( + select 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry as a, + 'POLYGON((11 0, 11 10, 20 10, 20 0, 11 0), + (15 5, 15 8, 17 8, 17 5, 15 5))'::geometry as b + ) as foo; + +--#1502 +SELECT '#1502', ST_Dwithin(a,b,0.0) from +(SELECT 'LINESTRING(-97364 -97364, 9736.4 9736.4)'::geometry a, 'POINT(0 0)'::geometry b ) foo; + +--st_shortestline + +select 'st_shortestline_134', st_astext(st_shortestline('POINT(1 2)', 'POINT(1 2)')); +select 'st_shortestline_135', st_astext(st_shortestline('POINT(5 0)', 'POINT(10 12)')); + +select 'st_shortestline_136', st_astext(st_shortestline('POINT(0 0)', ST_translate('POINT(0 0)', 5, 12, 0))); + +-- postgis-users/2006-May/012174.html +select 'st_shortestline_dist', st_astext(st_shortestline(a,b)), st_astext(st_shortestline(b,a)) from ( + select 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry as a, + 'POLYGON((11 0, 12 10, 20 10, 20 0, 11 0), + (15 5, 15 8, 17 8, 17 5, 15 5))'::geometry as b + ) as foo; + + +--st_maxdistance + +select 'st_maxdistance_134', st_maxdistance('POINT(1 2)', 'POINT(1 2)'); +select 'st_maxdistance_135', st_maxdistance('POINT(5 0)', 'POINT(10 12)'); + +select 'st_maxdistance_136', st_maxdistance('POINT(0 0)', ST_translate('POINT(0 0)', 5, 12, 0)); + +-- postgis-users/2006-May/012174.html +select 'st_maxdistance_dist', st_maxdistance(a,b), st_maxdistance(b,a) from ( + select 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry as a, + 'POLYGON((11 0, 11 10, 20 10, 20 0, 11 0), + (15 5, 15 8, 17 8, 17 5, 15 5))'::geometry as b + ) as foo; + + + +--st_longestline + +select 'st_longestline_134', st_astext(st_longestline('POINT(1 2)', 'POINT(1 2)')); +select 'st_longestline_135', st_astext(st_longestline('POINT(5 0)', 'POINT(10 12)')); + +select 'st_longestline_136', st_astext(st_longestline('POINT(0 0)', ST_translate('POINT(0 0)', 5, 12, 0))); + +-- postgis-users/2006-May/012174.html +select 'st_longestline_dist', st_astext(st_longestline(a,b)), st_astext(st_longestline(b,a)) from ( + select 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry as a, + 'POLYGON((11 0, 11 10, 20 10, 20 0, 11 0), + (15 5, 15 8, 17 8, 17 5, 15 5))'::geometry as b + ) as foo; + +select 'distancetest1', + ST_Distance(a, b), + st_maxdistance(a, b), + st_astext(st_shortestline(a,b)), + st_astext(st_shortestline(b,a)), + st_astext(st_longestline(a,b)), + st_astext(st_longestline(b,a)) from ( +select + ST_GeomFromText('MULTILINESTRING((17 16, 16 17, 17 18, 17 17, 17 16), (28 35,29 39, 30 35))') as a, + ST_GeomFromText('MULTIPOLYGON(((-1 -1, -1 25, 25 25, 25 -1, -1 -1), (14 14,14 19,19 19,19 14,14 14)),((33 35,33 40, 35 40, 35 35, 33 35)))') as b +) as foo; + +select 'distancetest2', + ST_Distance(a, b), + st_maxdistance(a, b), + round(st_x(st_startpoint(st_shortestline(a,b)))::numeric, 10), + round(st_y(st_startpoint(st_shortestline(a,b)))::numeric, 10), + round(st_x(st_endpoint(st_shortestline(a,b)))::numeric, 10), + round(st_y(st_endpoint(st_shortestline(a,b)))::numeric, 10), + st_astext(st_longestline(a,b)), + st_astext(st_longestline(b,a)) from ( +select + ST_GeomFromText('LINESTRING(-40 -20 , 4 2)') as a, + ST_GeomFromText('LINESTRING(-10 20, 1 -2)') as b +) as foo; + +select 'distancepoly1', + ST_Distance(a, b), + st_maxdistance(a, b), + st_astext(st_shortestline(a,b)), + st_astext(st_shortestline(b,a)), + st_astext(st_longestline(a,b)), + st_astext(st_longestline(b,a)) from ( +select + ST_GeomFromText('MULTIPOLYGON(((17 16, 16 17, 17 18, 17 17, 17 16)), ((28 35,29 39, 30 35, 28 35)))') as a, + ST_GeomFromText('MULTIPOLYGON(((-1 -1, -1 25, 25 25, 25 -1, -1 -1), (14 14,14 19,19 19,19 14,14 14)),((33 35,33 40, 35 40, 35 35, 33 35)))') as b +) as foo; + +select 'distancepoly2', + ST_Distance(a, b), + st_maxdistance(a, b), + st_astext(st_shortestline(a,b)), + st_astext(st_shortestline(b,a)), + st_astext(st_longestline(a,b)), + st_astext(st_longestline(b,a)) from ( + select ST_GeomFromText('POLYGON((17 14, 16 17, 17 18, 17 17, 17 14))') as a, + ST_GeomFromText('POLYGON((-1 -1, -1 25, 25 25, 25 -1, -1 -1), (14 14,14 19,19 19,19 14,14 14))') as b + ) as foo; + + + +select 'distancepoly3', + ST_Distance(a, b), + st_maxdistance(a, b), + st_astext(st_shortestline(a,b)), + st_astext(st_shortestline(b,a)), + st_astext(st_longestline(a,b)), + st_astext(st_longestline(b,a)) from ( + select ST_GeomFromText('POLYGON((17 16, 16 17, 17 19, 17 17, 17 16))') as a, + ST_GeomFromText('POLYGON((-1 -1, -1 25, 25 25, 25 -1, -1 -1), (14 14,14 19,19 19,19 14,14 14))') as b + ) as foo; + + +select 'distancepoly4', + ST_Distance(a, b), + st_maxdistance(a, b), + st_astext(st_shortestline(a,b)), + st_astext(st_shortestline(b,a)), + st_astext(st_longestline(a,b)), + st_astext(st_longestline(b,a)) from ( + select ST_GeomFromText('POLYGON((17 16, 16 17, 16 20, 18 20, 18 17, 17 16))') as a, + ST_GeomFromText('POLYGON((-1 -1, -1 25, 25 25, 25 -1, -1 -1), (14 14,14 19,19 19,19 14,14 14))') as b + ) as foo; + + + +select 'distancepoly5', + ST_Distance(a, b), + st_maxdistance(a, b), + st_astext(st_shortestline(a,b)), + st_astext(st_shortestline(b,a)), + st_astext(st_longestline(a,b)), + st_astext(st_longestline(b,a)) from ( + select ST_GeomFromText('POLYGON((17 12, 16 17, 17 18, 17 17, 17 12))') as a, + ST_GeomFromText('POLYGON((-1 -1, -1 25, 25 25, 25 -1, -1 -1), (14 14,14 19,19 19,19 14,14 14))') as b + ) as foo; + + + + +select 'distancepoly6', + ST_Distance(a, b), + st_maxdistance(a, b), + st_astext(st_shortestline(a,b)), + st_astext(st_shortestline(b,a)), + st_astext(st_longestline(a,b)), + st_astext(st_longestline(b,a)) from ( + select ST_GeomFromText('POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))') as a, + ST_GeomFromText('POLYGON((-1 -1, -1 25, 25 25, 25 -1, -1 -1), (14 14,14 19,19 19,19 14,14 14))') as b + ) as foo; + +--3D Distance functions + + +SELECT '3dDistancetest1', + ST_3DDistance(a,b), + ST_3DMaxDistance(a,b), + ST_3DDWithin(a,b,5), + ST_3DDFullyWithin(a,b,5), + ST_ASEWKT(ST_3DShortestline(a,b)), + ST_ASEWKT(ST_3DClosestpoint(a,b)), + ST_ASEWKT(ST_3DLongestline(a,b)) FROM ( + SELECT 'POINT(1 1 1)'::geometry as a, 'POINT(3 2 7)'::geometry as b + ) as foo; + + +SELECT '3dDistancetest2', + ST_3DDistance(a,b), + ST_3DMaxDistance(a,b), + ST_3DDWithin(a,b,5), + ST_3DDFullyWithin(a,b,5), + ST_ASEWKT(ST_3DShortestline(a,b)), + ST_ASEWKT(ST_3DClosestpoint(a,b)), + ST_ASEWKT(ST_3DLongestline(a,b)) FROM ( + SELECT 'POINT(1 1 1)'::geometry as a, 'LINESTRING(0 0 0, 2 2 2)'::geometry as b + ) as foo; + + +SELECT '3dDistancetest3', + ST_3DDistance(a,b), + ST_3DMaxDistance(a,b), + ST_3DDWithin(a,b,5), + ST_3DDFullyWithin(a,b,5), + ST_ASEWKT(ST_SnapToGrid(ST_3DShortestline(a,b), 1e-14)), + ST_ASEWKT(ST_3DClosestpoint(a,b)), + ST_ASEWKT(ST_3DLongestline(a,b)) FROM ( + SELECT 'POINT(1 1 1)'::geometry as a, 'LINESTRING(5 2 6, -3 -2 4)'::geometry as b + ) as foo; + + +SELECT '3dDistancetest4', + ST_3DDistance(a,b), + ST_3DMaxDistance(a,b), + ST_3DDWithin(a,b,5), + ST_3DDFullyWithin(a,b,5), + ST_ASEWKT(ST_3DShortestline(a,b)), + ST_ASEWKT(ST_3DClosestpoint(a,b)), + ST_ASEWKT(ST_3DLongestline(a,b)) FROM ( + SELECT 'LINESTRING(1 1 3, 5 7 8)'::geometry as a, 'POINT(1 1 1)'::geometry as b + ) as foo; + + SELECT '3dDistancetest5', + ST_3DDistance(a,b), + ST_3DMaxDistance(a,b), + ST_3DDWithin(a,b,5), + ST_3DDFullyWithin(a,b,5), + ST_ASEWKT(ST_3DShortestline(a,b)), + ST_ASEWKT(ST_3DClosestpoint(a,b)), + ST_ASEWKT(ST_3DLongestline(a,b)) FROM ( + SELECT 'LINESTRING(1 0 5, 11 0 5)'::geometry as a, 'LINESTRING(5 2 0, 5 2 10, 5 0 13)'::geometry as b + ) as foo; + +SELECT '3dDistancetest6', + ST_3DDistance(a,b) FROM ( + SELECT 'LINESTRING(1 1 1 , 2 2 2)'::geometry as a, 'POLYGON((0 0 0, 2 2 2, 3 3 0, 0 0 0))'::geometry as b) as foo; + +-- Area of an empty polygon +select 'emptyPolyArea', st_area('POLYGON EMPTY'); + +-- Area of an empty linestring +select 'emptyLineArea', st_area('LINESTRING EMPTY'); + +-- Area of an empty point +select 'emptyPointArea', st_area('POINT EMPTY'); + +-- Area of an empty multipolygon +select 'emptyMultiPolyArea', st_area('MULTIPOLYGON EMPTY'); + +-- Area of an empty multilinestring +select 'emptyMultiLineArea', st_area('MULTILINESTRING EMPTY'); + +-- Area of an empty multilipoint +select 'emptyMultiPointArea', st_area('MULTIPOINT EMPTY'); + +-- Area of an empty collection +select 'emptyCollectionArea', st_area('GEOMETRYCOLLECTION EMPTY'); + +-- +select 'spheroidLength1', round(st_length_spheroid('MULTILINESTRING((-118.584 38.374,-118.583 38.5),(-71.05957 42.3589 , -71.061 43))'::geometry,'SPHEROID["GRS_1980",6378137,298.257222101]'::spheroid)::numeric,5); diff --git a/regress/sfcgal/measures_expected b/regress/sfcgal/measures_expected new file mode 100644 index 000000000..f945b1502 --- /dev/null +++ b/regress/sfcgal/measures_expected @@ -0,0 +1,45 @@ +113|291 +114|140 +115|140 +116|4.24264068711929 +117|4.24264068711929 +118|5.19615242270663 +134|0 +135|13 +136|13 +dist|1|1 +#1502|t +st_shortestline_134|LINESTRING(1 2,1 2) +st_shortestline_135|LINESTRING(5 0,10 12) +st_shortestline_136|LINESTRING(0 0,5 12) +st_shortestline_dist|LINESTRING(10 0,11 0)|LINESTRING(11 0,10 0) +st_maxdistance_134|0 +st_maxdistance_135|13 +st_maxdistance_136|13 +st_maxdistance_dist|22.3606797749979|22.3606797749979 +st_longestline_134|LINESTRING(1 2,1 2) +st_longestline_135|LINESTRING(5 0,10 12) +st_longestline_136|LINESTRING(0 0,5 12) +st_longestline_dist|LINESTRING(0 0,20 10)|LINESTRING(20 10,0 0) +distancetest1|1|50|LINESTRING(17 18,17 19)|LINESTRING(17 19,17 18)|LINESTRING(29 39,-1 -1)|LINESTRING(-1 -1,29 39) +distancetest2|0|50|0.0000000000|0.0000000000|0.0000000000|0.0000000000|LINESTRING(-40 -20,-10 20)|LINESTRING(-10 20,-40 -20) +distancepoly1|1|50|LINESTRING(17 18,17 19)|LINESTRING(17 19,17 18)|LINESTRING(29 39,-1 -1)|LINESTRING(-1 -1,29 39) +distancepoly2|0|26.1725046566048|LINESTRING(17 14,17 14)|LINESTRING(17 14,17 14)|LINESTRING(17 18,-1 -1)|LINESTRING(-1 -1,17 18) +distancepoly3|0|26.9072480941474|LINESTRING(17 19,17 19)|LINESTRING(17 19,17 19)|LINESTRING(17 19,-1 -1)|LINESTRING(-1 -1,17 19) +distancepoly4|0|28.3196045170126|LINESTRING(16 19,16 19)|LINESTRING(16 19,16 19)|LINESTRING(18 20,-1 -1)|LINESTRING(-1 -1,18 20) +distancepoly5|0|26.1725046566048|LINESTRING(17 12,17 12)|LINESTRING(17 12,17 12)|LINESTRING(17 18,-1 -1)|LINESTRING(-1 -1,17 18) +distancepoly6|0|32.5269119345812|LINESTRING(2 2,2 2)|LINESTRING(2 2,2 2)|LINESTRING(2 2,25 25)|LINESTRING(25 25,2 2) +3dDistancetest1|6.40312423743285|6.40312423743285|f|f|LINESTRING(1 1 1,3 2 7)|POINT(1 1 1)|LINESTRING(1 1 1,3 2 7) +3dDistancetest2|0|1.73205080756888|t|t|LINESTRING(1 1 1,1 1 1)|POINT(1 1 1)|LINESTRING(1 1 1,0 0 0) +3dDistancetest3|4.09994192757944|6.48074069840786|t|f|LINESTRING(1 1 1,0.61904761904762 -0.19047619047619 4.90476190476191)|POINT(1 1 1)|LINESTRING(1 1 1,5 2 6) +3dDistancetest4|2|10.0498756211209|t|f|LINESTRING(1 1 3,1 1 1)|POINT(1 1 3)|LINESTRING(5 7 8,1 1 1) +3dDistancetest5|2|10|t|f|LINESTRING(5 0 5,5 2 5)|POINT(5 0 5)|LINESTRING(11 0 5,5 0 13) +3dDistancetest6|0 +emptyPolyArea|0 +emptyLineArea|0 +emptyPointArea|0 +emptyMultiPolyArea|0 +emptyMultiLineArea|0 +emptyMultiPointArea|0 +emptyCollectionArea|0 +spheroidLength1|85204.52077 diff --git a/regress/sfcgal/regress.sql b/regress/sfcgal/regress.sql new file mode 100644 index 000000000..969a5289b --- /dev/null +++ b/regress/sfcgal/regress.sql @@ -0,0 +1,286 @@ +SET postgis.backend = 'sfcgal'; +--- regression test for postGIS + + + +--- assume datatypes already defined + + + +--- basic datatypes (correct) + +select '1',ST_asewkt('POINT( 1 2 )'::GEOMETRY) as geom; +select '2',ST_asewkt('POINT( 1 2 3)'::GEOMETRY) as geom; + +select '3',ST_asewkt('LINESTRING( 0 0, 1 1, 2 2, 3 3 , 4 4)'::GEOMETRY) as geom; +select '4',ST_asewkt('LINESTRING( 0 0 0 , 1 1 1 , 2 2 2 , 3 3 3, 4 4 4)'::GEOMETRY) as geom; +select '5',ST_asewkt('LINESTRING( 1 2 3 , 4 5 6 , 7 8 9 , 10 11 12, 13 14 15)'::GEOMETRY) as geom; + +select '6',ST_asewkt('POLYGON( (0 0, 10 0, 10 10, 0 10, 0 0) )'::GEOMETRY) as geom; +select '7',ST_asewkt('POLYGON( (0 0 1 , 10 0 1, 10 10 1, 0 10 1, 0 0 1) )'::GEOMETRY) as geom; +select '8',ST_asewkt('POLYGON( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5) )'::GEOMETRY) as geom; +select '9',ST_asewkt('POLYGON( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5),(1 1,2 1, 2 2, 1 2, 1 1) )'::GEOMETRY) as geom; +select '10',ST_asewkt('POLYGON( (0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1 , 5 7 1, 5 5 1) )'::GEOMETRY) as geom; +select '11',ST_asewkt('POLYGON( (0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1, 5 7 1, 5 5 1),(1 1 1,2 1 1, 2 2 1, 1 2 1, 1 1 1) )'::GEOMETRY) as geom; + +select '12',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 ))'::GEOMETRY); +select '13',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 3))'::GEOMETRY); +select '14',ST_asewkt('GEOMETRYCOLLECTION(LINESTRING( 0 0, 1 1, 2 2, 3 3 , 4 4))'::GEOMETRY); +select '15',ST_asewkt('GEOMETRYCOLLECTION(LINESTRING( 1 2 3 , 4 5 6 , 7 8 9 , 10 11 12, 13 14 15))'::GEOMETRY); +select '16',ST_asewkt('GEOMETRYCOLLECTION(POLYGON( (0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1 , 5 7 1, 5 5 1) ))'::GEOMETRY); +select '17',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 0),POINT( 1 2 3) )'::GEOMETRY); +select '18',ST_asewkt('GEOMETRYCOLLECTION(LINESTRING( 0 0 0, 1 1 0, 2 2 0, 3 3 0, 4 4 0),POINT( 1 2 3) )'::GEOMETRY); +select '19',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 ),LINESTRING( 0 0, 1 1, 2 2, 3 3 , 4 4) )'::GEOMETRY); +select '20',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 0 ),POINT( 1 2 3),LINESTRING( 1 2 3 , 4 5 6 , 7 8 9 , 10 11 12, 13 14 15) )'::GEOMETRY); +select '21',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 0 ),POINT( 1 2 3),LINESTRING( 1 2 3 , 4 5 6 , 7 8 9 , 10 11 12, 13 14 15),POLYGON( (0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0) ) )'::GEOMETRY); +select '22',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 0),POINT( 1 2 3),POLYGON( (0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1, 5 7 1, 5 5 1),(1 1 1,2 1 1, 2 2 1, 1 2 1, 1 1 1) ) )'::GEOMETRY); + +select '23',ST_asewkt('MULTIPOINT( 1 2)'::GEOMETRY) as geom; +select '24',ST_asewkt('MULTIPOINT( 1 2 3)'::GEOMETRY) as geom; +select '25',ST_asewkt('MULTIPOINT( 1 2, 3 4, 5 6)'::GEOMETRY) as geom; +select '26',ST_asewkt('MULTIPOINT( 1 2 3, 5 6 7, 8 9 10, 11 12 13)'::GEOMETRY) as geom; +select '27',ST_asewkt('MULTIPOINT( 1 2 0, 1 2 3, 4 5 0, 6 7 8)'::GEOMETRY) as geom; +select '28',ST_asewkt('MULTIPOINT( 1 2 3,4 5 0)'::GEOMETRY) as geom; + +select '29',ST_asewkt('MULTILINESTRING( (0 0, 1 1, 2 2, 3 3 , 4 4) )'::GEOMETRY) as geom; +select '30',ST_asewkt('MULTILINESTRING( (0 0, 1 1, 2 2, 3 3 , 4 4),(0 0, 1 1, 2 2, 3 3 , 4 4))'::GEOMETRY) as geom; +select '31',ST_asewkt('MULTILINESTRING( (0 0 0, 1 1 0, 2 2 0, 3 3 0, 4 4 0),(0 0 0, 1 1 0, 2 2 0, 3 3 0, 4 4 0),(1 2 3 , 4 5 6 , 7 8 9 , 10 11 12, 13 14 15) )'::GEOMETRY) as geom; +select '32',ST_asewkt('MULTILINESTRING( (1 2 3 , 4 5 6 , 7 8 9 , 10 11 12, 13 14 15),(0 0 0, 1 1 0, 2 2 0, 3 3 0, 4 4 0),(0 0 0, 1 1 0, 2 2 0, 3 3 0 , 4 4 0))'::GEOMETRY) as geom; + +select '33',ST_asewkt('MULTIPOLYGON( ((0 0, 10 0, 10 10, 0 10, 0 0)) )'::GEOMETRY) as geom; +select '34',ST_asewkt('MULTIPOLYGON( ((0 0, 10 0, 10 10, 0 10, 0 0)),( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5) ) )'::GEOMETRY) as geom; +select '35',ST_asewkt('MULTIPOLYGON( ((0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0)),( (0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0),(5 5 0, 7 5 0, 7 7 0, 5 7 0, 5 5 0) ) ,( (0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1, 5 7 1, 5 5 1),(1 1 1,2 1 1, 2 2 1, 1 2 1, 1 1 1) ) )'::GEOMETRY) as geom; + + +select '36',ST_asewkt('GEOMETRYCOLLECTION(MULTIPOINT( 1 2))'::GEOMETRY); +select '37',ST_asewkt('GEOMETRYCOLLECTION(MULTIPOINT( 1 2 3))'::GEOMETRY); +select '38',ST_asewkt('GEOMETRYCOLLECTION(MULTIPOINT( 1 2 3, 5 6 7, 8 9 10, 11 12 13))'::GEOMETRY); +select '39',ST_asewkt('GEOMETRYCOLLECTION(MULTILINESTRING( (0 0, 1 1, 2 2, 3 3 , 4 4) ))'::GEOMETRY); +select '40',ST_asewkt('GEOMETRYCOLLECTION(MULTILINESTRING( (1 2 3 , 4 5 6 , 7 8 9 , 10 11 12, 13 14 15),(0 0 0, 1 1 0, 2 2 0, 3 3 0, 4 4 0),(0 0 0, 1 1 0, 2 2 0, 3 3 0, 4 4 0)))'::GEOMETRY); +select '41',ST_asewkt('GEOMETRYCOLLECTION(MULTIPOLYGON( ((0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0)),( (0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0),(5 5 0, 7 5 0, 7 7 0, 5 7 0, 5 5 0) ) ,( (0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1, 5 7 1, 5 5 1),(1 1 1,2 1 1, 2 2 1, 1 2 1, 1 1 1) ) ))'::GEOMETRY); +select '42',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 0),MULTIPOINT( 1 2 3))'::GEOMETRY); +select '43',ST_asewkt('GEOMETRYCOLLECTION(MULTIPOINT( 1 2 0, 3 4 0, 5 6 0),POINT( 1 2 3))'::GEOMETRY); +select '44',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 3),MULTILINESTRING( (0 0 0, 1 1 0, 2 2 0, 3 3 0 , 4 4 0) ))'::GEOMETRY); +select '45',ST_asewkt('GEOMETRYCOLLECTION(MULTILINESTRING( (0 0 0, 1 1 0, 2 2 0, 3 3 0 , 4 4 0) ),POINT( 1 2 3))'::GEOMETRY); +select '46',ST_asewkt('GEOMETRYCOLLECTION(POINT( 1 2 3), MULTIPOLYGON( ((0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0)),( (0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0),(5 5 0, 7 5 0, 7 7 0, 5 7 0, 5 5 0) ) ,( (0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1, 5 7 1, 5 5 1),(1 1 1,2 1 1, 2 2 1, 1 2 1, 1 1 1) ) ))'::GEOMETRY); +select '47',ST_asewkt('GEOMETRYCOLLECTION(MULTIPOLYGON( ((0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0)),( (0 0 0, 10 0 0, 10 10 0, 0 10 0, 0 0 0),(5 5 0, 7 5 0, 7 7 0, 5 7 0, 5 5 0) ) ,( (0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1, 5 7 1, 5 5 1),(1 1 1,2 1 1, 2 2 1, 1 2 1, 1 1 1) ) ),MULTILINESTRING( (0 0 0, 1 1 0, 2 2 0, 3 3 0, 4 4 0),(0 0 0, 1 1 0, 2 2 0, 3 3 0, 4 4 0),(1 2 3 , 4 5 6 , 7 8 9 , 10 11 12, 13 14 15) ),MULTIPOINT( 1 2 3, 5 6 7, 8 9 10, 11 12 13))'::GEOMETRY); + +select '48',ST_asewkt('MULTIPOINT( -1 -2 -3, 5.4 6.6 7.77, -5.4 -6.6 -7.77, 1e6 1e-6 -1e6, -1.3e-6 -1.4e-5 0)'::GEOMETRY) as geom; + +select '49', ST_asewkt('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(1 1) ))'::GEOMETRY) as geom; +--- basic datatype (incorrect) + +select '50', 'POINT()'::GEOMETRY as geom; +select '51', 'POINT(1)'::GEOMETRY as geom; +select '52', 'POINT(,)'::GEOMETRY as geom; +select '53', 'MULTIPOINT(,)'::GEOMETRY as geom; +select '54', 'POINT(a b)'::GEOMETRY as geom; +select '55', 'MULTIPOINT()'::GEOMETRY as geom; +select '56', ST_asewkt('POLYGON( (0 0, 10 0, 10 10, 0 10) )'::GEOMETRY); +select '57', ST_asewkt('POLYGON( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7) )'::GEOMETRY); +select '58', ST_asewkt('MULTILINESTRING((0 0, 1 1),(0 0, 1 1, 2 2,) )'::GEOMETRY); + + +--- funny results + +select '59',ST_asewkt('POINT(1 2 3, 4 5 6)'::GEOMETRY); +select '60',ST_asewkt('POINT(1 2 3 4 5 6 7)'::GEOMETRY); +select '61',ST_asewkt('LINESTRING(1 1)'::GEOMETRY); +select '62',regexp_replace(ST_asewkt('POINT( 1e700 0)'::GEOMETRY), E'(Infinity|1\.#INF)', 'inf'); +select '63',regexp_replace(ST_asewkt('POINT( -1e700 0)'::GEOMETRY), E'(Infinity|1\.#INF)', 'inf'); +--select '62',ST_asewkt('POINT( 1e700 0)'::GEOMETRY); +--select '63',ST_asewkt('POINT( -1e700 0)'::GEOMETRY); +select '64',ST_asewkt('MULTIPOINT(1 1, 2 2'::GEOMETRY); + + +--- is_same() testing + +select '65','POINT(1 1)'::GEOMETRY ~= 'POINT(1 1)'::GEOMETRY as bool; +select '65a',ST_OrderingEquals('POINT(1 1)'::GEOMETRY,'POINT(1 1)'::GEOMETRY) as bool; +select '66','POINT(1 1 0)'::GEOMETRY ~= 'POINT(1 1)'::GEOMETRY as bool; +select '66a',ST_OrderingEquals('POINT(1 1 0)'::GEOMETRY,'POINT(1 1)'::GEOMETRY) as bool; +select '67','POINT(1 1 0)'::GEOMETRY ~= 'POINT(1 1 0)'::GEOMETRY as bool; +select '67a',ST_OrderingEquals('POINT(1 1 0)'::GEOMETRY,'POINT(1 1 0)'::GEOMETRY) as bool; + +select '68','MULTIPOINT(1 1,2 2)'::GEOMETRY ~= 'MULTIPOINT(1 1,2 2)'::GEOMETRY as bool; +select '68a',ST_OrderingEquals('MULTIPOINT(1 1,2 2)'::GEOMETRY,'MULTIPOINT(1 1,2 2)'::GEOMETRY) as bool; +select '69','MULTIPOINT(2 2, 1 1)'::GEOMETRY ~= 'MULTIPOINT(1 1,2 2)'::GEOMETRY as bool; +select '69a',ST_OrderingEquals('MULTIPOINT(2 2, 1 1)'::GEOMETRY,'MULTIPOINT(1 1,2 2)'::GEOMETRY) as bool; + +select '70','GEOMETRYCOLLECTION(POINT( 1 2 3),POINT(4 5 6))'::GEOMETRY ~= 'GEOMETRYCOLLECTION(POINT( 4 5 6),POINT(1 2 3))'::GEOMETRY as bool; +select '70a',ST_OrderingEquals('GEOMETRYCOLLECTION(POINT( 1 2 3),POINT(4 5 6))'::GEOMETRY,'GEOMETRYCOLLECTION(POINT( 4 5 6),POINT(1 2 3))'::GEOMETRY) as bool; +select '71','MULTIPOINT(4 5 6, 1 2 3)'::GEOMETRY ~= 'GEOMETRYCOLLECTION(POINT( 4 5 6),POINT(1 2 3))'::GEOMETRY as bool; +select '71a',ST_OrderingEquals('MULTIPOINT(4 5 6, 1 2 3)'::GEOMETRY,'GEOMETRYCOLLECTION(POINT( 4 5 6),POINT(1 2 3))'::GEOMETRY) as bool; +select '72','MULTIPOINT(1 2 3, 4 5 6)'::GEOMETRY ~= 'GEOMETRYCOLLECTION(POINT( 4 5 6),POINT(1 2 3))'::GEOMETRY as bool; +select '72a',ST_OrderingEquals('MULTIPOINT(1 2 3, 4 5 6)'::GEOMETRY,'GEOMETRYCOLLECTION(POINT( 4 5 6),POINT(1 2 3))'::GEOMETRY) as bool; +select '73','MULTIPOINT(1 2 3, 4 5 6)'::GEOMETRY ~= 'GEOMETRYCOLLECTION(MULTIPOINT(1 2 3, 4 5 6))'::GEOMETRY as bool; +select '73a',ST_OrderingEquals('MULTIPOINT(1 2 3, 4 5 6)'::GEOMETRY,'GEOMETRYCOLLECTION(MULTIPOINT(1 2 3, 4 5 6))'::GEOMETRY) as bool; + + +select '74','LINESTRING(1 1,2 2)'::GEOMETRY ~= 'POINT(1 1)'::GEOMETRY as bool; +select '74a',ST_OrderingEquals('LINESTRING(1 1,2 2)'::GEOMETRY,'POINT(1 1)'::GEOMETRY) as bool; +select '75','LINESTRING(1 1, 2 2)'::GEOMETRY ~= 'LINESTRING(2 2, 1 1)'::GEOMETRY as bool; +select '75a',ST_OrderingEquals('LINESTRING(1 1, 2 2)'::GEOMETRY,'LINESTRING(2 2, 1 1)'::GEOMETRY) as bool; +select '76','LINESTRING(1 1, 2 2)'::GEOMETRY ~= 'LINESTRING(1 1, 2 2, 3 3)'::GEOMETRY as bool; +select '76a',ST_OrderingEquals('LINESTRING(1 1, 2 2)'::GEOMETRY,'LINESTRING(1 1, 2 2, 3 3)'::GEOMETRY) as bool; + +--- operator testing (testing is on the BOUNDING BOX (2d), not the actual geometries) + +select '77','POINT(1 1)'::GEOMETRY &< 'POINT(1 1)'::GEOMETRY as bool; +select '78','POINT(1 1)'::GEOMETRY &< 'POINT(2 1)'::GEOMETRY as bool; +select '79','POINT(2 1)'::GEOMETRY &< 'POINT(1 1)'::GEOMETRY as bool; + +select '80','POINT(1 1)'::GEOMETRY << 'POINT(1 1)'::GEOMETRY as bool; +select '81','POINT(1 1)'::GEOMETRY << 'POINT(2 1)'::GEOMETRY as bool; +select '82','POINT(2 1)'::GEOMETRY << 'POINT(1 1)'::GEOMETRY as bool; + + +select '83','POINT(1 1)'::GEOMETRY &> 'POINT(1 1)'::GEOMETRY as bool; +select '84','POINT(1 1)'::GEOMETRY &> 'POINT(2 1)'::GEOMETRY as bool; +select '85','POINT(2 1)'::GEOMETRY &> 'POINT(1 1)'::GEOMETRY as bool; + +select '86','POINT(1 1)'::GEOMETRY >> 'POINT(1 1)'::GEOMETRY as bool; +select '87','POINT(1 1)'::GEOMETRY >> 'POINT(2 1)'::GEOMETRY as bool; +select '88','POINT(2 1)'::GEOMETRY >> 'POINT(1 1)'::GEOMETRY as bool; + +-- overlap + +select '89','POINT(1 1)'::GEOMETRY && 'POINT(1 1)'::GEOMETRY as bool; +select '90','POINT(1 1)'::GEOMETRY && 'POINT(2 2)'::GEOMETRY as bool; +select '91','MULTIPOINT(0 0, 1 1)'::GEOMETRY && 'MULTIPOINT(1 1, 2 2)'::GEOMETRY as bool; +select '92','MULTIPOINT(0 0, 1 1)'::GEOMETRY && 'MULTIPOINT(1.0001 1, 2 2)'::GEOMETRY as bool; +select '93','MULTIPOINT(0 0, 1 1)'::GEOMETRY && 'MULTIPOINT(1 1.0001, 2 2)'::GEOMETRY as bool; +select '94','MULTIPOINT(0 0, 1 1)'::GEOMETRY && 'MULTIPOINT(1 0, 2 2)'::GEOMETRY as bool; +select '95','MULTIPOINT(0 0, 1 1)'::GEOMETRY && 'MULTIPOINT(1.0001 0, 2 2)'::GEOMETRY as bool; + +select '96','MULTIPOINT(0 0, 1 1)'::GEOMETRY && 'MULTIPOINT(0 1, 1 2)'::GEOMETRY as bool; +select '97','MULTIPOINT(0 0, 1 1)'::GEOMETRY && 'MULTIPOINT(0 1.0001, 1 2)'::GEOMETRY as bool; + +--- contains + +select '98','MULTIPOINT(0 0, 10 10)'::GEOMETRY ~ 'MULTIPOINT(5 5, 7 7)'::GEOMETRY as bool; +select '99','MULTIPOINT(5 5, 7 7)'::GEOMETRY ~ 'MULTIPOINT(0 0, 10 10)'::GEOMETRY as bool; +select '100','MULTIPOINT(0 0, 7 7)'::GEOMETRY ~ 'MULTIPOINT(0 0, 10 10)'::GEOMETRY as bool; +select '101','MULTIPOINT(-0.0001 0, 7 7)'::GEOMETRY ~ 'MULTIPOINT(0 0, 10 10)'::GEOMETRY as bool; + +--- contained by + +select '102','MULTIPOINT(0 0, 10 10)'::GEOMETRY @ 'MULTIPOINT(5 5, 7 7)'::GEOMETRY as bool; +select '103','MULTIPOINT(5 5, 7 7)'::GEOMETRY @ 'MULTIPOINT(0 0, 10 10)'::GEOMETRY as bool; +select '104','MULTIPOINT(0 0, 7 7)'::GEOMETRY @ 'MULTIPOINT(0 0, 10 10)'::GEOMETRY as bool; +select '105','MULTIPOINT(-0.0001 0, 7 7)'::GEOMETRY @ 'MULTIPOINT(0 0, 10 10)'::GEOMETRY as bool; + + + +--- function testing +--- conversion function + +select '106',box3d('MULTIPOINT(0 0, 7 7)'::GEOMETRY) as bvol; + +-- box3d only type is only used for indexing -- NEVER use one yourself +select '107',ST_AsEWKT(geometry('BOX3D(0 0 0, 7 7 7 )'::BOX3D)); + +--- debug function testing + +select '108',ST_NPoints('MULTIPOINT(0 0, 7 7)'::GEOMETRY) as value; +select '109',ST_NPoints('GEOMETRYCOLLECTION(POINT(1 1), LINESTRING( 1 1 , 2 2, 3 3))'::GEOMETRY) as value; + +select '110', ST_NRings('MULTIPOLYGON( ((0 0, 10 0, 10 10, 0 10, 0 0)),( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5) ) ,( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7, 5 7, 5 5),(1 1,2 1, 2 2, 1 2, 1 1) ) )'::GEOMETRY) as value; + +select '111', ST_mem_size(PostGIS_DropBBOX('MULTIPOLYGON( ((0 0, 10 0, 10 10, 0 10, 0 0)),( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5) ) ,( (0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7, 5 7, 5 5),(1 1,2 1, 2 2, 1 2, 1 1) ) )'::GEOMETRY)) as value; + +select '112',ST_NumGeometries('GEOMETRYCOLLECTION(POINT(1 1), LINESTRING( 1 1 , 2 2, 3 3),MULTIPOINT(1 1, 2 2))'::GEOMETRY) as value; + +---selection + + + +--- TOAST testing + +-- create a table with data that will be TOASTed (even after compression) +create table TEST(a GEOMETRY, b GEOMETRY); +\i regress_biginsert.sql + + +---test basic ops on this + +select '121',box3d(a) as box3d_a, box3d(b) as box3d_b from TEST; + +select '122',a <>b from TEST; +select '125',a &>b from TEST; + +select '126',a ~= b from TEST; +select '127',a @ b from TEST; +select '128',a ~ b from TEST; + +select '129', ST_mem_size(PostGIS_DropBBOX(a)), ST_mem_size(PostGIS_DropBBOX(b)) from TEST; + +select '131', ST_X('POINT(1 2)'); +select '132', ST_Y('POINT(1 2)'); +select '133', ST_Z('POINT(1 2)'); +select '133a', ST_Z('POINT(1 2 3)'); +select '133b', ST_Z('POINTM(1 2 3)'); +select '133c', ST_M('POINT(1 2)'); +select '133d', ST_M('POINTM(1 2 4)'); +select '133e', ST_M('POINT(1 2 4)'); + +select '137', box3d('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY)'::geometry); +select '138', box3d('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY, POINT(0 0))'::geometry); + +select '139', ST_AsEWKT(ST_multi(ST_setsrid('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY, POINT(0 0))'::geometry, 2))); +select '140', ST_AsEWKT(ST_multi(ST_setsrid('POINT(2 2)'::geometry, 3))); +select '141', ST_AsEWKT(ST_multi(ST_setsrid('LINESTRING(2 2, 3 3)'::geometry, 4))); +select '142', ST_AsEWKT(ST_multi(ST_setsrid('LINESTRING(2 2, 3 3)'::geometry, 5))); +select '143', ST_AsEWKT(ST_multi(ST_setsrid('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))'::geometry, 6))); +select '143c1', ST_AsEWKT(ST_multi('CIRCULARSTRING(0 0, 1 1, 2 2)'::geometry)); +select '144', ST_AsEWKT(ST_force_3dm('POINT(1 2 3)')); +select '145', ST_AsEWKT(ST_force_3dz('POINTM(1 2 3)')); +select '146', ST_AsEWKT(ST_force_4d('POINTM(1 2 3)')); +select '147', ST_AsEWKT(ST_force_4d('POINT(1 2 3)')); + +select '148', ST_AsText(ST_segmentize('LINESTRING(0 0, 10 0)'::geometry, 5)); + +select '149', ST_AsText(ST_segmentize('GEOMETRYCOLLECTION EMPTY'::geometry, 0.5)); + +select '150', ST_AsEWKT(ST_force_collection(ST_setsrid('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))'::geometry, 6))); + +select '151', ST_MakeEnvelope(0, 0, 1, 1, 4326); +select '152', ST_SRID(ST_MakeEnvelope(0, 0, 1, 1, 4326)); +select '152.1', ST_SRID(ST_MakeEnvelope(0, 0, 1, 1)) = ST_SRID('POINT(0 0)'::geometry); +select '152.2', ST_SRID(ST_SetSRID(ST_MakeEnvelope(0, 0, 1, 1), 4326)); + +select '153', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(POINT(0 0))',1)); +select '154', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(0 0)))',1)); +select '155', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(0 0), POINT(1 1)))',1)); +select '156', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)))',1)); +select '157', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)))',2)); +select '158', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)),LINESTRING(2 2, 3 3))',2)); +select '159', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)),LINESTRING(2 2, 3 3))',3)); +select '160', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)),LINESTRING(2 2, 3 3))',1)); +select '161', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), GEOMETRYCOLLECTION(POINT(1 1))),LINESTRING(2 2, 3 3))',2)); +select '162', ST_MakeLine(ST_GeomFromText('POINT(-11.1111111 40)'),ST_GeomFromText('LINESTRING(-11.1111111 70,70 -11.1111111)')) As result; +select '163', ST_AsEWKT('POLYGON((0 0 0, 1 0 0, 1 1 0, 0 1 0, 0 0 0))'); +select '164', ST_AsEWKT('POLYGON((0 0 0, 1 0 0, 1 1 0, 0 1 0, 0 0 1))'); +select '165', ST_AsEWKT('POLYGON((0 0 0, 1 0 0, 1 1 0, 0 1 0, 0 0.1 1))'); +select '166', ST_AsText('POINT EMPTY'); +select '167', ST_AsText('LINESTRING EMPTY'); +select '168', ST_AsText('POLYGON EMPTY'); +select '169', ST_AsText('CIRCULARSTRING EMPTY'); +select '170', ST_AsText('COMPOUNDCURVE EMPTY'); +select '171', ST_AsText('CURVEPOLYGON EMPTY'); +select '172', ST_AsText('MULTIPOINT EMPTY'); +select '173', ST_AsText('MULTILINESTRING EMPTY'); +select '174', ST_AsText('MULTIPOLYGON EMPTY'); +select '175', ST_AsText('TRIANGLE EMPTY'); +select '176', ST_AsText('TIN EMPTY'); +select '177', ST_AsText('POLYHEDRALSURFACE EMPTY'); +select '178', ST_AsText('MULTISURFACE EMPTY'); +select '179', ST_AsText('MULTICURVE EMPTY'); +select '180', ST_AsText('GEOMETRYCOLLECTION EMPTY'); +select '181', ST_AsText('GEOMETRYCOLLECTION(TRIANGLE EMPTY,TIN EMPTY)'); + + +-- Drop test table +DROP table test; diff --git a/regress/sfcgal/regress_expected b/regress/sfcgal/regress_expected new file mode 100644 index 000000000..6c409ad42 --- /dev/null +++ b/regress/sfcgal/regress_expected @@ -0,0 +1,189 @@ +1|POINT(1 2) +2|POINT(1 2 3) +3|LINESTRING(0 0,1 1,2 2,3 3,4 4) +4|LINESTRING(0 0 0,1 1 1,2 2 2,3 3 3,4 4 4) +5|LINESTRING(1 2 3,4 5 6,7 8 9,10 11 12,13 14 15) +6|POLYGON((0 0,10 0,10 10,0 10,0 0)) +7|POLYGON((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1)) +8|POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5)) +9|POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5),(1 1,2 1,2 2,1 2,1 1)) +10|POLYGON((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1)) +11|POLYGON((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1),(1 1 1,2 1 1,2 2 1,1 2 1,1 1 1)) +12|GEOMETRYCOLLECTION(POINT(1 2)) +13|GEOMETRYCOLLECTION(POINT(1 2 3)) +14|GEOMETRYCOLLECTION(LINESTRING(0 0,1 1,2 2,3 3,4 4)) +15|GEOMETRYCOLLECTION(LINESTRING(1 2 3,4 5 6,7 8 9,10 11 12,13 14 15)) +16|GEOMETRYCOLLECTION(POLYGON((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1))) +17|GEOMETRYCOLLECTION(POINT(1 2 0),POINT(1 2 3)) +18|GEOMETRYCOLLECTION(LINESTRING(0 0 0,1 1 0,2 2 0,3 3 0,4 4 0),POINT(1 2 3)) +19|GEOMETRYCOLLECTION(POINT(1 2),LINESTRING(0 0,1 1,2 2,3 3,4 4)) +20|GEOMETRYCOLLECTION(POINT(1 2 0),POINT(1 2 3),LINESTRING(1 2 3,4 5 6,7 8 9,10 11 12,13 14 15)) +21|GEOMETRYCOLLECTION(POINT(1 2 0),POINT(1 2 3),LINESTRING(1 2 3,4 5 6,7 8 9,10 11 12,13 14 15),POLYGON((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0))) +22|GEOMETRYCOLLECTION(POINT(1 2 0),POINT(1 2 3),POLYGON((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1),(1 1 1,2 1 1,2 2 1,1 2 1,1 1 1))) +23|MULTIPOINT(1 2) +24|MULTIPOINT(1 2 3) +25|MULTIPOINT(1 2,3 4,5 6) +26|MULTIPOINT(1 2 3,5 6 7,8 9 10,11 12 13) +27|MULTIPOINT(1 2 0,1 2 3,4 5 0,6 7 8) +28|MULTIPOINT(1 2 3,4 5 0) +29|MULTILINESTRING((0 0,1 1,2 2,3 3,4 4)) +30|MULTILINESTRING((0 0,1 1,2 2,3 3,4 4),(0 0,1 1,2 2,3 3,4 4)) +31|MULTILINESTRING((0 0 0,1 1 0,2 2 0,3 3 0,4 4 0),(0 0 0,1 1 0,2 2 0,3 3 0,4 4 0),(1 2 3,4 5 6,7 8 9,10 11 12,13 14 15)) +32|MULTILINESTRING((1 2 3,4 5 6,7 8 9,10 11 12,13 14 15),(0 0 0,1 1 0,2 2 0,3 3 0,4 4 0),(0 0 0,1 1 0,2 2 0,3 3 0,4 4 0)) +33|MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0))) +34|MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0)),((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5))) +35|MULTIPOLYGON(((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0)),((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0),(5 5 0,7 5 0,7 7 0,5 7 0,5 5 0)),((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1),(1 1 1,2 1 1,2 2 1,1 2 1,1 1 1))) +36|GEOMETRYCOLLECTION(MULTIPOINT(1 2)) +37|GEOMETRYCOLLECTION(MULTIPOINT(1 2 3)) +38|GEOMETRYCOLLECTION(MULTIPOINT(1 2 3,5 6 7,8 9 10,11 12 13)) +39|GEOMETRYCOLLECTION(MULTILINESTRING((0 0,1 1,2 2,3 3,4 4))) +40|GEOMETRYCOLLECTION(MULTILINESTRING((1 2 3,4 5 6,7 8 9,10 11 12,13 14 15),(0 0 0,1 1 0,2 2 0,3 3 0,4 4 0),(0 0 0,1 1 0,2 2 0,3 3 0,4 4 0))) +41|GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0)),((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0),(5 5 0,7 5 0,7 7 0,5 7 0,5 5 0)),((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1),(1 1 1,2 1 1,2 2 1,1 2 1,1 1 1)))) +42|GEOMETRYCOLLECTION(POINT(1 2 0),MULTIPOINT(1 2 3)) +43|GEOMETRYCOLLECTION(MULTIPOINT(1 2 0,3 4 0,5 6 0),POINT(1 2 3)) +44|GEOMETRYCOLLECTION(POINT(1 2 3),MULTILINESTRING((0 0 0,1 1 0,2 2 0,3 3 0,4 4 0))) +45|GEOMETRYCOLLECTION(MULTILINESTRING((0 0 0,1 1 0,2 2 0,3 3 0,4 4 0)),POINT(1 2 3)) +46|GEOMETRYCOLLECTION(POINT(1 2 3),MULTIPOLYGON(((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0)),((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0),(5 5 0,7 5 0,7 7 0,5 7 0,5 5 0)),((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1),(1 1 1,2 1 1,2 2 1,1 2 1,1 1 1)))) +47|GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0)),((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0),(5 5 0,7 5 0,7 7 0,5 7 0,5 5 0)),((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1),(1 1 1,2 1 1,2 2 1,1 2 1,1 1 1))),MULTILINESTRING((0 0 0,1 1 0,2 2 0,3 3 0,4 4 0),(0 0 0,1 1 0,2 2 0,3 3 0,4 4 0),(1 2 3,4 5 6,7 8 9,10 11 12,13 14 15)),MULTIPOINT(1 2 3,5 6 7,8 9 10,11 12 13)) +48|MULTIPOINT(-1 -2 -3,5.4 6.6 7.77,-5.4 -6.6 -7.77,1000000 1e-6 -1000000,-1.3e-6 -1.4e-5 0) +49|GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(1 1))) +ERROR: parse error - invalid geometry at character 14 +ERROR: parse error - invalid geometry at character 14 +ERROR: parse error - invalid geometry at character 14 +ERROR: parse error - invalid geometry at character 14 +ERROR: parse error - invalid geometry at character 14 +ERROR: parse error - invalid geometry at character 14 +ERROR: geometry contains non-closed rings at character 24 +ERROR: geometry contains non-closed rings at character 24 +ERROR: parse error - invalid geometry at character 24 +ERROR: geometry has too many points at character 23 +ERROR: parse error - invalid geometry at character 23 +ERROR: geometry requires more points at character 23 +62|POINT(inf 0) +63|POINT(-inf 0) +ERROR: parse error - invalid geometry at character 23 +65|t +65a|t +66|t +66a|f +67|t +67a|t +68|t +68a|t +69|t +69a|f +70|t +70a|f +71|t +71a|f +72|t +72a|f +73|t +73a|f +74|f +74a|f +75|t +75a|f +76|f +76a|f +77|t +78|t +79|f +80|f +81|t +82|f +83|t +84|f +85|t +86|f +87|f +88|t +89|t +90|f +91|t +92|f +93|f +94|t +95|f +96|t +97|f +98|t +99|f +100|f +101|f +102|f +103|t +104|t +105|f +106|BOX3D(0 0 0,7 7 0) +107|POLYGON((0 0,0 7,7 7,7 0,0 0)) +108|2 +109|4 +110|6 +111|552 +112|3 +121|BOX3D(1.19894826 1.20265412 0,999.932129 999.692932 0)|BOX3D(1.40486765 1.3484304 0,999.857666 999.936401 0) +122|f +123|f +124|f +125|f +126|f +127|f +128|f +129|48016|48016 +131|1 +132|2 +133| +133a|3 +133b| +133c| +133d|4 +133e| +137| +138|BOX3D(0 0 0,0 0 0) +139|SRID=2;GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY,POINT(0 0)) +140|SRID=3;MULTIPOINT(2 2) +141|SRID=4;MULTILINESTRING((2 2,3 3)) +142|SRID=5;MULTILINESTRING((2 2,3 3)) +143|SRID=6;MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0))) +143c1|MULTICURVE(CIRCULARSTRING(0 0,1 1,2 2)) +144|POINTM(1 2 0) +145|POINT(1 2 0) +146|POINT(1 2 0 3) +147|POINT(1 2 3 0) +148|LINESTRING(0 0,5 0,10 0) +149|GEOMETRYCOLLECTION EMPTY +150|SRID=6;GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))) +151|0103000020E61000000100000005000000000000000000000000000000000000000000000000000000000000000000F03F000000000000F03F000000000000F03F000000000000F03F000000000000000000000000000000000000000000000000 +152|4326 +152.1|t +152.2|4326 +153|MULTIPOINT(0 0) +154|MULTIPOINT(0 0) +155|MULTIPOINT(0 0,1 1) +156|MULTIPOINT(1 1) +157|MULTILINESTRING((0 0,1 1)) +158|MULTILINESTRING((0 0,1 1),(2 2,3 3)) +159|MULTIPOLYGON EMPTY +160|MULTIPOINT(1 1) +161|MULTILINESTRING((0 0,1 1),(2 2,3 3)) +162|010200000003000000F771D98DE33826C00000000000004440F771D98DE33826C000000000008051400000000000805140F771D98DE33826C0 +163|POLYGON((0 0 0,1 0 0,1 1 0,0 1 0,0 0 0)) +164|POLYGON((0 0 0,1 0 0,1 1 0,0 1 0,0 0 1)) +ERROR: geometry contains non-closed rings +166|POINT EMPTY +167|LINESTRING EMPTY +168|POLYGON EMPTY +169|CIRCULARSTRING EMPTY +170|COMPOUNDCURVE EMPTY +171|CURVEPOLYGON EMPTY +172|MULTIPOINT EMPTY +173|MULTILINESTRING EMPTY +174|MULTIPOLYGON EMPTY +175|TRIANGLE EMPTY +176|TIN EMPTY +177|POLYHEDRALSURFACE EMPTY +178|MULTISURFACE EMPTY +179|MULTICURVE EMPTY +180|GEOMETRYCOLLECTION EMPTY +181|GEOMETRYCOLLECTION(TRIANGLE EMPTY,TIN EMPTY) diff --git a/regress/sfcgal/regress_ogc.sql b/regress/sfcgal/regress_ogc.sql new file mode 100644 index 000000000..8203f6686 --- /dev/null +++ b/regress/sfcgal/regress_ogc.sql @@ -0,0 +1,153 @@ +--- +--- SFCGAL backend tests based on GEOS/JTS implemented functions +--- +--- + +SET postgis.backend = 'sfcgal'; + +-- Repeat all tests with new function names. +SELECT 'buffer', ST_astext(ST_SnapToGrid(ST_buffer('POINT(0 0)', 1, 2), 1.0e-6)); + +SELECT 'geomunion', ST_astext(ST_union('POINT(0 0)', 'POINT(1 1)')); +SELECT 'convexhull', ST_asewkt(ST_convexhull('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0),(2 2, 2 4, 4 4, 4 2, 2 2))')); +SELECT 'relate', ST_relate('POINT(0 0)', 'LINESTRING(0 0, 1 1)'); +SELECT 'relate', ST_relate('POINT(0 0)', 'LINESTRING(0 0, 1 1)', 'F0FFFF*02'); +SELECT 'relate', ST_relate('POINT(0 0)', 'LINESTRING(0 0, 1 1)', 'F0FFF0*02'); +SELECT 'disjoint', ST_disjoint('POINT(0 0)', 'LINESTRING(0 0, 1 1)'); +SELECT 'touches', ST_touches('LINESTRING(0 10, 0 -10)', 'LINESTRING(0 0, 1 1)'); +SELECT 'intersects', ST_intersects('LINESTRING(0 10, 0 -10)', 'LINESTRING(0 0, 1 1)'); +SELECT 'crosses', ST_crosses('LINESTRING(0 10, 0 -10)', 'LINESTRING(0 0, 1 1)'); +SELECT 'crosses', ST_crosses('LINESTRING(0 10, 0 -10)', 'LINESTRING(-4 0, 1 1)'); +-- PIP - point within polygon +SELECT 'within100', ST_within('POINT(5 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point on vertex of polygon +SELECT 'within101', ST_within('POINT(0 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point outside polygon +SELECT 'within102', ST_within('POINT(-1 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point on edge of polygon +SELECT 'within103', ST_within('POINT(0 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point in line with polygon edge +SELECT 'within104', ST_within('POINT(0 12)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point vertically aligned with polygon vertex +SELECT 'within105', ST_within(ST_GeomFromText('POINT(521513 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)); +-- PIP - repeated vertex +SELECT 'within106', ST_within(ST_GeomFromText('POINT(521513 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)); +-- PIP - point within polygon +SELECT 'disjoint100', ST_disjoint('POINT(5 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point on polygon vertex +SELECT 'disjoint101', ST_disjoint('POINT(0 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point outside polygon +SELECT 'disjoint102', ST_disjoint('POINT(-1 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point on polygon edge +SELECT 'disjoint103', ST_disjoint('POINT(0 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point in line with polygon edge +SELECT 'disjoint104', ST_disjoint('POINT(0 12)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point vertically aligned with polygon vertex +SELECT 'disjoint105', ST_disjoint(ST_GeomFromText('POINT(521513 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)); +-- PIP - repeated vertex +SELECT 'disjoint106', ST_disjoint(ST_GeomFromText('POINT(521543 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)); +-- PIP - point within polygon +SELECT 'disjoint150', ST_disjoint('POINT(5 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point on polygon vertex +SELECT 'disjoint151', ST_disjoint('POINT(0 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point outside polygon +SELECT 'disjoint152', ST_disjoint('POINT(-1 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point on polygon edge +SELECT 'disjoint153', ST_disjoint('POINT(0 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point in line with polygon edge +SELECT 'disjoint154', ST_disjoint('POINT(0 12)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point vertically aligned with polygon vertex +SELECT 'disjoint155', ST_disjoint(ST_GeomFromText('POINT(521513 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)); +-- PIP - repeated vertex +SELECT 'disjoint156', ST_disjoint(ST_GeomFromText('POINT(521543 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)); +-- PIP - point within polygon +SELECT 'intersects100', ST_intersects('POINT(5 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point on polygon vertex +SELECT 'intersects101', ST_intersects('POINT(0 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point outside polygon +SELECT 'intersects102', ST_intersects('POINT(-1 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point on polygon edge +SELECT 'intersects103', ST_intersects('POINT(0 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point in line with polygon edge +SELECT 'intersects104', ST_intersects('POINT(0 12)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point vertically aligned with polygon vertex +SELECT 'intersects105', ST_intersects(ST_GeomFromText('POINT(521513 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)); +-- PIP - repeated vertex +SELECT 'intersects106', ST_intersects(ST_GeomFromText('POINT(521543 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)); +-- PIP - point within polygon +SELECT 'intersects150', ST_intersects('POINT(5 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point on polygon vertex +SELECT 'intersects151', ST_intersects('POINT(0 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point outside polygon +SELECT 'intersects152', ST_intersects('POINT(-1 0)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point on polygon edge +SELECT 'intersects153', ST_intersects('POINT(0 5)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point in line with polygon edge +SELECT 'intersects154', ST_intersects('POINT(0 12)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +-- PIP - point vertically aligned with polygon vertex +SELECT 'intersects155', ST_intersects(ST_GeomFromText('POINT(521513 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)); +-- PIP - repeated vertex +SELECT 'intersects156', ST_intersects(ST_GeomFromText('POINT(521543 5377804)', 32631), ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)); +-- PIP - point within polygon +SELECT 'contains100', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'); +-- PIP - point on vertex of polygon +SELECT 'contains101', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 0)'); +-- PIP - point outside polygon +SELECT 'contains102', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(-1 0)'); +-- PIP - point on edge of polygon +SELECT 'contains103', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 5)'); +-- PIP - point in line with polygon edge +SELECT 'contains104', ST_contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 12)'); +-- PIP - point vertically aligned with polygon vertex +SELECT 'contains105', ST_contains(ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631), ST_GeomFromText('POINT(521513 5377804)', 32631)); +-- PIP - repeated vertex +SELECT 'contains106', ST_contains(ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631), ST_GeomFromText('POINT(521513 5377804)', 32631)); +-- moved here from regress.sql +select 'within119', ST_within('LINESTRING(-1 -1, -1 101, 101 101, 101 -1)'::GEOMETRY,'BOX3D(0 0, 100 100)'::BOX3D); +select 'within120', ST_within('LINESTRING(-1 -1, -1 100, 101 100, 101 -1)'::GEOMETRY,'BOX3D(0 0, 100 100)'::BOX3D); +SELECT 'contains110', ST_Contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'LINESTRING(1 10, 9 10, 9 8)'); +SELECT 'contains111', ST_Contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'LINESTRING(1 10, 10 10, 10 8)'); +SELECT 'within130', ST_Within('LINESTRING(1 10, 9 10, 9 8)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +SELECT 'within131', ST_Within('LINESTRING(1 10, 10 10, 10 8)', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +SELECT 'overlaps', ST_overlaps('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))','POINT(5 5)'); +SELECT 'isvalid', ST_isvalid('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'); +SELECT 'isvalid', ST_isvalid('POLYGON((0 0, 0 10, 10 10, -5 10, 10 0, 0 0))'); +SELECT 'isvalid', ST_isvalid('GEOMETRYCOLLECTION EMPTY'); +SELECT 'intersection', ST_astext(ST_intersection('LINESTRING(0 10, 0 -10)', 'LINESTRING(0 0, 1 1)')); +SELECT 'difference', ST_astext(ST_difference('LINESTRING(0 10, 0 -10)'::GEOMETRY, 'LINESTRING(0 2, 0 -2)'::GEOMETRY)); +SELECT 'boundary', ST_astext(ST_boundary('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0),(2 2, 2 4, 4 4, 4 2, 2 2))')); +SELECT 'symdifference', ST_astext(ST_symdifference('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0),(2 2, 2 4, 4 4, 4 2, 2 2))', 'LINESTRING(0 0, 20 20)')); +SELECT 'issimple', ST_issimple('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0),(2 2, 2 4, 4 4, 4 2, 2 2))'); +SELECT 'equals', ST_equals('LINESTRING(0 0, 1 1)', 'LINESTRING(1 1, 0 0)'); +WITH inp AS ( SELECT + 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0),(2 2, 2 4, 4 4, 4 2, 2 2))' +::geometry as g ) +SELECT 'pointonsurface', ST_Contains(g, ST_pointonsurface(g)) from inp; +SELECT 'centroid', ST_astext(ST_centroid('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0),(2 2, 2 4, 4 4, 4 2, 2 2))')); +SELECT 'exteriorring', ST_astext(ST_exteriorring(ST_PolygonFromText('POLYGON((52 18,66 23,73 9,48 6,52 18),(59 18,67 18,67 13,59 13,59 18))'))); +SELECT 'polygonize_garray', ST_astext(ST_polygonize('{0102000000020000000000000000000000000000000000000000000000000024400000000000000000:0102000000020000000000000000002440000000000000000000000000000000000000000000000000:0102000000020000000000000000002440000000000000244000000000000000000000000000000000:0102000000020000000000000000002440000000000000244000000000000024400000000000000000:0102000000020000000000000000002440000000000000244000000000000000000000000000002440:0102000000020000000000000000000000000000000000244000000000000000000000000000002440:0102000000020000000000000000000000000000000000244000000000000024400000000000002440:0102000000020000000000000000000000000000000000244000000000000000000000000000000000:0102000000020000000000000000000000000000000000244000000000000024400000000000000000}'::geometry[])); + +SELECT 'polygonize_garray', ST_astext(ST_geometryn(ST_polygonize('{LINESTRING(0 0, 10 0):LINESTRING(10 0, 10 10):LINESTRING(10 10, 0 10):LINESTRING(0 10, 0 0)}'::geometry[]), 1)); + +select 'linemerge149', ST_asewkt(ST_linemerge('GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), LINESTRING(4 4, 1 1), LINESTRING(-5 -5, 0 0))'::geometry)); + +--- postgis-devel/2005-December/001784.html +select 'intersects', ST_intersects( + ST_polygonfromtext('POLYGON((0.0 0.0,1.0 0.0,1.0 1.0,1.0 0.0,0.0 0.0))'), + ST_polygonfromtext('POLYGON((0.0 2.0,1.0 2.0,1.0 3.0,0.0 3.0,0.0 2.0))') + ); + +select 'ST_GeometryN', ST_asewkt(ST_GeometryN('LINESTRING(0 0, 1 1)'::geometry, 1)); +select 'ST_NumGeometries', ST_NumGeometries('LINESTRING(0 0, 1 1)'::geometry); +select 'ST_Union1', ST_AsText(ST_Union(ARRAY['POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))'::geometry, 'POLYGON((0.5 0.5, 1.5 0.5, 1.5 1.5, 0.5 1.5, 0.5 0.5))'::geometry])); +select 'ST_StartPoint1',ST_AsText(ST_StartPoint('LINESTRING(0 0, 1 1, 2 2)')); +select 'ST_EndPoint1', ST_AsText(ST_Endpoint('LINESTRING(0 0, 1 1, 2 2)')); +select 'ST_PointN1', ST_AsText(ST_PointN('LINESTRING(0 0, 1 1, 2 2)',2)); +select 'ST_PointN2', ST_AsText(ST_PointN('LINESTRING(0 0, 1 1, 2 2)',3)); +select 'ST_PointN3', ST_AsText(ST_PointN('LINESTRING(0 0, 1 1, 2 2)',4)); +select 'ST_PointN4', ST_AsText(ST_PointN('LINESTRING(0 0, 1 1, 2 2)',0)); +select 'ST_PointN5', ST_AsText(ST_PointN('LINESTRING(0 0, 1 1, 2 2)',1)); +select 'ST_PointN6', ST_AsText(ST_PointN('POLYGON((0 0, 1 1, 0 1, 0 0))',1)); + +-- issues with EMPTY -- +select 'ST_Buffer(empty)', ST_AsText(ST_Buffer('POLYGON EMPTY', 0.5)); diff --git a/regress/sfcgal/regress_ogc_expected b/regress/sfcgal/regress_ogc_expected new file mode 100644 index 000000000..cd05535d0 --- /dev/null +++ b/regress/sfcgal/regress_ogc_expected @@ -0,0 +1,89 @@ +buffer|POLYGON((1 0,0.707107 -0.707107,0 -1,-0.707107 -0.707107,-1 0,-0.707107 0.707107,0 1,0.707107 0.707107,1 0)) +geomunion|MULTIPOINT(0 0,1 1) +convexhull|POLYGON((0 0,0 10,10 10,10 0,0 0)) +relate|F0FFFF102 +relate|t +relate|f +disjoint|f +touches|t +intersects|t +crosses|f +crosses|t +within100|t +within101|f +within102|f +within103|f +within104|f +within105|t +within106|t +disjoint100|f +disjoint101|f +disjoint102|t +disjoint103|f +disjoint104|t +disjoint105|f +disjoint106|t +disjoint150|f +disjoint151|f +disjoint152|t +disjoint153|f +disjoint154|t +disjoint155|f +disjoint156|t +intersects100|t +intersects101|t +intersects102|f +intersects103|t +intersects104|f +intersects105|t +intersects106|f +intersects150|t +intersects151|t +intersects152|f +intersects153|t +intersects154|f +intersects155|t +intersects156|f +contains100|t +contains101|f +contains102|f +contains103|f +contains104|f +contains105|t +contains106|t +within119|f +within120|f +contains110|t +contains111|f +within130|t +within131|f +overlaps|f +isvalid|t +NOTICE: Self-intersection +isvalid|f +isvalid|t +intersection|POINT(-0 -0) +difference|MULTILINESTRING((0 10,0 2),(0 -2,0 -10)) +boundary|MULTILINESTRING((0 0,0 10,10 10,10 0,0 0),(2 2,2 4,4 4,4 2,2 2)) +symdifference|GEOMETRYCOLLECTION(LINESTRING(2 2,4 4),LINESTRING(10 10,20 20),POLYGON((0 0,0 10,10 10,10 0,0 0),(4 4,2 4,2 2,4 2,4 4))) +issimple|t +equals|t +pointonsurface|t +centroid|POINT(5.08333333333333 5.08333333333333) +exteriorring|LINESTRING(52 18,66 23,73 9,48 6,52 18) +polygonize_garray|GEOMETRYCOLLECTION EMPTY +polygonize_garray|POLYGON((10 0,0 0,0 10,10 10,10 0)) +linemerge149|LINESTRING(-5 -5,0 0,1 1,4 4) +intersects|f +ST_GeometryN|LINESTRING(0 0,1 1) +ST_NumGeometries|1 +ST_Union1|POLYGON((0 0,0 1,0.5 1,0.5 1.5,1.5 1.5,1.5 0.5,1 0.5,1 0,0 0)) +ST_StartPoint1|POINT(0 0) +ST_EndPoint1|POINT(2 2) +ST_PointN1|POINT(1 1) +ST_PointN2|POINT(2 2) +ST_PointN3| +ST_PointN4| +ST_PointN5|POINT(0 0) +ST_PointN6| +ST_Buffer(empty)|POLYGON EMPTY diff --git a/regress/sfcgal/regress_ogc_prep.sql b/regress/sfcgal/regress_ogc_prep.sql new file mode 100644 index 000000000..a4e53ece6 --- /dev/null +++ b/regress/sfcgal/regress_ogc_prep.sql @@ -0,0 +1,300 @@ +--- +--- 9DIM Tests based on GEOS/JTS ones +--- +--- + +SET postgis.backend = 'sfcgal'; + +SELECT c, ST_Intersects(ply, pt) FROM +( VALUES +-- PIP - point within polygon (no cache) +('intersects099', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), +-- PIP - point within polygon +('intersects100', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), +-- PIP - point on polygon vertex +('intersects101', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 0)'), +-- PIP - point outside polygon +('intersects102', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(-1 0)'), +-- PIP - point on polygon edge +('intersects103', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 5)'), +-- PIP - point in line with polygon edge +('intersects104', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 12)') +) AS v(c,ply,pt); + +SELECT c, ST_Contains(ply, pt) FROM +( VALUES +-- PIP - point within polygon (no cache) +('contains099', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), +-- PIP - point within polygon +('contains100', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), +-- PIP - point on polygon vertex +('contains101', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 0)'), +-- PIP - point outside polygon +('contains102', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(-1 0)'), +-- PIP - point on polygon edge +('contains103', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 5)'), +-- PIP - point in line with polygon edge +('contains104', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 12)') +) AS v(c,ply,pt); + +SELECT c, ST_Covers(ply, pt) FROM +( VALUES +-- PIP - point within polygon (no cache) +('covers099', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), +-- PIP - point within polygon +('covers100', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), +-- PIP - point on polygon vertex +('covers101', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 0)'), +-- PIP - point outside polygon +('covers102', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(-1 0)'), +-- PIP - point on polygon edge +('covers103', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 5)'), +-- PIP - point in line with polygon edge +('covers104', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 12)') +) AS v(c,ply,pt); + +SELECT c, ST_ContainsProperly(ply, pt) FROM +( VALUES +-- PIP - point within polygon (no cache) +('containsproperly099', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), +-- PIP - point within polygon +('containsproperly100', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), +-- PIP - point on polygon vertex +('containsproperly101', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 0)'), +-- PIP - point outside polygon +('containsproperly102', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(-1 0)'), +-- PIP - point on polygon edge +('containsproperly103', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 5)'), +-- PIP - point in line with polygon edge +('containsproperly104', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(0 12)') +) AS v(c,ply,pt); + + +-- PIP - point vertically aligned with polygon vertex, poly first +SELECT 'intersects105', ST_Intersects(p, ST_GeomFromText('POINT(521513 5377804)', 32631)) FROM +( VALUES + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) +) AS v(p); +-- PIP - point vertically aligned with polygon vertex, point first +SELECT 'intersects106', ST_Intersects(ST_GeomFromText('POINT(521513 5377804)', 32631), p) FROM +( VALUES + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) +) AS v(p); +-- PIP - repeated vertex, poly first +SELECT 'intersects107', ST_Intersects(p, ST_GeomFromText('POINT(521543 5377804)', 32631)) FROM +( VALUES + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) +) AS v(p); +-- PIP - repeated vertex, point first +SELECT 'intersects108', ST_Intersects(ST_GeomFromText('POINT(521543 5377804)', 32631), p) FROM +( VALUES + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) +) AS v(p); + + +-- PIP - point vertically aligned with polygon vertex, poly first +SELECT 'contains105', ST_Contains(p, ST_GeomFromText('POINT(521513 5377804)', 32631)) FROM +( VALUES + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) +) AS v(p); +-- PIP - point vertically aligned with polygon vertex, point first +SELECT 'contains106', ST_Contains(ST_GeomFromText('POINT(521513 5377804)', 32631), p) FROM +( VALUES + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) +) AS v(p); +-- PIP - repeated vertex, poly first +SELECT 'contains107', ST_Contains(p, ST_GeomFromText('POINT(521543 5377804)', 32631)) FROM +( VALUES + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) +) AS v(p); +-- PIP - repeated vertex, point first +SELECT 'contains108', ST_Contains(ST_GeomFromText('POINT(521543 5377804)', 32631), p) FROM +( VALUES + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) +) AS v(p); + +-- PIP - point vertically aligned with polygon vertex, poly first +SELECT 'containsproperly105', ST_ContainsProperly(p, ST_GeomFromText('POINT(521513 5377804)', 32631)) FROM +( VALUES + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) +) AS v(p); +-- PIP - point vertically aligned with polygon vertex, point first +SELECT 'containsproperly106', ST_ContainsProperly(ST_GeomFromText('POINT(521513 5377804)', 32631), p) FROM +( VALUES + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) +) AS v(p); +-- PIP - repeated vertex, poly first +SELECT 'containsproperly107', ST_ContainsProperly(p, ST_GeomFromText('POINT(521543 5377804)', 32631)) FROM +( VALUES + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) +) AS v(p); +-- PIP - repeated vertex, point first +SELECT 'containsproperly108', ST_ContainsProperly(ST_GeomFromText('POINT(521543 5377804)', 32631), p) FROM +( VALUES + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) +) AS v(p); + +-- PIP - point vertically aligned with polygon vertex, poly first +SELECT 'covers105', ST_Covers(p, ST_GeomFromText('POINT(521513 5377804)', 32631)) FROM +( VALUES + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) +) AS v(p); +-- PIP - point vertically aligned with polygon vertex, point first +SELECT 'covers106', ST_Covers(ST_GeomFromText('POINT(521513 5377804)', 32631), p) FROM +( VALUES + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521481 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) +) AS v(p); +-- PIP - repeated vertex, poly first +SELECT 'covers107', ST_Covers(p, ST_GeomFromText('POINT(521543 5377804)', 32631)) FROM +( VALUES + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) +) AS v(p); +-- PIP - repeated vertex, point first +SELECT 'covers108', ST_Covers(ST_GeomFromText('POINT(521543 5377804)', 32631), p) FROM +( VALUES + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)), + (ST_GeomFromText('POLYGON((521526 5377783, 521482 5377811, 521494 5377832, 521539 5377804, 521526 5377783))', 32631)) +) AS v(p); + + +SELECT c, ST_Intersects(p1, p2) AS intersects_p1p2, ST_Intersects(p2, p1) AS intersects_p2p1 FROM +( VALUES +('intersects200', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), +('intersects201', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), +('intersects202', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))'), +('intersects203', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((-5 -5, 5 -5, 5 5, -5 5, -5 -5))'), +('intersects204', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((-2 -2, -2 -3, -3 -3, -3 -2, -2 -2))'), +('intersects205', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), +('intersects206', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), +('intersects207', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))'), +('intersects208', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((-5 -5, 5 -5, 5 5, -5 5, -5 -5))'), +('intersects209', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((-2 -2, -2 -3, -3 -3, -3 -2, -2 -2))') +) AS v(c,p1,p2); + +SELECT c, ST_Contains(p1, p2) AS contains_p1p2, ST_Contains(p2, p1) AS contains_p2p1 FROM +( VALUES +('contains200', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), +('contains201', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), +('contains202', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))'), +('contains203', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((-5 -5, 5 -5, 5 5, -5 5, -5 -5))'), +('contains204', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((-2 -2, -2 -3, -3 -3, -3 -2, -2 -2))'), +('contains205', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), +('contains206', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), +('contains207', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))'), +('contains208', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((-5 -5, 5 -5, 5 5, -5 5, -5 -5))'), +('contains209', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((-2 -2, -2 -3, -3 -3, -3 -2, -2 -2))') +) AS v(c,p1,p2); + +SELECT c, ST_ContainsProperly(p1, p2) AS containsproperly_p1p2, ST_ContainsProperly(p2, p1) AS containsproperly_p2p1 FROM +( VALUES +('containsproperly200', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), +('containsproperly201', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), +('containsproperly202', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))'), +('containsproperly203', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((-5 -5, 5 -5, 5 5, -5 5, -5 -5))'), +('containsproperly204', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((-2 -2, -2 -3, -3 -3, -3 -2, -2 -2))'), +('containsproperly205', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), +('containsproperly206', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), +('containsproperly207', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))'), +('containsproperly208', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((-5 -5, 5 -5, 5 5, -5 5, -5 -5))'), +('containsproperly209', 'POLYGON((0 0, 0 10, 10 11, 10 0, 0 0))', 'POLYGON((-2 -2, -2 -3, -3 -3, -3 -2, -2 -2))') +) AS v(c,p1,p2); + +SELECT c, ST_Covers(p1, p2) AS covers_p1p2, ST_Covers(p2, p1) AS covers_p2p1 FROM +( VALUES +('covers200', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), +('covers201', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), +('covers202', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))'), +('covers203', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((-5 -5, 5 -5, 5 5, -5 5, -5 -5))'), +('covers204', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((-2 -2, -2 -3, -3 -3, -3 -2, -2 -2))'), +('covers205', 'POLYGON((0 0, 0 10, 10 10, 11 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), +('covers206', 'POLYGON((0 0, 0 10, 10 10, 11 0, 0 0))', 'POLYGON((2 2, 2 3, 3 3, 3 2, 2 2))'), +('covers207', 'POLYGON((0 0, 0 10, 10 10, 11 0, 0 0))', 'POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))'), +('covers208', 'POLYGON((0 0, 0 10, 10 10, 11 0, 0 0))', 'POLYGON((-5 -5, 5 -5, 5 5, -5 5, -5 -5))'), +('covers209', 'POLYGON((0 0, 0 10, 10 10, 11 0, 0 0))', 'POLYGON((-2 -2, -2 -3, -3 -3, -3 -2, -2 -2))') +) AS v(c,p1,p2); + +-- UNEXPECTED GEOMETRY TYPES -- + +SELECT c, ST_Contains(p1, p2) AS contains_p1p2, ST_Contains(p2, p1) AS contains_p2p1, + ST_Covers(p1, p2) AS covers_p1p2, ST_Covers(p2, p1) AS covers_p2p1, + ST_Intersects(p1, p2) AS intersects_p1p2, ST_Intersects(p2, p1) AS intersects_p2p1, + ST_ContainsProperly(p1, p2) AS containsproper_p1p2, ST_ContainsProperly(p2, p1) AS containsproper_p2p1 + FROM +( VALUES +('types100', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), +('types101', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), +('types102', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POINT(5 5)'), +('types103', 'LINESTRING(0 0, 0 10, 10 10, 10 0)', 'POINT(5 5)'), +('types104', 'LINESTRING(0 0, 0 10, 10 10, 10 0)', 'POINT(5 5)'), +('types105', 'LINESTRING(0 0, 0 10, 10 10, 10 0)', 'POINT(5 5)'), +('types106', 'POINT(5 5)', 'POINT(5 5)'), +('types107', 'POINT(5 5)', 'POINT(5 5)'), +('types108', 'POINT(5 5)', 'POINT(5 5)'), +('types109', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'), +('types110', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'), +('types111', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'), +('types112', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'LINESTRING(0 0, 0 10, 10 10, 10 0)'), +('types113', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'LINESTRING(0 0, 0 10, 10 10, 10 0)'), +('types114', 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', 'LINESTRING(0 0, 0 10, 10 10, 10 0)') +) AS v(c,p1,p2); + + +SELECT 'intersects310', ST_intersects('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', p) FROM ( VALUES +('LINESTRING(1 10, 9 10, 9 8)'),('LINESTRING(1 10, 9 10, 9 8)'),('LINESTRING(1 10, 9 10, 9 8)') +) AS v(p); +SELECT 'intersects311', ST_intersects('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', p) FROM ( VALUES +('LINESTRING(1 10, 10 10, 10 8)'),('LINESTRING(1 10, 10 10, 10 8)'),('LINESTRING(1 10, 10 10, 10 8)') +) AS v(p); + +SELECT 'contains310', ST_Contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', p) FROM ( VALUES +('LINESTRING(1 10, 9 10, 9 8)'),('LINESTRING(1 10, 9 10, 9 8)'),('LINESTRING(1 10, 9 10, 9 8)') +) AS v(p); +SELECT 'contains311', ST_Contains('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', p) FROM ( VALUES +('LINESTRING(1 10, 10 10, 10 8)'),('LINESTRING(1 10, 10 10, 10 8)'),('LINESTRING(1 10, 10 10, 10 8)') +) AS v(p); + +SELECT 'containsproperly310', ST_ContainsProperly('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', p) FROM ( VALUES +('LINESTRING(1 10, 9 10, 9 8)'),('LINESTRING(1 10, 9 10, 9 8)'),('LINESTRING(1 10, 9 10, 9 8)') +) AS v(p); +SELECT 'containsproperly311', ST_ContainsProperly('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', p) FROM ( VALUES +('LINESTRING(1 10, 10 10, 10 8)'),('LINESTRING(1 10, 10 10, 10 8)'),('LINESTRING(1 10, 10 10, 10 8)') +) AS v(p); + +SELECT 'covers310', ST_Covers('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', p) FROM ( VALUES +('LINESTRING(1 10, 9 10, 9 8)'),('LINESTRING(1 10, 9 10, 9 8)'),('LINESTRING(1 10, 9 10, 9 8)') +) AS v(p); +SELECT 'covers311', ST_Covers('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))', p) FROM ( VALUES +('LINESTRING(1 10, 10 10, 10 8)'),('LINESTRING(1 10, 10 10, 10 8)'),('LINESTRING(1 10, 10 10, 10 8)') +) AS v(p); + diff --git a/regress/sfcgal/regress_ogc_prep_expected b/regress/sfcgal/regress_ogc_prep_expected new file mode 100644 index 000000000..4600388de --- /dev/null +++ b/regress/sfcgal/regress_ogc_prep_expected @@ -0,0 +1,151 @@ +intersects099|t +intersects100|t +intersects101|t +intersects102|f +intersects103|t +intersects104|f +contains099|t +contains100|t +contains101|f +contains102|f +contains103|f +contains104|f +covers099|t +covers100|t +covers101|t +covers102|f +covers103|t +covers104|f +containsproperly099|t +containsproperly100|t +containsproperly101|f +containsproperly102|f +containsproperly103|f +containsproperly104|f +intersects105|t +intersects105|t +intersects105|t +intersects106|t +intersects106|t +intersects106|t +intersects107|f +intersects107|f +intersects107|f +intersects108|f +intersects108|f +intersects108|f +contains105|t +contains105|t +contains105|t +contains106|f +contains106|f +contains106|f +contains107|f +contains107|f +contains107|f +contains108|f +contains108|f +contains108|f +containsproperly105|t +containsproperly105|t +containsproperly105|t +containsproperly106|f +containsproperly106|f +containsproperly106|f +containsproperly107|f +containsproperly107|f +containsproperly107|f +containsproperly108|f +containsproperly108|f +containsproperly108|f +covers105|t +covers105|t +covers105|t +covers106|f +covers106|f +covers106|f +covers107|f +covers107|f +covers107|f +covers108|f +covers108|f +covers108|f +intersects200|t|t +intersects201|t|t +intersects202|t|t +intersects203|t|t +intersects204|f|f +intersects205|t|t +intersects206|t|t +intersects207|t|t +intersects208|t|t +intersects209|f|f +contains200|t|f +contains201|t|f +contains202|t|f +contains203|f|f +contains204|f|f +contains205|t|f +contains206|t|f +contains207|t|f +contains208|f|f +contains209|f|f +containsproperly200|t|f +containsproperly201|t|f +containsproperly202|f|f +containsproperly203|f|f +containsproperly204|f|f +containsproperly205|t|f +containsproperly206|t|f +containsproperly207|f|f +containsproperly208|f|f +containsproperly209|f|f +covers200|t|f +covers201|t|f +covers202|t|f +covers203|f|f +covers204|f|f +covers205|t|f +covers206|t|f +covers207|t|f +covers208|f|f +covers209|f|f +types100|t|f|t|f|t|t|t|f +types101|t|f|t|f|t|t|t|f +types102|t|f|t|f|t|t|t|f +types103|f|f|f|f|f|f|f|f +types104|f|f|f|f|f|f|f|f +types105|f|f|f|f|f|f|f|f +types106|t|t|t|t|t|t|t|t +types107|t|t|t|t|t|t|t|t +types108|t|t|t|t|t|t|t|t +types109|t|t|t|t|t|t|f|f +types110|t|t|t|t|t|t|f|f +types111|t|t|t|t|t|t|f|f +types112|f|f|t|f|t|t|f|f +types113|f|f|t|f|t|t|f|f +types114|f|f|t|f|t|t|f|f +intersects310|t +intersects310|t +intersects310|t +intersects311|t +intersects311|t +intersects311|t +contains310|t +contains310|t +contains310|t +contains311|f +contains311|f +contains311|f +containsproperly310|f +containsproperly310|f +containsproperly310|f +containsproperly311|f +containsproperly311|f +containsproperly311|f +covers310|t +covers310|t +covers310|t +covers311|t +covers311|t +covers311|t diff --git a/regress/sfcgal/tickets.sql b/regress/sfcgal/tickets.sql new file mode 100644 index 000000000..d3f7c3bca --- /dev/null +++ b/regress/sfcgal/tickets.sql @@ -0,0 +1,826 @@ +-- +-- Regression tests that were filed as cases in bug tickets, +-- referenced by bug number for historical interest. +-- + +SET postgis.backend = 'sfcgal'; + +-- NOTE: some tests _require_ spatial_ref_sys entries. +-- In particular, the GML output ones want auth_name and auth_srid too, +-- so we provide one for EPSG:4326 +DELETE FROM spatial_ref_sys; +INSERT INTO spatial_ref_sys ( srid, proj4text ) VALUES ( 32611, '+proj=utm +zone=11 +ellps=WGS84 +datum=WGS84 +units=m +no_defs' ); +INSERT INTO spatial_ref_sys ( auth_name, auth_srid, srid, proj4text ) VALUES ( 'EPSG', 4326, 4326, '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs' ); +INSERT INTO spatial_ref_sys ( srid, proj4text ) VALUES ( 32602, '+proj=utm +zone=2 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ' ); +INSERT INTO spatial_ref_sys ( srid, proj4text ) VALUES ( 32702, '+proj=utm +zone=2 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ' ); +INSERT INTO spatial_ref_sys ( srid, proj4text ) VALUES ( 3395, '+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ' ); + +INSERT INTO spatial_ref_sys (srid,proj4text) VALUES (32707,'+proj=utm +zone=7 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs '); + + +-- #2 -- +SELECT '#2', ST_AsText(ST_Union(g)) FROM +( VALUES +('SRID=4326;MULTIPOLYGON(((1 1,1 2,2 2,2 1,1 1)))'), +('SRID=4326;MULTIPOLYGON(((2 1,3 1,3 2,2 2,2 1)))') +) AS v(g); + +-- #11 -- +SELECT '#11', round(ST_Distance (a.g, ST_Intersection(b.g, a.g))) AS distance +FROM (SELECT '01020000000200000050E8303FC2E85141B017CFC05A825541000000E0C0E85141000000205C825541'::geometry AS g) a, + (SELECT 'LINESTRING(4694792.35840419 5638508.89950758,4694793.20840419 5638506.34950758)'::geometry AS g) b; + +-- #21 -- +SELECT '#21', ST_AsEWKT(ST_Locate_Along_Measure(g, 4566)) FROM +( VALUES +(ST_GeomFromEWKT('SRID=31293;LINESTRINGM( 6193.76 5337404.95 4519, 6220.13 5337367.145 4566, 6240.889 5337337.383 4603 )')) +) AS v(g); + +-- #22 -- +SELECT ST_Within(g, 'POLYGON((0 0,10 0,20 10,10 20,0 20,-10 10,0 0))') FROM +(VALUES +('POLYGON((4 9,6 9,6 11,4 11,4 9))') +) AS v(g); + +-- #33 -- +CREATE TABLE road_pg (ID INTEGER, NAME VARCHAR(32)); +SELECT '#33', AddGeometryColumn( '', 'public', 'road_pg','roads_geom', 330000, 'POINT', 2 ); +DROP TABLE road_pg; + +-- #44 -- +SELECT '#44', ST_Relate(g1, g2, 'T12101212'), ST_Relate(g1, g2, 't12101212') FROM +(VALUES +('POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))', 'POLYGON((1 1, 3 1, 3 3, 1 3, 1 1))') +) AS v(g1, g2); + +-- #58 -- +SELECT '#58', round(ST_xmin(g)),round(ST_ymin(g)),round(ST_xmax(g)),round(ST_ymax(g)) FROM (SELECT ST_Envelope('CIRCULARSTRING(220268.439465645 150415.359530563,220227.333322076 150505.561285879,220227.353105332 150406.434743975)') as g) AS foo; + +-- #65 -- +SELECT '#65', ST_AsGML(ST_GeometryFromText('CURVEPOLYGON(CIRCULARSTRING(4 2,3 -1.0,1 -1,-1.0 4,4 2))')); + +-- #66 -- +SELECT '#66', ST_AsText((ST_Dump(ST_GeomFromEWKT('CIRCULARSTRING(0 0,1 1,2 2)'))).geom); + +-- #68 -- +SELECT '#68a', ST_AsText(ST_Shift_Longitude(ST_GeomFromText('MULTIPOINT(1 3, 4 5)'))); +SELECT '#68b', ST_AsText(ST_Shift_Longitude(ST_GeomFromText('CIRCULARSTRING(1 3, 4 5, 6 7)'))); + +-- #69 -- +SELECT '#69', ST_AsText(ST_Translate(ST_GeomFromText('CIRCULARSTRING(220268 150415,220227 150505,220227 150406)'),1,2)); + +-- #70 -- +SELECT '#70', ST_NPoints(ST_LinetoCurve(ST_Buffer('POINT(1 2)',3))); + +-- #73 -- +SELECT '#73', ST_AsText(ST_Force_Collection(ST_GeomFromEWKT('CIRCULARSTRING(1 1, 2 3, 4 5, 6 7, 5 6)'))); + +-- #80 -- +SELECT '#80', ST_AsText(ST_Multi('MULTILINESTRING((0 0,1 1))')); + +-- #83 -- +SELECT '#83', ST_AsText(ST_Multi(ST_GeomFromText('CIRCULARSTRING(220268 150415,220227 150505,220227 150406)'))); + +-- #85 -- +SELECT '#85', ST_Distance(ST_GeomFromText('CIRCULARSTRING(220268 150415,220227 150505,220227 150406)'), ST_Point(220268, 150415)); + +-- #112 -- +SELECT '#112', ST_AsText(ST_CurveToLine('GEOMETRYCOLLECTION(POINT(-10 50))'::geometry)); + +-- #113 -- +SELECT '#113', ST_Locate_Along_Measure('LINESTRING(0 0 0, 1 1 1)', 0.5); + +-- #116 -- +SELECT '#116', ST_AsText('010300000000000000'); + +-- #122 -- +SELECT '#122', ST_AsText(ST_SnapToGrid(ST_GeomFromText('CIRCULARSTRING(220268 150415,220227 150505,220227 150406)'), 0.1)); + +-- #124 -- +SELECT '#124a', ST_AsText(ST_GeomFromEWKT('COMPOUNDCURVE(CIRCULARSTRING(0 0,1 1,1 0),(1 0,30 5),CIRCULARSTRING(30 5,34 56,67 89))')); +SELECT '#124b', ST_AsText(ST_GeomFromEWKT('COMPOUNDCURVE(CIRCULARSTRING(0 0,1 1,1 0),(1 0,30 6),CIRCULARSTRING(30 5,34 56,67 89))')); + +-- #145 -- +SELECT '#145a', ST_Buffer(ST_GeomFromText('LINESTRING(-116.93414544665981 34.16033385105459,-116.87777514700957 34.10831080544884,-116.86972224705954 34.086748622072776,-116.9327074288116 34.08458099517253,-117.00216369088065 34.130329331330216,-117.00216369088065 34.130329331330216)', 4326), 0); +SELECT '#145b', ST_Area(ST_Buffer(ST_GeomFromText('LINESTRING(-116.93414544665981 34.16033385105459,-116.87777514700957 34.10831080544884,-116.86972224705954 34.086748622072776,-116.9327074288116 34.08458099517253,-117.00216369088065 34.130329331330216,-117.00216369088065 34.130329331330216)', 4326), 0)); + +-- #146 -- +SELECT '#146', ST_Distance(g1,g2), ST_Dwithin(g1,g2,0.01), ST_AsEWKT(g2) FROM (SELECT ST_geomFromEWKT('LINESTRING(1 2, 2 4)') As g1, ST_Collect(ST_GeomFromEWKT('LINESTRING(0 0, -1 -1)'), ST_GeomFromEWKT('MULTIPOINT(1 2,2 3)')) As g2) As foo; + +-- #156 -- +SELECT '#156', ST_AsEWKT('0106000000010000000103000000010000000700000024213D12AA7BFD40945FF42576511941676A32F9017BFD40B1D67BEA7E511941C3E3C640DB7DFD4026CE38F4EE531941C91289C5A7EFD40017B8518E3531941646F1599AB7DFD409627F1F0AE521941355EBA49547CFD407B14AEC74652194123213D12AA7BFD40945FF42576511941'); + +-- #157 -- +SELECT + '#157', + ST_GeometryType(g) As newname, + GeometryType(g) as oldname +FROM ( VALUES + (ST_GeomFromText('POLYGON((-0.25 -1.25,-0.25 1.25,2.5 1.25,2.5 -1.25,-0.25 -1.25), (2.25 0,1.25 1,1.25 -1,2.25 0),(1 -1,1 1,0 0,1 -1))') ), + ( ST_Point(1,2) ), + ( ST_Buffer(ST_Point(1,2), 3) ), + ( ST_LineToCurve(ST_Buffer(ST_Point(1,2), 3)) ) , + ( ST_LineToCurve(ST_Boundary(ST_Buffer(ST_Point(1,2), 3))) ) + ) AS v(g); + + +-- #168 -- +SELECT '#168', ST_NPoints(g), ST_AsText(g), ST_isValidReason(g) +FROM ( VALUES +('01060000C00100000001030000C00100000003000000E3D9107E234F5041A3DB66BC97A30F4122ACEF440DAF9440FFFFFFFFFFFFEFFFE3D9107E234F5041A3DB66BC97A30F4122ACEF440DAF9440FFFFFFFFFFFFEFFFE3D9107E234F5041A3DB66BC97A30F4122ACEF440DAF9440FFFFFFFFFFFFEFFF'::geometry) +) AS v(g); + +-- #175 -- +SELECT '#175', ST_AsEWKT(ST_GeomFromEWKT('SRID=26915;POINT(482020 4984378.)')); + +-- #178 -- +SELECT '#178a', ST_XMin(ST_MakeBox2D(ST_Point(5, 5), ST_Point(0, 0))); +SELECT '#178b', ST_XMax(ST_MakeBox2D(ST_Point(5, 5), ST_Point(0, 0))); + +-- #179 -- +SELECT '#179a', ST_MakeLine(ARRAY[NULL,NULL,NULL,NULL]); +SELECT '#179b', ST_MakeLine(ARRAY[NULL,NULL,NULL,NULL]); + +-- #183 -- +SELECT '#183', ST_AsText(ST_SnapToGrid(ST_LineToCurve(ST_LineMerge(ST_Collect(ST_CurveToLine(ST_GeomFromEWKT('CIRCULARSTRING(0 0, 1 1, 1 0)')),ST_GeomFromEWKT('LINESTRING(1 0, 0 1)') ))), 1E-10)); + +-- #210 -- +SELECT '#210a', ST_Union(ARRAY[NULL,NULL,NULL,NULL]) ; +SELECT '#210b', ST_MakeLine(ARRAY[NULL,NULL,NULL,NULL]) ; + +-- #213 -- +SELECT '#213', round(ST_Perimeter(ST_CurveToLine(ST_GeomFromEWKT('CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0,2 0, 2 1, 2 3, 4 3),(4 3, 4 5, 1 4, 0 0)))')))); + +-- #234 -- +SELECT '#234', ST_AsText(ST_GeomFromText('COMPOUNDCURVE( (0 0,1 1) )')); + +-- #239 -- +--SELECT '#239', ST_AsSVG('010700002031BF0D0000000000'); + +-- #241 -- +CREATE TABLE c ( the_geom GEOMETRY); +INSERT INTO c SELECT ST_MakeLine(ST_Point(-10,40),ST_Point(40,-10)) As the_geom; +INSERT INTO c SELECT ST_MakeLine(ST_Point(-10,40),ST_Point(40,-10)) As the_geom; +SELECT '#241', sum(ST_LineCrossingDirection(the_geom, ST_GeomFromText('LINESTRING(1 2,3 4)'))) FROM c; +DROP TABLE c; + +-- #254 -- +SELECT '#254', ST_Segmentize(ST_GeomFromText('GEOMETRYCOLLECTION EMPTY'), 0.5); + +-- #259 -- +SELECT '#259', ST_Distance(ST_GeographyFromText('SRID=4326;POLYGON EMPTY'), ST_GeographyFromText('SRID=4326;POINT(1 2)')); + +-- #260 -- +SELECT '#260', round(ST_Distance(ST_GeographyFromText('SRID=4326;POINT(-10 40)'), ST_GeographyFromText('SRID=4326;POINT(-10 55)'))); + +-- #261 -- +SELECT '#261', ST_Distance(ST_GeographyFromText('SRID=4326;POINT(-71.0325022849392 42.3793285830812)'),ST_GeographyFromText('SRID=4326;POLYGON((-71.0325022849392 42.3793285830812,-71.0325745928559 42.3793012556699,-71.0326708728343 42.3794450989722,-71.0326045866257 42.3794706688942,-71.0325022849392 42.3793285830812))')); + +-- #262 -- +SELECT '#262', ST_AsText(pt.the_geog) As wkt_pt, ST_Covers(poly.the_geog, pt.the_geog) As geog, + ST_Covers( + ST_Transform(CAST(poly.the_geog As geometry),32611), + ST_Transform(CAST(pt.the_geog As geometry),32611)) As utm, + ST_Covers( + CAST(poly.the_geog As geometry), + CAST(pt.the_geog As geometry) + ) As pca +FROM (SELECT ST_GeographyFromText('SRID=4326;POLYGON((-119.5434 34.9438,-119.5437 34.9445,-119.5452 34.9442,-119.5434 34.9438))') As the_geog) + As poly + CROSS JOIN + (VALUES + ( ST_GeographyFromText('SRID=4326;POINT(-119.5434 34.9438)') ) , + ( ST_GeographyFromText('SRID=4326;POINT(-119.5452 34.9442)') ) , + ( ST_GeographyFromText('SRID=4326;POINT(-119.5434 34.9438)') ), + ( ST_GeographyFromText('SRID=4326;POINT(-119.5438 34.9443)') ) + ) + As pt(the_geog); + +-- #263 -- +SELECT '#263', ST_AsEWKT(geometry(geography(pt.the_geom))) As wkt, + ST_Covers( + ST_Transform(poly.the_geom,32611), + ST_Transform(pt.the_geom,32611)) As utm, + ST_Covers( + poly.the_geom, + pt.the_geom) + As pca, + ST_Covers(geometry(geography(poly.the_geom)), + geometry(geography(pt.the_geom))) As gm_to_gg_gm_pca + +FROM (SELECT ST_GeomFromEWKT('SRID=4326;POLYGON((-119.5434 34.9438,-119.5437 34.9445,-119.5452 34.9442,-119.5434 34.9438))') As the_geom) + As poly + CROSS JOIN + (VALUES + ( ST_GeomFromEWKT('SRID=4326;POINT(-119.5434 34.9438)') ) , + ( ST_GeomFromEWKT('SRID=4326;POINT(-119.5452 34.9442)') ) , + ( ST_GeomFromEWKT('SRID=4326;POINT(-119.5434 34.9438)') ), + ( ST_GeomFromEWKT('SRID=4326;POINT(-119.5438 34.9443)') ) + ) + As pt(the_geom); + +-- #271 -- +SELECT '#271', ST_Covers( +'POLYGON((-9.123456789 50,51 -11.123456789,-10.123456789 50,-9.123456789 50))'::geography, +'POINT(-10.123456789 50)'::geography +); + +-- #272 -- +SELECT '#272', ST_LineCrossingDirection(foo.line1, foo.line2) As l1_cross_l2 , + ST_LineCrossingDirection(foo.line2, foo.line1) As l2_cross_l1 +FROM (SELECT + ST_GeomFromText('LINESTRING(25 169,89 114,40 70,86 43)') As line1, ST_GeomFromText('LINESTRING(2.99 90.16,71 74,20 140,171 154)') As line2 ) As foo; + +-- #277 -- +SELECT '#277', ST_AsGML(2, ST_GeomFromText('POINT(1 1e308)')); + +-- #299 -- +SELECT '#299', round(ST_Y(geometry(ST_Intersection(ST_GeographyFromText('POINT(1.2456 2)'), ST_GeographyFromText('POINT(1.2456 2)'))))); + +-- #304 -- + +SELECT '#304'; + +CREATE OR REPLACE FUNCTION utmzone(geometry) + RETURNS integer AS +$BODY$ +DECLARE + geomgeog geometry; + zone int; + pref int; + +BEGIN + geomgeog:= ST_Transform($1,4326); + + IF (ST_Y(geomgeog))>0 THEN + pref:=32600; + ELSE + pref:=32700; + END IF; + + zone:=floor((ST_X(geomgeog)+180)/6)+1; + IF ( zone > 60 ) THEN zone := 60; END IF; + + RETURN zone+pref; +END; +$BODY$ LANGUAGE 'plpgsql' IMMUTABLE + COST 100; + +CREATE TABLE utm_dots ( the_geog geography, utm_srid integer); +INSERT INTO utm_dots SELECT geography(ST_SetSRID(ST_Point(i*10,j*10),4326)) As the_geog, utmzone(ST_SetSRID(ST_Point(i*10,j*10),4326)) As utm_srid FROM generate_series(-17,17) As i CROSS JOIN generate_series(-8,8) As j; + +SELECT ST_AsText(the_geog) as the_pt, + utm_srid, + ST_Area(ST_Buffer(the_geog,10)) As the_area, + ST_Area(geography(ST_Transform(ST_Buffer(ST_Transform(geometry(the_geog),utm_srid),10),4326))) As geog_utm_area +FROM utm_dots +WHERE ST_Area(ST_Buffer(the_geog,10)) NOT between 307 and 315 +LIMIT 10; + +SELECT '#304.a', Count(*) FROM utm_dots WHERE ST_DWithin(the_geog, 'POINT(0 0)'::geography, 3000000); + +CREATE INDEX utm_dots_gix ON utm_dots USING GIST (the_geog); +SELECT '#304.b', Count(*) FROM utm_dots WHERE ST_DWithin(the_geog, 'POINT(0 0)'::geography, 300000); + +DROP FUNCTION utmzone(geometry); +DROP TABLE utm_dots; + +-- #408 -- +SELECT '#408', substring(st_isvalidreason('0105000020E0670000010000000102000020E06700000100000016DA52BA62A04141FFF3AD290B735241') from E'.*\\['); +SELECT '#408.1', st_isvalid('01050000000100000001020000000100000000000000000000000000000000000000'); +SELECT '#408.2', st_isvalidreason('01020000000100000000000000000000000000000000000000'); +SELECT '#408.3', st_isvalid('0106000020BB0B000001000000010300000005000000D6000000000000C0F1A138410AD7A3103190524114AE4721F7A138410000000030905241713D0A57FAA1384185EB51982C9052417B14AE87FAA13841000000402A905241AE47E13AFBA1384114AE474128905241EC51B81EFDA138413D0AD7632690524152B81E85FFA13841D7A3707D2590524152B81E4500A23841713D0A072590524100000000FFA13841713D0AF724905241CDCCCCCCFFA13841CDCCCC0C249052419A99991901A238419A999919249052411F85EBD101A23841D7A3704D23905241E17A14AE02A23841A4703D3A2290524185EB51F808A23841000000D021905241E17A14EE0BA238413333335321905241666666A615A23841B81E85AB1F905241713D0AD710A23841B81E858B1E905241666666260CA2384114AE4731209052410AD7A37009A23841CDCCCCEC20905241AE47E13A06A23841EC51B87E219052419A9999D903A23841EC51B80E21905241EC51B8DE08A238418FC2F5681F905241666666660EA23841A4703D9A1D9052413D0AD7A30FA2384114AE47A11C9052413333333311A23841000000101C90524148E17A1414A23841333333931A905241EC51B81E1AA23841EC51B89E1890524185EB51381CA23841D7A370BD17905241295C8FC220A2384185EB51C816905241C3F528DC2BA238418FC2F5E814905241E17A14EE2EA23841EC51B8FE13905241AE47E1FA2BA23841EC51B8EE119052415C8FC2F52BA2384185EB51C810905241333333332EA2384114AE4701109052417B14AEC73BA238410AD7A3300D905241CDCCCCCC43A238417B14AE870B905241CDCCCC4C45A23841A4703D3A0B9052413D0AD7A34DA238411F85EB810A905241295C8F8250A23841CDCCCCBC09905241000000C053A238410AD7A36009905241A4703D0A5CA2384114AE4751099052418FC2F5A866A23841A4703D4A0A9052410000008069A2384114AE47B10A9052415C8FC2B573A23841B81E851B0D905241AE47E1FA76A23841666666C60D9052417B14AE077BA238411F85EB510E905241AE47E1FA7FA23841666666E60E9052415C8FC2358DA23841000000F010905241EC51B85E95A2384148E17A14119052417B14AE4795A23841CDCCCCCC1090524114AE47E18CA2384185EB51F80F90524148E17AD480A2384114AE47A10E9052413D0AD76383A23841713D0AF70C9052417B14AEC784A23841A4703D8A0C9052410000000086A23841A4703D0A0B9052411F85EB9187A23841B81E851B09905241F6285CCF86A2384100000010099052417B14AE4787A2384185EB51180890524114AE472186A23841CDCCCCFC079052410AD7A3B086A23841C3F5280C07905241333333B385A23841CDCCCC0C07905241000000407EA2384152B81E15079052419A9999197BA23841A4703D2A079052416666666673A2384114AE47710790524114AE47A16EA238413D0AD7F30690524114AE472170A238418FC2F5D8059052413D0AD72372A2384185EB511806905241A4703DCA71A23841D7A3707D05905241EC51B8DE7EA238411F85EBD104905241E17A14AE76A23841333333E30390524185EB51B875A23841713D0A47029052415C8FC2F576A23841D7A3703D029052419A99999976A2384114AE475101905241333333B378A23841EC51B83E019052410AD7A3307CA238410AD7A320019052418FC2F52885A23841295C8FD20090524148E17A9483A238416666664600905241295C8FC276A238411F85EB9100905241CDCCCC4C76A2384100000070FF8F5241AE47E13A76A2384133333343FF8F52417B14AE0783A23841D7A370FDFE8F5241E17A14AE81A23841C3F5283CFE8F52415C8FC2357DA2384114AE47A1FE8F5241CDCCCC8C7BA238415C8FC275FD8F524148E17AD47FA238417B14AE17FD8F5241000000807EA238413D0AD7A3FC8F5241713D0AD776A2384133333363FD8F5241CDCCCC8C73A2384152B81EF5FD8F5241E17A14AE70A2384114AE4711FE8F524185EB51B870A23841B81E852BFF8F524152B81E056CA2384114AE4731FF8F5241B81E856B6BA2384152B81E25FE8F5241AE47E13A69A23841E17A142EFE8F52419A99995962A238415C8FC275FE8F52415C8FC27562A238411F85EB710090524114AE47A15BA23841EC51B86E00905241EC51B85E5BA238419A9999E902905241295C8F025BA238417B14AE8704905241A4703D8A54A23841713D0A7704905241C3F5285C51A2384148E17A44049052418FC2F5E84CA23841A4703D4A049052410AD7A3304CA2384148E17A94049052419A9999994CA238413D0AD7F305905241AE47E1FA49A2384114AE471106905241EC51B85E49A23841AE47E1FA07905241AE47E13A43A238415C8FC255099052416666662644A23841D7A3707D0A9052415C8FC2F53FA23841CDCCCC2C0B90524185EB517839A2384185EB51380C90524152B81E4532A23841D7A370DD099052419A9999592FA2384152B81E4509905241D7A3707D2AA23841B81E857B089052415C8FC27526A238416666667608905241EC51B81E26A238417B14AE7707905241295C8F0226A23841F6285C1F07905241666666A61CA23841CDCCCC6C07905241713D0A1716A23841B81E856B07905241B81E85EB15A2384100000040079052411F85EB1108A2384114AE4741079052415C8FC23505A2384148E17AC40790524152B81E0506A23841EC51B84E09905241713D0A5707A23841AE47E10A0A905241EC51B81E12A2384152B81EA50890524152B81E4521A23841F6285CDF0890524148E17A1427A23841EC51B80E099052415C8FC2B52AA2384185EB5168099052413D0AD7E32FA23841CDCCCC3C0A9052413D0AD7A331A23841333333930A90524185EB51F833A238410AD7A3B00B9052411F85EB5135A23841EC51B8AE0B90524185EB513836A23841333333530D9052410000004030A238415C8FC2B50E905241000000802FA238415C8FC2750E9052410000008028A238419A9999B90E905241F6285C0F28A23841333333630E90524114AE47E123A23841333333730E905241D7A3707D23A2384152B81E750E9052410000008023A2384185EB51E80E905241D7A370BD1EA23841713D0A170F9052419A9999991EA23841333333830F9052419A9999991CA238411F85EB810F90524152B81E450EA2384152B81E750F9052417B14AE470AA23841EC51B89E0F905241B81E85EB05A238410AD7A3F00F905241D7A3707DFFA138417B14AEF71090524185EB51F8FDA138413D0AD72311905241295C8F02FAA13841EC51B83E11905241713D0A17EFA13841E17A145E129052417B14AE87CBA1384152B81E05179052418FC2F528C0A13841D7A3709D17905241D7A370BDC0A13841F6285C5F18905241295C8F82CBA138419A9999F917905241AE47E1BAD7A138415C8FC255169052411F85EB91E0A13841000000401590524114AE47A1E2A1384185EB5108159052415C8FC235ECA13841C3F5286C13905241C3F528DCF4A13841000000701290524152B81E45F5A138415C8FC2A51290524100000040F6A13841CDCCCC7C129052417B14AE47FBA138410000000012905241EC51B85E00A2384185EB51A8119052413D0AD7A305A238419A99990911905241EC51B81E0AA238411F85EB611090524148E17A940EA23841A4703D0A1090524152B81E0514A2384152B81EE50F905241F6285CCF15A238410AD7A3E00F9052417B14AEC718A23841CDCCCCDC0F9052419A9999191AA238415C8FC2E50F905241EC51B81E20A238415C8FC2E50F90524148E17A1420A23841333333C30F9052417B14AE8729A23841713D0AA70F905241000000002AA238413D0AD733119052411F85EB9129A23841C3F528EC12905241E17A142E28A238419A999919149052418FC2F5A825A23841CDCCCC1C15905241C3F5285C21A2384114AE473116905241F6285C4F1BA2384152B81E4517905241D7A3707D1AA2384148E17A1417905241C3F5285C19A23841D7A3702D179052413333333318A23841B81E85CB17905241000000C017A2384185EB5108189052413D0AD72310A238419A9999F91790524148E17A5410A2384148E17AD41690524148E17AD40DA2384152B81ED516905241B81E85AB09A23841F6285C1F179052418FC2F5A809A2384185EB51C8179052418FC2F56808A238417B14AEC7179052410000008008A2384185EB515818905241AE47E1BA16A23841F6285C6F189052410AD7A33017A23841C3F5289C18905241000000C012A23841AE47E10A1A9052411F85EB5110A238413D0AD7131B905241000000800DA238415C8FC2451C90524148E17A140DA23841A4703D4A1C9052413D0AD7230BA2384148E17A141E905241295C8F4205A23841295C8F421E905241F6285C4F00A238419A9999691E905241C3F5289CFDA13841AE47E16A1E905241D7A370FDFDA1384114AE47711F90524185EB51F801A23841B81E855B1F905241A4703D0A05A23841CDCCCCAC1F905241E17A14AE02A23841EC51B89E20905241295C8F82FFA138419A9999E9219052419A999919FEA1384185EB5188239052410AD7A330FAA13841E17A14DE25905241C3F5281CF9A13841F6285CFF26905241AE47E13AF8A138415C8FC2E527905241CDCCCC8CF7A1384185EB51B82890524185EB51F8F7A138413333334329905241C3F5281CF6A138418FC2F5182C905241A4703D4AF5A13841EC51B8BE2C905241CDCCCC0CF4A13841713D0AF72E90524185EB5138F3A13841000000502F905241000000C0F1A138410AD7A3103190524111000000CDCCCC4C6AA23841713D0A170A905241CDCCCC4C6FA238411F85EB710790524148E17A947AA2384114AE47410890524185EB51387BA23841D7A370ED07905241666666267BA23841713D0A7707905241EC51B85E7EA2384114AE476107905241E17A14AE7EA2384114AE473108905241713D0A5785A23841CDCCCCBC089052410AD7A33083A23841F6285C9F0B9052413333337382A23841666666460C90524148E17AD481A23841333333D30C90524114AE472181A23841333333730D905241AE47E1BA7FA23841CDCCCC3C0E9052418FC2F56876A238415C8FC2050D90524185EB513872A238418FC2F5D80B90524185EB513870A23841EC51B82E0B905241CDCCCC4C6AA23841713D0A170A90524113000000A4703DCA6BA238415C8FC295FF8F5241B81E856B74A238410AD7A380FF8F5241EC51B89E74A23841E17A149E00905241AE47E1BA74A23841F6285C4F019052419A99995974A23841295C8F520290524148E17AD473A2384114AE47B10390524152B81EC572A2384114AE4701059052417B14AE476DA23841AE47E1DA04905241F6285C8F6DA23841333333A303905241000000006CA2384152B81E9503905241EC51B81E69A23841A4703D7A039052410AD7A3B068A23841B81E85AB049052415C8FC2F55CA23841CDCCCC8C0490524152B81E455DA238411F85EB0103905241333333B35DA23841AE47E1DA00905241EC51B85E67A23841C3F528FC009052410AD7A3B067A23841CDCCCCCCFF8F524185EB51B86BA23841333333C3FF8F5241A4703DCA6BA238415C8FC295FF8F5241020000003D0AD7A346A238413D0AD7E3099052413D0AD7A346A238413D0AD7E309905241100000007B14AEC74DA238410AD7A3B008905241EC51B85E4EA23841B81E850B079052413D0AD7234FA23841C3F528DC0490524185EB51385CA23841EC51B8EE04905241B81E852B60A23841A4703DDA049052410000008066A23841A4703DFA049052411F85EB116AA23841CDCCCC0C05905241CDCCCC8C6EA23841A4703D5A05905241A4703D0A6CA238417B14AE37079052411F85EBD16AA23841A4703DCA07905241AE47E1FA68A23841E17A14FE08905241295C8F0268A238410AD7A320099052419A99999963A23841AE47E10A099052415C8FC2B55AA23841333333C30890524114AE476156A23841CDCCCCBC089052417B14AEC74DA238410AD7A3B008905241'); +SELECT '#408.4', st_isvalidreason('0106000020BB0B000001000000010300000005000000D6000000000000C0F1A138410AD7A3103190524114AE4721F7A138410000000030905241713D0A57FAA1384185EB51982C9052417B14AE87FAA13841000000402A905241AE47E13AFBA1384114AE474128905241EC51B81EFDA138413D0AD7632690524152B81E85FFA13841D7A3707D2590524152B81E4500A23841713D0A072590524100000000FFA13841713D0AF724905241CDCCCCCCFFA13841CDCCCC0C249052419A99991901A238419A999919249052411F85EBD101A23841D7A3704D23905241E17A14AE02A23841A4703D3A2290524185EB51F808A23841000000D021905241E17A14EE0BA238413333335321905241666666A615A23841B81E85AB1F905241713D0AD710A23841B81E858B1E905241666666260CA2384114AE4731209052410AD7A37009A23841CDCCCCEC20905241AE47E13A06A23841EC51B87E219052419A9999D903A23841EC51B80E21905241EC51B8DE08A238418FC2F5681F905241666666660EA23841A4703D9A1D9052413D0AD7A30FA2384114AE47A11C9052413333333311A23841000000101C90524148E17A1414A23841333333931A905241EC51B81E1AA23841EC51B89E1890524185EB51381CA23841D7A370BD17905241295C8FC220A2384185EB51C816905241C3F528DC2BA238418FC2F5E814905241E17A14EE2EA23841EC51B8FE13905241AE47E1FA2BA23841EC51B8EE119052415C8FC2F52BA2384185EB51C810905241333333332EA2384114AE4701109052417B14AEC73BA238410AD7A3300D905241CDCCCCCC43A238417B14AE870B905241CDCCCC4C45A23841A4703D3A0B9052413D0AD7A34DA238411F85EB810A905241295C8F8250A23841CDCCCCBC09905241000000C053A238410AD7A36009905241A4703D0A5CA2384114AE4751099052418FC2F5A866A23841A4703D4A0A9052410000008069A2384114AE47B10A9052415C8FC2B573A23841B81E851B0D905241AE47E1FA76A23841666666C60D9052417B14AE077BA238411F85EB510E905241AE47E1FA7FA23841666666E60E9052415C8FC2358DA23841000000F010905241EC51B85E95A2384148E17A14119052417B14AE4795A23841CDCCCCCC1090524114AE47E18CA2384185EB51F80F90524148E17AD480A2384114AE47A10E9052413D0AD76383A23841713D0AF70C9052417B14AEC784A23841A4703D8A0C9052410000000086A23841A4703D0A0B9052411F85EB9187A23841B81E851B09905241F6285CCF86A2384100000010099052417B14AE4787A2384185EB51180890524114AE472186A23841CDCCCCFC079052410AD7A3B086A23841C3F5280C07905241333333B385A23841CDCCCC0C07905241000000407EA2384152B81E15079052419A9999197BA23841A4703D2A079052416666666673A2384114AE47710790524114AE47A16EA238413D0AD7F30690524114AE472170A238418FC2F5D8059052413D0AD72372A2384185EB511806905241A4703DCA71A23841D7A3707D05905241EC51B8DE7EA238411F85EBD104905241E17A14AE76A23841333333E30390524185EB51B875A23841713D0A47029052415C8FC2F576A23841D7A3703D029052419A99999976A2384114AE475101905241333333B378A23841EC51B83E019052410AD7A3307CA238410AD7A320019052418FC2F52885A23841295C8FD20090524148E17A9483A238416666664600905241295C8FC276A238411F85EB9100905241CDCCCC4C76A2384100000070FF8F5241AE47E13A76A2384133333343FF8F52417B14AE0783A23841D7A370FDFE8F5241E17A14AE81A23841C3F5283CFE8F52415C8FC2357DA2384114AE47A1FE8F5241CDCCCC8C7BA238415C8FC275FD8F524148E17AD47FA238417B14AE17FD8F5241000000807EA238413D0AD7A3FC8F5241713D0AD776A2384133333363FD8F5241CDCCCC8C73A2384152B81EF5FD8F5241E17A14AE70A2384114AE4711FE8F524185EB51B870A23841B81E852BFF8F524152B81E056CA2384114AE4731FF8F5241B81E856B6BA2384152B81E25FE8F5241AE47E13A69A23841E17A142EFE8F52419A99995962A238415C8FC275FE8F52415C8FC27562A238411F85EB710090524114AE47A15BA23841EC51B86E00905241EC51B85E5BA238419A9999E902905241295C8F025BA238417B14AE8704905241A4703D8A54A23841713D0A7704905241C3F5285C51A2384148E17A44049052418FC2F5E84CA23841A4703D4A049052410AD7A3304CA2384148E17A94049052419A9999994CA238413D0AD7F305905241AE47E1FA49A2384114AE471106905241EC51B85E49A23841AE47E1FA07905241AE47E13A43A238415C8FC255099052416666662644A23841D7A3707D0A9052415C8FC2F53FA23841CDCCCC2C0B90524185EB517839A2384185EB51380C90524152B81E4532A23841D7A370DD099052419A9999592FA2384152B81E4509905241D7A3707D2AA23841B81E857B089052415C8FC27526A238416666667608905241EC51B81E26A238417B14AE7707905241295C8F0226A23841F6285C1F07905241666666A61CA23841CDCCCC6C07905241713D0A1716A23841B81E856B07905241B81E85EB15A2384100000040079052411F85EB1108A2384114AE4741079052415C8FC23505A2384148E17AC40790524152B81E0506A23841EC51B84E09905241713D0A5707A23841AE47E10A0A905241EC51B81E12A2384152B81EA50890524152B81E4521A23841F6285CDF0890524148E17A1427A23841EC51B80E099052415C8FC2B52AA2384185EB5168099052413D0AD7E32FA23841CDCCCC3C0A9052413D0AD7A331A23841333333930A90524185EB51F833A238410AD7A3B00B9052411F85EB5135A23841EC51B8AE0B90524185EB513836A23841333333530D9052410000004030A238415C8FC2B50E905241000000802FA238415C8FC2750E9052410000008028A238419A9999B90E905241F6285C0F28A23841333333630E90524114AE47E123A23841333333730E905241D7A3707D23A2384152B81E750E9052410000008023A2384185EB51E80E905241D7A370BD1EA23841713D0A170F9052419A9999991EA23841333333830F9052419A9999991CA238411F85EB810F90524152B81E450EA2384152B81E750F9052417B14AE470AA23841EC51B89E0F905241B81E85EB05A238410AD7A3F00F905241D7A3707DFFA138417B14AEF71090524185EB51F8FDA138413D0AD72311905241295C8F02FAA13841EC51B83E11905241713D0A17EFA13841E17A145E129052417B14AE87CBA1384152B81E05179052418FC2F528C0A13841D7A3709D17905241D7A370BDC0A13841F6285C5F18905241295C8F82CBA138419A9999F917905241AE47E1BAD7A138415C8FC255169052411F85EB91E0A13841000000401590524114AE47A1E2A1384185EB5108159052415C8FC235ECA13841C3F5286C13905241C3F528DCF4A13841000000701290524152B81E45F5A138415C8FC2A51290524100000040F6A13841CDCCCC7C129052417B14AE47FBA138410000000012905241EC51B85E00A2384185EB51A8119052413D0AD7A305A238419A99990911905241EC51B81E0AA238411F85EB611090524148E17A940EA23841A4703D0A1090524152B81E0514A2384152B81EE50F905241F6285CCF15A238410AD7A3E00F9052417B14AEC718A23841CDCCCCDC0F9052419A9999191AA238415C8FC2E50F905241EC51B81E20A238415C8FC2E50F90524148E17A1420A23841333333C30F9052417B14AE8729A23841713D0AA70F905241000000002AA238413D0AD733119052411F85EB9129A23841C3F528EC12905241E17A142E28A238419A999919149052418FC2F5A825A23841CDCCCC1C15905241C3F5285C21A2384114AE473116905241F6285C4F1BA2384152B81E4517905241D7A3707D1AA2384148E17A1417905241C3F5285C19A23841D7A3702D179052413333333318A23841B81E85CB17905241000000C017A2384185EB5108189052413D0AD72310A238419A9999F91790524148E17A5410A2384148E17AD41690524148E17AD40DA2384152B81ED516905241B81E85AB09A23841F6285C1F179052418FC2F5A809A2384185EB51C8179052418FC2F56808A238417B14AEC7179052410000008008A2384185EB515818905241AE47E1BA16A23841F6285C6F189052410AD7A33017A23841C3F5289C18905241000000C012A23841AE47E10A1A9052411F85EB5110A238413D0AD7131B905241000000800DA238415C8FC2451C90524148E17A140DA23841A4703D4A1C9052413D0AD7230BA2384148E17A141E905241295C8F4205A23841295C8F421E905241F6285C4F00A238419A9999691E905241C3F5289CFDA13841AE47E16A1E905241D7A370FDFDA1384114AE47711F90524185EB51F801A23841B81E855B1F905241A4703D0A05A23841CDCCCCAC1F905241E17A14AE02A23841EC51B89E20905241295C8F82FFA138419A9999E9219052419A999919FEA1384185EB5188239052410AD7A330FAA13841E17A14DE25905241C3F5281CF9A13841F6285CFF26905241AE47E13AF8A138415C8FC2E527905241CDCCCC8CF7A1384185EB51B82890524185EB51F8F7A138413333334329905241C3F5281CF6A138418FC2F5182C905241A4703D4AF5A13841EC51B8BE2C905241CDCCCC0CF4A13841713D0AF72E90524185EB5138F3A13841000000502F905241000000C0F1A138410AD7A3103190524111000000CDCCCC4C6AA23841713D0A170A905241CDCCCC4C6FA238411F85EB710790524148E17A947AA2384114AE47410890524185EB51387BA23841D7A370ED07905241666666267BA23841713D0A7707905241EC51B85E7EA2384114AE476107905241E17A14AE7EA2384114AE473108905241713D0A5785A23841CDCCCCBC089052410AD7A33083A23841F6285C9F0B9052413333337382A23841666666460C90524148E17AD481A23841333333D30C90524114AE472181A23841333333730D905241AE47E1BA7FA23841CDCCCC3C0E9052418FC2F56876A238415C8FC2050D90524185EB513872A238418FC2F5D80B90524185EB513870A23841EC51B82E0B905241CDCCCC4C6AA23841713D0A170A90524113000000A4703DCA6BA238415C8FC295FF8F5241B81E856B74A238410AD7A380FF8F5241EC51B89E74A23841E17A149E00905241AE47E1BA74A23841F6285C4F019052419A99995974A23841295C8F520290524148E17AD473A2384114AE47B10390524152B81EC572A2384114AE4701059052417B14AE476DA23841AE47E1DA04905241F6285C8F6DA23841333333A303905241000000006CA2384152B81E9503905241EC51B81E69A23841A4703D7A039052410AD7A3B068A23841B81E85AB049052415C8FC2F55CA23841CDCCCC8C0490524152B81E455DA238411F85EB0103905241333333B35DA23841AE47E1DA00905241EC51B85E67A23841C3F528FC009052410AD7A3B067A23841CDCCCCCCFF8F524185EB51B86BA23841333333C3FF8F5241A4703DCA6BA238415C8FC295FF8F5241020000003D0AD7A346A238413D0AD7E3099052413D0AD7A346A238413D0AD7E309905241100000007B14AEC74DA238410AD7A3B008905241EC51B85E4EA23841B81E850B079052413D0AD7234FA23841C3F528DC0490524185EB51385CA23841EC51B8EE04905241B81E852B60A23841A4703DDA049052410000008066A23841A4703DFA049052411F85EB116AA23841CDCCCC0C05905241CDCCCC8C6EA23841A4703D5A05905241A4703D0A6CA238417B14AE37079052411F85EBD16AA23841A4703DCA07905241AE47E1FA68A23841E17A14FE08905241295C8F0268A238410AD7A320099052419A99999963A23841AE47E10A099052415C8FC2B55AA23841333333C30890524114AE476156A23841CDCCCCBC089052417B14AEC74DA238410AD7A3B008905241'); + +-- #457 -- +SELECT '#457.1', st_astext(st_collectionExtract('POINT(0 0)', 1)); +SELECT '#457.2', st_astext(st_collectionExtract('POINT(0 0)', 2)); +SELECT '#457.3', st_astext(st_collectionExtract('POINT(0 0)', 3)); +SELECT '#457.4', st_astext(st_collectionExtract('LINESTRING(0 0, 1 1)', 1)); +SELECT '#457.5', st_astext(st_collectionExtract('LINESTRING(0 0, 1 1)', 2)); +SELECT '#457.6', st_astext(st_collectionExtract('LINESTRING(0 0, 1 1)', 3)); +SELECT '#457.7', st_astext(st_collectionExtract('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))', 1)); +SELECT '#457.8', st_astext(st_collectionExtract('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))', 2)); +SELECT '#457.9', st_astext(st_collectionExtract('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))', 3)); + +-- #835 -- +SELECT '#835.1', st_astext(st_collectionExtract('POLYGON EMPTY', 1)); +SELECT '#835.2', st_astext(st_collectionExtract('POLYGON EMPTY', 2)); +SELECT '#835.3', st_astext(st_collectionExtract('POLYGON EMPTY', 3)); +SELECT '#835.4', st_astext(st_collectionExtract('LINESTRING EMPTY', 1)); +SELECT '#835.5', st_astext(st_collectionExtract('LINESTRING EMPTY', 2)); +SELECT '#835.6', st_astext(st_collectionExtract('LINESTRING EMPTY', 3)); +SELECT '#835.7', st_astext(st_collectionExtract('POINT EMPTY', 1)); +SELECT '#835.8', st_astext(st_collectionExtract('POINT EMPTY', 2)); +SELECT '#835.9', st_astext(st_collectionExtract('POINT EMPTY', 3)); +SELECT '#835.10', st_astext(st_collectionExtract('GEOMETRYCOLLECTION EMPTY', 1)); +SELECT '#835.11', st_astext(st_collectionExtract('GEOMETRYCOLLECTION EMPTY', 2)); +SELECT '#835.12', st_astext(st_collectionExtract('GEOMETRYCOLLECTION EMPTY', 3)); + +-- #650 -- +SELECT '#650', ST_AsText(ST_Collect(ARRAY[ST_MakePoint(0,0), ST_MakePoint(1,1), null, ST_MakePoint(2,2)])); + +-- #662 -- +--SELECT '#662', ST_MakePolygon(ST_AddPoint(ST_AddPoint(ST_MakeLine(ST_SetSRID(ST_MakePointM(i+m,j,m),4326),ST_SetSRID(ST_MakePointM(j+m,i-m,m),4326)),ST_SetSRID(ST_MakePointM(i,j,m),4326)),ST_SetSRID(ST_MakePointM(i+m,j,m),4326))) As the_geom FROM generate_series(-10,50,20) As i CROSS JOIN generate_series(50,70, 20) As j CROSS JOIN generate_series(1,2) As m ORDER BY i, j, m, i*j*m LIMIT 1; + +-- #667 -- +SELECT '#667', ST_AsEWKT(ST_LineToCurve(ST_Buffer(ST_SetSRID(ST_Point(i,j),4326), j))) As the_geom FROM generate_series(-10,50,10) As i CROSS JOIN generate_series(40,70, 20) As j ORDER BY i, j, i*j LIMIT 1; + +-- #677 -- +SELECT '#677',round(ST_Distance_Spheroid(ST_GeomFromEWKT('MULTIPOLYGON(((-10 40,-10 55,-10 70,5 40,-10 40)))'), ST_GeomFromEWKT('MULTIPOINT(20 40,20 55,20 70,35 40,35 55,35 70,50 40,50 55,50 70)'), 'SPHEROID["GRS_1980",6378137,298.257222101]')) As result; + +-- #680 -- +SELECT '#680', encode(ST_AsBinary(geography(foo1.the_geom)),'hex') As result FROM ((SELECT ST_SetSRID(ST_MakePointM(i,j,m),4326) As the_geom FROM generate_series(-10,50,10) As i CROSS JOIN generate_series(50,70, 20) AS j CROSS JOIN generate_series(1,2) As m ORDER BY i, j, i*j*m)) As foo1 LIMIT 1; + +-- #681 -- +SELECT '#681a', ST_AsGML(ST_GeomFromText('POINT EMPTY', 4326)); +SELECT '#681b', ST_AsGML(ST_GeomFromText('POLYGON EMPTY', 4326)); +SELECT '#681c', ST_AsGML(ST_GeomFromText('LINESTRING EMPTY', 4326)); +SELECT '#681d', ST_AsGML(ST_GeomFromText('MULTIPOINT EMPTY', 4326)); +SELECT '#681e', ST_AsGML(ST_GeomFromText('MULTILINESTRING EMPTY', 4326)); +SELECT '#681f', ST_AsGML(ST_GeomFromText('MULTIPOLYGON EMPTY', 4326)); +SELECT '#681g', ST_AsGML(ST_GeomFromText('GEOMETRYCOLLECTION EMPTY', 4326)); + + +-- #682 -- +SELECT '#682', ST_Buffer(ST_GeomFromText('POLYGON EMPTY',4326) , 0.5); + +-- #683 -- +SELECT '#683', ST_BuildArea(ST_GeomFromText('POINT EMPTY',4326)); + +-- #684,#2109 -- +SELECT '#684,#2109', ST_AsEWKT(ST_Centroid(ST_GeomFromText('POLYGON EMPTY',4326))); +SELECT '#2109', ST_AsEWKT(ST_Centroid(ST_GeomFromText('MULTILINESTRING ZM EMPTY',3395))); + +-- #685 -- +SELECT '#685', ST_ConvexHull(ST_GeomFromText('POLYGON EMPTY',4326)); + +-- #686 -- +SELECT '#686', ST_COLLECT(ST_GeomFromText('POLYGON EMPTY',4326),ST_GeomFromText('TRIANGLE EMPTY',4326)); + +-- #687 -- +SELECT '#687', ST_DFullyWithin(ST_GeomFromText('LINESTRING(-10 50,50 -10)',4326), ST_GeomFromText('POLYGON EMPTY',4326),5); + +-- #689 -- +SELECT '#689', ST_CoveredBy(ST_GeomFromText('POLYGON EMPTY'), ST_GeomFromText('LINESTRING(-10 50,50 -10)')); + +-- #690 -- +SELECT '#690'; +SELECT ST_MakeLine(ST_GeomFromText('POINT(-11.1111111 40)'), ST_GeomFromText('LINESTRING(-11.1111111 70,70 -11.1111111)')) As result; + +-- #693 -- +SELECT '#693a', ST_GeomFromEWKT('SRID=4326;POLYGONM((-71.1319 42.2503 1,-71.132 42.2502 3,-71.1323 42.2504 -2,-71.1322 42.2505 1,-71.1319 42.2503 0))'); +SELECT '#693b', ST_GeomFromEWKT('SRID=4326;POLYGONM((-71.1319 42.2512 0,-71.1318 42.2511 20,-71.1317 42.2511 -20,-71.1317 42.251 5,-71.1317 42.2509 4,-71.132 42.2511 6,-71.1319 42.2512 30))'); + +-- #694 -- +SELECT '#694'; +SELECT ST_MakePolygon('POINT(1 2)'::geometry); + +-- #695 -- +SELECT '#695'; +SELECT ST_RemovePoint('POINT(-11.1111111 40)'::geometry, 1); + +-- #696 -- +SELECT '#696',ST_Segmentize(ST_GeomFromEWKT('PolyhedralSurface( ((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)), ((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)), ((0 0 0, 1 0 0, 1 0 1, 0 0 1, 0 0 0)), ((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)), ((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)), ((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)) )'), 0.5); + +-- #720 -- +SELECT '#720', ST_AsText(ST_SnapTogrid(ST_Transform(ST_GeomFromText('MULTIPOINT(-10 40,-10 55,-10 70,5 40,5 55,5 70,20 40,20 55,20 70,35 40,35 55,35 70,50 40,50 55,50 70)',4326), 3395), 0.01)); + +-- #723 -- +SELECT '#723', + ST_SnapToGrid( ST_Intersection(a.geog, b.geog)::geometry, 0.00001) +FROM (VALUES (ST_GeogFromText('SRID=4326;POINT(-11.1111111 40)') ), (ST_GeogFromText('SRID=4326;POINT(-11.1111111 55)') ) ) As a(geog) CROSS JOIN ( VALUES (ST_GeogFromText('SRID=4326;POINT(-11.1111111 40)') ), (ST_GeogFromText('SRID=4326;POINT(-11.1111111 55)') )) As b(geog); + +-- #729 -- +--SELECT '#729',ST_MakeLine(foo1.the_geom) As result FROM ((SELECT ST_GeomFromText('POINT EMPTY',4326) As the_geom UNION ALL SELECT ST_GeomFromText('MULTIPOINT EMPTY',4326) As the_geom UNION ALL SELECT ST_GeomFromText('MULTIPOLYGON EMPTY',4326) As the_geom UNION ALL SELECT ST_GeomFromText('LINESTRING EMPTY',4326) As the_geom UNION ALL SELECT ST_GeomFromText('MULTILINESTRING EMPTY',4326) As the_geom ) ) As foo1; + +-- #804 +SELECT '#804', ST_AsGML(3, 'SRID=4326;POINT(0 0)'::geometry, 0, 1); + + +-- #845 +SELECT '#845', ST_Intersects('POINT(169.69960846592 -46.5061209281002)'::geometry, 'POLYGON((169.699607857174 -46.5061218662,169.699607857174 -46.5061195965597,169.699608806526 -46.5061195965597,169.699608806526 -46.5061218662,169.699607857174 -46.5061218662))'::geometry); + +-- #834 +SELECT '#834', ST_AsEWKT(ST_Intersection('LINESTRING(0 0,0 10,10 10,10 0)', 'LINESTRING(10 10 4,10 0 5,0 0 5)')); + +-- #884 -- +CREATE TABLE foo (id integer, the_geom geometry); +INSERT INTO foo VALUES (1, st_geomfromtext('MULTIPOLYGON(((-113.6 35.4,-113.6 35.8,-113.2 35.8,-113.2 35.4,-113.6 35.4),(-113.5 35.5,-113.3 35.5,-113.3 35.7,-113.5 35.7,-113.5 35.5)))')); +INSERT INTO foo VALUES (2, st_geomfromtext('MULTIPOLYGON(((-113.7 35.3,-113.7 35.9,-113.1 35.9,-113.1 35.3,-113.7 35.3),(-113.6 35.4,-113.2 35.4,-113.2 35.8,-113.6 35.8,-113.6 35.4)),((-113.5 35.5,-113.5 35.7,-113.3 35.7,-113.3 35.5,-113.5 35.5)))')); + +select '#884', id, ST_Within( +ST_GeomFromText('POINT (-113.4 35.6)'), the_geom +) from foo; + +select '#938', 'POLYGON EMPTY'::geometry::box2d; + +DROP TABLE foo; + +-- #668 -- +select '#668',box2d('CIRCULARSTRING(10 2,12 2,14 2)'::geometry) as b; + +-- #711 -- +select '#711', ST_GeoHash(ST_GeomFromText('POLYGON EMPTY',4326)); + +-- #712 -- +SELECT '#712',ST_IsValid(ST_GeomFromText('POLYGON EMPTY',4326)); + +-- #756 +WITH inp AS ( SELECT 'LINESTRING(0 0, 1 1)'::geometry as s, + 'LINESTRING EMPTY'::geometry as e ) + SELECT '#756.1', ST_Equals(s, st_multi(s)), + ST_Equals(s, st_collect(s, e)) + FROM inp; + + +-- #1023 -- +select '#1023', 'POINT(10 4)'::geometry = 'POINT(10 4)'::geometry; +select '#1023.a', 'POINT(10 4)'::geometry = 'POINT(10 5)'::geometry; +select '#1023.b', postgis_addbbox('POINT(10 4)'::geometry) = 'POINT(10 4)'::geometry; + +-- #1069 -- +select '#1060', ST_Relate(ST_GeomFromText('POINT EMPTY',4326), ST_GeomFromText('POINT EMPTY',4326)) As result; + +-- #1273 -- +WITH p AS ( SELECT 'POINT(832694.188 816254.625)'::geometry as g ) +SELECT '#1273', st_equals(p.g, postgis_addbbox(p.g)) from p; + +-- Another for #1273 -- +WITH p AS ( SELECT 'MULTIPOINT((832694.188 816254.625))'::geometry as g ) +SELECT '#1273.1', st_equals(p.g, postgis_dropbbox(p.g)) from p; + +-- #877, #818 +create table t(g geometry); +select '#877.1', ST_EstimatedExtent('t','g'); +analyze t; +select '#877.2', ST_EstimatedExtent('public', 't','g'); +select '#877.2.deprecated', ST_Estimated_Extent('public', 't','g'); +insert into t(g) values ('LINESTRING(-10 -50, 20 30)'); + +-- #877.3 +with e as ( select ST_EstimatedExtent('t','g') as e ) +select '#877.3', round(st_xmin(e.e)::numeric, 5), round(st_xmax(e.e)::numeric, 5), +round(st_ymin(e.e)::numeric, 5), round(st_ymax(e.e)::numeric, 5) from e; + +-- #877.4 +analyze t; +with e as ( select ST_EstimatedExtent('t','g') as e ) +select '#877.4', round(st_xmin(e.e)::numeric, 5), round(st_xmax(e.e)::numeric, 5), +round(st_ymin(e.e)::numeric, 5), round(st_ymax(e.e)::numeric, 5) from e; + +-- #877.5 +truncate t; +with e as ( select ST_EstimatedExtent('t','g') as e ) +select '#877.5', round(st_xmin(e.e)::numeric, 5), round(st_xmax(e.e)::numeric, 5), +round(st_ymin(e.e)::numeric, 5), round(st_ymax(e.e)::numeric, 5) from e; +drop table t; + +-- #1292 +SELECT '#1292', ST_AsText(ST_SnapToGrid(ST_GeomFromText( + 'GEOMETRYCOLLECTION(POINT(180 90),POLYGON((140 50,150 50,180 50,140 50),(140 60,150 60,180 60,140 60)))' + , 4326), 0.00001)::geography); + +-- #1292.1 +SELECT '#1292.1', ST_AsText(ST_GeomFromText('POINT(180.00000000001 95)')::geography), + ST_AsText(ST_GeomFromText('POINT(185 90.00000000001)')::geography); + +-- #1320 +SELECT '<#1320>'; +CREATE TABLE A ( geom geometry(MultiPolygon, 4326), + geog geography(MultiPolygon, 4326) ); +-- Valid inserts +INSERT INTO a(geog) VALUES('SRID=4326;MULTIPOLYGON (((0 0, 10 0, 10 10, 0 0)))'::geography); +INSERT INTO a(geom) VALUES('SRID=4326;MULTIPOLYGON (((0 0, 10 0, 10 10, 0 0)))'::geometry); +SELECT '#1320.geog.1', geometrytype(geog::geometry), st_srid(geog::geometry) FROM a where geog is not null; +SELECT '#1320.geom.1', geometrytype(geom), st_srid(geom) FROM a where geom is not null; +-- Type mismatches is not allowed +INSERT INTO a(geog) VALUES('SRID=4326;POLYGON ((0 0, 10 0, 10 10, 0 0))'::geography); +INSERT INTO a(geom) VALUES('SRID=4326;POLYGON ((0 0, 10 0, 10 10, 0 0))'::geometry); +SELECT '#1320.geog.2', geometrytype(geog::geometry), st_srid(geog::geometry) FROM a where geog is not null; +SELECT '#1320.geom.2', geometrytype(geom), st_srid(geom) FROM a where geom is not null; +-- Even if it's a trigger changing the type +CREATE OR REPLACE FUNCTION triga() RETURNS trigger AS +$$ BEGIN + NEW.geom = ST_GeometryN(New.geom,1); + NEW.geog = ST_GeometryN(New.geog::geometry,1)::geography; + RETURN NEW; +END; $$ language plpgsql VOLATILE; +CREATE TRIGGER triga_before + BEFORE INSERT ON a FOR EACH ROW + EXECUTE PROCEDURE triga(); +INSERT INTO a(geog) VALUES('SRID=4326;MULTIPOLYGON (((0 0, 10 0, 10 10, 0 0)))'::geography); +INSERT INTO a(geom) VALUES('SRID=4326;MULTIPOLYGON (((0 0, 10 0, 10 10, 0 0)))'::geometry); +SELECT '#1320.geog.3', geometrytype(geog::geometry), st_srid(geog::geometry) FROM a where geog is not null; +SELECT '#1320.geom.3', geometrytype(geom), st_srid(geom) FROM a where geom is not null; +DROP TABLE A; +DROP FUNCTION triga(); +SELECT ''; + +-- 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( + ' + + + + + 711540.35 1070163.61 711523.82 1070166.54 711521.30 1070164.14 711519.52 1070162.44 711518.57 1070164.62 712154.47 1070824.94 + + + + + + 712154.47 1070824.94 712154.98 1070826.04 712154.41 1070827.22 + + + + + + + 712154.41 1070827.22 712160.31 1070837.07 712160.92 1070835.36 712207.89 1071007.95 + + + + 712207.89 1071007.95 712207.48 1071005.59 712208.38 1071001.28712208.38 1071001.28 712228.74 1070949.67 712233.98 1070936.15 712124.93 1070788.72712124.93 1070788.72 712124.28 1070785.87 712124.63 1070783.38712124.63 1070783.38 712141.04 1070764.12 712146.60 1070757.01 711540.35 1070163.61 + + + 713061.62 1070354.46 713053.59 1070335.12 713049.58 1070315.92 713049.65 1070298.33 713061.62 1070354.46 + + + ')); + +-- #1957 -- +SELECT '#1957', ST_Distance(ST_Makeline(ARRAY['POINT(1 0)'::geometry]), 'POINT(0 0)'::geometry); + +-- #1978 -- +SELECT '#1978', round(ST_Length(ST_GeomFromText('CIRCULARSTRING(0 0,1 0,0 0)',0))::numeric,4); + +-- #1996 -- +SELECT '#1996', ST_AsGeoJSON(ST_GeomFromText('POINT EMPTY')); + +-- #2001 -- +SELECT '#2001', ST_AsText(ST_CurveToLine(ST_GeomFromText('CURVEPOLYGON((0 0, 0 1, 1 1, 0 0))'), 2)); + +-- #2028 -- +SELECT '#2028', ST_AsText(ST_Multi('TRIANGLE((0 0, 0 1, 1 1, 0 0))')); + + +-- #2035 START ------------------------------------------------------------ + +-- Simple geographic table, with single point. +CREATE TABLE "city" ( + "id" integer, + "name" varchar(30) NOT NULL, + "point" geometry(POINT,4326) NOT NULL +); +CREATE INDEX "city_point_id" ON "city" USING GIST ( "point" ); + +-- Initial data, with points around the world. +INSERT INTO "city" (id, name, point) VALUES (1, 'Houston', 'SRID=4326;POINT(-95.363151 29.763374)'); +INSERT INTO "city" (id, name, point) VALUES (2, 'Dallas', 'SRID=4326;POINT(-95.363151 29.763374)'); +INSERT INTO "city" (id, name, point) VALUES (3, 'Oklahoma City', 'SRID=4326;POINT(-97.521157 34.464642)'); +INSERT INTO "city" (id, name, point) VALUES (4, 'Wellington', 'SRID=4326;POINT(174.783117 -41.315268)'); +INSERT INTO "city" (id, name, point) VALUES (5, 'Pueblo', 'SRID=4326;POINT(-104.609252 38.255001)'); +INSERT INTO "city" (id, name, point) VALUES (6, 'Lawrence', 'SRID=4326;POINT(-95.23506 38.971823)'); +INSERT INTO "city" (id, name, point) VALUES (7, 'Chicago', 'SRID=4326;POINT(-87.650175 41.850385)'); +INSERT INTO "city" (id, name, point) VALUES (8, 'Victoria', 'SRID=4326;POINT(-123.305196 48.462611)'); + +-- This query, or COUNT(*), does not return anything; should return 6 cities, +-- excluding Pueblo and Victoria. The Polygon is a simple approximation of +-- Colorado. +SELECT '#2035a', Count(*) FROM "city" + WHERE "city"."point" >> ST_GeomFromEWKT('SRID=4326;POLYGON ((-109.060253 36.992426, -109.060253 41.003444, -102.041524 41.003444, -102.041524 36.992426, -109.060253 36.992426))'); + +-- However, when a LIMIT is placed on statement, the query suddenly works. +SELECT '#2035b', Count(*) FROM "city" + WHERE "city"."point" >> ST_GeomFromEWKT('SRID=4326;POLYGON ((-109.060253 36.992426, -109.060253 41.003444, -102.041524 41.003444, -102.041524 36.992426, -109.060253 36.992426))') LIMIT 6; + +DROP TABLE "city"; +-- #2035 END -------------------------------------------------------------- + + +-- #2084 -- +SELECT '#2048', num, ST_Within('POINT(-54.394 56.522)', "the_geom"), ST_CoveredBy('POINT(-54.394 56.522)', "the_geom") +FROM ( VALUES +(1, '0103000000010000000E00000051C6F7C5A5324BC02EB69F8CF13F4C40F12EA4C343364BC0326AA2CF47434C402BC1A8A44E364BC02A50E10852434C407F2990D959364BC0A0D1730B5D434C404102452C62364BC0ECF335CB65434C400903232F6B364BC0F635E84B6F434C40BD0CC51D6F364BC0D2805EB873434C40B9E6E26F7B364BC0F20B93A982434C40D9FAAF73D3344BC0FE84D04197444C40BD5C8AABCA344BC0CED05CA791444C4023F2237EC5344BC02A84F23E8E444C40BDCDD8077B324BC0C60FB90F01434C409FD1702E65324BC04EF1915C17404C4051C6F7C5A5324BC02EB69F8CF13F4C40'::geometry), +(2, '0103000000010000001C00000003F25650F73B4BC098477F523E3E4C40C9A6A344CE3C4BC0C69698653E3E4C40BDD0E979373E4BC0081FA0FB723E4C400FD252793B3E4BC01A137F14753E4C40537170E998414BC070D3BCE314414C4023FC51D499474BC0D4D100DE024F4C40638C47A984454BC024130D52F0504C40B9442DCDAD404BC03A29E96168554C40C7108DEE20404BC07C7C26FBE7554C40195D6BEF533F4BC0E20391459A564C40239FE40E9B344BC08C1ADB6B41514C40132D3F7095314BC0BA2ADF33124F4C409DB91457952D4BC02C7B681F2B4C4C4089DC60A8C32C4BC07C5C3810924B4C40D7ED409DF22A4BC0F64389963C4A4C405D1EF818AC2A4BC00EC84274084A4C401B48A46DFC294BC0B271A8DF85494C40E78AA6B393294BC01ED0EFFB37494C4081C64B3789294BC0DC5BE7DF2E494C409B23329287294BC0F0D6974E2D494C40CD22D5D687294BC0844316D72C494C40F5229D4FE2294BC002F19825AB484C40A3D0BD5AE9294BC06C0776A9A2484C409FD1702E65324BC04EF1915C17404C409F860AA7BD324BC0162CA390E33F4C40539A5C1C23334BC0FE86B04EB03F4C4081511DFF90334BC088FF36D4873F4C4003F25650F73B4BC098477F523E3E4C40'::geometry), +(3, '010300000001000000100000008D57CD101A214BC0AECDD34E072C4C400DBB72E6EC274BC0A8088D60E32C4C40CF8FD7E6734E4BC0B22695BE4A324C40BFA74213934F4BC020BE505D4C354C4057CD4BEE454E4BC0BA6CF3940F3D4C40E7BDC5FD263E4BC09A4B297D5B484C4073A46A86701C4BC0B287F08D93364C4045501F86701C4BC05EBDB78D93364C40A37DB6586D1C4BC0841E7D2891364C409FBF445F6D1C4BC01E225C5690364C40D1BA97726D1C4BC06E2AF7EA8D364C4019B60C9B751C4BC0D2FD702575364C40FDE4394B5E1F4BC08C40F231CC2F4C402343DF40F51F4BC022008E3D7B2E4C400BB57B45F9204BC0908CE2EA3A2C4C408D57CD101A214BC0AECDD34E072C4C40'::geometry) +) AS f(num, the_geom); + +-- #2112 -- Start +SELECT '#2112a', ST_3DDistance(a,b), ST_ASEWKT(ST_3DShortestLine(a,b)) +FROM (SELECT 'POLYGON((1 1 1, 5 1 1,5 5 1, 1 5 1,1 1 1))'::geometry as a, 'LINESTRING(0 0 2, 0 0 0,5 5 2)'::geometry as b + ) as foo; + +SELECT '#2112b', ST_3DDistance(a,b), ST_ASEWKT(ST_3DShortestLine(a,b)) +FROM (SELECT 'POLYGON((1 1 1, 5 1 1,5 5 1, 1 5 1,1 1 1))'::geometry as a, 'LINESTRING(1 0 2, 1 0 0,5 5 -1)'::geometry as b + ) as foo; +-- 2112 -- End + +SELECT '#2108', ST_AsEWKT(ST_LineInterpolatePoint('SRID=3395;LINESTRING M EMPTY'::geometry, 0.5)); +SELECT '#2117', ST_AsEWKT(ST_PointOnSurface('SRID=3395;MULTIPOLYGON M EMPTY'::geometry)); + +SELECT '#2110.1', 'POINT(0 0)'::geometry = 'POINT EMPTY'::geometry; +SELECT '#2110.2', 'POINT EMPTY'::geometry = 'POINT EMPTY'::geometry; +SELECT '#2110.3', 'POINT(0 0)'::geometry = 'POINT(0 0)'::geometry; + + +SELECT '#2145', +round(ST_Length(St_Segmentize(ST_GeographyFromText('LINESTRING(-89.3000030518 28.2000007629,-89.1999969482 89.1999969482,-89.1999969482 89.1999969482)'), 10000))::numeric,0); + + +-- Clean up +DELETE FROM spatial_ref_sys; diff --git a/regress/sfcgal/tickets_expected b/regress/sfcgal/tickets_expected new file mode 100644 index 000000000..fbdaf4fad --- /dev/null +++ b/regress/sfcgal/tickets_expected @@ -0,0 +1,245 @@ +#2|POLYGON((1 1,1 2,2 2,3 2,3 1,2 1,1 1)) +#11|0 +NOTICE: ST_Locate_Between_Measures and ST_Locate_Along_Measure are deprecated. Use ST_LocateAlong and ST_LocateBetween. +#21|SRID=31293;POINTM(6220.13 5337367.145 4566) +t +ERROR: AddGeometryColumn() - invalid SRID +#44|t|t +#58|220187|150406|220289|150507 +ERROR: lwgeom_to_gml2: 'CurvePolygon' geometry type not supported +#66|CIRCULARSTRING(0 0,1 1,2 2) +#68a|MULTIPOINT(1 3,4 5) +ERROR: lwgeom_longitude_shift: unsupported geom type: CircularString +#69|CIRCULARSTRING(220269 150417,220228 150507,220228 150408) +#70|3 +#73|GEOMETRYCOLLECTION(CIRCULARSTRING(1 1,2 3,4 5,6 7,5 6)) +#80|MULTILINESTRING((0 0,1 1)) +#83|MULTICURVE(CIRCULARSTRING(220268 150415,220227 150505,220227 150406)) +ERROR: LWGEOM2SFCGAL: Unknown geometry type ! +#112|GEOMETRYCOLLECTION(POINT(-10 50)) +NOTICE: ST_Locate_Between_Measures and ST_Locate_Along_Measure are deprecated. Use ST_LocateAlong and ST_LocateBetween. +ERROR: Geometry argument does not have an 'M' ordinate +#116|POLYGON EMPTY +#122|CIRCULARSTRING(220268 150415,220227 150505,220227 150406) +#124a|COMPOUNDCURVE(CIRCULARSTRING(0 0,1 1,1 0),(1 0,30 5),CIRCULARSTRING(30 5,34 56,67 89)) +ERROR: incontinuous compound curve +#145a|0103000020E610000000000000 +#145b|0 +#146|0|t|GEOMETRYCOLLECTION(LINESTRING(0 0,-1 -1),MULTIPOINT(1 2,2 3)) +ERROR: Invalid hex string, length (267) has to be a multiple of two! +#157|ST_Polygon|POLYGON +#157|ST_Point|POINT +#157|ST_Polygon|POLYGON +#157|ST_CurvePolygon|CURVEPOLYGON +#157|ST_CircularString|CIRCULARSTRING +#168|3|MULTIPOLYGON ZM (((4275341.96977851 259186.966993061 1323.76295828331 -1.79769313486232e+308,4275341.96977851 259186.966993061 1323.76295828331 -1.79769313486232e+308,4275341.96977851 259186.966993061 1323.76295828331 -1.79769313486232e+308)))|IllegalArgumentException: Invalid number of points in LinearRing found 3 - must be 0 or >= 4 +#175|SRID=26915;POINT(482020 4984378) +#178a|0 +#178b|5 +NOTICE: No points or linestrings in input array +#179a| +NOTICE: No points or linestrings in input array +#179b| +#183|CIRCULARSTRING(0 0,0.5 1.2071067812,0 1) +#210a| +NOTICE: No points or linestrings in input array +#210b| +#213|17 +#234|COMPOUNDCURVE((0 0,1 1)) +#241|0 +#254|010700000000000000 +#259| +#260|1667701 +#261|0 +#262|POINT(-119.5434 34.9438)|t|t|t +#262|POINT(-119.5452 34.9442)|t|t|t +#262|POINT(-119.5434 34.9438)|t|t|t +#262|POINT(-119.5438 34.9443)|t|t|t +#263|SRID=4326;POINT(-119.5434 34.9438)|t|t|t +#263|SRID=4326;POINT(-119.5452 34.9442)|t|t|t +#263|SRID=4326;POINT(-119.5434 34.9438)|t|t|t +#263|SRID=4326;POINT(-119.5438 34.9443)|t|t|t +#271|t +#272|-2|2 +#277|1,1e+308 +#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|0 0 +#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 + +#1344|25 +#1385| +#657.1|-166.78 +#657.2|10.00 +#657.3|t +#1305.1|POINT(10 10) +#1305.2|t +#1305.3|t +ERROR: MultiPolygon cannot contain MultiPoint element at character 8 +ERROR: MultiLineString cannot contain MultiPoint element at character 8 +ERROR: MultiPoint cannot contain MultiPoint element at character 8 +ERROR: CompoundCurve cannot contain MultiPoint element at character 8 +ERROR: MultiCurve cannot contain MultiPoint element at character 8 +ERROR: MultiSurface cannot contain MultiPoint element at character 8 +#1453.1|t +#1453.2|f +#1454|t +#1414|CURVEPOLYGON Z EMPTY +#1478|01040000200100000000000000 +#745|GEOMETRYCOLLECTION(POLYGON((-72 42 1,-70 43 1,-71 41 1,-72 42 1))) +#1450|POINT|POLYGON +#1482|4326 +#852.1|1|f|f +#852.1|2|f|f +#852.2|1|t|t +#852.2|2|t|t +#1489|MULTIPOINT EMPTY|0|MULTILINESTRING EMPTY|0|MULTIPOLYGON EMPTY|0|GEOMETRYCOLLECTION EMPTY|0 +ERROR: AddToPROJ4SRSCache: could not parse proj4 string '' +#1038| +#1042|2 +#1170|90 +#1264|t +#1398a|POINT(-119.093153 45.632669) +#1398b|POINT(-160.137654 77.091608) +#1543|MULTILINESTRING((0 0,10 0,10 10,0 0),(0 0))|POLYGON((0 0,10 10,10 0,0 0)) +#1578|f|f +#1580.1|Point[BS] +ERROR: transform: couldn't project point (180 90 0): tolerance condition error (-20) +#1580.3|Point[BS] +#1596.1|public.road_pg.roads_geom SRID:3395 TYPE:POINT DIMS:2 +ERROR: invalid SRID: 330000 not found in spatial_ref_sys +#1596.3|3395 +ERROR: invalid SRID: 999000 not found in spatial_ref_sys +#1596.5|3395 +NOTICE: SRID value -1 converted to the officially unknown SRID value 0 +#1596.6|public.road_pg.roads_geom SRID changed to 0 +#1596.7|0 +#1596|Point[BGS] +#1695|MULTIPOLYGON EMPTY +#1697.1|0 +#1697.2|0 +#1697.3|1024 +#1734.1|1026 +#1755|01010000A0E6100000000000000040554000000000008041400000000000000000 +#1776|POLYGON((0 0,10 0,10 10,0 0))|POLYGON((0 0,10 0,10 10,0 0)) +#1780|t +#1791|4.7 +ERROR: ST_Segmentize: invalid max_distance 0 (must be >= 0) +ERROR: invalid GML representation +#1957|inf +#1978|3.1413 +#1996|{"type":"Point","coordinates":[]} +#2001|POLYGON((0 0,0 1,1 1,0 0)) +#2028|TIN(((0 0,0 1,1 1,0 0))) +#2035a|6 +#2035b|6 +#2048|1|f|f +#2048|2|t|t +#2048|3|f|f +#2112a|0|LINESTRING(2.5 2.5 1,2.5 2.5 1) +#2112b|1|LINESTRING(1 1 1,1 0 1) +#2108|SRID=3395;POINTM EMPTY +#2117|SRID=3395;POINTM EMPTY +#2110.1|f +#2110.2|t +#2110.3|t +#2145|6792004 diff --git a/regress/sfcgal/wmsservers.sql b/regress/sfcgal/wmsservers.sql new file mode 100644 index 000000000..290f456d2 --- /dev/null +++ b/regress/sfcgal/wmsservers.sql @@ -0,0 +1,39 @@ +SET postgis.backend = 'sfcgal'; +SET client_min_messages TO warning; + +SELECT 'Starting up MapServer/Geoserver tests...'; +-- Set up the data table +SELECT 'Setting up the data table...'; +CREATE TABLE public.wmstest ( id INTEGER, pt GEOMETRY(Polygon,4326) ); +INSERT INTO wmstest SELECT lon * 100 + lat AS id, st_setsrid(st_buffer(st_makepoint(lon, lat),1.0),4326) AS pt +FROM (select lon, generate_series(-80,80, 5) AS lat FROM (SELECT generate_series(-175, 175, 5) AS lon) AS sq1) AS sq2; +--INSERT INTO geometry_columns (f_table_catalog, f_table_schema, f_table_name, f_geometry_column, coord_dimension, srid, type) VALUES ('', 'public','wmstest','pt',2,4326,'POLYGON'); +ALTER TABLE wmstest add PRIMARY KEY ( id ); +CREATE INDEX wmstest_geomidx ON wmstest using gist ( pt ); + +-- Geoserver 2.0 NG tests +SELECT 'Running Geoserver 2.0 NG tests...'; +-- Run a Geoserver 2.0 NG metadata query +SELECT 'Geoserver1', upper(TYPE) As TYPE FROM GEOMETRY_COLUMNS WHERE F_TABLE_SCHEMA = 'public' AND F_TABLE_NAME = 'wmstest' AND F_GEOMETRY_COLUMN = 'pt'; +SELECT 'Geoserver2', SRID FROM GEOMETRY_COLUMNS WHERE F_TABLE_SCHEMA = 'public' AND F_TABLE_NAME = 'wmstest' AND F_GEOMETRY_COLUMN = 'pt'; +-- Run a Geoserver 2.0 NG WMS query +SELECT 'Geoserver3', "id",substr(encode(ST_AsBinary(ST_Force_2d("pt"),'XDR'),'base64'),0,16) as "pt" FROM "public"."wmstest" WHERE "pt" && ST_GeomFromText('POLYGON ((-6.58216065979069 -0.7685569763184591, -6.58216065979069 0.911225433349509, -3.050569931030911 0.911225433349509, -3.050569931030911 -0.7685569763184591, -6.58216065979069 -0.7685569763184591))', 4326); +-- Run a Geoserver 2.0 NG KML query +SELECT 'Geoserver4', count(*) FROM "public"."wmstest" WHERE "pt" && ST_GeomFromText('POLYGON ((-1.504017942347938 24.0332272532341, -1.504017942347938 25.99364254836741, 1.736833353559741 25.99364254836741, 1.736833353559741 24.0332272532341, -1.504017942347938 24.0332272532341))', 4326); +SELECT 'Geoserver5', "id",substr(encode(ST_AsBinary(ST_Force_2d("pt"),'XDR'),'base64'),0,16) as "pt" FROM "public"."wmstest" WHERE "pt" && ST_GeomFromText('POLYGON ((-1.504017942347938 24.0332272532341, -1.504017942347938 25.99364254836741, 1.736833353559741 25.99364254836741, 1.736833353559741 24.0332272532341, -1.504017942347938 24.0332272532341))', 4326); +SELECT 'Geoserver6', "id",substr(encode(ST_AsBinary(ST_Force_2d("pt"),'XDR'),'base64'),0,16) as "pt" FROM "public"."wmstest" WHERE "pt" && ST_GeomFromText('POLYGON ((-1.507182836191598 24.031312785172446, -1.507182836191598 25.995557016429064, 1.7399982474034008 25.995557016429064, 1.7399982474034008 24.031312785172446, -1.507182836191598 24.031312785172446))', 4326); + +-- MapServer 5.4 tests +select 'MapServer1', attname from pg_attribute, pg_constraint, pg_class where pg_constraint.conrelid = pg_class.oid and pg_class.oid = pg_attribute.attrelid and pg_constraint.contype = 'p' and pg_constraint.conkey[1] = pg_attribute.attnum and pg_class.relname = 'wmstest' and pg_table_is_visible(pg_class.oid) and pg_constraint.conkey[2] is null; +select 'MapServer2', "id",substr(encode(ST_AsBinary(ST_Force_collection(ST_Force_2d("pt")),'NDR'),'base64'),0,16) as geom,"id" from wmstest where pt && ST_GeomFromText('POLYGON((-98.5 32,-98.5 39,-91.5 39,-91.5 32,-98.5 32))',find_srid('','wmstest','pt')); + +-- MapServer 5.6 tests +select * from wmstest where false limit 0; +select 'MapServer3', attname from pg_attribute, pg_constraint, pg_class where pg_constraint.conrelid = pg_class.oid and pg_class.oid = pg_attribute.attrelid and pg_constraint.contype = 'p' and pg_constraint.conkey[1] = pg_attribute.attnum and pg_class.relname = 'wmstest' and pg_table_is_visible(pg_class.oid) and pg_constraint.conkey[2] is null; +select 'MapServer4', "id",substr(encode(ST_AsBinary(ST_Force_collection(ST_Force_2d("pt")),'NDR'),'hex'),0,16) as geom,"id" from wmstest where pt && ST_GeomFromText('POLYGON((-98.5 32,-98.5 39,-91.5 39,-91.5 32,-98.5 32))',find_srid('','wmstest','pt')); + +-- Drop the data table +SELECT 'Removing the data table...'; +DROP TABLE wmstest; +--DELETE FROM geometry_columns WHERE f_table_name = 'wmstest' AND f_table_schema = 'public'; +SELECT 'Done.'; diff --git a/regress/sfcgal/wmsservers_expected b/regress/sfcgal/wmsservers_expected new file mode 100644 index 000000000..d2702ad97 --- /dev/null +++ b/regress/sfcgal/wmsservers_expected @@ -0,0 +1,18 @@ +Starting up MapServer/Geoserver tests... +Setting up the data table... +ALTER TABLE +Running Geoserver 2.0 NG tests... +Geoserver1|POLYGON +Geoserver2|4326 +Geoserver3|-500|AAAAAAMAAAABAAA +Geoserver4|1 +Geoserver5|25|AAAAAAMAAAABAAA +Geoserver6|25|AAAAAAMAAAABAAA +MapServer1|id +MapServer2|-9465|AQcAAAABAAAAAQM|-9465 +MapServer2|-9460|AQcAAAABAAAAAQM|-9460 +MapServer3|id +MapServer4|-9465|010700000001000|-9465 +MapServer4|-9460|010700000001000|-9460 +Removing the data table... +Done. -- 2.40.0