diff --git a/.travis.yml b/.travis.yml
index 758f119..4df87d5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,9 +8,10 @@ env:
- PG_SUPPORTED_VERSIONS=13
- PG_SUPPORTED_VERSIONS=14
- PG_SUPPORTED_VERSIONS=15
+ - PG_SUPPORTED_VERSIONS=16
language: C
-dist: bionic
+dist: focal
before_install:
# extra apt.pg.o.sh options added in version 204, travis currently has 199 (2019-11-27)
diff --git a/Makefile b/Makefile
index dca3b7d..c3351cb 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-PGSPHERE_VERSION = 1.2.3
+PGSPHERE_VERSION = 1.3.0
EXTENSION = pg_sphere
RELEASE_SQL = $(EXTENSION)--$(PGSPHERE_VERSION).sql
USE_PGXS = 1
@@ -11,7 +11,7 @@ MODULE_big = pg_sphere
OBJS = src/sscan.o src/sparse.o src/sbuffer.o src/vector3d.o src/point.o \
src/euler.o src/circle.o src/line.o src/ellipse.o src/polygon.o \
src/path.o src/box.o src/output.o src/gq_cache.o src/gist.o \
- src/key.o src/gnomo.o src/epochprop.o
+ src/key.o src/gnomo.o src/epochprop.o src/brin.o
ifneq ($(USE_HEALPIX),0)
OBJS += src/healpix.o src/moc.o src/process_moc.o \
@@ -27,11 +27,13 @@ DATA_built = $(RELEASE_SQL) \
pg_sphere--1.1.5beta4gavo--1.2.0.sql \
pg_sphere--1.2.0--1.2.1.sql \
pg_sphere--1.2.1--1.2.2.sql \
- pg_sphere--1.2.2--1.2.3.sql
+ pg_sphere--1.2.2--1.2.3.sql \
+ pg_sphere--1.2.3--1.3.0.sql
DOCS = README.pg_sphere COPYRIGHT.pg_sphere
REGRESS = init tables points euler circle line ellipse poly path box index \
- contains_ops contains_ops_compat bounding_box_gist gnomo epochprop
+ contains_ops contains_ops_compat bounding_box_gist gnomo epochprop \
+ contains overlaps spoint_brin sbox_brin
ifneq ($(USE_HEALPIX),0)
REGRESS += healpix moc mocautocast
@@ -41,7 +43,7 @@ REGRESS_9_5 = index_9.5 # experimental for spoint3
TESTS = init_test tables points euler circle line ellipse poly path box \
index contains_ops contains_ops_compat bounding_box_gist gnomo \
- epochprop
+ epochprop contains overlaps spoint_brin sbox_brin
ifneq ($(USE_HEALPIX),0)
TESTS += healpix moc mocautocast
@@ -64,7 +66,7 @@ CRUSH_TESTS = init_extended circle_extended
PGS_SQL = pgs_types.sql pgs_point.sql pgs_euler.sql pgs_circle.sql \
pgs_line.sql pgs_ellipse.sql pgs_polygon.sql pgs_path.sql \
pgs_box.sql pgs_contains_ops.sql pgs_contains_ops_compat.sql \
- pgs_gist.sql gnomo.sql
+ pgs_gist.sql gnomo.sql pgs_brin.sql
ifneq ($(USE_HEALPIX),0)
PGS_SQL += healpix.sql
@@ -260,6 +262,9 @@ endif
pg_sphere--1.2.2--1.2.3.sql:
cat upgrade_scripts/$@.in > $@
+pg_sphere--1.2.3--1.3.0.sql: pgs_brin.sql.in
+ cat upgrade_scripts/$@.in $^ > $@
+
# end of local stuff
src/sscan.o : src/sparse.c
diff --git a/README.pg_sphere b/README.pg_sphere
index 6d36fef..95a2563 100644
--- a/README.pg_sphere
+++ b/README.pg_sphere
@@ -9,11 +9,26 @@ It provides:
* Object rotation by Euler angles
* Indexing of spherical data types
-This is an R-Tree implementation using GiST for spherical objects like
+This is an R-tree implementation using GiST for spherical objects like
spherical points and spherical circles with useful functions and operators.
+It also supports the Block Range INdexing (BRIN) for large datasets.
NOTICE:
- This version will work only with PostgreSQL version 9.6 and above.
+ This version will work only with PostgreSQL version 10 and above.
+
+VERSIONING:
+
+Stable versions are marked with tags containing version numbers in the GitHub
+repository at https://github.com/postgrespro/pgsphere/. Each stable version
+contains upgrade scripts for updating an existing installation to the latest
+version using the ALTER EXTENSION UPDATE TO command.
+
+The master branch is intended for development purposes and may contain
+intermediate changes. The current version in the master branch and its
+functionality are subject to change.
+
+Note: The master branch should not be used in production because the upgrade
+scripts and the current version number may be changed.
INSTALLATION:
diff --git a/doc/functions.sgm b/doc/functions.sgm
index 30118bf..d5bb457 100644
--- a/doc/functions.sgm
+++ b/doc/functions.sgm
@@ -463,7 +463,7 @@
Positions at a path
- pgSphere provides two functions to
+ pgSphere provides three functions to
get points at a path.
@@ -477,6 +477,10 @@
spath path
float8 f
+
+ spath_as_array
+ spath path
+
The first function returns the i-th
@@ -495,6 +499,36 @@
+
+
+
+
+ Codestin Search App
+
+ SELECT spoint( spath '{(0, 0),(1, 1)}', 1 );]]>
+
+
+
+
+
+ SELECT spoint( spath '{(0, 0),(1, 1)}', 2 );]]>
+
+
+
+
+
+
+
+ Codestin Search App
+
+ SELECT spath_as_array( spath '{(0, 0),(1, 1)}');]]>
+
+
+
@@ -532,7 +566,85 @@
-
+
+ Codestin Search App
+
+ pgSphere provides two functions to
+ get points at a path.
+
+
+
+ spoint
+ spoly path
+ int4 i
+
+
+ spoly_as_array
+ spath path
+
+
+
+ Codestin Search App
+
+ SELECT spoint( spoly '{(0,0),(1,0),(1,1)}', 1 );]]>
+
+
+
+
+
+ SELECT spoint( spoly '{(0,0),(1,0),(1,1)}', 2 );]]>
+
+
+
+
+
+ SELECT spoint( spoly '{(0,0),(1,0),(1,1)}', 3 );]]>
+
+
+
+
+
+
+
+ Codestin Search App
+
+ SELECT spoly_as_array( spoly '{(0,0),(1,0),(1,1)}' );]]>
+
+
+
+
+
+
+
+
+
+ Codestin Search App
+
+ Returns true if the specified spherical polygon is convex.
+ Returns false otherwise.
+
+
+
+ spoly_is_convex
+ spoly polygon
+
+
+
+ Codestin Search App
+
+ SELECT spoly_is_convex( spoly '{(0,0),(1,0),(1,1),(1,2)}' );]]>
+
+
+
+
+
+
+
+
diff --git a/doc/indices.sgm b/doc/indices.sgm
index 8103072..11940c2 100644
--- a/doc/indices.sgm
+++ b/doc/indices.sgm
@@ -8,15 +8,29 @@
pgSphere uses GiST
- to create spherical indices. An index speeds up the execution
- time of operators BRIN) algorithms to create
+ spherical indices.
+ GiST indexes utilize an R-tree implementation for
+ spherical objects, while BRIN indexes are based on the "summarization"
+ of data blocks (pages) on physical storage in order to
+ organize data searches on ranges of summarized data that can be easily skipped
+ on the base of search filters (see
+ PostgreSQL documentation for further details on BRIN indexes).
+ As a consequence, BRIN indexes are very small indexes (up to 1000 times smaller
+ than GiST ones), generally with lower performance compared with a GiST one,
+ but up to 100 times faster than a full sequential scan of a table performed
+ without any index. So BRIN indexes are particularly suitable in a big data context.
+ An index speeds up the execution time of searches based on operators <@, @, &&, #, =, and !=. You can create
- an index with the following spherical data types:
+ linkend="op.equal">!=.
+
+
+ You can create a GiST index with the following spherical data types:
@@ -55,6 +69,10 @@
+
+ BRIN indexing supports just spherical points (spoint)
+ and spherical coordinates range (sbox) at the moment.
+
Codestin Search App
@@ -65,6 +83,23 @@
+
+ BRIN index can be created through the following syntax:
+
+
+
+
+
+ By default, BRIN indexes summarize blocks of 128 pages. The smaller the
+ number of pages specified, the higher the granularity in searches,
+ and the gap in performance between GiST indexes and BRIN indexes will be
+ decreased. Note that the size of the BRIN indexes increases as well.
+ Different summarizations can be specified with the following
+ command:
+
+
+
+
diff --git a/doc/operators.sgm b/doc/operators.sgm
index 7162a01..73ebb83 100644
--- a/doc/operators.sgm
+++ b/doc/operators.sgm
@@ -331,7 +331,8 @@
a non-boolean operator returning the distance between two
objects in radians. Currently,
pgSphere supports only distances
- between points, circles, and between point and circle. If the
+ between points, circles, between point and circle, and
+ between point and line. If the
objects are overlapping, the distance operator returns zero
(0.0).
@@ -343,6 +344,17 @@
+
+
+
+
+ Codestin Search App
+
+ SELECT 180 * (sline '( 0d, 0d, 0d, XYZ ), 40d ' <-> spoint '( 0d, 90d )')]]>
+
+
+
+
diff --git a/doc/pg_sphere.xml b/doc/pg_sphere.xml
index a48b1e7..950a530 100644
--- a/doc/pg_sphere.xml
+++ b/doc/pg_sphere.xml
@@ -31,7 +31,7 @@
Codestin Search App
pgSphere development team
@@ -50,8 +50,9 @@
PostgreSQL.
- The project is hosted at pgfoundry.org
- and https://github.com/akorotkov/pgsphere
+ The project is hosted at
+ https://github.com/postgrespro/pgsphere
+
This document
diff --git a/expected/circle.out b/expected/circle.out
index 60a0159..02e5334 100644
--- a/expected/circle.out
+++ b/expected/circle.out
@@ -5,6 +5,22 @@
(1 row)
-- Input/Output ---
+SELECT scircle_deg(spoint(10,10), 90);
+ scircle_deg
+------------------------------------------
+ <(0.57522204 , -0.57522204) , 1.5707963>
+(1 row)
+
+SELECT scircle_deg(spoint(10,10), 91);
+ERROR: radius must not be greater than 90 degrees or less than 0
+SELECT scircle_deg(spoint(0,0), 0);
+ scircle_deg
+---------------
+ <(0 , 0) , 0>
+(1 row)
+
+SELECT scircle_deg(spoint(10,10), -1);
+ERROR: radius must not be greater than 90 degrees or less than 0
SELECT set_sphere_output( 'RAD' );
set_sphere_output
-------------------
diff --git a/expected/contains.out b/expected/contains.out
new file mode 100644
index 0000000..e86fcad
--- /dev/null
+++ b/expected/contains.out
@@ -0,0 +1,233 @@
+/*
+This set of tests is designed to verify the compliance of the contain operation with the DE-9IM model
+*/
+-- sline vs spoint
+-- the point lies far beyond the line
+select 'sline ~ spoint', 'f' as expected, sline(spoint'(270d,10d)', spoint'(270d,30d)') ~ spoint'(0d, 50d)' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ sline ~ spoint | f | f
+(1 row)
+
+-- the point lies in the boundary of line
+select 'sline ~ spoint', 'f' as expected, sline(spoint'(270d,10d)', spoint'(270d,30d)') ~ spoint'(270d, 10d)' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ sline ~ spoint | f | t
+(1 row)
+
+-- the point lies in the interior of line
+select 'sline ~ spoint', 't' as expected, sline(spoint'(270d,10d)', spoint'(270d,30d)') ~ spoint'(270d, 20d)' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ sline ~ spoint | t | t
+(1 row)
+
+-- the point and line that degenerated into the point coincide
+select 'sline ~ spoint', 't' as expected, sline(spoint'(270d,10d)', spoint'(270d,10d)') ~ spoint'(270d, 10d)' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ sline ~ spoint | t | t
+(1 row)
+
+-- the point and line that degenerated into the point do not coincide
+select 'sline ~ spoint', 'f' as expected, sline(spoint'(270d,10d)', spoint'(270d,10d)') ~ spoint'(270d, 20d)' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ sline ~ spoint | f | f
+(1 row)
+
+-- spoint vs scircle
+-- the point lies far beyond the circle
+select 'spoint @ scircle', 'f' as expected, spoint'(0d,0d)' @ scircle'<(0d,90d),50d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ spoint @ scircle | f | f
+(1 row)
+
+-- the point lies in the boundary of circle
+select 'spoint @ scircle', 'f' as expected, spoint'(0d,80d)' @ scircle'<(0d,90d),10d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ spoint @ scircle | f | t
+(1 row)
+
+-- the point lies in the interior of circle
+select 'spoint @ scircle', 't' as expected, spoint'(0d,80d)' @ scircle'<(0d,90d),50d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ spoint @ scircle | t | t
+(1 row)
+
+-- the point and circle that degenerated into the point coincide
+select 'spoint @ scircle', 't' as expected, spoint'(0d,90d)' @ scircle'<(0d,90d),0d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ spoint @ scircle | t | t
+(1 row)
+
+-- the point and circle that degenerated into the point do not coincide
+select 'spoint @ scircle', 'f' as expected, spoint'(0d,50d)' @ scircle'<(0d,90d),0d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ spoint @ scircle | f | f
+(1 row)
+
+-- sellipse vs spoint
+-- the point lies far beyond the ellipse
+select 'sellipse ~ spoint', 'f' as expected, sellipse'<{ 30d , 20d }, (0d , 90d) , 0d>' ~ spoint'(0d, 0d)' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ sellipse ~ spoint | f | f
+(1 row)
+
+-- the point lies in the boundary of ellipse
+select 'sellipse ~ spoint', 'f' as expected, sellipse'<{ 30d , 20d }, (0d , 90d) , 0d>' ~ spoint'(0d, 70d)' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ sellipse ~ spoint | f | t
+(1 row)
+
+-- the point lies in the interior of ellipse
+select 'sellipse ~ spoint', 't' as expected, sellipse'<{ 30d , 20d }, (0d , 90d) , 0d>' ~ spoint'(90d, 65d)' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ sellipse ~ spoint | t | t
+(1 row)
+
+-- the point lies in the boundary of ellipse that degenerated into the line
+select 'sellipse ~ spoint', 't' as expected, sellipse'<{ 10d , 0d }, (0d , 0d) , 0d>' ~ spoint'(10d, 0d)' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ sellipse ~ spoint | t | t
+(1 row)
+
+-- the point lies in the interior of ellipse that degenerated into the line
+select 'sellipse ~ spoint', 't' as expected, sellipse'<{ 10d , 0d }, (0d , 0d) , 0d>' ~ spoint'(0d, 0d)' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ sellipse ~ spoint | t | t
+(1 row)
+
+-- the point and ellipse that degenerated into the point coincide
+select 'sellipse ~ spoint', 't' as expected, sellipse'<{ 0d , 0d }, (0d , 90d) , 0d>' ~ spoint'(0d, 90d)' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ sellipse ~ spoint | t | t
+(1 row)
+
+-- the point and ellipse that degenerated into the point do not coincide
+select 'sellipse ~ spoint', 'f' as expected, sellipse'<{ 0d , 0d }, (0d , 90d) , 0d>' ~ spoint'(0d, 91d)' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ sellipse ~ spoint | f | f
+(1 row)
+
+-- spath vs spoint
+-- the point lies far beyond the opened path
+select 'spath ~ spoint', 'f' as expected, spath'{ (-10d, 0d),(10d,0d),(45d,15d),(80d,30d) }' ~ spoint'(0d, 90d)' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath ~ spoint | f | f
+(1 row)
+
+-- the point lies in the boundary of opened path
+select 'spath ~ spoint', 'f' as expected, spath'{ (-10d, 0d),(10d,0d),(45d,15d),(80d,30d) }' ~ spoint'(-10d, 0d)' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath ~ spoint | f | t
+(1 row)
+
+-- the point lies in the boundary of unsimple opened path
+select 'spath ~ spoint', 'f' as expected, spath'{ (-10d, 0d),(10d,0d),(45d,15d),(80d,30d),(-5d, 0d) }' ~ spoint'(-5d, 0d)' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath ~ spoint | f | t
+(1 row)
+
+-- the point lies in the interior of opened path
+select 'spath ~ spoint', 't' as expected, spath'{ (-10d, 0d),(10d,0d),(45d,15d),(80d,30d) }' ~ spoint'(9d, 0d)' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath ~ spoint | t | t
+(1 row)
+
+-- the point lies in the interior of closed path
+select 'spath ~ spoint', 't' as expected, spath'{ (-10d, 0d),(10d,0d),(45d,15d),(80d,30d),(-10d, 0d) }' ~ spoint'(-10d, 0d)' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath ~ spoint | t | t
+(1 row)
+
+-- spoly vs spoint
+-- the point lies far beyond the polygon
+select 'spoly ~ spoint', 'f' as expected, spoly'{ (0d,0d), (10d,0d), (20d,20d) }' ~ spoint'(0d, 90d)' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spoly ~ spoint | f | f
+(1 row)
+
+-- the point lies in the boundary of polygon
+select 'spoly ~ spoint', 'f' as expected, spoly'{ (0d,0d), (10d,0d), (20d,20d) }' ~ spoint'(5d, 0d)' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spoly ~ spoint | f | t
+(1 row)
+
+-- the point lies in the boundary of polygon
+select 'spoly ~ spoint', 'f' as expected, spoly'{ (0d,0d), (10d,0d), (20d,20d) }' ~ spoint'(20d, 20d)' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spoly ~ spoint | f | t
+(1 row)
+
+-- the point lies in the interior of polygon
+select 'spoly ~ spoint', 't' as expected, spoly'{ (0d,0d), (10d,0d), (20d,20d) }' ~ spoint'(5d, 5d)' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spoly ~ spoint | t | t
+(1 row)
+
+-- sbox vs spoint
+-- the point lies far beyond the box
+select 'sbox ~ spoint', 'f' as expected, sbox'( (0d,0d), (20d,10d) )' ~ spoint'(0d, 90d)' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox ~ spoint | f | f
+(1 row)
+
+-- the point lies in the boundary of box
+select 'sbox ~ spoint', 'f' as expected, sbox'( (0d,0d), (20d,10d) )' ~ spoint'(0d, 5d)' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox ~ spoint | f | t
+(1 row)
+
+-- the point lies in the boundary of box
+select 'sbox ~ spoint', 'f' as expected, sbox'( (0d,0d), (20d,10d) )' ~ spoint'(0d, 0d)' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox ~ spoint | f | t
+(1 row)
+
+-- the point lies in the interior of box
+select 'sbox ~ spoint', 't' as expected, sbox'( (0d,0d), (20d,10d) )' ~ spoint'(5d, 5d)' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox ~ spoint | t | t
+(1 row)
+
+-- the point and box that degenerated into the point coincide
+select 'sbox ~ spoint', 't' as expected, sbox'( (0d,0d), (0d,0d) )' ~ spoint'(0d, 0d)' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox ~ spoint | t | t
+(1 row)
+
+-- the point and box that degenerated into the point do not coincide
+select 'sbox ~ spoint', 'f' as expected, sbox'( (0d,0d), (0d,0d) )' ~ spoint'(0d, 1d)' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox ~ spoint | f | f
+(1 row)
+
diff --git a/expected/init.out b/expected/init.out
index 519c140..fc47f40 100644
--- a/expected/init.out
+++ b/expected/init.out
@@ -6,6 +6,6 @@ CREATE EXTENSION pg_sphere;
select pg_sphere_version();
pg_sphere_version
-------------------
- 1.2.3
+ 1.3.0
(1 row)
diff --git a/expected/init_test.out.in b/expected/init_test.out.in
index 129283c..6fbd06b 100644
--- a/expected/init_test.out.in
+++ b/expected/init_test.out.in
@@ -18,18 +18,18 @@ psql:pg_sphere.test.sql:108: NOTICE: argument type sellipse is only a shell
psql:pg_sphere.test.sql:126: NOTICE: type "spoly" is not yet defined
DETAIL: Creating a shell type definition.
psql:pg_sphere.test.sql:133: NOTICE: argument type spoly is only a shell
-psql:pg_sphere.test.sql:152: NOTICE: type "spath" is not yet defined
+psql:pg_sphere.test.sql:151: NOTICE: type "spath" is not yet defined
DETAIL: Creating a shell type definition.
-psql:pg_sphere.test.sql:159: NOTICE: argument type spath is only a shell
-psql:pg_sphere.test.sql:178: NOTICE: type "sbox" is not yet defined
+psql:pg_sphere.test.sql:158: NOTICE: argument type spath is only a shell
+psql:pg_sphere.test.sql:177: NOTICE: type "sbox" is not yet defined
DETAIL: Creating a shell type definition.
-psql:pg_sphere.test.sql:185: NOTICE: argument type sbox is only a shell
-psql:pg_sphere.test.sql:8540: NOTICE: type "spherekey" is not yet defined
+psql:pg_sphere.test.sql:184: NOTICE: argument type sbox is only a shell
+psql:pg_sphere.test.sql:8658: NOTICE: type "spherekey" is not yet defined
DETAIL: Creating a shell type definition.
-psql:pg_sphere.test.sql:8547: NOTICE: argument type spherekey is only a shell
-psql:pg_sphere.test.sql:8561: NOTICE: type "pointkey" is not yet defined
+psql:pg_sphere.test.sql:8665: NOTICE: argument type spherekey is only a shell
+psql:pg_sphere.test.sql:8679: NOTICE: type "pointkey" is not yet defined
DETAIL: Creating a shell type definition.
-psql:pg_sphere.test.sql:8568: NOTICE: argument type pointkey is only a shell
-psql:pg_sphere.test.sql:8574: NOTICE: argument type pointkey is only a shell
-psql:pg_sphere.test.sql:8580: NOTICE: argument type pointkey is only a shell
-psql:pg_sphere.test.sql:8586: NOTICE: argument type pointkey is only a shell
+psql:pg_sphere.test.sql:8686: NOTICE: argument type pointkey is only a shell
+psql:pg_sphere.test.sql:8692: NOTICE: argument type pointkey is only a shell
+psql:pg_sphere.test.sql:8698: NOTICE: argument type pointkey is only a shell
+psql:pg_sphere.test.sql:8704: NOTICE: argument type pointkey is only a shell
diff --git a/expected/init_test_healpix.out.in b/expected/init_test_healpix.out.in
index 330dc68..b87a70d 100644
--- a/expected/init_test_healpix.out.in
+++ b/expected/init_test_healpix.out.in
@@ -1,2 +1,2 @@
-psql:pg_sphere.test.sql:9153: NOTICE: return type smoc is only a shell
-psql:pg_sphere.test.sql:9159: NOTICE: argument type smoc is only a shell
+psql:pg_sphere.test.sql:9684: NOTICE: return type smoc is only a shell
+psql:pg_sphere.test.sql:9690: NOTICE: argument type smoc is only a shell
diff --git a/expected/line.out b/expected/line.out
index b05286b..eb4d2ac 100644
--- a/expected/line.out
+++ b/expected/line.out
@@ -4,6 +4,7 @@
SET 8
(1 row)
+SET extra_float_digits TO -3;
-- checking spherical line operators
SELECT sline ( spoint '(0, 90d)', spoint '(0, -89d)' ) =
sline ( spoint '(0, 90d)', spoint '(0, -89d)' ) ;
@@ -134,4 +135,35 @@ SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) #
f
(1 row)
-
+-- checking the distance between a line and a point
+SELECT sline '( 90d, 0d, 0d, XYZ ), 40d ' <-> spoint '( 0d, 90d )';
+ ?column?
+----------------
+ 0.872664625997
+(1 row)
+
+SELECT sline '( 90d, 0d, 0d, XYZ ), 40d ' <-> spoint '( 0d, 90d )' =
+ spoint '( 0d, 90d )' <-> sline '( 90d, 0d, 0d, XYZ ), 40d ';
+ ?column?
+----------
+ t
+(1 row)
+
+SELECT sline '( 0d, 0d, 0d, XYZ ), 0d ' <-> spoint '( 0d, 90d )';
+ ?column?
+---------------
+ 1.57079632679
+(1 row)
+
+SELECT sline '( 0d, 0d, 0d, XYZ ), 0d ' <-> spoint '( 0d, 0d )';
+ ?column?
+----------
+ 0
+(1 row)
+
+SELECT sline '( 0d, 0d, 0d, XYZ ), 30d ' <-> spoint '( 0d, 30d )';
+ ?column?
+----------------
+ 0.523598775598
+(1 row)
+
diff --git a/expected/moc100.out b/expected/moc100.out
index dfe0399..51d668b 100644
--- a/expected/moc100.out
+++ b/expected/moc100.out
@@ -1,3 +1,14 @@
+\set ECHO none
+ outputfile_for_majorversion
+-----------------------------
+ 10, 11, 12
+(1 row)
+
+ outputfile_for_arch_bits
+--------------------------
+ 64-bit
+(1 row)
+
CREATE TABLE moc100 (
ivoid text,
coverage smoc,
diff --git a/expected/moc100_1.out b/expected/moc100_1.out
index 648d7c7..c7d6255 100644
--- a/expected/moc100_1.out
+++ b/expected/moc100_1.out
@@ -1,3 +1,14 @@
+\set ECHO none
+ outputfile_for_majorversion
+-----------------------------
+ 10, 11, 12
+(1 row)
+
+ outputfile_for_arch_bits
+--------------------------
+ 32-bit
+(1 row)
+
CREATE TABLE moc100 (
ivoid text,
coverage smoc,
diff --git a/expected/moc100_2.out b/expected/moc100_2.out
index e19ec64..0f511a8 100644
--- a/expected/moc100_2.out
+++ b/expected/moc100_2.out
@@ -1,3 +1,14 @@
+\set ECHO none
+ outputfile_for_majorversion
+-----------------------------
+ 13, 14, 15
+(1 row)
+
+ outputfile_for_arch_bits
+--------------------------
+ 64-bit
+(1 row)
+
CREATE TABLE moc100 (
ivoid text,
coverage smoc,
diff --git a/expected/moc100_3.out b/expected/moc100_3.out
index 2f85349..c650501 100644
--- a/expected/moc100_3.out
+++ b/expected/moc100_3.out
@@ -1,3 +1,14 @@
+\set ECHO none
+ outputfile_for_majorversion
+-----------------------------
+ 13, 14, 15
+(1 row)
+
+ outputfile_for_arch_bits
+--------------------------
+ 32-bit
+(1 row)
+
CREATE TABLE moc100 (
ivoid text,
coverage smoc,
diff --git a/expected/moc100_4.out b/expected/moc100_4.out
new file mode 100644
index 0000000..0dc26bd
--- /dev/null
+++ b/expected/moc100_4.out
@@ -0,0 +1,309 @@
+\set ECHO none
+ outputfile_for_majorversion
+-----------------------------
+ 16+
+(1 row)
+
+ outputfile_for_arch_bits
+--------------------------
+ 64-bit
+(1 row)
+
+CREATE TABLE moc100 (
+ ivoid text,
+ coverage smoc,
+ ref_system_name text
+);
+COPY moc100 FROM STDIN;
+CREATE INDEX ON moc100 USING GIN (coverage);
+SELECT ivoid FROM moc100 WHERE coverage && '4/0' ORDER BY ivoid;
+ ivoid
+------------------------------------------
+ ivo://byu.arvo/dfbsspec/q/getssa
+ ivo://cadc.nrc.ca/archive/cfht
+ ivo://cadc.nrc.ca/archive/hst
+ ivo://cds.vizier/b/assocdata
+ ivo://cds.vizier/b/swift
+ ivo://cds.vizier/i/241
+ ivo://cds.vizier/iv/12
+ ivo://cds.vizier/ix/13
+ ivo://cds.vizier/j/a+a/316/147
+ ivo://cds.vizier/j/a+as/105/311
+ ivo://cds.vizier/j/a+as/122/235
+ ivo://chivo/gaia/q/dr1
+ ivo://chivo/openngc/q/data
+ ivo://cxc.harvard.edu/csc
+ ivo://irsa.ipac/2mass/catalog/psc
+ ivo://irsa.ipac/2mass/catalog/xsc
+ ivo://irsa.ipac/2mass/images/asky-ql
+ ivo://irsa.ipac/cosmos/images
+ ivo://irsa.ipac/iras/images/issa
+ ivo://irsa.ipac/mast/scrapbook
+ ivo://irsa.ipac/spitzer/images/swire
+ ivo://mssl.ucl.ac.uk/xmmsuss_dsa/xmmsuss
+ ivo://ned.ipac/sia
+ ivo://ned.ipac/tap
+ ivo://svo.cab/cat/gbs
+ ivo://svo.cab/cat/uves
+ ivo://svo.cab/cat/xshooter
+ ivo://vopdc.iap/fss
+ ivo://vopdc.obspm/imcce/m4ast
+ ivo://vopdc.obspm/imcce/miriade
+ ivo://vopdc.obspm/imcce/skybot
+ ivo://vopdc.obspm/lesia/bestars/besc
+ ivo://vopdc.obspm/lesia/bestars/bess
+ ivo://vopdc.obspm/luth/exoplanet
+ ivo://vopdc.obspm/luth/hess
+(35 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage && '0/';
+ QUERY PLAN
+----------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=0.00..4.01 rows=1 width=96) (actual rows=0 loops=1)
+ Recheck Cond: (coverage && '0/'::smoc)
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..0.00 rows=1 width=0) (actual rows=0 loops=1)
+ Index Cond: (coverage && '0/'::smoc)
+ Planning:
+ Buffers: shared hit=5
+(6 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage && '4/0';
+ QUERY PLAN
+--------------------------------------------------------------------------------
+ Seq Scan on moc100 (cost=0.00..7.26 rows=1 width=96) (actual rows=35 loops=1)
+ Filter: (coverage && '4/0'::smoc)
+ Rows Removed by Filter: 66
+ Buffers: shared hit=115
+ Planning:
+ Buffers: shared hit=1
+(6 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage = '0/0-11';
+ QUERY PLAN
+--------------------------------------------------------------------------------
+ Seq Scan on moc100 (cost=0.00..7.26 rows=1 width=96) (actual rows=23 loops=1)
+ Filter: (coverage = '0/0-11'::smoc)
+ Rows Removed by Filter: 78
+ Buffers: shared hit=60
+ Planning:
+ Buffers: shared hit=4
+(6 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage = '6/43225,43227';
+ QUERY PLAN
+-------------------------------------------------------------------------------
+ Seq Scan on moc100 (cost=0.00..7.26 rows=1 width=96) (actual rows=1 loops=1)
+ Filter: (coverage = '6/43225 43227'::smoc)
+ Rows Removed by Filter: 100
+ Buffers: shared hit=60
+ Planning:
+ Buffers: shared hit=1
+(6 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage = '0/';
+ QUERY PLAN
+-------------------------------------------------------------------------------
+ Seq Scan on moc100 (cost=0.00..7.26 rows=1 width=96) (actual rows=1 loops=1)
+ Filter: (coverage = '0/'::smoc)
+ Rows Removed by Filter: 100
+ Buffers: shared hit=60
+ Planning:
+ Buffers: shared hit=1
+(6 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage <> '0/0-11';
+ QUERY PLAN
+----------------------------------------------------------------------------------
+ Seq Scan on moc100 (cost=0.00..7.26 rows=100 width=96) (actual rows=78 loops=1)
+ Filter: (coverage <> '0/0-11'::smoc)
+ Rows Removed by Filter: 23
+ Buffers: shared hit=60
+ Planning:
+ Buffers: shared hit=4
+(6 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage <> '6/43225,43227';
+ QUERY PLAN
+-----------------------------------------------------------------------------------
+ Seq Scan on moc100 (cost=0.00..7.26 rows=100 width=96) (actual rows=100 loops=1)
+ Filter: (coverage <> '6/43225 43227'::smoc)
+ Rows Removed by Filter: 1
+ Buffers: shared hit=60
+ Planning:
+ Buffers: shared hit=1
+(6 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage <> '0/';
+ QUERY PLAN
+-----------------------------------------------------------------------------------
+ Seq Scan on moc100 (cost=0.00..7.26 rows=100 width=96) (actual rows=100 loops=1)
+ Filter: (coverage <> '0/'::smoc)
+ Rows Removed by Filter: 1
+ Buffers: shared hit=60
+ Planning:
+ Buffers: shared hit=1
+(6 rows)
+
+SET enable_seqscan = off;
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage && '4/0';
+ QUERY PLAN
+------------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=38.92..42.93 rows=1 width=96) (actual rows=35 loops=1)
+ Recheck Cond: (coverage && '4/0'::smoc)
+ Heap Blocks: exact=5
+ Buffers: shared hit=85
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..38.92 rows=1 width=0) (actual rows=35 loops=1)
+ Index Cond: (coverage && '4/0'::smoc)
+ Buffers: shared hit=9
+ Planning:
+ Buffers: shared hit=1
+(9 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage <@ '4/0';
+ QUERY PLAN
+------------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=47.61..51.63 rows=1 width=96) (actual rows=1 loops=1)
+ Recheck Cond: (coverage <@ '4/0'::smoc)
+ Rows Removed by Index Recheck: 35
+ Heap Blocks: exact=5
+ Buffers: shared hit=33
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..47.61 rows=1 width=0) (actual rows=36 loops=1)
+ Index Cond: (coverage <@ '4/0'::smoc)
+ Buffers: shared hit=12
+ Planning:
+ Buffers: shared hit=4
+(10 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage @> '4/0';
+ QUERY PLAN
+------------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=38.92..42.93 rows=1 width=96) (actual rows=28 loops=1)
+ Recheck Cond: (coverage @> '4/0'::smoc)
+ Rows Removed by Index Recheck: 1
+ Heap Blocks: exact=4
+ Buffers: shared hit=36
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..38.92 rows=1 width=0) (actual rows=29 loops=1)
+ Index Cond: (coverage @> '4/0'::smoc)
+ Buffers: shared hit=9
+ Planning:
+ Buffers: shared hit=4
+(10 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage = '0/0-11';
+ QUERY PLAN
+----------------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=106879.01..106883.02 rows=1 width=96) (actual rows=23 loops=1)
+ Recheck Cond: (coverage = '0/0-11'::smoc)
+ Rows Removed by Index Recheck: 1
+ Heap Blocks: exact=2
+ Buffers: shared hit=24581
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..106879.01 rows=1 width=0) (actual rows=24 loops=1)
+ Index Cond: (coverage = '0/0-11'::smoc)
+ Buffers: shared hit=24577
+ Planning:
+ Buffers: shared hit=1
+ JIT:
+ Functions: 2
+ Options: Inlining false, Optimization false, Expressions true, Deforming true
+(13 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage = '6/43225,43227';
+ QUERY PLAN
+------------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=12.83..16.84 rows=1 width=96) (actual rows=1 loops=1)
+ Recheck Cond: (coverage = '6/43225 43227'::smoc)
+ Rows Removed by Index Recheck: 28
+ Heap Blocks: exact=3
+ Buffers: shared hit=12
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..12.83 rows=1 width=0) (actual rows=29 loops=1)
+ Index Cond: (coverage = '6/43225 43227'::smoc)
+ Buffers: shared hit=3
+ Planning:
+ Buffers: shared hit=1
+(10 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage = '0/';
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=12.83..16.84 rows=1 width=96) (actual rows=1 loops=1)
+ Recheck Cond: (coverage = '0/'::smoc)
+ Heap Blocks: exact=1
+ Buffers: shared hit=5
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..12.83 rows=1 width=0) (actual rows=1 loops=1)
+ Index Cond: (coverage = '0/'::smoc)
+ Buffers: shared hit=4
+ Planning:
+ Buffers: shared hit=1
+(9 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage <> '0/0-11';
+ QUERY PLAN
+-------------------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=106888.23..106895.48 rows=100 width=96) (actual rows=78 loops=1)
+ Recheck Cond: (coverage <> '0/0-11'::smoc)
+ Rows Removed by Index Recheck: 23
+ Heap Blocks: exact=5
+ Buffers: shared hit=24821
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..106888.20 rows=100 width=0) (actual rows=101 loops=1)
+ Index Cond: (coverage <> '0/0-11'::smoc)
+ Buffers: shared hit=24762
+ Planning:
+ Buffers: shared hit=1
+ JIT:
+ Functions: 2
+ Options: Inlining false, Optimization false, Expressions true, Deforming true
+(13 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage <> '6/43225,43227';
+ QUERY PLAN
+-------------------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=106888.23..106895.48 rows=100 width=96) (actual rows=100 loops=1)
+ Recheck Cond: (coverage <> '6/43225 43227'::smoc)
+ Rows Removed by Index Recheck: 1
+ Heap Blocks: exact=5
+ Buffers: shared hit=247
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..106888.20 rows=100 width=0) (actual rows=101 loops=1)
+ Index Cond: (coverage <> '6/43225 43227'::smoc)
+ Buffers: shared hit=188
+ Planning:
+ Buffers: shared hit=1
+ JIT:
+ Functions: 2
+ Options: Inlining false, Optimization false, Expressions true, Deforming true
+(13 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage <> '0/';
+ QUERY PLAN
+-------------------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=106888.23..106895.48 rows=100 width=96) (actual rows=100 loops=1)
+ Recheck Cond: (coverage <> '0/'::smoc)
+ Rows Removed by Index Recheck: 1
+ Heap Blocks: exact=5
+ Buffers: shared hit=245
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..106888.20 rows=100 width=0) (actual rows=101 loops=1)
+ Index Cond: (coverage <> '0/'::smoc)
+ Buffers: shared hit=186
+ Planning:
+ Buffers: shared hit=1
+ JIT:
+ Functions: 2
+ Options: Inlining false, Optimization false, Expressions true, Deforming true
+(13 rows)
+
diff --git a/expected/moc100_5.out b/expected/moc100_5.out
new file mode 100644
index 0000000..3fb98a4
--- /dev/null
+++ b/expected/moc100_5.out
@@ -0,0 +1,309 @@
+\set ECHO none
+ outputfile_for_majorversion
+-----------------------------
+ 16+
+(1 row)
+
+ outputfile_for_arch_bits
+--------------------------
+ 32-bit
+(1 row)
+
+CREATE TABLE moc100 (
+ ivoid text,
+ coverage smoc,
+ ref_system_name text
+);
+COPY moc100 FROM STDIN;
+CREATE INDEX ON moc100 USING GIN (coverage);
+SELECT ivoid FROM moc100 WHERE coverage && '4/0' ORDER BY ivoid;
+ ivoid
+------------------------------------------
+ ivo://byu.arvo/dfbsspec/q/getssa
+ ivo://cadc.nrc.ca/archive/cfht
+ ivo://cadc.nrc.ca/archive/hst
+ ivo://cds.vizier/b/assocdata
+ ivo://cds.vizier/b/swift
+ ivo://cds.vizier/i/241
+ ivo://cds.vizier/iv/12
+ ivo://cds.vizier/ix/13
+ ivo://cds.vizier/j/a+a/316/147
+ ivo://cds.vizier/j/a+as/105/311
+ ivo://cds.vizier/j/a+as/122/235
+ ivo://chivo/gaia/q/dr1
+ ivo://chivo/openngc/q/data
+ ivo://cxc.harvard.edu/csc
+ ivo://irsa.ipac/2mass/catalog/psc
+ ivo://irsa.ipac/2mass/catalog/xsc
+ ivo://irsa.ipac/2mass/images/asky-ql
+ ivo://irsa.ipac/cosmos/images
+ ivo://irsa.ipac/iras/images/issa
+ ivo://irsa.ipac/mast/scrapbook
+ ivo://irsa.ipac/spitzer/images/swire
+ ivo://mssl.ucl.ac.uk/xmmsuss_dsa/xmmsuss
+ ivo://ned.ipac/sia
+ ivo://ned.ipac/tap
+ ivo://svo.cab/cat/gbs
+ ivo://svo.cab/cat/uves
+ ivo://svo.cab/cat/xshooter
+ ivo://vopdc.iap/fss
+ ivo://vopdc.obspm/imcce/m4ast
+ ivo://vopdc.obspm/imcce/miriade
+ ivo://vopdc.obspm/imcce/skybot
+ ivo://vopdc.obspm/lesia/bestars/besc
+ ivo://vopdc.obspm/lesia/bestars/bess
+ ivo://vopdc.obspm/luth/exoplanet
+ ivo://vopdc.obspm/luth/hess
+(35 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage && '0/';
+ QUERY PLAN
+----------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=0.00..4.01 rows=1 width=96) (actual rows=0 loops=1)
+ Recheck Cond: (coverage && '0/'::smoc)
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..0.00 rows=1 width=0) (actual rows=0 loops=1)
+ Index Cond: (coverage && '0/'::smoc)
+ Planning:
+ Buffers: shared hit=5
+(6 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage && '4/0';
+ QUERY PLAN
+--------------------------------------------------------------------------------
+ Seq Scan on moc100 (cost=0.00..6.26 rows=1 width=96) (actual rows=35 loops=1)
+ Filter: (coverage && '4/0'::smoc)
+ Rows Removed by Filter: 66
+ Buffers: shared hit=115
+ Planning:
+ Buffers: shared hit=1
+(6 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage = '0/0-11';
+ QUERY PLAN
+--------------------------------------------------------------------------------
+ Seq Scan on moc100 (cost=0.00..6.26 rows=1 width=96) (actual rows=23 loops=1)
+ Filter: (coverage = '0/0-11'::smoc)
+ Rows Removed by Filter: 78
+ Buffers: shared hit=59
+ Planning:
+ Buffers: shared hit=4
+(6 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage = '6/43225,43227';
+ QUERY PLAN
+-------------------------------------------------------------------------------
+ Seq Scan on moc100 (cost=0.00..6.26 rows=1 width=96) (actual rows=1 loops=1)
+ Filter: (coverage = '6/43225 43227'::smoc)
+ Rows Removed by Filter: 100
+ Buffers: shared hit=59
+ Planning:
+ Buffers: shared hit=1
+(6 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage = '0/';
+ QUERY PLAN
+-------------------------------------------------------------------------------
+ Seq Scan on moc100 (cost=0.00..6.26 rows=1 width=96) (actual rows=1 loops=1)
+ Filter: (coverage = '0/'::smoc)
+ Rows Removed by Filter: 100
+ Buffers: shared hit=59
+ Planning:
+ Buffers: shared hit=1
+(6 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage <> '0/0-11';
+ QUERY PLAN
+----------------------------------------------------------------------------------
+ Seq Scan on moc100 (cost=0.00..6.26 rows=100 width=96) (actual rows=78 loops=1)
+ Filter: (coverage <> '0/0-11'::smoc)
+ Rows Removed by Filter: 23
+ Buffers: shared hit=59
+ Planning:
+ Buffers: shared hit=4
+(6 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage <> '6/43225,43227';
+ QUERY PLAN
+-----------------------------------------------------------------------------------
+ Seq Scan on moc100 (cost=0.00..6.26 rows=100 width=96) (actual rows=100 loops=1)
+ Filter: (coverage <> '6/43225 43227'::smoc)
+ Rows Removed by Filter: 1
+ Buffers: shared hit=59
+ Planning:
+ Buffers: shared hit=1
+(6 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage <> '0/';
+ QUERY PLAN
+-----------------------------------------------------------------------------------
+ Seq Scan on moc100 (cost=0.00..6.26 rows=100 width=96) (actual rows=100 loops=1)
+ Filter: (coverage <> '0/'::smoc)
+ Rows Removed by Filter: 1
+ Buffers: shared hit=59
+ Planning:
+ Buffers: shared hit=1
+(6 rows)
+
+SET enable_seqscan = off;
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage && '4/0';
+ QUERY PLAN
+------------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=38.92..42.93 rows=1 width=96) (actual rows=35 loops=1)
+ Recheck Cond: (coverage && '4/0'::smoc)
+ Heap Blocks: exact=5
+ Buffers: shared hit=86
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..38.92 rows=1 width=0) (actual rows=35 loops=1)
+ Index Cond: (coverage && '4/0'::smoc)
+ Buffers: shared hit=9
+ Planning:
+ Buffers: shared hit=1
+(9 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage <@ '4/0';
+ QUERY PLAN
+------------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=47.61..51.63 rows=1 width=96) (actual rows=1 loops=1)
+ Recheck Cond: (coverage <@ '4/0'::smoc)
+ Rows Removed by Index Recheck: 35
+ Heap Blocks: exact=5
+ Buffers: shared hit=33
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..47.61 rows=1 width=0) (actual rows=36 loops=1)
+ Index Cond: (coverage <@ '4/0'::smoc)
+ Buffers: shared hit=12
+ Planning:
+ Buffers: shared hit=4
+(10 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage @> '4/0';
+ QUERY PLAN
+------------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=38.92..42.93 rows=1 width=96) (actual rows=28 loops=1)
+ Recheck Cond: (coverage @> '4/0'::smoc)
+ Rows Removed by Index Recheck: 1
+ Heap Blocks: exact=4
+ Buffers: shared hit=36
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..38.92 rows=1 width=0) (actual rows=29 loops=1)
+ Index Cond: (coverage @> '4/0'::smoc)
+ Buffers: shared hit=9
+ Planning:
+ Buffers: shared hit=4
+(10 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage = '0/0-11';
+ QUERY PLAN
+----------------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=106879.01..106883.02 rows=1 width=96) (actual rows=23 loops=1)
+ Recheck Cond: (coverage = '0/0-11'::smoc)
+ Rows Removed by Index Recheck: 1
+ Heap Blocks: exact=2
+ Buffers: shared hit=24581
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..106879.01 rows=1 width=0) (actual rows=24 loops=1)
+ Index Cond: (coverage = '0/0-11'::smoc)
+ Buffers: shared hit=24577
+ Planning:
+ Buffers: shared hit=1
+ JIT:
+ Functions: 2
+ Options: Inlining false, Optimization false, Expressions true, Deforming true
+(13 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage = '6/43225,43227';
+ QUERY PLAN
+------------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=12.83..16.84 rows=1 width=96) (actual rows=1 loops=1)
+ Recheck Cond: (coverage = '6/43225 43227'::smoc)
+ Rows Removed by Index Recheck: 28
+ Heap Blocks: exact=3
+ Buffers: shared hit=12
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..12.83 rows=1 width=0) (actual rows=29 loops=1)
+ Index Cond: (coverage = '6/43225 43227'::smoc)
+ Buffers: shared hit=3
+ Planning:
+ Buffers: shared hit=1
+(10 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage = '0/';
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=12.83..16.84 rows=1 width=96) (actual rows=1 loops=1)
+ Recheck Cond: (coverage = '0/'::smoc)
+ Heap Blocks: exact=1
+ Buffers: shared hit=5
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..12.83 rows=1 width=0) (actual rows=1 loops=1)
+ Index Cond: (coverage = '0/'::smoc)
+ Buffers: shared hit=4
+ Planning:
+ Buffers: shared hit=1
+(9 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage <> '0/0-11';
+ QUERY PLAN
+-------------------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=106888.23..106894.48 rows=100 width=96) (actual rows=78 loops=1)
+ Recheck Cond: (coverage <> '0/0-11'::smoc)
+ Rows Removed by Index Recheck: 23
+ Heap Blocks: exact=5
+ Buffers: shared hit=24804
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..106888.20 rows=100 width=0) (actual rows=101 loops=1)
+ Index Cond: (coverage <> '0/0-11'::smoc)
+ Buffers: shared hit=24745
+ Planning:
+ Buffers: shared hit=1
+ JIT:
+ Functions: 2
+ Options: Inlining false, Optimization false, Expressions true, Deforming true
+(13 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage <> '6/43225,43227';
+ QUERY PLAN
+-------------------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=106888.23..106894.48 rows=100 width=96) (actual rows=100 loops=1)
+ Recheck Cond: (coverage <> '6/43225 43227'::smoc)
+ Rows Removed by Index Recheck: 1
+ Heap Blocks: exact=5
+ Buffers: shared hit=230
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..106888.20 rows=100 width=0) (actual rows=101 loops=1)
+ Index Cond: (coverage <> '6/43225 43227'::smoc)
+ Buffers: shared hit=171
+ Planning:
+ Buffers: shared hit=1
+ JIT:
+ Functions: 2
+ Options: Inlining false, Optimization false, Expressions true, Deforming true
+(13 rows)
+
+EXPLAIN (ANALYZE, BUFFERS, TIMING OFF, SUMMARY OFF)
+ SELECT * FROM moc100 WHERE coverage <> '0/';
+ QUERY PLAN
+-------------------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on moc100 (cost=106888.23..106894.48 rows=100 width=96) (actual rows=100 loops=1)
+ Recheck Cond: (coverage <> '0/'::smoc)
+ Rows Removed by Index Recheck: 1
+ Heap Blocks: exact=5
+ Buffers: shared hit=228
+ -> Bitmap Index Scan on moc100_coverage_idx (cost=0.00..106888.20 rows=100 width=0) (actual rows=101 loops=1)
+ Index Cond: (coverage <> '0/'::smoc)
+ Buffers: shared hit=169
+ Planning:
+ Buffers: shared hit=1
+ JIT:
+ Functions: 2
+ Options: Inlining false, Optimization false, Expressions true, Deforming true
+(13 rows)
+
diff --git a/expected/overlaps.out b/expected/overlaps.out
new file mode 100644
index 0000000..5b1f885
--- /dev/null
+++ b/expected/overlaps.out
@@ -0,0 +1,1017 @@
+/*
+This set of tests is designed to verify the compliance of the overlap operation with the DE-9IM model
+*/
+-- sline vs sline
+-- the lines have no common points
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(10d,0d)') && sline( spoint'(20d,0d)', spoint'(30d,0d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ sline && sline | f | f
+(1 row)
+
+-- the point of intersection of the lines is the boundary for both
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(10d,0d)') && sline( spoint'(10d,0d)', spoint'(20d,0d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ sline && sline | f | t
+(1 row)
+
+-- one line intersects the other at the boundary point of the latter
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(10d,0d)') && sline( spoint'(0d,90d)', spoint'(0d,-10d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ sline && sline | f | t
+(1 row)
+
+-- the interiors of the lines intersect at one point
+select 'sline && sline', 'f' as expected, sline( spoint'(-10d,0d)', spoint'(10d,0d)') && sline( spoint'(0d,90d)', spoint'(0d,-10d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ sline && sline | f | t
+(1 row)
+
+-- the lines match
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(10d,0d)') && sline( spoint'(0d,0d)', spoint'(10d,0d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ sline && sline | f | t
+(1 row)
+
+-- one line lies completely in the other and they have an intersection at the boundary point
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(10d,0d)') && sline( spoint'(0d,0d)', spoint'(5d,0d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ sline && sline | f | t
+(1 row)
+
+-- one line lies completely in the other and they have no intersection at the boundary point
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(10d,0d)') && sline( spoint'(2d,0d)', spoint'(5d,0d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ sline && sline | f | t
+(1 row)
+
+-- one line partially lies in the other
+select 'sline && sline', 't' as expected, sline( spoint'(0d,0d)', spoint'(10d,0d)') && sline( spoint'(5d,0d)', spoint'(20d,0d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ sline && sline | t | t
+(1 row)
+
+-- the line degenerated into the point lies on the boundary of another
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(10d,0d)') && sline( spoint'(0d,0d)', spoint'(0d,0d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ sline && sline | f | t
+(1 row)
+
+-- the line degenerated into the point lies in the interior of another
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(10d,0d)') && sline( spoint'(5d,0d)', spoint'(5d,0d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ sline && sline | f | t
+(1 row)
+
+-- both lines are degenerated into the point and coincide
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(0d,0d)') && sline( spoint'(0d,0d)', spoint'(0d,0d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ sline && sline | f | t
+(1 row)
+
+-- both lines are degenerated into the point and do not coincide, but lie close to each other
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(0d,0d)') && sline( spoint'(1d,0d)', spoint'(1d,0d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ sline && sline | f | f
+(1 row)
+
+-- scircle vs scircle
+-- the circles have no common points
+select 'scircle && scircle', 'f' as expected, scircle'<(0d , 0d) , 20d>' && scircle'<(30d , 0d) , 5d>' as actual;
+ ?column? | expected | actual
+--------------------+----------+--------
+ scircle && scircle | f | f
+(1 row)
+
+-- the point of intersection of the circles is the boundary for both
+select 'scircle && scircle', 'f' as expected, scircle'<(-10d , 0d) , 10d>' && scircle'<(10d , 0d) , 10d>' as actual;
+ ?column? | expected | actual
+--------------------+----------+--------
+ scircle && scircle | f | t
+(1 row)
+
+-- the circles match
+select 'scircle && scircle', 'f' as expected, scircle'<(-10d , 0d) , 10d>' && scircle'<(-10d , 0d) , 10d>' as actual;
+ ?column? | expected | actual
+--------------------+----------+--------
+ scircle && scircle | f | t
+(1 row)
+
+-- one circle lies completely in the other and they have an intersection at the boundary point
+select 'scircle && scircle', 'f' as expected, scircle'<(0d , 0d) , 20d>' && scircle'<(-10d , 0d) , 10d>' as actual;
+ ?column? | expected | actual
+--------------------+----------+--------
+ scircle && scircle | f | t
+(1 row)
+
+-- one circle lies completely in the other and they have no intersection at the boundary point
+select 'scircle && scircle', 'f' as expected, scircle'<(0d , 0d) , 20d>' && scircle'<(0d , 0d) , 5d>' as actual;
+ ?column? | expected | actual
+--------------------+----------+--------
+ scircle && scircle | f | t
+(1 row)
+
+-- one circle partially lies in the other
+select 'scircle && scircle', 't' as expected, scircle'<(0d , 0d) , 20d>' && scircle'<(10d , 0d) , 20d>' as actual;
+ ?column? | expected | actual
+--------------------+----------+--------
+ scircle && scircle | t | t
+(1 row)
+
+-- the circle degenerated into the point lies on the boundary of another
+select 'scircle && scircle', 'f' as expected, scircle'<(0d , 0d) , 20d>' && scircle'<(20d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+--------------------+----------+--------
+ scircle && scircle | f | t
+(1 row)
+
+-- the circle degenerated into the point lies in the interior of another
+select 'scircle && scircle', 'f' as expected, scircle'<(0d , 0d) , 20d>' && scircle'<(0d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+--------------------+----------+--------
+ scircle && scircle | f | t
+(1 row)
+
+-- both circles are degenerated into the point and coincide
+select 'scircle && scircle', 'f' as expected, scircle'<(0d , 0d) , 0d>' && scircle'<(0d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+--------------------+----------+--------
+ scircle && scircle | f | t
+(1 row)
+
+-- both circles are degenerated into the point and do not coincide, but lie close to each other
+select 'scircle && scircle', 'f' as expected, scircle'<(1d , 0d) , 0d>' && scircle'<(0d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+--------------------+----------+--------
+ scircle && scircle | f | f
+(1 row)
+
+-- sellipse vs sellipse
+-- the ellipses have no common points
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 45d , 20d }, (-45d , 0d) , 0d>' && sellipse'<{ 45d , 20d }, (50 , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+----------------------+----------+--------
+ sellipse && sellipse | f | t
+(1 row)
+
+-- the point of intersection of the ellipses is the boundary for both
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 45d , 20d }, (-45d , 0d) , 0d>' && sellipse'<{ 45d , 20d }, (45d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+----------------------+----------+--------
+ sellipse && sellipse | f | f
+(1 row)
+
+-- the ellipses match
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 45d , 20d }, (-45d , 0d) , 0d>' && sellipse'<{ 45d , 20d }, (-45d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+----------------------+----------+--------
+ sellipse && sellipse | f | t
+(1 row)
+
+-- one ellipse lies completely in the other and they have an intersection at the boundary point
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 40d , 30d }, (0d , 0d) , 0d>' && sellipse'<{ 20d , 5d }, (-20d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+----------------------+----------+--------
+ sellipse && sellipse | f | t
+(1 row)
+
+-- one ellipse lies completely in the other and they have no intersection at the boundary point
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 40d , 30d }, (0d , 0d) , 0d>' && sellipse'<{ 10d , 5d }, (-20d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+----------------------+----------+--------
+ sellipse && sellipse | f | t
+(1 row)
+
+-- one ellipse partially lies in the other
+select 'sellipse && sellipse', 't' as expected, sellipse'<{ 45d , 30d }, (0d , 0d) , 0d>' && sellipse'<{ 20d , 5d }, (30d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+----------------------+----------+--------
+ sellipse && sellipse | t | t
+(1 row)
+
+-- the ellipse degenerated into the line lies completely in the interior of another (non-degenerate) ellipse
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 40d , 30d }, (0d , 0d) , 0d>' && sellipse'<{ 10d , 0d }, (10d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+----------------------+----------+--------
+ sellipse && sellipse | f | t
+(1 row)
+
+-- the ellipse degenerated into the line partially lies in the interior of another (non-degenerate) ellipse
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 40d , 30d }, (0d , 0d) , 0d>' && sellipse'<{ 20d , 0d }, (30d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+----------------------+----------+--------
+ sellipse && sellipse | f | t
+(1 row)
+
+-- the ellipse degenerated into the point lies on the boundary of another
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 40d , 30d }, (0d , 0d) , 0d>' && sellipse'<{ 0d , 0d }, (30d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+----------------------+----------+--------
+ sellipse && sellipse | f | t
+(1 row)
+
+-- the ellipse degenerated into the point lies in the interior of another
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 40d , 30d }, (0d , 0d) , 0d>' && sellipse'<{ 0d , 0d }, (40d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+----------------------+----------+--------
+ sellipse && sellipse | f | t
+(1 row)
+
+-- both ellipses are degenerated into the point and coincide
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 0d , 0d }, (0d , 0d) , 0d>' && sellipse'<{ 0d , 0d }, (0d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+----------------------+----------+--------
+ sellipse && sellipse | f | t
+(1 row)
+
+-- both ellipses are degenerated into the point and do not coincide, but lie close to each other
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 0d , 0d }, (0d , 0d) , 0d>' && sellipse'<{ 0d , 0d }, (1d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+----------------------+----------+--------
+ sellipse && sellipse | f | f
+(1 row)
+
+-- sellipse vs scircle
+-- the ellipse and circle have no common points
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 20d , 10d }, (0d , 0d) , 0d>' && scircle'<(30d , 0d) , 5d>' as actual;
+ ?column? | expected | actual
+---------------------+----------+--------
+ sellipse && scircle | f | f
+(1 row)
+
+-- the point of intersection of the ellipse and circle is the boundary for both
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 20d , 10d }, (0d , 0d) , 0d>' && scircle'<(30d , 0d) , 10d>' as actual;
+ ?column? | expected | actual
+---------------------+----------+--------
+ sellipse && scircle | f | f
+(1 row)
+
+-- the ellipse and circle match
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 10d , 10d }, (30d , 0d) , 0d>' && scircle'<(30d , 0d) , 10d>' as actual;
+ ?column? | expected | actual
+---------------------+----------+--------
+ sellipse && scircle | f | t
+(1 row)
+
+-- the ellipse lies completely in the circle and they have an intersection at the boundary point
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 20d , 10d }, (0d , 0d) , 0d>' && scircle'<(20d , 0d) , 40d>' as actual;
+ ?column? | expected | actual
+---------------------+----------+--------
+ sellipse && scircle | f | t
+(1 row)
+
+-- the ellipse lies completely in the circle and they have no intersection at the boundary point
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 20d , 10d }, (20d , 0d) , 0d>' && scircle'<(20d , 0d) , 40d>' as actual;
+ ?column? | expected | actual
+---------------------+----------+--------
+ sellipse && scircle | f | t
+(1 row)
+
+-- the circle lies completely in the ellipse
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 20d , 10d }, (0d , 0d) , 0d>' && scircle'<(0d , 0d) , 5d>' as actual;
+ ?column? | expected | actual
+---------------------+----------+--------
+ sellipse && scircle | f | t
+(1 row)
+
+-- the circle partially lies in the ellipse
+select 'sellipse && scircle', 't' as expected, sellipse'<{ 20d , 10d }, (0d , 0d) , 0d>' && scircle'<(20d , 0d) , 15d>' as actual;
+ ?column? | expected | actual
+---------------------+----------+--------
+ sellipse && scircle | t | t
+(1 row)
+
+-- the ellipse degenerated into the line lies completely in the interior of circle
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 20d , 0d }, (0d , 0d) , 0d>' && scircle'<(0d , 0d) , 20d>' as actual;
+ ?column? | expected | actual
+---------------------+----------+--------
+ sellipse && scircle | f | t
+(1 row)
+
+-- the ellipse degenerated into the line partially lies in the interior of circle
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 20d , 0d }, (10d , 0d) , 0d>' && scircle'<(0d , 0d) , 20d>' as actual;
+ ?column? | expected | actual
+---------------------+----------+--------
+ sellipse && scircle | f | t
+(1 row)
+
+-- the ellipse degenerated into the point lies on the boundary of circle
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 0d , 0d }, (10d , 0d) , 0d>' && scircle'<(0d , 0d) , 10d>' as actual;
+ ?column? | expected | actual
+---------------------+----------+--------
+ sellipse && scircle | f | t
+(1 row)
+
+-- the ellipse degenerated into the point lies in the interior of circle
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 0d , 0d }, (5d , 0d) , 0d>' && scircle'<(0d , 0d) , 10d>' as actual;
+ ?column? | expected | actual
+---------------------+----------+--------
+ sellipse && scircle | f | t
+(1 row)
+
+-- the ellipse and circle are degenerated into the point and coincide
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 0d , 0d }, (0d , 0d) , 0d>' && scircle'<(0d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+---------------------+----------+--------
+ sellipse && scircle | f | t
+(1 row)
+
+-- the ellipses are degenerated into the point and do not coincide, but lie close to each other
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 0d , 0d }, (0d , 0d) , 0d>' && scircle'<(1d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+---------------------+----------+--------
+ sellipse && scircle | f | f
+(1 row)
+
+-- spath vs spath
+-- the opened paths have no common points
+select 'spath && spath', 'f' as expected, spath'{ (-10d, 0d),(10d,0d),(45d,15d) }' && spath'{ (60d, 15d),(70d, 20d),(75d, 20d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && spath | f | f
+(1 row)
+
+-- the points of intersection of the opened paths is the boundary for both
+select 'spath && spath', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && spath'{ (-10d, 0d),(0d, 10d),(45d, 15d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && spath | f | t
+(1 row)
+
+-- one opened path intersects the other at the boundary point of the latter
+select 'spath && spath', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && spath'{ (-20d, -10d),(-10d, 0d),(0d, 10d),(45d, 15d),(60d, 15d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && spath | f | t
+(1 row)
+
+-- the interiors of the opened paths intersect at one point
+select 'spath && spath', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && spath'{ (0d, 10d),(0d, -10d),(10d, -10d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && spath | f | t
+(1 row)
+
+-- the interiors of the opened paths intersect at two points
+select 'spath && spath', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && spath'{ (0d, 10d),(0d, -10d),(5d, 0d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && spath | f | t
+(1 row)
+
+-- the opened paths match
+select 'spath && spath', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && spath | f | t
+(1 row)
+
+-- the closed paths match
+select 'spath && spath', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d),(-10d, 0d) }' && spath'{ (-10d, 0d),(10d, 0d),(45d, 15d),(-10d, 0d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && spath | f | t
+(1 row)
+
+-- one opened path lies completely in the other and they have an intersection at the boundary point
+select 'spath && spath', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d),(60d, 15d),(70d, 20d) }' && spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && spath | f | t
+(1 row)
+
+-- one opened path lies completely in the other and they have no intersection at the boundary point
+select 'spath && spath', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d),(60d, 15d),(70d, 20d) }' && spath'{ (10d, 0d),(45d, 15d),(60d, 15d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && spath | f | t
+(1 row)
+
+-- one opened path partially lies in the other
+select 'spath && spath', 't' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && spath'{ (45d, 15d),(60d, 15d),(70d, 20d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && spath | t | t
+(1 row)
+
+-- one closed path partially lies in the other
+select 'spath && spath', 't' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d),(-10d, 0d) }' && spath'{ (45d, 15d),(60d, 15d),(70d, 20d),(45d, 15d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && spath | t | t
+(1 row)
+
+-- the opened path partially lies in the closed path
+select 'spath && spath', 't' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d),(-10d, 0d) }' && spath'{ (45d, 15d),(60d, 15d),(70d, 20d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && spath | t | t
+(1 row)
+
+-- spath vs sline
+-- the opened path and line have no common points
+select 'spath && sline', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && sline( spoint'(20d, 0d)', spoint'(30d, 0d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && sline | f | f
+(1 row)
+
+-- the points of intersection of the opened path and line is the boundary for both
+select 'spath && sline', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && sline( spoint'(-10d, 0d)', spoint'(45d, 15d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && sline | f | t
+(1 row)
+
+-- the interiors of the opened path and line intersect at one point
+select 'spath && sline', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && sline( spoint'(0d, 10d)', spoint'(0d, -10d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && sline | f | t
+(1 row)
+
+-- the path and line match
+select 'spath && sline', 'f' as expected, spath'{ (0d, 10d),(0d, -10d) }' && sline( spoint'(0d, 10d)', spoint'(0d, -10d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && sline | f | t
+(1 row)
+
+-- the line lies completely in the opened path and they have an intersection at the boundary point
+select 'spath && sline', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d),(60d, 20d) }' && sline( spoint'(-10d, 0d)', spoint'(10d, 0d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && sline | f | t
+(1 row)
+
+-- the line lies completely in the opened path and they have no intersection at the boundary point
+select 'spath && sline', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d),(60d, 20d) }' && sline( spoint'(10d, 0d)', spoint'(45d, 15d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && sline | f | t
+(1 row)
+
+-- the line partially lies in the open path
+select 'spath && sline', 't' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && sline( spoint'(5d, 0d)', spoint'(20d, 0d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && sline | t | t
+(1 row)
+
+-- the line degenerated into the point lies in the boundary of open path
+select 'spath && sline', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && sline( spoint'(-10d, 0d)', spoint'(-10d, 0d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && sline | f | t
+(1 row)
+
+-- the line degenerated into the point lies in the interior of open path
+select 'spath && sline', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && sline( spoint'(0d, 0d)', spoint'(0d, 0d)') as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spath && sline | f | t
+(1 row)
+
+-- spoly vs spoly
+-- the polygons have no common points
+select 'spoly && spoly', 'f' as expected, spoly'{ (0d, 0d),(-10d, 0d),(0d, 10d) }' && spoly'{ (10d, 0d),(20d, 0d),(10d, 10d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spoly && spoly | f | f
+(1 row)
+
+-- the point of intersection of the polygons is the boundary for both
+select 'spoly && spoly', 'f' as expected, spoly'{ (0d, 0d),(-10d, 0d),(0d, 10d) }' && spoly'{ (10d, 0d),(20d, 0d),(0d, 10d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spoly && spoly | f | t
+(1 row)
+
+-- the interiors of the polygons intersect at one line
+select 'spoly && spoly', 'f' as expected, spoly'{ (0d, 0d),(-10d, 0d),(0d, 10d) }' && spoly'{ (0d, 0d),(20d, 0d),(0d, 10d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spoly && spoly | f | t
+(1 row)
+
+-- the polygons matches
+select 'spoly && spoly', 'f' as expected, spoly'{ (0d, 0d),(-10d, 0d),(0d, 10d) }' && spoly'{ (0d, 0d),(-10d, 0d),(0d, 10d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spoly && spoly | f | t
+(1 row)
+
+-- one polygon lies completely in the other and they have an intersection at the boundary line
+select 'spoly && spoly', 'f' as expected, spoly'{ (0d, 0d),(20d, 0d),(20d, 20d),(0d, 20d) }' && spoly'{ (0d, 0d),(20d, 0d),(0d, 20d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spoly && spoly | f | t
+(1 row)
+
+-- one polygon lies completely in the other and they have no intersection at the boundary line or point
+select 'spoly && spoly', 'f' as expected, spoly'{ (0d, 0d),(20d, 0d),(20d, 20d),(0d, 20d) }' && spoly'{ (5d, 5d),(15d, 5d),(15d, 15d),(5d,15d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spoly && spoly | f | t
+(1 row)
+
+-- one polygon partially lies in the other
+select 'spoly && spoly', 't' as expected, spoly'{ (0d, 0d),(-10d, 0d),(0d, 10d) }' && spoly'{ (5d, 5d),(30d, 5d),(30d, 15d),(5d,15d) }' as actual;
+ ?column? | expected | actual
+----------------+----------+--------
+ spoly && spoly | t | f
+(1 row)
+
+-- spoly vs scircle
+-- the polygon and circle have no common points
+select 'spoly && scircle', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && scircle'<(0d , 90d) , 10d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ spoly && scircle | f | f
+(1 row)
+
+-- the point of intersection of the polygon and circle is the boundary for both
+select 'spoly && scircle', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && scircle'<(0d , 90d) , 80d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ spoly && scircle | f | t
+(1 row)
+
+-- the circle lies completely in the polygon and they have an intersection at the boundary point
+select 'spoly && scircle', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && scircle'<(5d , 1d) , 1d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ spoly && scircle | f | t
+(1 row)
+
+-- the circle lies completely in the polygon and they have no intersection at the boundary point
+select 'spoly && scircle', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && scircle'<(5d , 2d) , 1d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ spoly && scircle | f | t
+(1 row)
+
+-- the polygon lies completely in the circle
+select 'spoly && scircle', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && scircle'<(0d , 15d) , 20d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ spoly && scircle | f | t
+(1 row)
+
+-- the polygon partially lies in the circle
+select 'spoly && scircle', 't' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && scircle'<(0d , 5d) , 5d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ spoly && scircle | t | t
+(1 row)
+
+-- the circle degenerated into the point lies in the boundary of polygon
+select 'spoly && scircle', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && scircle'<(0d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ spoly && scircle | f | t
+(1 row)
+
+-- the circle degenerated into the point lies in the interior of polygon
+select 'spoly && scircle', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && scircle'<(2d , 2d) , 0d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ spoly && scircle | f | t
+(1 row)
+
+-- spoly vs sellipse
+-- the polygon and ellipse have no common points
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && sellipse'<{ 30d , 20d }, (0d , 90d) , 0d>' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ spoly && sellipse | f | f
+(1 row)
+
+-- the point of intersection of the polygon and ellipse is the boundary for both
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && sellipse'<{ 80d , 20d }, (0d , 90d) , 90d>' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ spoly && sellipse | f | t
+(1 row)
+
+-- the ellipse lies completely in the polygon and they have an intersection at the boundary points
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 0d),(20d, 0d),(20d, 20d),(0d, 20d) }' && sellipse'<{ 10d , 5d }, (10d , 10d), 0d>' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ spoly && sellipse | f | t
+(1 row)
+
+-- the ellipse lies completely in the polygon and they have no intersection at the boundary points
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 0d),(20d, 0d),(20d, 20d),(0d, 20d) }' && sellipse'<{ 7d , 5d }, (10d , 10d), 0d>' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ spoly && sellipse | f | t
+(1 row)
+
+-- the polygon lies completely in the ellipse and they have an intersection at the boundary points
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 5d),(10d, 10d),(20d, 5d),(10d, 0d) }' && sellipse'<{ 10d , 5d }, (10d , 5d), 0d>' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ spoly && sellipse | f | t
+(1 row)
+
+-- the polygon lies completely in the ellipse and they have no intersection at the boundary points
+select 'spoly && sellipse', 'f' as expected, spoly'{ (1d, 5d),(10d, 9d),(19d, 5d),(10d, 1d) }' && sellipse'<{ 10d , 5d }, (10d , 10d), 0d>' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ spoly && sellipse | f | t
+(1 row)
+
+-- the ellipse partially lies in the polygon
+select 'spoly && sellipse', 't' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && sellipse'<{ 10d , 2d }, (0d , 5d) , 0d>' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ spoly && sellipse | t | t
+(1 row)
+
+-- the ellipse degenerated into the point lies in the boundary of polygon
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && sellipse'<{ 0d , 0d }, (0d , 0d), 0d>' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ spoly && sellipse | f | t
+(1 row)
+
+-- the ellipse degenerated into the point lies in the interior of polygon
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && sellipse'<{ 0d , 0d }, (5d , 2d), 0d>' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ spoly && sellipse | f | t
+(1 row)
+
+-- the ellipse degenerated into the line lies in the boundary of polygon
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && sellipse'<{ 5d , 0d }, (5d , 0d), 0d>' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ spoly && sellipse | f | t
+(1 row)
+
+-- the ellipse degenerated into the line lies in the interior of polygon
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && sellipse'<{ 2d , 0d }, (1d , 4d), 90d>' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ spoly && sellipse | f | t
+(1 row)
+
+-- the ellipse degenerated into the line partially lies in the interior of polygon
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && sellipse'<{ 10d , 0d }, (1d , 4d), 0d>' as actual;
+ ?column? | expected | actual
+-------------------+----------+--------
+ spoly && sellipse | f | t
+(1 row)
+
+-- sbox vs sbox
+-- the boxes have no common points
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((30d , 30d), (50d , 50d))' as actual;
+ ?column? | expected | actual
+--------------+----------+--------
+ sbox && sbox | f | f
+(1 row)
+
+-- the point of intersection of the boxes is the boundary for both
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((20d , 20d), (50d , 50d))' as actual;
+ ?column? | expected | actual
+--------------+----------+--------
+ sbox && sbox | f | t
+(1 row)
+
+-- the boundaries of the boxes intersect at one line
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((20d , 0d), (50d , 20d))' as actual;
+ ?column? | expected | actual
+--------------+----------+--------
+ sbox && sbox | f | t
+(1 row)
+
+-- the boxes matches
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((5d , 5d), (10d , 10d))' as actual;
+ ?column? | expected | actual
+--------------+----------+--------
+ sbox && sbox | f | t
+(1 row)
+
+-- one box lies completely in the other and they have no intersection at the boundary line or point
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((5d , 5d), (10d , 10d))' as actual;
+ ?column? | expected | actual
+--------------+----------+--------
+ sbox && sbox | f | t
+(1 row)
+
+-- one box partially lies in the other
+select 'sbox && sbox', 't' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((10d , 10d), (30d , 30d))' as actual;
+ ?column? | expected | actual
+--------------+----------+--------
+ sbox && sbox | t | t
+(1 row)
+
+-- one box degenerated into the line lies in the boundary of other
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((0d , 0d), (20d , 0d))' as actual;
+ ?column? | expected | actual
+--------------+----------+--------
+ sbox && sbox | f | t
+(1 row)
+
+-- one box degenerated into the line lies in the interior of other
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((5d , 5d), (10d , 5d))' as actual;
+ ?column? | expected | actual
+--------------+----------+--------
+ sbox && sbox | f | t
+(1 row)
+
+-- one box degenerated into the point lies in the boundary of other
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((0d , 0d), (0d , 0d))' as actual;
+ ?column? | expected | actual
+--------------+----------+--------
+ sbox && sbox | f | t
+(1 row)
+
+-- one box degenerated into the point lies in the interior of other
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((5d , 5d), (5d , 5d))' as actual;
+ ?column? | expected | actual
+--------------+----------+--------
+ sbox && sbox | f | t
+(1 row)
+
+-- the boxes are degenerated into the point and coincide
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (0d , 0d))' && sbox'((0d , 0d), (0d , 0d))' as actual;
+ ?column? | expected | actual
+--------------+----------+--------
+ sbox && sbox | f | t
+(1 row)
+
+-- the boxes are degenerated into the point and not coincide
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (0d , 0d))' && sbox'((10d , 10d), (10d , 10d))' as actual;
+ ?column? | expected | actual
+--------------+----------+--------
+ sbox && sbox | f | f
+(1 row)
+
+-- sbox vs scircle
+-- the box and circle have no common points
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && scircle'<(0d , 90d) , 10d>' as actual;
+ ?column? | expected | actual
+-----------------+----------+--------
+ sbox && scircle | f | f
+(1 row)
+
+-- the point of intersection of the box and circle is the boundary for both
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && scircle'<(30d , 0d) , 10d>' as actual;
+ ?column? | expected | actual
+-----------------+----------+--------
+ sbox && scircle | f | t
+(1 row)
+
+-- the circle lies completely in the box and they have an intersection at the boundary points
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && scircle'<(10d , 10d) , 10d>' as actual;
+ ?column? | expected | actual
+-----------------+----------+--------
+ sbox && scircle | f | t
+(1 row)
+
+-- the circle lies completely in the box and they have no intersection at the boundary points
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && scircle'<(10d , 10d) , 5d>' as actual;
+ ?column? | expected | actual
+-----------------+----------+--------
+ sbox && scircle | f | t
+(1 row)
+
+-- the box lies completely in the circle and they have an intersection at the boundary points
+select 'sbox && scircle', 'f' as expected, sbox'((-4d , -3d), (3d , 4d))' && scircle'<(0d , 0d) , 5d>' as actual;
+ ?column? | expected | actual
+-----------------+----------+--------
+ sbox && scircle | f | t
+(1 row)
+
+-- the box lies completely in the circle and they have no intersection at the boundary points
+select 'sbox && scircle', 'f' as expected, sbox'((-4d , -3d), (3d , 4d))' && scircle'<(0d , 0d) , 10d>' as actual;
+ ?column? | expected | actual
+-----------------+----------+--------
+ sbox && scircle | f | t
+(1 row)
+
+-- the box degenerated into the line intersects circle
+select 'sbox && scircle', 'f' as expected, sbox'((-20d , 0d), (20d , 0d))' && scircle'<(0d , 0d) , 10d>' as actual;
+ ?column? | expected | actual
+-----------------+----------+--------
+ sbox && scircle | f | f
+(1 row)
+
+-- the circle partially lies in the box
+select 'sbox && scircle', 't' as expected, sbox'((0d , 0d), (20d , 20d))' && scircle'<(15d , 15d) , 10d>' as actual;
+ ?column? | expected | actual
+-----------------+----------+--------
+ sbox && scircle | t | t
+(1 row)
+
+-- the circle degenerated into the point lies in the boundary of box
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && scircle'<(0d , 10d) , 0d>' as actual;
+ ?column? | expected | actual
+-----------------+----------+--------
+ sbox && scircle | f | t
+(1 row)
+
+-- the circle degenerated into the point lies in the interior of box
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && scircle'<(10d , 10d) , 0d>' as actual;
+ ?column? | expected | actual
+-----------------+----------+--------
+ sbox && scircle | f | t
+(1 row)
+
+-- the box degenerated into the point lies in the boundary of circle
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (0d , 0d))' && scircle'<(10d , 0d) , 10d>' as actual;
+ ?column? | expected | actual
+-----------------+----------+--------
+ sbox && scircle | f | t
+(1 row)
+
+-- the box degenerated into the point lies in the interior of circle
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (0d , 0d))' && scircle'<(0d , 0d) , 10d>' as actual;
+ ?column? | expected | actual
+-----------------+----------+--------
+ sbox && scircle | f | t
+(1 row)
+
+-- the box and circle are degenerated into the point and coincide
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (0d , 0d))' && scircle'<(0d , 0d) , 0d>' as actual;
+ ?column? | expected | actual
+-----------------+----------+--------
+ sbox && scircle | f | t
+(1 row)
+
+-- the box and circle are degenerated into the point and not coincide
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (0d , 0d))' && scircle'<(5d , 5d) , 0d>' as actual;
+ ?column? | expected | actual
+-----------------+----------+--------
+ sbox && scircle | f | f
+(1 row)
+
+-- sbox vs spoly
+-- the box and polygon have no common points
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && spoly'{ (30d, 0d),(40d, 0d),(30d, 20d) }' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox && spoly | f | f
+(1 row)
+
+-- the point of intersection of the box and polygon is the boundary for both
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && spoly'{ (30d, 0d),(40d, 0d),(30d, 20d) }' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox && spoly | f | f
+(1 row)
+
+-- the boundaries of the boxes intersect at one line
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && spoly'{ (20d, 0d),(30d, 0d),(20d, 20d) }' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox && spoly | f | t
+(1 row)
+
+-- the box and circle matches
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && spoly'{ (0d, 0d),(20d, 0d),(20d, 20d),(0d, 20d) }' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox && spoly | f | t
+(1 row)
+
+-- the polygon lies completely in the box and they have an intersection at the boundary line
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && spoly'{ (0d, 0d),(20d, 0d),(0d, 20d) }' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox && spoly | f | t
+(1 row)
+
+-- the polygon lies completely in the box and they have no intersection at the boundary
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && spoly'{ (1d, 1d),(11d, 1d),(1d, 19d) }' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox && spoly | f | t
+(1 row)
+
+-- the box lies completely in the polygon and they have an intersection at the boundary line
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 0d), (10d , 10d))' && spoly'{ (0d, 0d),(20d, 0d),(0d, 20d) }' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox && spoly | f | t
+(1 row)
+
+-- the box lies completely in the polygon and they have no intersection at the boundary
+select 'sbox && spoly', 'f' as expected, sbox'((1d , 1d), (2d , 2d))' && spoly'{ (0d, 0d),(20d, 0d),(0d, 20d) }' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox && spoly | f | t
+(1 row)
+
+-- the polygon partially lies in the box
+select 'sbox && spoly', 't' as expected, sbox'((0d , 0d), (20d , 20d))' && spoly'{ (15d, 0d),(35d, 0d),(15d, 35d) }' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox && spoly | t | t
+(1 row)
+
+-- the box degenerated into the line lies in the boundary of polygon
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 0d), (20d , 0d))' && spoly'{ (0d, 0d),(20d, 0d),(0d, 20d) }' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox && spoly | f | t
+(1 row)
+
+-- the box degenerated into the line lies in the interior of polygon
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 5d), (10d , 5d))' && spoly'{ (0d, 0d),(20d, 0d),(0d, 20d) }' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox && spoly | f | t
+(1 row)
+
+-- the box degenerated into the point lies in the boundary of polygon
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 0d), (0d , 0d))' && spoly'{ (0d, 0d),(20d, 0d),(0d, 20d) }' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox && spoly | f | t
+(1 row)
+
+-- the box degenerated into the point lies in the interior of polygon
+select 'sbox && spoly', 'f' as expected, sbox'((5d , 5d), (5d , 5d))' && spoly'{ (0d, 0d),(20d, 0d),(0d, 20d) }' as actual;
+ ?column? | expected | actual
+---------------+----------+--------
+ sbox && spoly | f | t
+(1 row)
+
+-- sbox vs sellipse
+-- the box and ellipse have no common points
+select 'sbox && sellipse', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sellipse'<{ 20d , 10d }, (0d, 90d) , 0d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ sbox && sellipse | f | f
+(1 row)
+
+-- the point of intersection of the box and ellipse is the boundary for both
+select 'sbox && sellipse', 'f' as expected, sbox'((-10d , -10d), (10d , 10d))' && sellipse'<{ 80d , 10d }, (0d, 90d) , 90d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ sbox && sellipse | f | f
+(1 row)
+
+-- the ellipse lies completely in the box and they have an intersection at the boundary points
+select 'sbox && sellipse', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sellipse'<{ 10d , 5d }, (10d, 10d) , 0d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ sbox && sellipse | f | t
+(1 row)
+
+-- the ellipse lies completely in the box and they have no intersection at the boundary points
+select 'sbox && sellipse', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sellipse'<{ 9d , 5d }, (10d, 10d) , 0d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ sbox && sellipse | f | t
+(1 row)
+
+-- the box lies completely in the ellipse and they have no intersection at the boundary points
+select 'sbox && sellipse', 'f' as expected, sbox'((-10d , -10d), (10d , 10d))' && sellipse'<{ 30d , 20d }, (0d, 0d) , 0d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ sbox && sellipse | f | t
+(1 row)
+
+-- the ellipse partially lies in the box
+select 'sbox && sellipse', 't' as expected, sbox'((-10d , -10d), (10d , 10d))' && sellipse'<{ 10d , 5d }, (10d, 10d) , 90d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ sbox && sellipse | t | t
+(1 row)
+
+-- the box degenerated into the point lies in the boundary of ellipse
+select 'sbox && sellipse', 'f' as expected, sbox'((30d , 0d), (30d , 0d))' && sellipse'<{ 30d , 20d }, (0d, 0d) , 0d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ sbox && sellipse | f | t
+(1 row)
+
+-- the box degenerated into the point lies in the interior of ellipse
+select 'sbox && sellipse', 'f' as expected, sbox'((0d , 0d), (10d , 0d))' && sellipse'<{ 30d , 20d }, (0d, 0d) , 0d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ sbox && sellipse | f | t
+(1 row)
+
+-- the box and ellipse are degenerated into the point and coincide
+select 'sbox && sellipse', 'f' as expected, sbox'((0d , 0d), (0d , 0d))' && sellipse'<{ 0d , 0d }, (0d, 0d) , 0d>' as actual;
+ ?column? | expected | actual
+------------------+----------+--------
+ sbox && sellipse | f | t
+(1 row)
+
diff --git a/expected/path.out b/expected/path.out
index 1734d8c..9f62534 100644
--- a/expected/path.out
+++ b/expected/path.out
@@ -468,3 +468,28 @@ SELECT spoint(p,2) FROM spheretmp6 WHERE id=2;
(1d , -5d)
(1 row)
+SELECT set_sphere_output( 'RAD' );
+ set_sphere_output
+-------------------
+ SET RAD
+(1 row)
+
+-- get n-th point and array representation path points tests
+SELECT spoint( spath '{(0, 0),(1, 1)}', 1 );
+ spoint
+---------
+ (0 , 0)
+(1 row)
+
+SELECT spoint( spath '{(0, 0),(1, 1)}', 2 );
+ spoint
+---------
+ (1 , 1)
+(1 row)
+
+SELECT spath_as_array( spath '{(0, 0),(1, 1)}');
+ spath_as_array
+-----------------------
+ {"(0 , 0)","(1 , 1)"}
+(1 row)
+
diff --git a/expected/points.out b/expected/points.out
index 84375e6..6fb3c17 100644
--- a/expected/points.out
+++ b/expected/points.out
@@ -239,6 +239,24 @@ SELECT spoint(0.0109083078249646 , -0.000727220521664407);
(0.625d , -0.041666667d)
(1 row)
+SELECT spoint_deg(57.2958, 57.2958);
+ spoint_deg
+-----------------------
+ (57.2958d , 57.2958d)
+(1 row)
+
+SELECT spoint_deg(0, 0);
+ spoint_deg
+------------
+ (0d , 0d)
+(1 row)
+
+SELECT spoint_deg(114.5916, 0);
+ spoint_deg
+------------------
+ (114.5916d , 0d)
+(1 row)
+
SELECT set_sphere_output( 'RAD' );
set_sphere_output
-------------------
diff --git a/expected/poly.out b/expected/poly.out
index 201b9be..50e510e 100644
--- a/expected/poly.out
+++ b/expected/poly.out
@@ -318,16 +318,47 @@ SELECT spoly '{(10d,0d),(10d,1d),(15d,0d)}';
{(10d , 0d),(10d , 1d),(15d , 0d)}
(1 row)
+SELECT spoly_deg(ARRAY[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
+ spoly_deg
+---------------------------------
+ {(1d , 2d),(3d , 4d),(5d , 6d)}
+(1 row)
+
+SELECT spoly_deg(ARRAY[10.0, 0.0, 10.0, 1.0, 15.0, 0.0]);
+ spoly_deg
+------------------------------------
+ {(10d , 0d),(10d , 1d),(15d , 0d)}
+(1 row)
+
-- incorrect input -----
SELECT spoly '{(10d,0d),(10d,1d)}';
ERROR: spherepoly_in: more than two points needed
LINE 1: SELECT spoly '{(10d,0d),(10d,1d)}';
^
+SELECT spoly_deg(ARRAY[1.0, 2.0, 3.0, 4.0, 5.0]);
+ERROR: spherepoly_deg: invalid number of arguments (must be even and >= 6)
+SELECT spoly_deg(ARRAY[]::float8[]);
+ERROR: spherepoly_deg: invalid number of arguments (must be even and >= 6)
+SELECT spoly_deg(NULL::float8[]);
+ spoly_deg
+-----------
+
+(1 row)
+
--- self-crossing input -----
SELECT spoly '{(0d,0d),(10d,10d),(0d,10d),(10d,0d)}';
ERROR: spherepoly_from_array: a line segment overlaps or polygon too large
LINE 1: SELECT spoly '{(0d,0d),(10d,10d),(0d,10d),(10d,0d)}';
^
+--- degenerate polygons -----
+SELECT spoly '{(0d,1d),(0d,2d),(0d,3d)}';
+ERROR: spherepoly_from_array: a line segment overlaps or polygon too large
+LINE 1: SELECT spoly '{(0d,1d),(0d,2d),(0d,3d)}';
+ ^
+SELECT spoly '{(1d,0d),(2d,0d),(3d,0d)}';
+ERROR: spherepoly_from_array: a line segment overlaps or polygon too large
+LINE 1: SELECT spoly '{(1d,0d),(2d,0d),(3d,0d)}';
+ ^
--- functions
SELECT npoints( spoly '{(10d,0d),(10d,1d),(15d,0d)}');
npoints
@@ -1738,3 +1769,58 @@ SELECT npoints( spoly '{
4
(1 row)
+SELECT set_sphere_output( 'RAD' );
+ set_sphere_output
+-------------------
+ SET RAD
+(1 row)
+
+SELECT spoint( spoly '{(0,0),(1,0),(1,1)}', 1 );
+ spoint
+---------
+ (0 , 0)
+(1 row)
+
+SELECT spoint( spoly '{(0,0),(1,0),(1,1)}', 2 );
+ spoint
+---------
+ (1 , 0)
+(1 row)
+
+SELECT spoint( spoly '{(0,0),(1,0),(1,1)}', 3 );
+ spoint
+---------
+ (1 , 1)
+(1 row)
+
+SELECT spoly_as_array( spoly '{(0,0),(1,0),(1,1)}' );
+ spoly_as_array
+---------------------------------
+ {"(0 , 0)","(1 , 0)","(1 , 1)"}
+(1 row)
+
+-- spoly is convex
+SELECT spoly_is_convex(spoly'{(53d 45m 35.0s, 37d 6m 30.0s), (52d 21m 36.0s, 41d 36m 7.0s), (54d 14m 18.0s, 45d 1m 35.0s), (51d 23m 3.0s, 45d 22m 49.0s), (51d 2m 12.0s, 41d 52m 1.0s), (50d 41m 47.0s, 38d 22m 0s) }');
+ spoly_is_convex
+-----------------
+ f
+(1 row)
+
+SELECT spoly_is_convex(spoly'{(12d,32d),(34d,12d),(59d,21d),(69d,21d)}');
+ spoly_is_convex
+-----------------
+ f
+(1 row)
+
+SELECT spoly_is_convex(spoly'{(12d,32d),(34d,12d),(59d,21d),(34d,40d)}');
+ spoly_is_convex
+-----------------
+ t
+(1 row)
+
+SELECT spoly_is_convex(NULL);
+ spoly_is_convex
+-----------------
+ f
+(1 row)
+
diff --git a/expected/sbox_brin.out b/expected/sbox_brin.out
new file mode 100644
index 0000000..43fd87c
--- /dev/null
+++ b/expected/sbox_brin.out
@@ -0,0 +1,91 @@
+SELECT set_sphere_output_precision(8);
+ set_sphere_output_precision
+-----------------------------
+ SET 8
+(1 row)
+
+CREATE TABLE test_boxes (
+ b sbox
+);
+COPY test_boxes (b) FROM stdin;
+CREATE OR REPLACE FUNCTION qnodes(q text) RETURNS text
+LANGUAGE 'plpgsql' AS
+$$
+DECLARE
+ exp TEXT;
+ mat TEXT[];
+ ret TEXT[];
+BEGIN
+ FOR exp IN EXECUTE 'EXPLAIN ' || q
+ LOOP
+ --RAISE NOTICE 'EXP: %', exp;
+ mat := regexp_matches(exp, ' *(?:-> *)?(.*Scan on (test_boxes|test_boxes_brin_idx))');
+ --RAISE NOTICE 'MAT: %', mat;
+ IF mat IS NOT NULL THEN
+ ret := array_append(ret, mat[1]);
+ END IF;
+ --RAISE NOTICE 'RET: %', ret;
+ END LOOP;
+ RETURN array_to_string(ret,',');
+END;
+$$;
+CREATE INDEX test_boxes_brin_idx ON test_boxes USING brin (b);
+SET enable_indexscan = OFF;
+SET enable_bitmapscan = OFF;
+SET enable_seqscan = ON;
+SELECT 'scan_seq', qnodes('SELECT * FROM test_boxes WHERE b <@ sbox ''( (10d,10d), (20d,20d) )''');
+ ?column? | qnodes
+----------+------------------------
+ scan_seq | Seq Scan on test_boxes
+(1 row)
+
+SELECT * FROM test_boxes WHERE b <@ sbox '( (10d,10d), (20d,20d) )';
+ b
+---
+(0 rows)
+
+SELECT 'scan_seq', qnodes('SELECT * FROM test_boxes WHERE b && sbox ''( (10d,10d), (20d,20d) )''');
+ ?column? | qnodes
+----------+------------------------
+ scan_seq | Seq Scan on test_boxes
+(1 row)
+
+SELECT * FROM test_boxes WHERE b && sbox '( (10d,10d), (20d,20d) )';
+ b
+--------------------------------------------------------
+ ((0.34906585 , 0.17453293), (0.35006585 , 0.17463293))
+(1 row)
+
+SET enable_indexscan = OFF;
+SET enable_bitmapscan = ON;
+SET enable_seqscan = OFF;
+SELECT 'scan_idx', qnodes('SELECT * FROM test_boxes WHERE b <@ sbox ''( (10d,10d), (20d,20d) )''');
+ ?column? | qnodes
+----------+-------------------------------------------------------------------------
+ scan_idx | Bitmap Heap Scan on test_boxes,Bitmap Index Scan on test_boxes_brin_idx
+(1 row)
+
+SELECT * FROM test_boxes WHERE b <@ sbox '( (10d,10d), (20d,20d) )';
+ b
+---
+(0 rows)
+
+SELECT 'scan_idx', qnodes('SELECT * FROM test_boxes WHERE b && sbox ''( (10d,10d), (20d,20d) )''');
+ ?column? | qnodes
+----------+-------------------------------------------------------------------------
+ scan_idx | Bitmap Heap Scan on test_boxes,Bitmap Index Scan on test_boxes_brin_idx
+(1 row)
+
+SELECT * FROM test_boxes WHERE b && sbox '( (10d,10d), (20d,20d) )';
+ b
+--------------------------------------------------------
+ ((0.34906585 , 0.17453293), (0.35006585 , 0.17463293))
+(1 row)
+
+---- cleanup
+DROP INDEX test_boxes_brin_idx;
+DROP TABLE test_boxes;
+DROP FUNCTION qnodes(text);
+SET enable_indexscan = ON;
+SET enable_bitmapscan = ON;
+SET enable_seqscan = ON;
diff --git a/expected/spoint_brin.out b/expected/spoint_brin.out
new file mode 100644
index 0000000..958c709
--- /dev/null
+++ b/expected/spoint_brin.out
@@ -0,0 +1,87 @@
+CREATE TABLE test_points (
+ p spoint
+);
+COPY test_points (p) FROM stdin;
+CREATE OR REPLACE FUNCTION qnodes(q text) RETURNS text
+LANGUAGE 'plpgsql' AS
+$$
+DECLARE
+ exp TEXT;
+ mat TEXT[];
+ ret TEXT[];
+BEGIN
+ FOR exp IN EXECUTE 'EXPLAIN ' || q
+ LOOP
+ --RAISE NOTICE 'EXP: %', exp;
+ mat := regexp_matches(exp, ' *(?:-> *)?(.*Scan on (test_points|brin_spoint))');
+ --RAISE NOTICE 'MAT: %', mat;
+ IF mat IS NOT NULL THEN
+ ret := array_append(ret, mat[1]);
+ END IF;
+ --RAISE NOTICE 'RET: %', ret;
+ END LOOP;
+ RETURN array_to_string(ret,',');
+END;
+$$;
+CREATE INDEX brin_spoint ON test_points USING brin (p) WITH (pages_per_range = 16);
+set enable_indexscan = off;
+set enable_bitmapscan = off;
+set enable_seqscan = on;
+SELECT 'scan_seq', qnodes('SELECT * FROM test_points WHERE p <@ sbox ''( (10d,10d), (20d,20d) )''');
+ ?column? | qnodes
+----------+-------------------------
+ scan_seq | Seq Scan on test_points
+(1 row)
+
+SELECT * FROM test_points WHERE p <@ sbox '( (10d,10d), (20d,20d) )';
+ p
+-----------------------------------------
+ (0.349065850398866 , 0.174532925199433)
+(1 row)
+
+SELECT 'scan_seq', qnodes('SELECT * FROM test_points WHERE p && sbox ''( (10d,10d), (20d,20d) )''');
+ ?column? | qnodes
+----------+-------------------------
+ scan_seq | Seq Scan on test_points
+(1 row)
+
+SELECT * FROM test_points WHERE p && sbox '( (10d,10d), (20d,20d) )';
+ p
+-----------------------------------------
+ (0.349065850398866 , 0.174532925199433)
+(1 row)
+
+set enable_indexscan = off;
+set enable_bitmapscan = on;
+set enable_seqscan = off;
+SELECT 'scan_idx', qnodes('SELECT * FROM test_points WHERE p <@ sbox ''( (10d,10d), (20d,20d) )''');
+ ?column? | qnodes
+----------+------------------------------------------------------------------
+ scan_idx | Bitmap Heap Scan on test_points,Bitmap Index Scan on brin_spoint
+(1 row)
+
+SELECT * FROM test_points WHERE p <@ sbox '( (10d,10d), (20d,20d) )';
+ p
+-----------------------------------------
+ (0.349065850398866 , 0.174532925199433)
+(1 row)
+
+SELECT 'scan_idx', qnodes('SELECT * FROM test_points WHERE p && sbox ''( (10d,10d), (20d,20d) )''');
+ ?column? | qnodes
+----------+------------------------------------------------------------------
+ scan_idx | Bitmap Heap Scan on test_points,Bitmap Index Scan on brin_spoint
+(1 row)
+
+SELECT * FROM test_points WHERE p && sbox '( (10d,10d), (20d,20d) )';
+ p
+-----------------------------------------
+ (0.349065850398866 , 0.174532925199433)
+(1 row)
+
+-- cleanup
+DROP INDEX brin_spoint;
+DROP TABLE test_points;
+DROP FUNCTION qnodes(text);
+set enable_indexscan = on;
+set enable_bitmapscan = on;
+set enable_seqscan = on;
diff --git a/pg_sphere--1.2.3.sql.in b/pg_sphere--1.3.0.sql.in
similarity index 100%
rename from pg_sphere--1.2.3.sql.in
rename to pg_sphere--1.3.0.sql.in
diff --git a/pg_sphere.control b/pg_sphere.control
index bebbe02..412cd57 100644
--- a/pg_sphere.control
+++ b/pg_sphere.control
@@ -1,5 +1,5 @@
# pg_sphere extension
comment = 'spherical objects with useful functions, operators and index support'
-default_version = '1.2.3'
+default_version = '1.3.0'
module_pathname = '$libdir/pg_sphere'
relocatable = true
diff --git a/pgs_brin.sql.in b/pgs_brin.sql.in
new file mode 100644
index 0000000..4b0fba5
--- /dev/null
+++ b/pgs_brin.sql.in
@@ -0,0 +1,413 @@
+
+--------------------------------------------------------------------
+-- BRIN support --
+--------------------------------------------------------------------
+
+--------------------------------
+-- the Operators --
+--------------------------------
+
+CREATE FUNCTION spoint_overlaps_spherekey(spoint, spherekey)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME', 'spoint_overlaps_spherekey'
+ LANGUAGE 'c' IMMUTABLE STRICT;
+
+CREATE FUNCTION spoint_contains_spherekey(spoint, spherekey)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME', 'spoint_contains_spherekey'
+ LANGUAGE 'c' IMMUTABLE STRICT;
+
+CREATE FUNCTION spoint_iscontained_spherekey(spoint, spherekey)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME', 'spoint_iscontained_spherekey'
+ LANGUAGE 'c' IMMUTABLE STRICT;
+
+CREATE FUNCTION sbox_overlaps_spherekey(sbox, spherekey)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME', 'sbox_overlaps_spherekey'
+ LANGUAGE 'c' IMMUTABLE STRICT;
+
+CREATE FUNCTION sbox_contains_spherekey(sbox, spherekey)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME', 'sbox_contains_spherekey'
+ LANGUAGE 'c' IMMUTABLE STRICT;
+
+CREATE FUNCTION sbox_iscontained_spherekey(sbox, spherekey)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME', 'sbox_iscontained_spherekey'
+ LANGUAGE 'c' IMMUTABLE STRICT;
+
+CREATE FUNCTION spherekey_overlaps_spherekey(spherekey, spherekey)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME', 'spherekey_overlaps_spherekey'
+ LANGUAGE 'c' IMMUTABLE STRICT;
+
+CREATE FUNCTION spherekey_contains_spherekey(spherekey, spherekey)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME', 'spherekey_contains_spherekey'
+ LANGUAGE 'c' IMMUTABLE STRICT;
+
+CREATE FUNCTION spherekey_iscontained_spherekey(spherekey, spherekey)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME', 'spoint_iscontained_spherekey'
+ LANGUAGE 'c' IMMUTABLE STRICT;
+
+CREATE OPERATOR && (
+ LEFTARG = spoint,
+ RIGHTARG = spherekey,
+ PROCEDURE = spoint_overlaps_spherekey,
+ COMMUTATOR = '&&',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+COMMENT ON OPERATOR && (spoint, spherekey) IS
+ 'true, if the spherical point overlaps a spherekey';
+
+CREATE OPERATOR @> (
+ LEFTARG = spoint,
+ RIGHTARG = spherekey,
+ PROCEDURE = spoint_contains_spherekey,
+ COMMUTATOR = '<@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+COMMENT ON OPERATOR @> (spoint, spherekey) IS
+ 'true, if the spherical point contains a spherekey - just needed to define the OpFamily';
+
+CREATE OPERATOR <@ (
+ LEFTARG = spoint,
+ RIGHTARG = spherekey,
+ PROCEDURE = spoint_iscontained_spherekey,
+ COMMUTATOR = '@>',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+COMMENT ON OPERATOR <@ (spoint, spherekey) IS
+ 'true, if the spherical point is contained in a spherekey';
+
+CREATE OPERATOR && (
+ LEFTARG = sbox,
+ RIGHTARG = spherekey,
+ PROCEDURE = sbox_overlaps_spherekey,
+ COMMUTATOR = '&&',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+COMMENT ON OPERATOR && (sbox, spherekey) IS
+ 'true, if the spherical box overlaps a spherekey';
+
+CREATE OPERATOR @> (
+ LEFTARG = sbox,
+ RIGHTARG = spherekey,
+ PROCEDURE = sbox_contains_spherekey,
+ COMMUTATOR = '<@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+COMMENT ON OPERATOR @> (sbox, spherekey) IS
+ 'true, if the spherical box contains a spherekey';
+
+CREATE OPERATOR <@ (
+ LEFTARG = sbox,
+ RIGHTARG = spherekey,
+ PROCEDURE = sbox_iscontained_spherekey,
+ COMMUTATOR = '@>',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+COMMENT ON OPERATOR <@ (sbox, spherekey) IS
+ 'true, if the spherical box is contained in a spherekey';
+
+CREATE OPERATOR && (
+ LEFTARG = spherekey,
+ RIGHTARG = spherekey,
+ PROCEDURE = spherekey_overlaps_spherekey,
+ COMMUTATOR = '&&',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+COMMENT ON OPERATOR && (spherekey, spherekey) IS
+ 'true, if the spherekey overlaps another spherekey';
+
+CREATE OPERATOR @> (
+ LEFTARG = spherekey,
+ RIGHTARG = spherekey,
+ PROCEDURE = spherekey_contains_spherekey,
+ COMMUTATOR = '<@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+COMMENT ON OPERATOR @> (spoint, spherekey) IS
+ 'true, if the spherekey contains another spherekey';
+
+CREATE OPERATOR <@ (
+ LEFTARG = spherekey,
+ RIGHTARG = spherekey,
+ PROCEDURE = spherekey_iscontained_spherekey,
+ COMMUTATOR = '@>',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+COMMENT ON OPERATOR <@ (spherekey, spherekey) IS
+ 'true, if the spherical point is contained in another spherekey';
+
+---------------------------------------------
+-- create operators with crossed datatypes --
+---------------------------------------------
+
+CREATE FUNCTION spherekey_overlaps_spoint(spherekey, spoint)
+ RETURNS boolean
+ AS $$
+ SELECT $2 && $1;
+ $$ LANGUAGE SQL IMMUTABLE STRICT;
+
+CREATE FUNCTION spherekey_contains_spoint(spherekey, spoint)
+ RETURNS boolean
+ AS $$
+ SELECT $2 <@ $1;
+ $$ LANGUAGE SQL IMMUTABLE STRICT;
+
+CREATE FUNCTION spherekey_iscontained_spoint(spherekey, spoint)
+ RETURNS boolean
+ AS $$
+ SELECT $2 @> $1;
+ $$ LANGUAGE SQL IMMUTABLE STRICT;
+
+CREATE FUNCTION spherekey_overlaps_sbox(spherekey, sbox)
+ RETURNS boolean
+ AS $$
+ SELECT $2 && $1;
+ $$ LANGUAGE SQL IMMUTABLE STRICT;
+
+CREATE FUNCTION spherekey_contains_sbox(spherekey, sbox)
+ RETURNS boolean
+ AS $$
+ SELECT $2 <@ $1;
+ $$ LANGUAGE SQL IMMUTABLE STRICT;
+
+CREATE FUNCTION spherekey_iscontained_sbox(spherekey, sbox)
+ RETURNS boolean
+ AS $$
+ SELECT $2 @> $1;
+ $$ LANGUAGE SQL IMMUTABLE STRICT;
+
+CREATE OPERATOR && (
+ LEFTARG = spherekey,
+ RIGHTARG = spoint,
+ PROCEDURE = spherekey_overlaps_spoint,
+ COMMUTATOR = '&&',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+COMMENT ON OPERATOR && (spherekey, spoint) IS
+ 'true, if the spherekey overlaps a spoint';
+
+CREATE OPERATOR @> (
+ LEFTARG = spherekey,
+ RIGHTARG = spoint,
+ PROCEDURE = spherekey_contains_spoint,
+ COMMUTATOR = '<@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+COMMENT ON OPERATOR @> (spherekey, spoint) IS
+ 'true, if the spherekey contains a spherical point';
+
+CREATE OPERATOR <@ (
+ LEFTARG = spherekey,
+ RIGHTARG = spoint,
+ PROCEDURE = spherekey_iscontained_spoint,
+ COMMUTATOR = '@>',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+COMMENT ON OPERATOR <@ (spherekey, spoint) IS
+ 'true, if the spherekey is contained in a spherical point - just needed to define the OpFamily';
+
+CREATE OPERATOR && (
+ LEFTARG = spherekey,
+ RIGHTARG = sbox,
+ PROCEDURE = spherekey_overlaps_sbox,
+ COMMUTATOR = '&&',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+COMMENT ON OPERATOR && (spherekey, sbox) IS
+ 'true, if the spherekey overlaps a spherical point';
+
+CREATE OPERATOR @> (
+ LEFTARG = spherekey,
+ RIGHTARG = sbox,
+ PROCEDURE = spherekey_contains_sbox,
+ COMMUTATOR = '<@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+COMMENT ON OPERATOR @> (spherekey, sbox) IS
+ 'true, if the spherekey contains a spherical point';
+
+CREATE OPERATOR <@ (
+ LEFTARG = spherekey,
+ RIGHTARG = sbox,
+ PROCEDURE = spherekey_iscontained_sbox,
+ COMMUTATOR = '@>',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+COMMENT ON OPERATOR <@ (spherekey, sbox) IS
+ 'true, if the spherekey is contained in a spherical point';
+
+-------------------------------------------------
+-- create operators that will actually be used --
+-------------------------------------------------
+
+CREATE FUNCTION spoint_overlaps_sbox(spoint, sbox)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME', 'spoint_overlaps_sbox'
+ LANGUAGE 'c' IMMUTABLE STRICT;
+
+CREATE OPERATOR && (
+ LEFTARG = spoint,
+ RIGHTARG = sbox,
+ PROCEDURE = spoint_overlaps_sbox,
+ COMMUTATOR = '&&',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+COMMENT ON OPERATOR && (spoint, sbox) IS
+ 'true, if the spherical point overlaps a spherical box';
+
+------------------------------------------------------------
+-- Complementar operators, needed for OpFamily definition --
+------------------------------------------------------------
+
+CREATE FUNCTION sbox_overlaps_spoint(sbox, spoint)
+ RETURNS boolean
+ AS $$
+ SELECT $2 && $1;
+ $$ LANGUAGE SQL IMMUTABLE STRICT;
+
+CREATE OPERATOR && (
+ LEFTARG = sbox,
+ RIGHTARG = spoint,
+ PROCEDURE = sbox_overlaps_spoint,
+ COMMUTATOR = '&&',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+COMMENT ON OPERATOR && (sbox, spoint) IS
+ 'true, if the spherical box overlaps a spherical point';
+
+CREATE FUNCTION sbox_iscontained_spoint(sbox, spoint)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME', 'sbox_iscontained_spoint'
+ LANGUAGE 'c' IMMUTABLE STRICT;
+
+CREATE OPERATOR <@ (
+ LEFTARG = sbox,
+ RIGHTARG = spoint,
+ PROCEDURE = sbox_iscontained_spoint,
+ COMMUTATOR = '@>',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE FUNCTION spoint_contains_sbox(spoint, sbox)
+ RETURNS boolean
+ AS $$
+ SELECT $2 <@ $1;
+ $$ LANGUAGE SQL IMMUTABLE STRICT;
+
+CREATE OPERATOR @> (
+ LEFTARG = spoint,
+ RIGHTARG = sbox,
+ PROCEDURE = spoint_contains_sbox,
+ COMMUTATOR = '<@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+--------------------------------
+-- the OpFamily --
+--------------------------------
+
+CREATE OPERATOR FAMILY brin_inclusion_spheric_ops USING brin;
+
+CREATE OR REPLACE FUNCTION spoint_brin_inclusion_add_value(internal, internal, internal, internal)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME','spoint_brin_inclusion_add_value'
+ LANGUAGE 'c';
+
+CREATE OR REPLACE FUNCTION sbox_brin_inclusion_add_value(internal, internal, internal, internal)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME','sbox_brin_inclusion_add_value'
+ LANGUAGE 'c';
+
+CREATE OPERATOR CLASS brin_spoint_inclusion_ops
+ DEFAULT FOR TYPE spoint
+ USING brin
+ FAMILY brin_inclusion_spheric_ops AS
+ FUNCTION 1 brin_inclusion_opcinfo(internal) ,
+ FUNCTION 2 spoint_brin_inclusion_add_value(internal, internal, internal, internal) ,
+ FUNCTION 3 brin_inclusion_consistent(internal, internal, internal) ,
+ FUNCTION 4 brin_inclusion_union(internal, internal, internal) ,
+ STORAGE spherekey;
+
+CREATE OPERATOR CLASS brin_sbox_inclusion_ops
+ DEFAULT FOR TYPE sbox
+ USING brin
+ FAMILY brin_inclusion_spheric_ops AS
+ FUNCTION 1 brin_inclusion_opcinfo(internal) ,
+ FUNCTION 2 sbox_brin_inclusion_add_value(internal, internal, internal, internal) ,
+ FUNCTION 3 brin_inclusion_consistent(internal, internal, internal) ,
+ FUNCTION 4 brin_inclusion_union(internal, internal, internal) ,
+ STORAGE spherekey;
+
+ALTER OPERATOR FAMILY brin_inclusion_spheric_ops USING brin ADD
+ OPERATOR 3 &&(spherekey, spoint),
+ OPERATOR 7 @>(spherekey, spoint),
+ OPERATOR 8 <@(spherekey, spoint),
+
+ OPERATOR 3 &&(spoint, spherekey),
+ OPERATOR 7 @>(spoint, spherekey),
+ OPERATOR 8 <@(spoint, spherekey),
+
+ OPERATOR 3 &&(spherekey, sbox),
+ OPERATOR 7 @>(spherekey, sbox),
+ OPERATOR 8 <@(spherekey, sbox),
+
+ OPERATOR 3 &&(sbox, spherekey),
+ OPERATOR 7 @>(sbox, spherekey),
+ OPERATOR 8 <@(sbox, spherekey),
+
+ OPERATOR 3 &&(spherekey, spherekey),
+ OPERATOR 7 @>(spherekey, spherekey),
+ OPERATOR 8 <@(spherekey, spherekey),
+
+ OPERATOR 3 &&(spoint, sbox),
+ OPERATOR 3 &&(sbox, spoint),
+ OPERATOR 7 @>(sbox, spoint),
+ OPERATOR 7 @>(spoint, sbox),
+ OPERATOR 8 <@(sbox, spoint),
+ OPERATOR 8 <@(spoint, sbox),
+
+ OPERATOR 3 &&(sbox, sbox),
+ OPERATOR 7 @>(sbox, sbox),
+ OPERATOR 8 <@(sbox, sbox);
diff --git a/pgs_circle.sql.in b/pgs_circle.sql.in
index e0c110d..9e386dd 100644
--- a/pgs_circle.sql.in
+++ b/pgs_circle.sql.in
@@ -32,6 +32,14 @@ CREATE FUNCTION scircle(spoint, float8)
COMMENT ON FUNCTION scircle(spoint, float8) IS
'spherical circle with spherical point as center and float8 as radius in radians';
+CREATE FUNCTION scircle_deg(spoint, float8)
+ RETURNS scircle
+ AS 'MODULE_PATHNAME' , 'spherecircle_by_center_deg'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT PARALLEL SAFE;
+
+COMMENT ON FUNCTION scircle_deg(spoint, float8) IS
+ 'spherical circle with spherical point as center and float8 as radius in degrees';
--
-- Casting point as circle
diff --git a/pgs_line.sql.in b/pgs_line.sql.in
index 9814355..3b51fba 100644
--- a/pgs_line.sql.in
+++ b/pgs_line.sql.in
@@ -593,3 +593,53 @@ COMMENT ON FUNCTION scircle_contains_line_com_neg(sline, scircle) IS
'returns true if spherical circle does not contain spherical line';
+--
+-- distance between line and point
+--
+
+CREATE FUNCTION dist(sline, spoint)
+ RETURNS FLOAT8
+ AS 'MODULE_PATHNAME', 'sphereline_point_distance'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT;
+
+COMMENT ON FUNCTION dist(sline, spoint) IS
+ 'returns the distance between spherical line and spherical point';
+
+
+CREATE OPERATOR <-> (
+ LEFTARG = sline,
+ RIGHTARG = spoint,
+ COMMUTATOR = '<->',
+ PROCEDURE = dist
+);
+
+COMMENT ON OPERATOR <-> (sline, spoint) IS
+ 'returns the distance between spherical line and spherical point';
+
+
+
+--
+-- distance between point and line
+--
+
+CREATE FUNCTION dist(spoint, sline)
+ RETURNS FLOAT8
+ AS 'MODULE_PATHNAME', 'sphereline_point_distance_com'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT;
+
+COMMENT ON FUNCTION dist(spoint, sline) IS
+ 'returns the distance between spherical line and spherical point';
+
+
+CREATE OPERATOR <-> (
+ LEFTARG = spoint,
+ RIGHTARG = sline,
+ COMMUTATOR = '<->',
+ PROCEDURE = dist
+);
+
+COMMENT ON OPERATOR <-> (spoint, sline) IS
+ 'returns the distance between spherical line and spherical point';
+
diff --git a/pgs_path.sql.in b/pgs_path.sql.in
index 94f3222..58268d4 100644
--- a/pgs_path.sql.in
+++ b/pgs_path.sql.in
@@ -34,6 +34,14 @@ CREATE FUNCTION spoint(spath, float8)
COMMENT ON FUNCTION spoint(spath, float8) IS
'returns n-th point of spherical path using linear interpolation';
+CREATE FUNCTION spath_as_array(spath)
+ RETURNS spoint[]
+ AS 'MODULE_PATHNAME', 'spherepath_get_array'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT PARALLEL SAFE;
+
+COMMENT ON FUNCTION spath_as_array(spath) IS
+ 'returns spath as array of points';
-- ******************************
--
diff --git a/pgs_point.sql.in b/pgs_point.sql.in
index a9afb84..908707e 100644
--- a/pgs_point.sql.in
+++ b/pgs_point.sql.in
@@ -15,6 +15,12 @@ CREATE FUNCTION spoint(FLOAT8, FLOAT8)
LANGUAGE 'c'
IMMUTABLE STRICT PARALLEL SAFE;
+CREATE FUNCTION spoint_deg(FLOAT8, FLOAT8)
+ RETURNS spoint
+ AS 'MODULE_PATHNAME', 'spherepoint_from_long_lat_deg'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT PARALLEL SAFE;
+
CREATE FUNCTION set_sphere_output_precision(INT4)
RETURNS CSTRING
AS 'MODULE_PATHNAME', 'set_sphere_output_precision'
@@ -28,6 +34,9 @@ CREATE FUNCTION set_sphere_output(CSTRING)
COMMENT ON FUNCTION spoint(FLOAT8, FLOAT8) IS
'returns a spherical point from longitude (arg1), latitude (arg2)';
+COMMENT ON FUNCTION spoint_deg(FLOAT8, FLOAT8) IS
+ 'returns a spherical point from longitude (arg1, in degrees), latitude (arg2, in degrees)';
+
CREATE FUNCTION long(spoint)
RETURNS FLOAT8
AS 'MODULE_PATHNAME', 'spherepoint_long'
diff --git a/pgs_polygon.sql.in b/pgs_polygon.sql.in
index 701c860..fdd4277 100644
--- a/pgs_polygon.sql.in
+++ b/pgs_polygon.sql.in
@@ -11,6 +11,24 @@ CREATE FUNCTION npoints(spoly)
COMMENT ON FUNCTION npoints(spoly) IS
'returns number of points of spherical polygon';
+CREATE FUNCTION spoint(spoly, int4)
+ RETURNS spoint
+ AS 'MODULE_PATHNAME', 'spherepoly_get_point'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT PARALLEL SAFE;
+
+COMMENT ON FUNCTION spoint(spoly, int4) IS
+ 'returns n-th point of spherical polygon';
+
+CREATE FUNCTION spoly_as_array(spoly)
+ RETURNS spoint[]
+ AS 'MODULE_PATHNAME', 'spherepoly_get_array'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT PARALLEL SAFE;
+
+COMMENT ON FUNCTION spoly_as_array(spoly) IS
+ 'returns spoly as array of points';
+
CREATE FUNCTION area(spoly)
RETURNS FLOAT8
AS 'MODULE_PATHNAME', 'spherepoly_area'
@@ -928,6 +946,18 @@ CREATE FUNCTION spoly_add_point_aggr (spoly, spoint)
COMMENT ON FUNCTION spoly_add_point_aggr (spoly, spoint) IS
'adds a spherical point to spherical polygon. Do not use it standalone!';
+CREATE FUNCTION spoly_deg(float8[])
+ RETURNS spoly
+ AS 'MODULE_PATHNAME', 'spherepoly_deg'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT;
+
+COMMENT ON FUNCTION spoly_deg(float8[]) IS
+ ' Create spoly from array of points.
+ Two consecutive numbers among those present
+ refer to the same occurrence and cover its
+ latitude and longitude, respectively.';
+
CREATE FUNCTION spoly_add_points_fin_aggr (spoly)
RETURNS spoly
AS 'MODULE_PATHNAME', 'spherepoly_add_points_finalize'
@@ -943,3 +973,17 @@ CREATE AGGREGATE spoly (
stype = spoly,
finalfunc = spoly_add_points_fin_aggr
);
+
+
+--
+-- polygon is convex
+--
+
+CREATE FUNCTION spoly_is_convex(spoly)
+ RETURNS BOOL
+ AS 'MODULE_PATHNAME', 'spherepoly_is_convex'
+ LANGUAGE 'c'
+ IMMUTABLE PARALLEL SAFE;
+
+COMMENT ON FUNCTION spoly_is_convex(spoly) IS
+ 'true if spherical polygon is convex';
diff --git a/pgs_types.sql.in b/pgs_types.sql.in
index e0ff8f3..4bede83 100644
--- a/pgs_types.sql.in
+++ b/pgs_types.sql.in
@@ -132,7 +132,6 @@ CREATE FUNCTION spoly_out(spoly)
LANGUAGE 'c'
IMMUTABLE STRICT;
-
CREATE TYPE spoly (
internallength = VARIABLE,
input = spoly_in,
diff --git a/sql/circle.sql b/sql/circle.sql
index 5fbbc91..0a57cab 100644
--- a/sql/circle.sql
+++ b/sql/circle.sql
@@ -5,6 +5,14 @@ SET extra_float_digits = 0;
-- Input/Output ---
+SELECT scircle_deg(spoint(10,10), 90);
+
+SELECT scircle_deg(spoint(10,10), 91);
+
+SELECT scircle_deg(spoint(0,0), 0);
+
+SELECT scircle_deg(spoint(10,10), -1);
+
SELECT set_sphere_output( 'RAD' );
SELECT '< (1h 2m 30s , +1d 2m 30s), 1.0d >'::scircle;
diff --git a/sql/contains.sql b/sql/contains.sql
new file mode 100644
index 0000000..4e348cc
--- /dev/null
+++ b/sql/contains.sql
@@ -0,0 +1,123 @@
+/*
+This set of tests is designed to verify the compliance of the contain operation with the DE-9IM model
+*/
+
+
+-- sline vs spoint
+
+
+-- the point lies far beyond the line
+select 'sline ~ spoint', 'f' as expected, sline(spoint'(270d,10d)', spoint'(270d,30d)') ~ spoint'(0d, 50d)' as actual;
+
+-- the point lies in the boundary of line
+select 'sline ~ spoint', 'f' as expected, sline(spoint'(270d,10d)', spoint'(270d,30d)') ~ spoint'(270d, 10d)' as actual;
+
+-- the point lies in the interior of line
+select 'sline ~ spoint', 't' as expected, sline(spoint'(270d,10d)', spoint'(270d,30d)') ~ spoint'(270d, 20d)' as actual;
+
+-- the point and line that degenerated into the point coincide
+select 'sline ~ spoint', 't' as expected, sline(spoint'(270d,10d)', spoint'(270d,10d)') ~ spoint'(270d, 10d)' as actual;
+
+-- the point and line that degenerated into the point do not coincide
+select 'sline ~ spoint', 'f' as expected, sline(spoint'(270d,10d)', spoint'(270d,10d)') ~ spoint'(270d, 20d)' as actual;
+
+
+-- spoint vs scircle
+
+
+-- the point lies far beyond the circle
+select 'spoint @ scircle', 'f' as expected, spoint'(0d,0d)' @ scircle'<(0d,90d),50d>' as actual;
+
+-- the point lies in the boundary of circle
+select 'spoint @ scircle', 'f' as expected, spoint'(0d,80d)' @ scircle'<(0d,90d),10d>' as actual;
+
+-- the point lies in the interior of circle
+select 'spoint @ scircle', 't' as expected, spoint'(0d,80d)' @ scircle'<(0d,90d),50d>' as actual;
+
+-- the point and circle that degenerated into the point coincide
+select 'spoint @ scircle', 't' as expected, spoint'(0d,90d)' @ scircle'<(0d,90d),0d>' as actual;
+
+-- the point and circle that degenerated into the point do not coincide
+select 'spoint @ scircle', 'f' as expected, spoint'(0d,50d)' @ scircle'<(0d,90d),0d>' as actual;
+
+
+-- sellipse vs spoint
+
+
+-- the point lies far beyond the ellipse
+select 'sellipse ~ spoint', 'f' as expected, sellipse'<{ 30d , 20d }, (0d , 90d) , 0d>' ~ spoint'(0d, 0d)' as actual;
+
+-- the point lies in the boundary of ellipse
+select 'sellipse ~ spoint', 'f' as expected, sellipse'<{ 30d , 20d }, (0d , 90d) , 0d>' ~ spoint'(0d, 70d)' as actual;
+
+-- the point lies in the interior of ellipse
+select 'sellipse ~ spoint', 't' as expected, sellipse'<{ 30d , 20d }, (0d , 90d) , 0d>' ~ spoint'(90d, 65d)' as actual;
+
+-- the point lies in the boundary of ellipse that degenerated into the line
+select 'sellipse ~ spoint', 't' as expected, sellipse'<{ 10d , 0d }, (0d , 0d) , 0d>' ~ spoint'(10d, 0d)' as actual;
+
+-- the point lies in the interior of ellipse that degenerated into the line
+select 'sellipse ~ spoint', 't' as expected, sellipse'<{ 10d , 0d }, (0d , 0d) , 0d>' ~ spoint'(0d, 0d)' as actual;
+
+-- the point and ellipse that degenerated into the point coincide
+select 'sellipse ~ spoint', 't' as expected, sellipse'<{ 0d , 0d }, (0d , 90d) , 0d>' ~ spoint'(0d, 90d)' as actual;
+
+-- the point and ellipse that degenerated into the point do not coincide
+select 'sellipse ~ spoint', 'f' as expected, sellipse'<{ 0d , 0d }, (0d , 90d) , 0d>' ~ spoint'(0d, 91d)' as actual;
+
+
+-- spath vs spoint
+
+
+-- the point lies far beyond the opened path
+select 'spath ~ spoint', 'f' as expected, spath'{ (-10d, 0d),(10d,0d),(45d,15d),(80d,30d) }' ~ spoint'(0d, 90d)' as actual;
+
+-- the point lies in the boundary of opened path
+select 'spath ~ spoint', 'f' as expected, spath'{ (-10d, 0d),(10d,0d),(45d,15d),(80d,30d) }' ~ spoint'(-10d, 0d)' as actual;
+
+-- the point lies in the boundary of unsimple opened path
+select 'spath ~ spoint', 'f' as expected, spath'{ (-10d, 0d),(10d,0d),(45d,15d),(80d,30d),(-5d, 0d) }' ~ spoint'(-5d, 0d)' as actual;
+
+-- the point lies in the interior of opened path
+select 'spath ~ spoint', 't' as expected, spath'{ (-10d, 0d),(10d,0d),(45d,15d),(80d,30d) }' ~ spoint'(9d, 0d)' as actual;
+
+-- the point lies in the interior of closed path
+select 'spath ~ spoint', 't' as expected, spath'{ (-10d, 0d),(10d,0d),(45d,15d),(80d,30d),(-10d, 0d) }' ~ spoint'(-10d, 0d)' as actual;
+
+
+-- spoly vs spoint
+
+
+-- the point lies far beyond the polygon
+select 'spoly ~ spoint', 'f' as expected, spoly'{ (0d,0d), (10d,0d), (20d,20d) }' ~ spoint'(0d, 90d)' as actual;
+
+-- the point lies in the boundary of polygon
+select 'spoly ~ spoint', 'f' as expected, spoly'{ (0d,0d), (10d,0d), (20d,20d) }' ~ spoint'(5d, 0d)' as actual;
+
+-- the point lies in the boundary of polygon
+select 'spoly ~ spoint', 'f' as expected, spoly'{ (0d,0d), (10d,0d), (20d,20d) }' ~ spoint'(20d, 20d)' as actual;
+
+-- the point lies in the interior of polygon
+select 'spoly ~ spoint', 't' as expected, spoly'{ (0d,0d), (10d,0d), (20d,20d) }' ~ spoint'(5d, 5d)' as actual;
+
+
+-- sbox vs spoint
+
+
+-- the point lies far beyond the box
+select 'sbox ~ spoint', 'f' as expected, sbox'( (0d,0d), (20d,10d) )' ~ spoint'(0d, 90d)' as actual;
+
+-- the point lies in the boundary of box
+select 'sbox ~ spoint', 'f' as expected, sbox'( (0d,0d), (20d,10d) )' ~ spoint'(0d, 5d)' as actual;
+
+-- the point lies in the boundary of box
+select 'sbox ~ spoint', 'f' as expected, sbox'( (0d,0d), (20d,10d) )' ~ spoint'(0d, 0d)' as actual;
+
+-- the point lies in the interior of box
+select 'sbox ~ spoint', 't' as expected, sbox'( (0d,0d), (20d,10d) )' ~ spoint'(5d, 5d)' as actual;
+
+-- the point and box that degenerated into the point coincide
+select 'sbox ~ spoint', 't' as expected, sbox'( (0d,0d), (0d,0d) )' ~ spoint'(0d, 0d)' as actual;
+
+-- the point and box that degenerated into the point do not coincide
+select 'sbox ~ spoint', 'f' as expected, sbox'( (0d,0d), (0d,0d) )' ~ spoint'(0d, 1d)' as actual;
diff --git a/sql/line.sql b/sql/line.sql
index 7fc6ebf..7a5a2dd 100644
--- a/sql/line.sql
+++ b/sql/line.sql
@@ -1,6 +1,7 @@
\set ECHO none
SELECT set_sphere_output_precision(8);
\set ECHO all
+SET extra_float_digits TO -3;
-- checking spherical line operators
@@ -66,4 +67,18 @@ SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) #
SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) #
sline ( spoint '(0.000001d, 0d)', spoint '(0.000001d, 0.0000005d)' ) ;
-
\ No newline at end of file
+
+
+-- checking the distance between a line and a point
+
+
+SELECT sline '( 90d, 0d, 0d, XYZ ), 40d ' <-> spoint '( 0d, 90d )';
+
+SELECT sline '( 90d, 0d, 0d, XYZ ), 40d ' <-> spoint '( 0d, 90d )' =
+ spoint '( 0d, 90d )' <-> sline '( 90d, 0d, 0d, XYZ ), 40d ';
+
+SELECT sline '( 0d, 0d, 0d, XYZ ), 0d ' <-> spoint '( 0d, 90d )';
+
+SELECT sline '( 0d, 0d, 0d, XYZ ), 0d ' <-> spoint '( 0d, 0d )';
+
+SELECT sline '( 0d, 0d, 0d, XYZ ), 30d ' <-> spoint '( 0d, 30d )';
diff --git a/sql/moc100.sql b/sql/moc100.sql
index 8195f81..8c700b1 100644
--- a/sql/moc100.sql
+++ b/sql/moc100.sql
@@ -1,3 +1,14 @@
+\set ECHO none
+SELECT CASE
+ WHEN setting::int/10000 IN (10, 11, 12) THEN '10, 11, 12' -- moc100
+ WHEN setting::int/10000 IN (13, 14, 15) THEN '13, 14, 15' -- moc100_2
+ ELSE '16+'
+END AS outputfile_for_majorversion
+FROM pg_settings WHERE name = 'server_version_num';
+
+SELECT (regexp_matches(version(), '..-bit'))[1] outputfile_for_arch_bits;
+\set ECHO queries
+
CREATE TABLE moc100 (
ivoid text,
coverage smoc,
diff --git a/sql/overlaps.sql b/sql/overlaps.sql
new file mode 100644
index 0000000..82db270
--- /dev/null
+++ b/sql/overlaps.sql
@@ -0,0 +1,484 @@
+/*
+This set of tests is designed to verify the compliance of the overlap operation with the DE-9IM model
+*/
+
+
+-- sline vs sline
+
+
+-- the lines have no common points
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(10d,0d)') && sline( spoint'(20d,0d)', spoint'(30d,0d)') as actual;
+
+-- the point of intersection of the lines is the boundary for both
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(10d,0d)') && sline( spoint'(10d,0d)', spoint'(20d,0d)') as actual;
+
+-- one line intersects the other at the boundary point of the latter
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(10d,0d)') && sline( spoint'(0d,90d)', spoint'(0d,-10d)') as actual;
+
+-- the interiors of the lines intersect at one point
+select 'sline && sline', 'f' as expected, sline( spoint'(-10d,0d)', spoint'(10d,0d)') && sline( spoint'(0d,90d)', spoint'(0d,-10d)') as actual;
+
+-- the lines match
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(10d,0d)') && sline( spoint'(0d,0d)', spoint'(10d,0d)') as actual;
+
+-- one line lies completely in the other and they have an intersection at the boundary point
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(10d,0d)') && sline( spoint'(0d,0d)', spoint'(5d,0d)') as actual;
+
+-- one line lies completely in the other and they have no intersection at the boundary point
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(10d,0d)') && sline( spoint'(2d,0d)', spoint'(5d,0d)') as actual;
+
+-- one line partially lies in the other
+select 'sline && sline', 't' as expected, sline( spoint'(0d,0d)', spoint'(10d,0d)') && sline( spoint'(5d,0d)', spoint'(20d,0d)') as actual;
+
+-- the line degenerated into the point lies on the boundary of another
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(10d,0d)') && sline( spoint'(0d,0d)', spoint'(0d,0d)') as actual;
+
+-- the line degenerated into the point lies in the interior of another
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(10d,0d)') && sline( spoint'(5d,0d)', spoint'(5d,0d)') as actual;
+
+-- both lines are degenerated into the point and coincide
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(0d,0d)') && sline( spoint'(0d,0d)', spoint'(0d,0d)') as actual;
+
+-- both lines are degenerated into the point and do not coincide, but lie close to each other
+select 'sline && sline', 'f' as expected, sline( spoint'(0d,0d)', spoint'(0d,0d)') && sline( spoint'(1d,0d)', spoint'(1d,0d)') as actual;
+
+
+-- scircle vs scircle
+
+
+-- the circles have no common points
+select 'scircle && scircle', 'f' as expected, scircle'<(0d , 0d) , 20d>' && scircle'<(30d , 0d) , 5d>' as actual;
+
+-- the point of intersection of the circles is the boundary for both
+select 'scircle && scircle', 'f' as expected, scircle'<(-10d , 0d) , 10d>' && scircle'<(10d , 0d) , 10d>' as actual;
+
+-- the circles match
+select 'scircle && scircle', 'f' as expected, scircle'<(-10d , 0d) , 10d>' && scircle'<(-10d , 0d) , 10d>' as actual;
+
+-- one circle lies completely in the other and they have an intersection at the boundary point
+select 'scircle && scircle', 'f' as expected, scircle'<(0d , 0d) , 20d>' && scircle'<(-10d , 0d) , 10d>' as actual;
+
+-- one circle lies completely in the other and they have no intersection at the boundary point
+select 'scircle && scircle', 'f' as expected, scircle'<(0d , 0d) , 20d>' && scircle'<(0d , 0d) , 5d>' as actual;
+
+-- one circle partially lies in the other
+select 'scircle && scircle', 't' as expected, scircle'<(0d , 0d) , 20d>' && scircle'<(10d , 0d) , 20d>' as actual;
+
+-- the circle degenerated into the point lies on the boundary of another
+select 'scircle && scircle', 'f' as expected, scircle'<(0d , 0d) , 20d>' && scircle'<(20d , 0d) , 0d>' as actual;
+
+-- the circle degenerated into the point lies in the interior of another
+select 'scircle && scircle', 'f' as expected, scircle'<(0d , 0d) , 20d>' && scircle'<(0d , 0d) , 0d>' as actual;
+
+-- both circles are degenerated into the point and coincide
+select 'scircle && scircle', 'f' as expected, scircle'<(0d , 0d) , 0d>' && scircle'<(0d , 0d) , 0d>' as actual;
+
+-- both circles are degenerated into the point and do not coincide, but lie close to each other
+select 'scircle && scircle', 'f' as expected, scircle'<(1d , 0d) , 0d>' && scircle'<(0d , 0d) , 0d>' as actual;
+
+
+-- sellipse vs sellipse
+
+
+-- the ellipses have no common points
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 45d , 20d }, (-45d , 0d) , 0d>' && sellipse'<{ 45d , 20d }, (50 , 0d) , 0d>' as actual;
+
+-- the point of intersection of the ellipses is the boundary for both
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 45d , 20d }, (-45d , 0d) , 0d>' && sellipse'<{ 45d , 20d }, (45d , 0d) , 0d>' as actual;
+
+-- the ellipses match
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 45d , 20d }, (-45d , 0d) , 0d>' && sellipse'<{ 45d , 20d }, (-45d , 0d) , 0d>' as actual;
+
+-- one ellipse lies completely in the other and they have an intersection at the boundary point
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 40d , 30d }, (0d , 0d) , 0d>' && sellipse'<{ 20d , 5d }, (-20d , 0d) , 0d>' as actual;
+
+-- one ellipse lies completely in the other and they have no intersection at the boundary point
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 40d , 30d }, (0d , 0d) , 0d>' && sellipse'<{ 10d , 5d }, (-20d , 0d) , 0d>' as actual;
+
+-- one ellipse partially lies in the other
+select 'sellipse && sellipse', 't' as expected, sellipse'<{ 45d , 30d }, (0d , 0d) , 0d>' && sellipse'<{ 20d , 5d }, (30d , 0d) , 0d>' as actual;
+
+-- the ellipse degenerated into the line lies completely in the interior of another (non-degenerate) ellipse
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 40d , 30d }, (0d , 0d) , 0d>' && sellipse'<{ 10d , 0d }, (10d , 0d) , 0d>' as actual;
+
+-- the ellipse degenerated into the line partially lies in the interior of another (non-degenerate) ellipse
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 40d , 30d }, (0d , 0d) , 0d>' && sellipse'<{ 20d , 0d }, (30d , 0d) , 0d>' as actual;
+
+-- the ellipse degenerated into the point lies on the boundary of another
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 40d , 30d }, (0d , 0d) , 0d>' && sellipse'<{ 0d , 0d }, (30d , 0d) , 0d>' as actual;
+
+-- the ellipse degenerated into the point lies in the interior of another
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 40d , 30d }, (0d , 0d) , 0d>' && sellipse'<{ 0d , 0d }, (40d , 0d) , 0d>' as actual;
+
+-- both ellipses are degenerated into the point and coincide
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 0d , 0d }, (0d , 0d) , 0d>' && sellipse'<{ 0d , 0d }, (0d , 0d) , 0d>' as actual;
+
+-- both ellipses are degenerated into the point and do not coincide, but lie close to each other
+select 'sellipse && sellipse', 'f' as expected, sellipse'<{ 0d , 0d }, (0d , 0d) , 0d>' && sellipse'<{ 0d , 0d }, (1d , 0d) , 0d>' as actual;
+
+
+-- sellipse vs scircle
+
+
+-- the ellipse and circle have no common points
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 20d , 10d }, (0d , 0d) , 0d>' && scircle'<(30d , 0d) , 5d>' as actual;
+
+-- the point of intersection of the ellipse and circle is the boundary for both
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 20d , 10d }, (0d , 0d) , 0d>' && scircle'<(30d , 0d) , 10d>' as actual;
+
+-- the ellipse and circle match
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 10d , 10d }, (30d , 0d) , 0d>' && scircle'<(30d , 0d) , 10d>' as actual;
+
+-- the ellipse lies completely in the circle and they have an intersection at the boundary point
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 20d , 10d }, (0d , 0d) , 0d>' && scircle'<(20d , 0d) , 40d>' as actual;
+
+-- the ellipse lies completely in the circle and they have no intersection at the boundary point
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 20d , 10d }, (20d , 0d) , 0d>' && scircle'<(20d , 0d) , 40d>' as actual;
+
+-- the circle lies completely in the ellipse
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 20d , 10d }, (0d , 0d) , 0d>' && scircle'<(0d , 0d) , 5d>' as actual;
+
+-- the circle partially lies in the ellipse
+select 'sellipse && scircle', 't' as expected, sellipse'<{ 20d , 10d }, (0d , 0d) , 0d>' && scircle'<(20d , 0d) , 15d>' as actual;
+
+-- the ellipse degenerated into the line lies completely in the interior of circle
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 20d , 0d }, (0d , 0d) , 0d>' && scircle'<(0d , 0d) , 20d>' as actual;
+
+-- the ellipse degenerated into the line partially lies in the interior of circle
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 20d , 0d }, (10d , 0d) , 0d>' && scircle'<(0d , 0d) , 20d>' as actual;
+
+-- the ellipse degenerated into the point lies on the boundary of circle
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 0d , 0d }, (10d , 0d) , 0d>' && scircle'<(0d , 0d) , 10d>' as actual;
+
+-- the ellipse degenerated into the point lies in the interior of circle
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 0d , 0d }, (5d , 0d) , 0d>' && scircle'<(0d , 0d) , 10d>' as actual;
+
+-- the ellipse and circle are degenerated into the point and coincide
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 0d , 0d }, (0d , 0d) , 0d>' && scircle'<(0d , 0d) , 0d>' as actual;
+
+-- the ellipses are degenerated into the point and do not coincide, but lie close to each other
+select 'sellipse && scircle', 'f' as expected, sellipse'<{ 0d , 0d }, (0d , 0d) , 0d>' && scircle'<(1d , 0d) , 0d>' as actual;
+
+
+-- spath vs spath
+
+
+-- the opened paths have no common points
+select 'spath && spath', 'f' as expected, spath'{ (-10d, 0d),(10d,0d),(45d,15d) }' && spath'{ (60d, 15d),(70d, 20d),(75d, 20d) }' as actual;
+
+-- the points of intersection of the opened paths is the boundary for both
+select 'spath && spath', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && spath'{ (-10d, 0d),(0d, 10d),(45d, 15d) }' as actual;
+
+-- one opened path intersects the other at the boundary point of the latter
+select 'spath && spath', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && spath'{ (-20d, -10d),(-10d, 0d),(0d, 10d),(45d, 15d),(60d, 15d) }' as actual;
+
+-- the interiors of the opened paths intersect at one point
+select 'spath && spath', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && spath'{ (0d, 10d),(0d, -10d),(10d, -10d) }' as actual;
+
+-- the interiors of the opened paths intersect at two points
+select 'spath && spath', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && spath'{ (0d, 10d),(0d, -10d),(5d, 0d) }' as actual;
+
+-- the opened paths match
+select 'spath && spath', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' as actual;
+
+-- the closed paths match
+select 'spath && spath', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d),(-10d, 0d) }' && spath'{ (-10d, 0d),(10d, 0d),(45d, 15d),(-10d, 0d) }' as actual;
+
+-- one opened path lies completely in the other and they have an intersection at the boundary point
+select 'spath && spath', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d),(60d, 15d),(70d, 20d) }' && spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' as actual;
+
+-- one opened path lies completely in the other and they have no intersection at the boundary point
+select 'spath && spath', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d),(60d, 15d),(70d, 20d) }' && spath'{ (10d, 0d),(45d, 15d),(60d, 15d) }' as actual;
+
+-- one opened path partially lies in the other
+select 'spath && spath', 't' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && spath'{ (45d, 15d),(60d, 15d),(70d, 20d) }' as actual;
+
+-- one closed path partially lies in the other
+select 'spath && spath', 't' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d),(-10d, 0d) }' && spath'{ (45d, 15d),(60d, 15d),(70d, 20d),(45d, 15d) }' as actual;
+
+-- the opened path partially lies in the closed path
+select 'spath && spath', 't' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d),(-10d, 0d) }' && spath'{ (45d, 15d),(60d, 15d),(70d, 20d) }' as actual;
+
+
+-- spath vs sline
+
+
+-- the opened path and line have no common points
+select 'spath && sline', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && sline( spoint'(20d, 0d)', spoint'(30d, 0d)') as actual;
+
+-- the points of intersection of the opened path and line is the boundary for both
+select 'spath && sline', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && sline( spoint'(-10d, 0d)', spoint'(45d, 15d)') as actual;
+
+-- the interiors of the opened path and line intersect at one point
+select 'spath && sline', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && sline( spoint'(0d, 10d)', spoint'(0d, -10d)') as actual;
+
+-- the path and line match
+select 'spath && sline', 'f' as expected, spath'{ (0d, 10d),(0d, -10d) }' && sline( spoint'(0d, 10d)', spoint'(0d, -10d)') as actual;
+
+-- the line lies completely in the opened path and they have an intersection at the boundary point
+select 'spath && sline', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d),(60d, 20d) }' && sline( spoint'(-10d, 0d)', spoint'(10d, 0d)') as actual;
+
+-- the line lies completely in the opened path and they have no intersection at the boundary point
+select 'spath && sline', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d),(60d, 20d) }' && sline( spoint'(10d, 0d)', spoint'(45d, 15d)') as actual;
+
+-- the line partially lies in the open path
+select 'spath && sline', 't' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && sline( spoint'(5d, 0d)', spoint'(20d, 0d)') as actual;
+
+-- the line degenerated into the point lies in the boundary of open path
+select 'spath && sline', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && sline( spoint'(-10d, 0d)', spoint'(-10d, 0d)') as actual;
+
+-- the line degenerated into the point lies in the interior of open path
+select 'spath && sline', 'f' as expected, spath'{ (-10d, 0d),(10d, 0d),(45d, 15d) }' && sline( spoint'(0d, 0d)', spoint'(0d, 0d)') as actual;
+
+
+-- spoly vs spoly
+
+
+-- the polygons have no common points
+select 'spoly && spoly', 'f' as expected, spoly'{ (0d, 0d),(-10d, 0d),(0d, 10d) }' && spoly'{ (10d, 0d),(20d, 0d),(10d, 10d) }' as actual;
+
+-- the point of intersection of the polygons is the boundary for both
+select 'spoly && spoly', 'f' as expected, spoly'{ (0d, 0d),(-10d, 0d),(0d, 10d) }' && spoly'{ (10d, 0d),(20d, 0d),(0d, 10d) }' as actual;
+
+-- the interiors of the polygons intersect at one line
+select 'spoly && spoly', 'f' as expected, spoly'{ (0d, 0d),(-10d, 0d),(0d, 10d) }' && spoly'{ (0d, 0d),(20d, 0d),(0d, 10d) }' as actual;
+
+-- the polygons matches
+select 'spoly && spoly', 'f' as expected, spoly'{ (0d, 0d),(-10d, 0d),(0d, 10d) }' && spoly'{ (0d, 0d),(-10d, 0d),(0d, 10d) }' as actual;
+
+-- one polygon lies completely in the other and they have an intersection at the boundary line
+select 'spoly && spoly', 'f' as expected, spoly'{ (0d, 0d),(20d, 0d),(20d, 20d),(0d, 20d) }' && spoly'{ (0d, 0d),(20d, 0d),(0d, 20d) }' as actual;
+
+-- one polygon lies completely in the other and they have no intersection at the boundary line or point
+select 'spoly && spoly', 'f' as expected, spoly'{ (0d, 0d),(20d, 0d),(20d, 20d),(0d, 20d) }' && spoly'{ (5d, 5d),(15d, 5d),(15d, 15d),(5d,15d) }' as actual;
+
+-- one polygon partially lies in the other
+select 'spoly && spoly', 't' as expected, spoly'{ (0d, 0d),(-10d, 0d),(0d, 10d) }' && spoly'{ (5d, 5d),(30d, 5d),(30d, 15d),(5d,15d) }' as actual;
+
+
+-- spoly vs scircle
+
+
+-- the polygon and circle have no common points
+select 'spoly && scircle', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && scircle'<(0d , 90d) , 10d>' as actual;
+
+-- the point of intersection of the polygon and circle is the boundary for both
+select 'spoly && scircle', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && scircle'<(0d , 90d) , 80d>' as actual;
+
+-- the circle lies completely in the polygon and they have an intersection at the boundary point
+select 'spoly && scircle', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && scircle'<(5d , 1d) , 1d>' as actual;
+
+-- the circle lies completely in the polygon and they have no intersection at the boundary point
+select 'spoly && scircle', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && scircle'<(5d , 2d) , 1d>' as actual;
+
+-- the polygon lies completely in the circle
+select 'spoly && scircle', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && scircle'<(0d , 15d) , 20d>' as actual;
+
+-- the polygon partially lies in the circle
+select 'spoly && scircle', 't' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && scircle'<(0d , 5d) , 5d>' as actual;
+
+-- the circle degenerated into the point lies in the boundary of polygon
+select 'spoly && scircle', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && scircle'<(0d , 0d) , 0d>' as actual;
+
+-- the circle degenerated into the point lies in the interior of polygon
+select 'spoly && scircle', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && scircle'<(2d , 2d) , 0d>' as actual;
+
+
+-- spoly vs sellipse
+
+
+-- the polygon and ellipse have no common points
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && sellipse'<{ 30d , 20d }, (0d , 90d) , 0d>' as actual;
+
+-- the point of intersection of the polygon and ellipse is the boundary for both
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && sellipse'<{ 80d , 20d }, (0d , 90d) , 90d>' as actual;
+
+-- the ellipse lies completely in the polygon and they have an intersection at the boundary points
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 0d),(20d, 0d),(20d, 20d),(0d, 20d) }' && sellipse'<{ 10d , 5d }, (10d , 10d), 0d>' as actual;
+
+-- the ellipse lies completely in the polygon and they have no intersection at the boundary points
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 0d),(20d, 0d),(20d, 20d),(0d, 20d) }' && sellipse'<{ 7d , 5d }, (10d , 10d), 0d>' as actual;
+
+-- the polygon lies completely in the ellipse and they have an intersection at the boundary points
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 5d),(10d, 10d),(20d, 5d),(10d, 0d) }' && sellipse'<{ 10d , 5d }, (10d , 5d), 0d>' as actual;
+
+-- the polygon lies completely in the ellipse and they have no intersection at the boundary points
+select 'spoly && sellipse', 'f' as expected, spoly'{ (1d, 5d),(10d, 9d),(19d, 5d),(10d, 1d) }' && sellipse'<{ 10d , 5d }, (10d , 10d), 0d>' as actual;
+
+-- the ellipse partially lies in the polygon
+select 'spoly && sellipse', 't' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && sellipse'<{ 10d , 2d }, (0d , 5d) , 0d>' as actual;
+
+-- the ellipse degenerated into the point lies in the boundary of polygon
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && sellipse'<{ 0d , 0d }, (0d , 0d), 0d>' as actual;
+
+-- the ellipse degenerated into the point lies in the interior of polygon
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && sellipse'<{ 0d , 0d }, (5d , 2d), 0d>' as actual;
+
+-- the ellipse degenerated into the line lies in the boundary of polygon
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && sellipse'<{ 5d , 0d }, (5d , 0d), 0d>' as actual;
+
+-- the ellipse degenerated into the line lies in the interior of polygon
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && sellipse'<{ 2d , 0d }, (1d , 4d), 90d>' as actual;
+
+-- the ellipse degenerated into the line partially lies in the interior of polygon
+select 'spoly && sellipse', 'f' as expected, spoly'{ (0d, 0d),(10d, 0d),(0d, 10d) }' && sellipse'<{ 10d , 0d }, (1d , 4d), 0d>' as actual;
+
+
+-- sbox vs sbox
+
+
+-- the boxes have no common points
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((30d , 30d), (50d , 50d))' as actual;
+
+-- the point of intersection of the boxes is the boundary for both
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((20d , 20d), (50d , 50d))' as actual;
+
+-- the boundaries of the boxes intersect at one line
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((20d , 0d), (50d , 20d))' as actual;
+
+-- the boxes matches
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((5d , 5d), (10d , 10d))' as actual;
+
+-- one box lies completely in the other and they have no intersection at the boundary line or point
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((5d , 5d), (10d , 10d))' as actual;
+
+-- one box partially lies in the other
+select 'sbox && sbox', 't' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((10d , 10d), (30d , 30d))' as actual;
+
+-- one box degenerated into the line lies in the boundary of other
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((0d , 0d), (20d , 0d))' as actual;
+
+-- one box degenerated into the line lies in the interior of other
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((5d , 5d), (10d , 5d))' as actual;
+
+-- one box degenerated into the point lies in the boundary of other
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((0d , 0d), (0d , 0d))' as actual;
+
+-- one box degenerated into the point lies in the interior of other
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sbox'((5d , 5d), (5d , 5d))' as actual;
+
+-- the boxes are degenerated into the point and coincide
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (0d , 0d))' && sbox'((0d , 0d), (0d , 0d))' as actual;
+
+-- the boxes are degenerated into the point and not coincide
+select 'sbox && sbox', 'f' as expected, sbox'((0d , 0d), (0d , 0d))' && sbox'((10d , 10d), (10d , 10d))' as actual;
+
+
+-- sbox vs scircle
+
+
+-- the box and circle have no common points
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && scircle'<(0d , 90d) , 10d>' as actual;
+
+-- the point of intersection of the box and circle is the boundary for both
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && scircle'<(30d , 0d) , 10d>' as actual;
+
+-- the circle lies completely in the box and they have an intersection at the boundary points
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && scircle'<(10d , 10d) , 10d>' as actual;
+
+-- the circle lies completely in the box and they have no intersection at the boundary points
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && scircle'<(10d , 10d) , 5d>' as actual;
+
+-- the box lies completely in the circle and they have an intersection at the boundary points
+select 'sbox && scircle', 'f' as expected, sbox'((-4d , -3d), (3d , 4d))' && scircle'<(0d , 0d) , 5d>' as actual;
+
+-- the box lies completely in the circle and they have no intersection at the boundary points
+select 'sbox && scircle', 'f' as expected, sbox'((-4d , -3d), (3d , 4d))' && scircle'<(0d , 0d) , 10d>' as actual;
+
+-- the box degenerated into the line intersects circle
+select 'sbox && scircle', 'f' as expected, sbox'((-20d , 0d), (20d , 0d))' && scircle'<(0d , 0d) , 10d>' as actual;
+
+-- the circle partially lies in the box
+select 'sbox && scircle', 't' as expected, sbox'((0d , 0d), (20d , 20d))' && scircle'<(15d , 15d) , 10d>' as actual;
+
+-- the circle degenerated into the point lies in the boundary of box
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && scircle'<(0d , 10d) , 0d>' as actual;
+
+-- the circle degenerated into the point lies in the interior of box
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && scircle'<(10d , 10d) , 0d>' as actual;
+
+-- the box degenerated into the point lies in the boundary of circle
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (0d , 0d))' && scircle'<(10d , 0d) , 10d>' as actual;
+
+-- the box degenerated into the point lies in the interior of circle
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (0d , 0d))' && scircle'<(0d , 0d) , 10d>' as actual;
+
+-- the box and circle are degenerated into the point and coincide
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (0d , 0d))' && scircle'<(0d , 0d) , 0d>' as actual;
+
+-- the box and circle are degenerated into the point and not coincide
+select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (0d , 0d))' && scircle'<(5d , 5d) , 0d>' as actual;
+
+
+-- sbox vs spoly
+
+
+-- the box and polygon have no common points
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && spoly'{ (30d, 0d),(40d, 0d),(30d, 20d) }' as actual;
+
+-- the point of intersection of the box and polygon is the boundary for both
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && spoly'{ (30d, 0d),(40d, 0d),(30d, 20d) }' as actual;
+
+-- the boundaries of the boxes intersect at one line
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && spoly'{ (20d, 0d),(30d, 0d),(20d, 20d) }' as actual;
+
+-- the box and circle matches
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && spoly'{ (0d, 0d),(20d, 0d),(20d, 20d),(0d, 20d) }' as actual;
+
+-- the polygon lies completely in the box and they have an intersection at the boundary line
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && spoly'{ (0d, 0d),(20d, 0d),(0d, 20d) }' as actual;
+
+-- the polygon lies completely in the box and they have no intersection at the boundary
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && spoly'{ (1d, 1d),(11d, 1d),(1d, 19d) }' as actual;
+
+-- the box lies completely in the polygon and they have an intersection at the boundary line
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 0d), (10d , 10d))' && spoly'{ (0d, 0d),(20d, 0d),(0d, 20d) }' as actual;
+
+-- the box lies completely in the polygon and they have no intersection at the boundary
+select 'sbox && spoly', 'f' as expected, sbox'((1d , 1d), (2d , 2d))' && spoly'{ (0d, 0d),(20d, 0d),(0d, 20d) }' as actual;
+
+-- the polygon partially lies in the box
+select 'sbox && spoly', 't' as expected, sbox'((0d , 0d), (20d , 20d))' && spoly'{ (15d, 0d),(35d, 0d),(15d, 35d) }' as actual;
+
+-- the box degenerated into the line lies in the boundary of polygon
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 0d), (20d , 0d))' && spoly'{ (0d, 0d),(20d, 0d),(0d, 20d) }' as actual;
+
+-- the box degenerated into the line lies in the interior of polygon
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 5d), (10d , 5d))' && spoly'{ (0d, 0d),(20d, 0d),(0d, 20d) }' as actual;
+
+-- the box degenerated into the point lies in the boundary of polygon
+select 'sbox && spoly', 'f' as expected, sbox'((0d , 0d), (0d , 0d))' && spoly'{ (0d, 0d),(20d, 0d),(0d, 20d) }' as actual;
+
+-- the box degenerated into the point lies in the interior of polygon
+select 'sbox && spoly', 'f' as expected, sbox'((5d , 5d), (5d , 5d))' && spoly'{ (0d, 0d),(20d, 0d),(0d, 20d) }' as actual;
+
+
+-- sbox vs sellipse
+
+
+-- the box and ellipse have no common points
+select 'sbox && sellipse', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sellipse'<{ 20d , 10d }, (0d, 90d) , 0d>' as actual;
+
+-- the point of intersection of the box and ellipse is the boundary for both
+select 'sbox && sellipse', 'f' as expected, sbox'((-10d , -10d), (10d , 10d))' && sellipse'<{ 80d , 10d }, (0d, 90d) , 90d>' as actual;
+
+-- the ellipse lies completely in the box and they have an intersection at the boundary points
+select 'sbox && sellipse', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sellipse'<{ 10d , 5d }, (10d, 10d) , 0d>' as actual;
+
+-- the ellipse lies completely in the box and they have no intersection at the boundary points
+select 'sbox && sellipse', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sellipse'<{ 9d , 5d }, (10d, 10d) , 0d>' as actual;
+
+-- the box lies completely in the ellipse and they have no intersection at the boundary points
+select 'sbox && sellipse', 'f' as expected, sbox'((-10d , -10d), (10d , 10d))' && sellipse'<{ 30d , 20d }, (0d, 0d) , 0d>' as actual;
+
+-- the ellipse partially lies in the box
+select 'sbox && sellipse', 't' as expected, sbox'((-10d , -10d), (10d , 10d))' && sellipse'<{ 10d , 5d }, (10d, 10d) , 90d>' as actual;
+
+-- the box degenerated into the point lies in the boundary of ellipse
+select 'sbox && sellipse', 'f' as expected, sbox'((30d , 0d), (30d , 0d))' && sellipse'<{ 30d , 20d }, (0d, 0d) , 0d>' as actual;
+
+-- the box degenerated into the point lies in the interior of ellipse
+select 'sbox && sellipse', 'f' as expected, sbox'((0d , 0d), (10d , 0d))' && sellipse'<{ 30d , 20d }, (0d, 0d) , 0d>' as actual;
+
+-- the box and ellipse are degenerated into the point and coincide
+select 'sbox && sellipse', 'f' as expected, sbox'((0d , 0d), (0d , 0d))' && sellipse'<{ 0d , 0d }, (0d, 0d) , 0d>' as actual;
diff --git a/sql/path.sql b/sql/path.sql
index fef5c1f..85fb3ff 100644
--- a/sql/path.sql
+++ b/sql/path.sql
@@ -104,3 +104,9 @@ SELECT set_sphere_output( 'DEG' );
-- test stored data
SELECT spoint(p,2) FROM spheretmp6 WHERE id=2;
+SELECT set_sphere_output( 'RAD' );
+
+-- get n-th point and array representation path points tests
+SELECT spoint( spath '{(0, 0),(1, 1)}', 1 );
+SELECT spoint( spath '{(0, 0),(1, 1)}', 2 );
+SELECT spath_as_array( spath '{(0, 0),(1, 1)}');
diff --git a/sql/points.sql b/sql/points.sql
index a2d53a6..5e63260 100644
--- a/sql/points.sql
+++ b/sql/points.sql
@@ -86,6 +86,12 @@ SELECT '(0.0109083078249646 , -0.000727220521664407)'::spoint;
SELECT spoint(0.0109083078249646 , -0.000727220521664407);
+SELECT spoint_deg(57.2958, 57.2958);
+
+SELECT spoint_deg(0, 0);
+
+SELECT spoint_deg(114.5916, 0);
+
SELECT set_sphere_output( 'RAD' );
SELECT spoint(7.28318530717958623 , 0.00);
diff --git a/sql/poly.sql b/sql/poly.sql
index 4168024..2281aba 100644
--- a/sql/poly.sql
+++ b/sql/poly.sql
@@ -78,14 +78,30 @@ SELECT spoly '{(359d,0d),(359d,1d),(4d,0d)}';
SELECT spoly '{(10d,0d),(10d,1d),(15d,0d)}';
+SELECT spoly_deg(ARRAY[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
+
+SELECT spoly_deg(ARRAY[10.0, 0.0, 10.0, 1.0, 15.0, 0.0]);
+
-- incorrect input -----
SELECT spoly '{(10d,0d),(10d,1d)}';
+SELECT spoly_deg(ARRAY[1.0, 2.0, 3.0, 4.0, 5.0]);
+
+SELECT spoly_deg(ARRAY[]::float8[]);
+
+SELECT spoly_deg(NULL::float8[]);
+
--- self-crossing input -----
SELECT spoly '{(0d,0d),(10d,10d),(0d,10d),(10d,0d)}';
+--- degenerate polygons -----
+
+SELECT spoly '{(0d,1d),(0d,2d),(0d,3d)}';
+
+SELECT spoly '{(1d,0d),(2d,0d),(3d,0d)}';
+
--- functions
SELECT npoints( spoly '{(10d,0d),(10d,1d),(15d,0d)}');
@@ -593,3 +609,16 @@ SELECT npoints( spoly '{
(1.5121581120647 , -1.93925472462553e-05),
(1.51214841579108 , -1.93925472462553e-05)
}');
+
+SELECT set_sphere_output( 'RAD' );
+
+SELECT spoint( spoly '{(0,0),(1,0),(1,1)}', 1 );
+SELECT spoint( spoly '{(0,0),(1,0),(1,1)}', 2 );
+SELECT spoint( spoly '{(0,0),(1,0),(1,1)}', 3 );
+SELECT spoly_as_array( spoly '{(0,0),(1,0),(1,1)}' );
+
+-- spoly is convex
+SELECT spoly_is_convex(spoly'{(53d 45m 35.0s, 37d 6m 30.0s), (52d 21m 36.0s, 41d 36m 7.0s), (54d 14m 18.0s, 45d 1m 35.0s), (51d 23m 3.0s, 45d 22m 49.0s), (51d 2m 12.0s, 41d 52m 1.0s), (50d 41m 47.0s, 38d 22m 0s) }');
+SELECT spoly_is_convex(spoly'{(12d,32d),(34d,12d),(59d,21d),(69d,21d)}');
+SELECT spoly_is_convex(spoly'{(12d,32d),(34d,12d),(59d,21d),(34d,40d)}');
+SELECT spoly_is_convex(NULL);
diff --git a/sql/sbox_brin.sql b/sql/sbox_brin.sql
new file mode 100644
index 0000000..24f30d0
--- /dev/null
+++ b/sql/sbox_brin.sql
@@ -0,0 +1,138 @@
+SELECT set_sphere_output_precision(8);
+
+CREATE TABLE test_boxes (
+ b sbox
+);
+
+COPY test_boxes (b) FROM stdin;
+( (0.349065850398866, 0.174532925199433), (0.350065850398866, 0.174632925199433) )
+( (1.59875999207035, 0.771416330759722), (1.5997599920703498, 0.771516330759722) )
+( (1.59876348272885, 0.77141458543047), (1.5997634827288498, 0.77151458543047) )
+( (1.59876697338736, 0.771412840101218), (1.5997669733873598, 0.771512840101218) )
+( (1.59877046404586, 0.771411094771966), (1.5997704640458599, 0.771511094771966) )
+( (1.59877395470437, 0.771409349442714), (1.59977395470437, 0.771509349442714) )
+( (1.59877744536287, 0.771407604113461), (1.59977744536287, 0.771507604113461) )
+( (1.59878093602137, 0.77140585878421), (1.59978093602137, 0.77150585878421) )
+( (1.59878442667988, 0.771404113454958), (1.59978442667988, 0.771504113454958) )
+( (1.59878791733838, 0.771402368125706), (1.59978791733838, 0.7715023681257059) )
+( (1.59879140799689, 0.771400622796454), (1.5997914079968898, 0.771500622796454) )
+( (1.59879489865539, 0.771398877467202), (1.5997948986553898, 0.771498877467202) )
+( (1.59879838931389, 0.77139713213795), (1.5997983893138898, 0.77149713213795) )
+( (1.5988018799724, 0.771395386808698), (1.5998018799723999, 0.771495386808698) )
+( (1.5988053706309, 0.771393641479446), (1.5998053706309, 0.771493641479446) )
+( (1.59880886128941, 0.771391896150194), (1.59980886128941, 0.771491896150194) )
+( (1.59881235194791, 0.771390150820941), (1.59981235194791, 0.771490150820941) )
+( (1.59881584260641, 0.77138840549169), (1.59981584260641, 0.77148840549169) )
+( (1.59881933326492, 0.771386660162438), (1.59981933326492, 0.7714866601624379) )
+( (1.59882282392342, 0.771384914833186), (1.5998228239234198, 0.771484914833186) )
+( (1.59882631458193, 0.771383169503934), (1.5998263145819298, 0.771483169503934) )
+( (1.59882980524043, 0.771381424174682), (1.5998298052404298, 0.771481424174682) )
+( (1.59883329589893, 0.77137967884543), (1.5998332958989299, 0.77147967884543) )
+( (1.59883678655744, 0.771377933516178), (1.5998367865574399, 0.771477933516178) )
+( (1.59884027721594, 0.771376188186926), (1.59984027721594, 0.771476188186926) )
+( (1.59884376787445, 0.771374442857673), (1.59984376787445, 0.771474442857673) )
+( (1.59884725853295, 0.771372697528422), (1.59984725853295, 0.771472697528422) )
+( (1.59885074919145, 0.77137095219917), (1.59985074919145, 0.77147095219917) )
+( (1.59885423984996, 0.771369206869918), (1.5998542398499598, 0.7714692068699179) )
+( (1.59885773050846, 0.771367461540666), (1.5998577305084598, 0.771467461540666) )
+( (1.59886122116697, 0.771365716211414), (1.5998612211669698, 0.771465716211414) )
+( (1.59886471182547, 0.771363970882162), (1.5998647118254699, 0.771463970882162) )
+( (1.59886820248397, 0.77136222555291), (1.5998682024839699, 0.77146222555291) )
+( (1.59887169314248, 0.771360480223658), (1.59987169314248, 0.771460480223658) )
+( (1.59887518380098, 0.771358734894406), (1.59987518380098, 0.771458734894406) )
+( (1.59887867445948, 0.771356989565154), (1.59987867445948, 0.771456989565154) )
+( (1.59888216511799, 0.771355244235902), (1.59988216511799, 0.771455244235902) )
+( (1.59888565577649, 0.77135349890665), (1.5998856557764898, 0.7714534989066499) )
+( (1.598889146435, 0.771351753577398), (1.5998891464349998, 0.771451753577398) )
+( (1.5988926370935, 0.771350008248146), (1.5998926370934998, 0.771450008248146) )
+( (1.59889612775201, 0.771348262918894), (1.5998961277520098, 0.771448262918894) )
+( (1.59889961841051, 0.771346517589642), (1.5998996184105099, 0.771446517589642) )
+( (1.59890310906901, 0.77134477226039), (1.59990310906901, 0.77144477226039) )
+( (1.59890659972752, 0.771343026931138), (1.59990659972752, 0.771443026931138) )
+( (1.59891009038602, 0.771341281601886), (1.59991009038602, 0.771441281601886) )
+( (1.59891358104452, 0.771339536272634), (1.59991358104452, 0.771439536272634) )
+( (1.59891707170303, 0.771337790943382), (1.59991707170303, 0.7714377909433819) )
+( (1.59892056236153, 0.77133604561413), (1.5999205623615298, 0.77143604561413) )
+( (1.59892405302004, 0.771334300284878), (1.5999240530200398, 0.771434300284878) )
+( (1.59892754367854, 0.771332554955626), (1.5999275436785398, 0.771432554955626) )
+( (1.59893103433705, 0.771330809626374), (1.5999310343370499, 0.771430809626374) )
+( (1.59893452499555, 0.771329064297122), (1.59993452499555, 0.771429064297122) )
+( (1.59893801565405, 0.77132731896787), (1.59993801565405, 0.77142731896787) )
+( (1.59894150631256, 0.771325573638618), (1.59994150631256, 0.771425573638618) )
+( (1.59894499697106, 0.771323828309366), (1.59994499697106, 0.771423828309366) )
+( (1.59894848762957, 0.771322082980114), (1.59994848762957, 0.7714220829801139) )
+( (1.59895197828807, 0.771320337650862), (1.5999519782880698, 0.771420337650862) )
+( (1.59895546894657, 0.77131859232161), (1.5999554689465698, 0.77141859232161) )
+( (3.61121537674092, -1.33598496521933), (3.6122153767409197, -1.33588496521933) )
+( (3.61121886739942, -1.33598321989008), (3.6122188673994198, -1.33588321989008) )
+( (3.61122235805792, -1.33598147456083), (3.61222235805792, -1.33588147456083) )
+( (3.61122584871643, -1.33597972923158), (3.61222584871643, -1.33587972923158) )
+( (3.61122933937493, -1.33597798390233), (3.61222933937493, -1.33587798390233) )
+( (3.61123283003344, -1.33597623857307), (3.61223283003344, -1.33587623857307) )
+( (3.61123632069194, -1.33597449324382), (3.61223632069194, -1.33587449324382) )
+( (3.61123981135044, -1.33597274791457), (3.61223981135044, -1.33587274791457) )
+( (3.61124330200895, -1.33597100258532), (3.6122433020089497, -1.33587100258532) )
+( (3.61124679266745, -1.33596925725607), (3.6122467926674497, -1.33586925725607) )
+( (3.61125028332595, -1.33596751192682), (3.6122502833259498, -1.33586751192682) )
+( (3.61125377398446, -1.33596576659756), (3.61225377398446, -1.33586576659756) )
+( (3.61125726464296, -1.33596402126831), (3.61225726464296, -1.33586402126831) )
+( (3.61126075530147, -1.33596227593906), (3.61226075530147, -1.33586227593906) )
+( (3.61126424595997, -1.33596053060981), (3.61226424595997, -1.33586053060981) )
+( (3.61126773661847, -1.33595878528056), (3.61226773661847, -1.33585878528056) )
+( (3.61127122727698, -1.3359570399513), (3.6122712272769797, -1.3358570399513001) )
+( (3.61127471793548, -1.33595529462205), (3.6122747179354797, -1.33585529462205) )
+( (3.61127820859399, -1.3359535492928), (3.61227820859399, -1.3358535492928) )
+\.
+
+CREATE OR REPLACE FUNCTION qnodes(q text) RETURNS text
+LANGUAGE 'plpgsql' AS
+$$
+DECLARE
+ exp TEXT;
+ mat TEXT[];
+ ret TEXT[];
+BEGIN
+ FOR exp IN EXECUTE 'EXPLAIN ' || q
+ LOOP
+ --RAISE NOTICE 'EXP: %', exp;
+ mat := regexp_matches(exp, ' *(?:-> *)?(.*Scan on (test_boxes|test_boxes_brin_idx))');
+ --RAISE NOTICE 'MAT: %', mat;
+ IF mat IS NOT NULL THEN
+ ret := array_append(ret, mat[1]);
+ END IF;
+ --RAISE NOTICE 'RET: %', ret;
+ END LOOP;
+ RETURN array_to_string(ret,',');
+END;
+$$;
+
+CREATE INDEX test_boxes_brin_idx ON test_boxes USING brin (b);
+
+SET enable_indexscan = OFF;
+SET enable_bitmapscan = OFF;
+SET enable_seqscan = ON;
+
+SELECT 'scan_seq', qnodes('SELECT * FROM test_boxes WHERE b <@ sbox ''( (10d,10d), (20d,20d) )''');
+SELECT * FROM test_boxes WHERE b <@ sbox '( (10d,10d), (20d,20d) )';
+
+SELECT 'scan_seq', qnodes('SELECT * FROM test_boxes WHERE b && sbox ''( (10d,10d), (20d,20d) )''');
+SELECT * FROM test_boxes WHERE b && sbox '( (10d,10d), (20d,20d) )';
+
+SET enable_indexscan = OFF;
+SET enable_bitmapscan = ON;
+SET enable_seqscan = OFF;
+
+SELECT 'scan_idx', qnodes('SELECT * FROM test_boxes WHERE b <@ sbox ''( (10d,10d), (20d,20d) )''');
+SELECT * FROM test_boxes WHERE b <@ sbox '( (10d,10d), (20d,20d) )';
+
+SELECT 'scan_idx', qnodes('SELECT * FROM test_boxes WHERE b && sbox ''( (10d,10d), (20d,20d) )''');
+SELECT * FROM test_boxes WHERE b && sbox '( (10d,10d), (20d,20d) )';
+
+---- cleanup
+DROP INDEX test_boxes_brin_idx;
+DROP TABLE test_boxes;
+DROP FUNCTION qnodes(text);
+
+SET enable_indexscan = ON;
+SET enable_bitmapscan = ON;
+SET enable_seqscan = ON;
diff --git a/sql/spoint_brin.sql b/sql/spoint_brin.sql
new file mode 100644
index 0000000..4a37f37
--- /dev/null
+++ b/sql/spoint_brin.sql
@@ -0,0 +1,136 @@
+CREATE TABLE test_points (
+ p spoint
+);
+
+COPY test_points (p) FROM stdin;
+(0.349065850398866 , 0.174532925199433)
+(1.59875999207035 , 0.771416330759722)
+(1.59876348272885 , 0.77141458543047)
+(1.59876697338736 , 0.771412840101218)
+(1.59877046404586 , 0.771411094771966)
+(1.59877395470437 , 0.771409349442714)
+(1.59877744536287 , 0.771407604113461)
+(1.59878093602137 , 0.77140585878421)
+(1.59878442667988 , 0.771404113454958)
+(1.59878791733838 , 0.771402368125706)
+(1.59879140799689 , 0.771400622796454)
+(1.59879489865539 , 0.771398877467202)
+(1.59879838931389 , 0.77139713213795)
+(1.5988018799724 , 0.771395386808698)
+(1.5988053706309 , 0.771393641479446)
+(1.59880886128941 , 0.771391896150194)
+(1.59881235194791 , 0.771390150820941)
+(1.59881584260641 , 0.77138840549169)
+(1.59881933326492 , 0.771386660162438)
+(1.59882282392342 , 0.771384914833186)
+(1.59882631458193 , 0.771383169503934)
+(1.59882980524043 , 0.771381424174682)
+(1.59883329589893 , 0.77137967884543)
+(1.59883678655744 , 0.771377933516178)
+(1.59884027721594 , 0.771376188186926)
+(1.59884376787445 , 0.771374442857673)
+(1.59884725853295 , 0.771372697528422)
+(1.59885074919145 , 0.77137095219917)
+(1.59885423984996 , 0.771369206869918)
+(1.59885773050846 , 0.771367461540666)
+(1.59886122116697 , 0.771365716211414)
+(1.59886471182547 , 0.771363970882162)
+(1.59886820248397 , 0.77136222555291)
+(1.59887169314248 , 0.771360480223658)
+(1.59887518380098 , 0.771358734894406)
+(1.59887867445948 , 0.771356989565154)
+(1.59888216511799 , 0.771355244235902)
+(1.59888565577649 , 0.77135349890665)
+(1.598889146435 , 0.771351753577398)
+(1.5988926370935 , 0.771350008248146)
+(1.59889612775201 , 0.771348262918894)
+(1.59889961841051 , 0.771346517589642)
+(1.59890310906901 , 0.77134477226039)
+(1.59890659972752 , 0.771343026931138)
+(1.59891009038602 , 0.771341281601886)
+(1.59891358104452 , 0.771339536272634)
+(1.59891707170303 , 0.771337790943382)
+(1.59892056236153 , 0.77133604561413)
+(1.59892405302004 , 0.771334300284878)
+(1.59892754367854 , 0.771332554955626)
+(1.59893103433705 , 0.771330809626374)
+(1.59893452499555 , 0.771329064297122)
+(1.59893801565405 , 0.77132731896787)
+(1.59894150631256 , 0.771325573638618)
+(1.59894499697106 , 0.771323828309366)
+(1.59894848762957 , 0.771322082980114)
+(1.59895197828807 , 0.771320337650862)
+(1.59895546894657 , 0.77131859232161)
+(3.61121537674092 , -1.33598496521933)
+(3.61121886739942 , -1.33598321989008)
+(3.61122235805792 , -1.33598147456083)
+(3.61122584871643 , -1.33597972923158)
+(3.61122933937493 , -1.33597798390233)
+(3.61123283003344 , -1.33597623857307)
+(3.61123632069194 , -1.33597449324382)
+(3.61123981135044 , -1.33597274791457)
+(3.61124330200895 , -1.33597100258532)
+(3.61124679266745 , -1.33596925725607)
+(3.61125028332595 , -1.33596751192682)
+(3.61125377398446 , -1.33596576659756)
+(3.61125726464296 , -1.33596402126831)
+(3.61126075530147 , -1.33596227593906)
+(3.61126424595997 , -1.33596053060981)
+(3.61126773661847 , -1.33595878528056)
+(3.61127122727698 , -1.3359570399513)
+(3.61127471793548 , -1.33595529462205)
+(3.61127820859399 , -1.3359535492928)
+\.
+
+CREATE OR REPLACE FUNCTION qnodes(q text) RETURNS text
+LANGUAGE 'plpgsql' AS
+$$
+DECLARE
+ exp TEXT;
+ mat TEXT[];
+ ret TEXT[];
+BEGIN
+ FOR exp IN EXECUTE 'EXPLAIN ' || q
+ LOOP
+ --RAISE NOTICE 'EXP: %', exp;
+ mat := regexp_matches(exp, ' *(?:-> *)?(.*Scan on (test_points|brin_spoint))');
+ --RAISE NOTICE 'MAT: %', mat;
+ IF mat IS NOT NULL THEN
+ ret := array_append(ret, mat[1]);
+ END IF;
+ --RAISE NOTICE 'RET: %', ret;
+ END LOOP;
+ RETURN array_to_string(ret,',');
+END;
+$$;
+
+CREATE INDEX brin_spoint ON test_points USING brin (p) WITH (pages_per_range = 16);
+
+set enable_indexscan = off;
+set enable_bitmapscan = off;
+set enable_seqscan = on;
+
+SELECT 'scan_seq', qnodes('SELECT * FROM test_points WHERE p <@ sbox ''( (10d,10d), (20d,20d) )''');
+SELECT * FROM test_points WHERE p <@ sbox '( (10d,10d), (20d,20d) )';
+
+SELECT 'scan_seq', qnodes('SELECT * FROM test_points WHERE p && sbox ''( (10d,10d), (20d,20d) )''');
+SELECT * FROM test_points WHERE p && sbox '( (10d,10d), (20d,20d) )';
+
+set enable_indexscan = off;
+set enable_bitmapscan = on;
+set enable_seqscan = off;
+
+SELECT 'scan_idx', qnodes('SELECT * FROM test_points WHERE p <@ sbox ''( (10d,10d), (20d,20d) )''');
+SELECT * FROM test_points WHERE p <@ sbox '( (10d,10d), (20d,20d) )';
+
+SELECT 'scan_idx', qnodes('SELECT * FROM test_points WHERE p && sbox ''( (10d,10d), (20d,20d) )''');
+SELECT * FROM test_points WHERE p && sbox '( (10d,10d), (20d,20d) )';
+
+-- cleanup
+DROP INDEX brin_spoint;
+DROP TABLE test_points;
+DROP FUNCTION qnodes(text);
+
+set enable_indexscan = on;
+set enable_bitmapscan = on;
+set enable_seqscan = on;
diff --git a/src/brin.c b/src/brin.c
new file mode 100644
index 0000000..1c5ae1b
--- /dev/null
+++ b/src/brin.c
@@ -0,0 +1,352 @@
+/*
+ * BRIN SUPPORT for spheric objects:
+ *
+ * The stored type is the spherekey, as for GiST support,
+ * so include some already defined stuffs. We have to define
+ * then all the cross-type functions needed by the OpFamilies.
+ */
+
+#include "brin.h"
+#include "gist.h"
+#include
+
+/*
+ * Functions needed to build a BRIN index
+ */
+PG_FUNCTION_INFO_V1(spoint_brin_inclusion_add_value);
+PG_FUNCTION_INFO_V1(sbox_brin_inclusion_add_value);
+
+/*
+ * Functions needed to define supported operators
+ */
+PG_FUNCTION_INFO_V1(spoint_overlaps_spherekey);
+PG_FUNCTION_INFO_V1(spoint_contains_spherekey);
+PG_FUNCTION_INFO_V1(spoint_iscontained_spherekey);
+PG_FUNCTION_INFO_V1(sbox_overlaps_spherekey);
+PG_FUNCTION_INFO_V1(sbox_contains_spherekey);
+PG_FUNCTION_INFO_V1(sbox_iscontained_spherekey);
+PG_FUNCTION_INFO_V1(spherekey_overlaps_spherekey);
+PG_FUNCTION_INFO_V1(spherekey_contains_spherekey);
+PG_FUNCTION_INFO_V1(spherekey_iscontained_spherekey);
+PG_FUNCTION_INFO_V1(spoint_overlaps_sbox);
+PG_FUNCTION_INFO_V1(sbox_iscontained_spoint);
+
+Datum
+spoint_brin_inclusion_add_value(PG_FUNCTION_ARGS)
+{
+ BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
+ SPoint *newval = (SPoint *) DatumGetPointer(PG_GETARG_DATUM(2));
+ bool isnull = PG_GETARG_BOOL(3);
+ int32 spointkey[6];
+ int32 *skey = (int32 *) column->bv_values[INCLUSION_UNION];
+
+ /*
+ * If the new value is null, we record that we saw it if it's the first
+ * one; otherwise, there's nothing to do.
+ */
+ if (isnull)
+ {
+ if (column->bv_hasnulls)
+ PG_RETURN_BOOL(false);
+
+ column->bv_hasnulls = true;
+ PG_RETURN_BOOL(true);
+ }
+
+ spherepoint_gen_key(spointkey, newval);
+
+ /*
+ * If spherekey pointer is NULL, we consider the spoint entry as 'empty'.
+ *
+ * The OpClass support empty entries: we need to set the "contains empty"
+ * flag in the element (unless already set).
+ */
+ /*
+ if (spointkey == NULL)
+ {
+ if (!DatumGetBool(column->bv_values[INCLUSION_CONTAINS_EMPTY]))
+ {
+ column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(true);
+ PG_RETURN_BOOL(true);
+ }
+
+ PG_RETURN_BOOL(false);
+ }
+ */
+
+ /* if the recorded value is null, we just need to store the spherekey */
+ if (column->bv_allnulls)
+ {
+ column->bv_values[INCLUSION_UNION] = datumCopy((Datum) spointkey, false,
+ (sizeof(int32) * 6));
+ column->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(false);
+ column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(false);
+ column->bv_allnulls = false;
+ PG_RETURN_BOOL(true);
+ }
+
+ /*
+ * Check if the stored spherekey already contains the key of the new value
+ */
+ if (spherekey_interleave(skey, spointkey) == SCKEY_IN)
+ {
+ PG_RETURN_BOOL(false);
+ }
+
+ /*
+ * Otherwise, we need to enlarge it to contains the current spoint
+ */
+ spherekey_union_two(skey, spointkey);
+
+ PG_RETURN_BOOL(true);
+}
+
+Datum
+sbox_brin_inclusion_add_value(PG_FUNCTION_ARGS)
+{
+ BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
+ SBOX *newval = (SBOX *) DatumGetPointer(PG_GETARG_DATUM(2));
+ bool isnull = PG_GETARG_BOOL(3);
+ int32 sboxkey[6];
+ int32 *skey = (int32 *) column->bv_values[INCLUSION_UNION];
+
+ /*
+ * If the new value is null, we record that we saw it if it's the first
+ * one; otherwise, there's nothing to do.
+ */
+ if (isnull)
+ {
+ if (column->bv_hasnulls)
+ PG_RETURN_BOOL(false);
+
+ column->bv_hasnulls = true;
+ PG_RETURN_BOOL(true);
+ }
+
+ spherebox_gen_key(sboxkey, newval);
+
+ /*
+ * If spherekey pointer is NULL, we consider the spoint entry as 'empty'.
+ *
+ * The OpClass support empty entries: we need to set the "contains empty"
+ * flag in the element (unless already set).
+ */
+ /*
+ if (sboxkey == NULL)
+ {
+ if (!DatumGetBool(column->bv_values[INCLUSION_CONTAINS_EMPTY]))
+ {
+ column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(true);
+ PG_RETURN_BOOL(true);
+ }
+
+ PG_RETURN_BOOL(false);
+ }
+ */
+
+ /* if the recorded value is null, we just need to store the spherekey */
+ if (column->bv_allnulls)
+ {
+ column->bv_values[INCLUSION_UNION] = datumCopy((Datum) sboxkey, false,
+ (sizeof(int32) * 6));
+ column->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(false);
+ column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(false);
+ column->bv_allnulls = false;
+ PG_RETURN_BOOL(true);
+ }
+
+ /*
+ * Check if the stored spherekey already contains the key of the new value
+ */
+ if (spherekey_interleave(skey, sboxkey) == SCKEY_IN)
+ {
+ PG_RETURN_BOOL(false);
+ }
+
+ /*
+ * Otherwise, we need to enlarge it to contains the current spoint
+ */
+ spherekey_union_two(skey, sboxkey);
+
+ PG_RETURN_BOOL(true);
+}
+
+/* */
+/* Define operators procedures below */
+/* */
+
+Datum
+spoint_overlaps_spherekey(PG_FUNCTION_ARGS)
+{
+ int32 k1[6];
+ SPoint *p1 = (SPoint *) PG_GETARG_POINTER(0);
+ int32 *k2 = (int32 *) PG_GETARG_POINTER(1);
+
+ spherepoint_gen_key(k1, p1);
+ if (spherekey_interleave(k1, k2) == SCKEY_OVERLAP)
+ {
+ PG_RETURN_BOOL(true);
+ }
+
+ PG_RETURN_BOOL(false);
+}
+
+Datum
+spoint_contains_spherekey(PG_FUNCTION_ARGS)
+{
+ int32 k1[6];
+ SPoint *p1 = (SPoint *) PG_GETARG_POINTER(0);
+ int32 *k2 = (int32 *) PG_GETARG_POINTER(1);
+
+ spherepoint_gen_key(k1, p1);
+ if (spherekey_interleave(k1, k2) == SCKEY_IN)
+ {
+ PG_RETURN_BOOL(true);
+ }
+
+ PG_RETURN_BOOL(false);
+}
+
+Datum
+spoint_iscontained_spherekey(PG_FUNCTION_ARGS)
+{
+ int32 k1[6];
+ SPoint *p1 = (SPoint *) PG_GETARG_POINTER(0);
+ int32 *k2 = (int32 *) PG_GETARG_POINTER(1);
+
+ spherepoint_gen_key(k1, p1);
+ if (spherekey_interleave(k2, k1) == SCKEY_IN)
+ {
+ PG_RETURN_BOOL(true);
+ }
+
+ PG_RETURN_BOOL(false);
+}
+
+Datum
+sbox_overlaps_spherekey(PG_FUNCTION_ARGS)
+{
+ int32 k1[6];
+ SBOX *p1 = (SBOX *) PG_GETARG_POINTER(0);
+ int32 *k2 = (int32 *) PG_GETARG_POINTER(1);
+
+ spherebox_gen_key(k1, p1);
+ if (spherekey_interleave(k1, k2) == SCKEY_OVERLAP)
+ {
+ PG_RETURN_BOOL(true);
+ }
+
+ PG_RETURN_BOOL(false);
+}
+
+Datum
+sbox_contains_spherekey(PG_FUNCTION_ARGS)
+{
+ int32 k1[6];
+ SBOX *p1 = (SBOX *) PG_GETARG_POINTER(0);
+ int32 *k2 = (int32 *) PG_GETARG_POINTER(1);
+
+ spherebox_gen_key(k1, p1);
+ if (spherekey_interleave(k1, k2) == SCKEY_IN)
+ {
+ PG_RETURN_BOOL(true);
+ }
+
+ PG_RETURN_BOOL(false);
+}
+
+Datum
+sbox_iscontained_spherekey(PG_FUNCTION_ARGS)
+{
+ int32 k1[6];
+ SBOX *p1 = (SBOX *) PG_GETARG_POINTER(0);
+ int32 *k2 = (int32 *) PG_GETARG_POINTER(1);
+
+ spherebox_gen_key(k1, p1);
+ if (spherekey_interleave(k2, k1) == SCKEY_IN)
+ {
+ PG_RETURN_BOOL(true);
+ }
+
+ PG_RETURN_BOOL(false);
+}
+
+Datum
+spherekey_overlaps_spherekey(PG_FUNCTION_ARGS)
+{
+ int32 *k1 = (int32 *) PG_GETARG_POINTER(0);
+ int32 *k2 = (int32 *) PG_GETARG_POINTER(1);
+
+ if (spherekey_interleave(k1, k2) == SCKEY_OVERLAP)
+ {
+ PG_RETURN_BOOL(true);
+ }
+
+ PG_RETURN_BOOL(false);
+}
+
+Datum
+spherekey_contains_spherekey(PG_FUNCTION_ARGS)
+{
+ int32 *k1 = (int32 *) PG_GETARG_POINTER(0);
+ int32 *k2 = (int32 *) PG_GETARG_POINTER(1);
+
+ if (spherekey_interleave(k1, k2) == SCKEY_IN)
+ {
+ PG_RETURN_BOOL(true);
+ }
+
+ PG_RETURN_BOOL(false);
+}
+
+Datum
+spherekey_iscontained_spherekey(PG_FUNCTION_ARGS)
+{
+ int32 *k1 = (int32 *) PG_GETARG_POINTER(0);
+ int32 *k2 = (int32 *) PG_GETARG_POINTER(1);
+
+ if (spherekey_interleave(k2, k1) == SCKEY_IN)
+ {
+ PG_RETURN_BOOL(true);
+ }
+
+ PG_RETURN_BOOL(false);
+}
+
+Datum
+spoint_overlaps_sbox(PG_FUNCTION_ARGS)
+{
+ int32 k1[6];
+ SPoint *p1 = (SPoint *) PG_GETARG_POINTER(0);
+ int32 k2[6];
+ SBOX *p2 = (SBOX *) PG_GETARG_POINTER(1);
+
+ spherepoint_gen_key(k1, p1);
+ spherebox_gen_key(k2, p2);
+
+ if (spherekey_interleave(k1, k2) == SCKEY_OVERLAP)
+ {
+ PG_RETURN_BOOL(true);
+ }
+
+ PG_RETURN_BOOL(false);
+}
+
+Datum
+sbox_iscontained_spoint(PG_FUNCTION_ARGS)
+{
+ int32 k1[6];
+ SBOX *p1 = (SBOX *) PG_GETARG_POINTER(0);
+ int32 k2[6];
+ SPoint *p2 = (SPoint *) PG_GETARG_POINTER(1);
+
+ spherebox_gen_key(k1, p1);
+ spherepoint_gen_key(k2, p2);
+
+ if (spherekey_interleave(k1, k2) == SCKEY_IN)
+ {
+ PG_RETURN_BOOL(true);
+ }
+
+ PG_RETURN_BOOL(false);
+}
diff --git a/src/brin.h b/src/brin.h
new file mode 100644
index 0000000..b1a1c2c
--- /dev/null
+++ b/src/brin.h
@@ -0,0 +1,40 @@
+#ifndef __PGS_BRIN_H__
+#define __PGS_BRIN_H__
+
+/*
+ * BRIN declarations
+ */
+
+#include "postgres.h"
+#include "fmgr.h"
+
+#include "key.h"
+
+#include
+#include
+#include
+#include
+#include "access/brin_tuple.h"
+#include "utils/datum.h"
+
+#define INCLUSION_UNION 0
+#define INCLUSION_UNMERGEABLE 1
+#define INCLUSION_CONTAINS_EMPTY 2
+
+Datum spoint_brin_inclusion_add_value(PG_FUNCTION_ARGS);
+Datum sbox_brin_inclusion_add_value(PG_FUNCTION_ARGS);
+
+Datum spoint_overlaps_spherekey(PG_FUNCTION_ARGS);
+Datum spoint_contains_spherekey(PG_FUNCTION_ARGS);
+Datum spoint_iscontained_spherekey(PG_FUNCTION_ARGS);
+Datum sbox_overlaps_spherekey(PG_FUNCTION_ARGS);
+Datum sbox_contains_spherekey(PG_FUNCTION_ARGS);
+Datum sbox_iscontained_spherekey(PG_FUNCTION_ARGS);
+Datum spherekey_overlaps_spherekey(PG_FUNCTION_ARGS);
+Datum spherekey_contains_spherekey(PG_FUNCTION_ARGS);
+Datum spherekey_iscontained_spherekey(PG_FUNCTION_ARGS);
+
+Datum spoint_overlaps_sbox(PG_FUNCTION_ARGS);
+Datum sbox_iscontained_spoint(PG_FUNCTION_ARGS);
+
+#endif
diff --git a/src/circle.c b/src/circle.c
index f2b2992..e28fe0c 100644
--- a/src/circle.c
+++ b/src/circle.c
@@ -1,4 +1,5 @@
#include "circle.h"
+#include "pgs_util.h"
/* Circle functions */
@@ -22,6 +23,7 @@ PG_FUNCTION_INFO_V1(spherecircle_center);
PG_FUNCTION_INFO_V1(spherecircle_radius);
PG_FUNCTION_INFO_V1(spherepoint_to_circle);
PG_FUNCTION_INFO_V1(spherecircle_by_center);
+PG_FUNCTION_INFO_V1(spherecircle_by_center_deg);
PG_FUNCTION_INFO_V1(spherecircle_area);
PG_FUNCTION_INFO_V1(spherecircle_circ);
PG_FUNCTION_INFO_V1(spheretrans_circle);
@@ -79,7 +81,7 @@ spherecircle_in(PG_FUNCTION_ARGS)
{
pfree(c);
c = NULL;
- elog(ERROR, "spherecircle_in: radius must be not greater than 90 degrees");
+ elog(ERROR, "spherecircle_in: radius must not be greater than 90 degrees or less than 0");
}
else if (FPeq(c->radius, PIH))
{
@@ -361,7 +363,7 @@ spherecircle_by_center(PG_FUNCTION_ARGS)
if (FPgt(rad, PIH) || FPlt(rad, 0.0))
{
- elog(ERROR, "radius must be not greater than 90 degrees or less than 0");
+ elog(ERROR, "radius must not be greater than 90 degrees or less than 0");
PG_RETURN_NULL();
}
c = (SCIRCLE *) palloc(sizeof(SCIRCLE));
@@ -370,6 +372,20 @@ spherecircle_by_center(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(c);
}
+Datum
+spherecircle_by_center_deg(PG_FUNCTION_ARGS)
+{
+ Datum res;
+ SPoint *p = (SPoint *) PG_GETARG_POINTER(0);
+ const float8 rad = deg_to_rad(PG_GETARG_FLOAT8(1));
+ res = DirectFunctionCall2(
+ spherecircle_by_center,
+ PointerGetDatum(p),
+ Float8GetDatum(rad)
+ );
+ PG_RETURN_DATUM(res);
+}
+
Datum
spherecircle_area(PG_FUNCTION_ARGS)
{
diff --git a/src/circle.h b/src/circle.h
index 8ac5175..b8aa520 100644
--- a/src/circle.h
+++ b/src/circle.h
@@ -132,6 +132,11 @@ Datum spherepoint_to_circle(PG_FUNCTION_ARGS);
*/
Datum spherecircle_by_center(PG_FUNCTION_ARGS);
+/*
+ * Creates a circle from center and radius(in degrees).
+ */
+Datum spherecircle_by_center_deg(PG_FUNCTION_ARGS);
+
/*
* Calculates the area of a circle in square radians.
*/
diff --git a/src/ellipse.c b/src/ellipse.c
index a08f8be..0e535ac 100644
--- a/src/ellipse.c
+++ b/src/ellipse.c
@@ -426,7 +426,7 @@ sellipse_ellipse_pos(const SELLIPSE *se1, const SELLIPSE *se2)
}
else if (diff[0] <= diff[2] && diff[2] <= diff[1])
{
- if (Abs(sp[0].lng - elng) < Abs(sp[2].lng - elng))
+ if (fabs(sp[0].lng - elng) < fabs(sp[2].lng - elng))
{
memcpy((void *) &sp[2], (void *) &sp[1], sizeof(SPoint));
}
@@ -446,7 +446,7 @@ sellipse_ellipse_pos(const SELLIPSE *se1, const SELLIPSE *se2)
}
else if (diff[2] <= diff[0] && diff[0] <= diff[1])
{
- if (Abs(sp[0].lng - elng) < Abs(sp[2].lng - elng))
+ if (fabs(sp[0].lng - elng) < fabs(sp[2].lng - elng))
{
memcpy((void *) &sp[2], (void *) &sp[1], sizeof(SPoint));
}
diff --git a/src/gist.c b/src/gist.c
index a142334..b3223a5 100644
--- a/src/gist.c
+++ b/src/gist.c
@@ -212,7 +212,7 @@ do \
{ \
int32 *k = (int32 *) palloc(KEYSIZE); \
if (detoast) \
- genkey(k, (type *) DatumGetPointer(PG_DETOAST_DATUM(entry->key))); \
+ genkey(k, (type *) (PG_DETOAST_DATUM(entry->key))); \
else \
genkey(k, (type *) DatumGetPointer(entry->key)); \
gistentryinit(*retval, PointerGetDatum(k), \
@@ -2202,7 +2202,7 @@ do_picksplit(Box3D *boxes, OffsetNumber maxoff, GIST_SPLITVEC *v)
for (i = 0; i < commonEntriesCount; i++)
{
box = &boxes[i];
- commonEntries[i].delta = Abs((unionSizeBox3D(leftBox, box) - leftBoxSize) -
+ commonEntries[i].delta = fabs((unionSizeBox3D(leftBox, box) - leftBoxSize) -
(unionSizeBox3D(rightBox, box) - rightBoxSize));
}
diff --git a/src/line.c b/src/line.c
index 315adfb..ad02575 100644
--- a/src/line.c
+++ b/src/line.c
@@ -33,6 +33,8 @@ PG_FUNCTION_INFO_V1(sphereline_overlap_neg);
PG_FUNCTION_INFO_V1(spheretrans_from_line);
PG_FUNCTION_INFO_V1(spheretrans_line);
PG_FUNCTION_INFO_V1(spheretrans_line_inverse);
+PG_FUNCTION_INFO_V1(sphereline_point_distance);
+PG_FUNCTION_INFO_V1(sphereline_point_distance_com);
/*
* Swaps the beginning and ending of the line.
@@ -347,7 +349,7 @@ sphereline_circle_pos(const SLine *sl, const SCIRCLE *sc)
{
/* line is point */
sline_begin(&p[0], sl);
- if (spoint_in_circle(&p[0], &c))
+ if (spoint_in_circle(&p[0], sc))
{
return PGS_CIRCLE_CONT_LINE;
}
@@ -494,15 +496,6 @@ sline_sline_pos(const SLine *l1, const SLine *l2)
vector3d_spoint(&p[2], &v[1][0]);
vector3d_spoint(&p[3], &v[1][1]);
- /* check connected lines */
- if (FPgt(il2->length, 0.0) && (vector3d_eq(&v[0][0], &v[1][0]) ||
- vector3d_eq(&v[0][0], &v[1][1]) ||
- vector3d_eq(&v[0][1], &v[1][0]) ||
- vector3d_eq(&v[0][1], &v[1][1])))
- {
- return PGS_LINE_CONNECT;
- }
-
/* Check, sl2 is at equator */
if (FPzero(p[2].lat) && FPzero(p[3].lat))
{
@@ -527,6 +520,15 @@ sline_sline_pos(const SLine *l1, const SLine *l2)
return PGS_LINE_AVOID;
}
+ /* check connected lines */
+ if (FPgt(il2->length, 0.0) && (vector3d_eq(&v[0][0], &v[1][0]) ||
+ vector3d_eq(&v[0][0], &v[1][1]) ||
+ vector3d_eq(&v[0][1], &v[1][0]) ||
+ vector3d_eq(&v[0][1], &v[1][1])))
+ {
+ return PGS_LINE_CONNECT;
+ }
+
/* Now sl2 is not at equator */
if (FPle(il2->length, seg_length))
@@ -642,6 +644,59 @@ sline_center(SPoint *c, const SLine *sl)
euler_spoint_trans(c, &p, &se);
}
+float8 sline_point_dist(const SLine *sl, const SPoint *p)
+{
+ Vector3D v_beg;
+ Vector3D v_end;
+ Vector3D v;
+ Vector3D normal1;
+ Vector3D normal2;
+ Vector3D line;
+ Vector3D first_p;
+ float8 norma;
+ SPoint fp;
+ SPoint sp;
+ float8 fpdist;
+ float8 spdist;
+
+ if (spoint_at_sline(p, sl))
+ {
+ return 0.0;
+ }
+
+ sline_vector_begin(&v_beg, sl);
+ sline_vector_end(&v_end, sl);
+ spoint_vector3d(&v, p);
+
+ /* normal1 to the plane passing through the line and the center of the sphere */
+ vector3d_cross(&normal1, &v_beg, &v_end);
+ if (vector3d_eq(&normal1, &v))
+ {
+ return PIH;
+ }
+
+ /* normal2 to the plane perpendicular to the given line. */
+ vector3d_cross(&normal2, &normal1, &v);
+ vector3d_cross(&line, &normal2, &normal1);
+ norma = sqrt(line.x * line.x + line.y * line.y + line.z * line.z);
+
+ first_p.x = line.x / norma;
+ first_p.y = line.y / norma;
+ first_p.z = line.z / norma;
+ vector3d_spoint(&fp, &first_p);
+
+ if (spoint_at_sline(&fp, sl))
+ {
+ return spoint_dist(&fp, p);
+ }
+
+ vector3d_spoint(&fp, &v_beg);
+ vector3d_spoint(&sp, &v_end);
+ fpdist = spoint_dist(p, &fp);
+ spdist = spoint_dist(p, &sp);
+ return Min(fpdist, spdist);
+}
+
Datum
sphereline_in(PG_FUNCTION_ARGS)
{
@@ -1051,3 +1106,20 @@ spheretrans_from_line(PG_FUNCTION_ARGS)
sphereline_to_euler(e, l);
PG_RETURN_POINTER(e);
}
+
+Datum
+sphereline_point_distance(PG_FUNCTION_ARGS)
+{
+ const SLine *s = (SLine *) PG_GETARG_POINTER(0);
+ const SPoint *p = (SPoint *) PG_GETARG_POINTER(1);
+ PG_RETURN_FLOAT8(sline_point_dist(s, p));
+}
+
+Datum
+sphereline_point_distance_com(PG_FUNCTION_ARGS)
+{
+ const SPoint *p = (SPoint *) PG_GETARG_POINTER(0);
+ const SLine *s = (SLine *) PG_GETARG_POINTER(1);
+ PG_RETURN_FLOAT8(sline_point_dist(s, p));
+}
+
diff --git a/src/line.h b/src/line.h
index 1a41767..002f371 100644
--- a/src/line.h
+++ b/src/line.h
@@ -129,6 +129,11 @@ void euler_sline_trans(SLine *out, const SLine *in, const SEuler *se);
*/
void sline_center(SPoint *c, const SLine *sl);
+/*
+ * Calculates the distance between a line 'sl' and a point 'p'
+ */
+float8 sline_point_dist(const SLine *sl, const SPoint *p);
+
/*
* The input function for spherical line.
*/
@@ -290,4 +295,14 @@ Datum spheretrans_line(PG_FUNCTION_ARGS);
*/
Datum spheretrans_line_inverse(PG_FUNCTION_ARGS);
+/*
+ * Returns the distance between a line and a point.
+ */
+Datum sphereline_point_distance(PG_FUNCTION_ARGS);
+
+/*
+ * Returns the distance between a point and a line.
+ */
+Datum sphereline_point_distance_com(PG_FUNCTION_ARGS);
+
#endif
diff --git a/src/output.c b/src/output.c
index 60e7464..7598d46 100644
--- a/src/output.c
+++ b/src/output.c
@@ -21,7 +21,11 @@
* Default is radians.
*/
static unsigned char sphere_output = OUTPUT_RAD;
-static short int sphere_output_precision = DBL_DIG;
+
+/*
+ * Defines the precision of floating point values in output.
+ */
+static int sphere_output_precision = DBL_DIG;
PG_FUNCTION_INFO_V1(set_sphere_output);
PG_FUNCTION_INFO_V1(spherepoint_out);
diff --git a/src/path.c b/src/path.c
index b72a753..f6d9495 100644
--- a/src/path.c
+++ b/src/path.c
@@ -1,4 +1,6 @@
#include "path.h"
+#include "point.h"
+#include
/*
* Path functions
@@ -50,6 +52,7 @@ PG_FUNCTION_INFO_V1(spheretrans_path);
PG_FUNCTION_INFO_V1(spheretrans_path_inverse);
PG_FUNCTION_INFO_V1(spherepath_add_point);
PG_FUNCTION_INFO_V1(spherepath_add_points_finalize);
+PG_FUNCTION_INFO_V1(spherepath_get_array);
/*
@@ -555,6 +558,30 @@ spherepath_get_point(PG_FUNCTION_ARGS)
PG_RETURN_NULL();
}
+Datum
+spherepath_get_array(PG_FUNCTION_ARGS)
+{
+ SPATH *path = PG_GETARG_SPATH(0);
+ Datum *datum_arr = (Datum *) palloc(sizeof(Datum) * path->npts);
+ ArrayType *res;
+ SPoint *p = (SPoint *) palloc(sizeof(SPoint) * path->npts);
+
+ for (size_t i = 0; i < path->npts; i++)
+ {
+ if (!spath_get_point(&p[i], path, i))
+ {
+ pfree(p);
+ pfree(datum_arr);
+ PG_RETURN_NULL();
+ }
+ datum_arr[i] = PointerGetDatum(&p[i]);
+ }
+
+ res = construct_array(datum_arr, path->npts, get_spoint_type_oid(), sizeof(SPoint), false, 'd');
+
+ PG_RETURN_ARRAYTYPE_P(res);
+}
+
Datum
spherepath_point(PG_FUNCTION_ARGS)
{
diff --git a/src/path.h b/src/path.h
index 1d0fc35..91e1662 100644
--- a/src/path.h
+++ b/src/path.h
@@ -36,7 +36,7 @@ typedef struct
#define PG_GETARG_SPATH(arg) \
- ( (SPATH *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(arg))) )
+ ( (SPATH *) (PG_DETOAST_DATUM(PG_GETARG_DATUM(arg))) )
/*
* Checks whether two paths are equal.
@@ -71,6 +71,11 @@ Datum spherepath_in(PG_FUNCTION_ARGS);
*/
Datum spherepath_get_point(PG_FUNCTION_ARGS);
+/*
+ * Returns spath as array of points
+ */
+Datum spherepath_get_array(PG_FUNCTION_ARGS);
+
/*
* This function interpolates between points of path. Returns the
* n-th point of a path where n is a float.
diff --git a/src/pgs_util.h b/src/pgs_util.h
index ad9763b..b79170b 100644
--- a/src/pgs_util.h
+++ b/src/pgs_util.h
@@ -26,4 +26,9 @@ conv_theta(double x)
return y;
}
+static inline double deg_to_rad(double in)
+{
+ return in * PI / 180;
+}
+
#endif
diff --git a/src/point.c b/src/point.c
index 5132835..0cbfa00 100644
--- a/src/point.c
+++ b/src/point.c
@@ -1,9 +1,12 @@
#include "point.h"
+#include "pgs_util.h"
+#include
/* This file contains definitions for spherical point functions. */
PG_FUNCTION_INFO_V1(spherepoint_in);
PG_FUNCTION_INFO_V1(spherepoint_from_long_lat);
+PG_FUNCTION_INFO_V1(spherepoint_from_long_lat_deg);
PG_FUNCTION_INFO_V1(spherepoint_distance);
PG_FUNCTION_INFO_V1(spherepoint_long);
PG_FUNCTION_INFO_V1(spherepoint_lat);
@@ -13,6 +16,17 @@ PG_FUNCTION_INFO_V1(spherepoint_z);
PG_FUNCTION_INFO_V1(spherepoint_xyz);
PG_FUNCTION_INFO_V1(spherepoint_equal);
+static Oid point_id = InvalidOid;
+
+Oid get_spoint_type_oid(void)
+{
+ if (point_id == InvalidOid)
+ {
+ point_id = TypenameGetTypid("spoint");
+ }
+ return point_id;
+}
+
bool
spoint_eq(const SPoint *p1, const SPoint *p2)
{
@@ -141,18 +155,38 @@ spherepoint_in(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(sp);
}
+void create_spherepoint_from_long_lat(SPoint *p, float8 lng, float8 lat)
+{
+ p->lat = lat;
+ p->lng = lng;
+ spoint_check(p);
+}
Datum
spherepoint_from_long_lat(PG_FUNCTION_ARGS)
{
SPoint *p = (SPoint *) palloc(sizeof(SPoint));
- p->lng = PG_GETARG_FLOAT8(0);
- p->lat = PG_GETARG_FLOAT8(1);
- spoint_check(p);
+ const float8 lng = PG_GETARG_FLOAT8(0);
+ const float8 lat = PG_GETARG_FLOAT8(1);
+ create_spherepoint_from_long_lat(p, lng, lat);
PG_RETURN_POINTER(p);
}
+Datum
+spherepoint_from_long_lat_deg(PG_FUNCTION_ARGS)
+{
+ Datum res;
+ const float8 lng = deg_to_rad(PG_GETARG_FLOAT8(0));
+ const float8 lat = deg_to_rad(PG_GETARG_FLOAT8(1));
+ res = DirectFunctionCall2(
+ spherepoint_from_long_lat,
+ Float8GetDatum(lng),
+ Float8GetDatum(lat)
+ );
+ PG_RETURN_DATUM(res);
+}
+
static double
norm2(double a, double b)
{
diff --git a/src/point.h b/src/point.h
index 76c2202..9269cf7 100644
--- a/src/point.h
+++ b/src/point.h
@@ -15,6 +15,8 @@ typedef struct
float8 lat; /* latitude value in radians */
} SPoint;
+Oid get_spoint_type_oid(void);
+
/*
* Calculate the distance between two spherical points in radians.
*/
@@ -45,11 +47,21 @@ void spoint_vector3d(Vector3D *v, const SPoint *p);
*/
Datum spherepoint_in(PG_FUNCTION_ARGS);
+/*
+ * Create spherical point from lat, lng and store to first argument(pointer)
+ */
+void create_spherepoint_from_long_lat(SPoint *p, float8 lng, float8 lat);
+
/*
* Create a spherical point from longitude and latitude both in radians.
*/
Datum spherepoint_from_long_lat(PG_FUNCTION_ARGS);
+/*
+ * Create a spherical point from longitude and latitude both in degrees.
+ */
+Datum spherepoint_from_long_lat_deg(PG_FUNCTION_ARGS);
+
/*
* Calculate the distance between two spherical points.
*/
diff --git a/src/polygon.c b/src/polygon.c
index 8ae3fe8..57786b8 100644
--- a/src/polygon.c
+++ b/src/polygon.c
@@ -1,14 +1,18 @@
#include "polygon.h"
+#include "point.h"
/* Polygon functions */
PG_FUNCTION_INFO_V1(spherepoly_in);
+PG_FUNCTION_INFO_V1(spherepoly_deg);
PG_FUNCTION_INFO_V1(spherepoly_equal);
PG_FUNCTION_INFO_V1(spherepoly_equal_neg);
PG_FUNCTION_INFO_V1(spherepoly_circ);
PG_FUNCTION_INFO_V1(spherepoly_npts);
PG_FUNCTION_INFO_V1(spherepoly_area);
+PG_FUNCTION_INFO_V1(spherepoly_get_point);
+PG_FUNCTION_INFO_V1(spherepoly_get_array);
PG_FUNCTION_INFO_V1(spherepoly_cont_point);
PG_FUNCTION_INFO_V1(spherepoly_cont_point_neg);
PG_FUNCTION_INFO_V1(spherepoly_cont_point_com);
@@ -55,6 +59,7 @@ PG_FUNCTION_INFO_V1(spheretrans_poly);
PG_FUNCTION_INFO_V1(spheretrans_poly_inverse);
PG_FUNCTION_INFO_V1(spherepoly_add_point);
PG_FUNCTION_INFO_V1(spherepoly_add_points_finalize);
+PG_FUNCTION_INFO_V1(spherepoly_is_convex);
/*
@@ -554,6 +559,57 @@ spoly_segment(SLine *sl, const SPOLY *poly, int32 i)
}
}
+static bool
+spoly_get_point(SPoint *sp, const SPOLY *poly, int32 i)
+{
+ if (i >= 0 && i < poly->npts)
+ {
+ memcpy((void *) sp, (void *) &poly->p[i], sizeof(SPoint));
+ return true;
+ }
+ return false;
+}
+
+Datum
+spherepoly_get_point(PG_FUNCTION_ARGS)
+{
+ int32 i;
+ SPOLY *poly = PG_GETARG_SPOLY(0);
+ SPoint *sp = (SPoint *) palloc(sizeof(SPoint));
+
+ i = PG_GETARG_INT32(1);
+ if (spoly_get_point(sp, poly, i - 1))
+ {
+ PG_RETURN_POINTER(sp);
+ }
+ pfree(sp);
+ PG_RETURN_NULL();
+}
+
+Datum
+spherepoly_get_array(PG_FUNCTION_ARGS)
+{
+ SPOLY *poly = PG_GETARG_SPOLY(0);
+ Datum *datum_arr = (Datum *) palloc(sizeof(Datum) * poly->npts);
+ ArrayType *res;
+ SPoint *p = (SPoint *) palloc(sizeof(SPoint) * poly->npts);
+
+ for (int i = 0; i < poly->npts; i++)
+ {
+ if (!spoly_get_point(&p[i], poly, i))
+ {
+ pfree(p);
+ pfree(datum_arr);
+ PG_RETURN_NULL();
+ }
+ datum_arr[i] = PointerGetDatum(&p[i]);
+ }
+
+ res = construct_array(datum_arr, poly->npts, get_spoint_type_oid(), sizeof(SPoint), false, 'd');
+
+ PG_RETURN_ARRAYTYPE_P(res);
+}
+
/*
* Checks whether a polygon contains a point.
*
@@ -850,6 +906,51 @@ spherepoly_in(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(poly);
}
+Datum
+spherepoly_deg(PG_FUNCTION_ARGS)
+{
+ int i,
+ np;
+ ArrayType *float_vector = PG_GETARG_ARRAYTYPE_P(0);
+ float8 *array_data;
+ SPoint *points;
+
+ np = ArrayGetNItems(ARR_NDIM(float_vector), ARR_DIMS(float_vector));
+
+ if (np < 6 || np % 2 != 0)
+ {
+ elog(
+ ERROR,
+ "spherepoly_deg: invalid number of arguments (must be even and >= 6)"
+ );
+ PG_RETURN_NULL();
+ }
+
+ np /= 2;
+
+ points = (SPoint *) palloc(np * sizeof(SPoint));
+ if (points == NULL)
+ {
+ elog(
+ ERROR,
+ "spherepoly_deg: failed for allocate memory for points array"
+ );
+ PG_RETURN_NULL();
+ }
+
+ array_data = (float8 *) ARR_DATA_PTR(float_vector);
+
+ for (i = 0; i < np; i++)
+ {
+ create_spherepoint_from_long_lat(
+ &points[i],
+ deg_to_rad(array_data[2 * i]),
+ deg_to_rad(array_data[2 * i + 1])
+ );
+ }
+ PG_RETURN_POINTER(spherepoly_from_array(points, np));
+}
+
Datum
spherepoly_equal(PG_FUNCTION_ARGS)
{
@@ -1431,3 +1532,54 @@ spherepoly_add_points_finalize(PG_FUNCTION_ARGS)
}
PG_RETURN_POINTER(poly);
}
+
+
+Datum
+spherepoly_is_convex(PG_FUNCTION_ARGS)
+{
+ Vector3D u,
+ v,
+ vsu,
+ wsv,
+ crs;
+ int32 i;
+ float8 cur = 0.0,
+ prev = 0.0;
+ SPOLY *poly = (SPOLY *) PG_GETARG_POINTER(0);
+
+ if (poly == NULL)
+ {
+ PG_RETURN_BOOL(false);
+ }
+
+ poly = PG_GETARG_SPOLY(0);
+ if (poly->npts == 3)
+ {
+ PG_RETURN_BOOL(true);
+ }
+
+ for (i = 0; i < poly->npts; i++)
+ {
+ const int j = (i - 1 + poly->npts) % poly->npts;
+ const int k = (i + 1) % poly->npts;
+
+ spoint_vector3d(&u, &poly->p[i]);
+ spoint_vector3d(&v, &poly->p[j]);
+ spoint_vector3d(&vsu, &poly->p[j]);
+ spoint_vector3d(&wsv, &poly->p[k]);
+
+ vector3d_addwithscalar(&vsu, -1, &u);
+ vector3d_addwithscalar(&wsv, -1, &v);
+
+ vector3d_cross(&crs, &vsu, &wsv);
+
+ cur = vector3d_scalar(&crs, &v);
+ if (cur * prev < 0)
+ {
+ PG_RETURN_BOOL(false);
+ }
+ prev = cur;
+ }
+
+ PG_RETURN_BOOL(true);
+}
diff --git a/src/polygon.h b/src/polygon.h
index 7f2aa80..d52a9c6 100644
--- a/src/polygon.h
+++ b/src/polygon.h
@@ -43,7 +43,7 @@ typedef struct
#define PG_GETARG_SPOLY( arg ) \
- ( (SPOLY *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(arg))) )
+ ( (SPOLY *) (PG_DETOAST_DATUM(PG_GETARG_DATUM(arg))) )
/*
* Checks whether two polygons are equal.
@@ -72,6 +72,11 @@ bool spoly_segment(SLine *sl, const SPOLY *poly, int32 i);
*/
bool spoly_contains_point(const SPOLY *pg, const SPoint *sp);
+/*
+ * Returns the n-th point of a spoly.
+ */
+Datum spherepoly_get_point(PG_FUNCTION_ARGS);
+
/*
* Returns the relationship between a polygon and a line as
* PGS_LINE_POLY_REL int8 value.
@@ -81,6 +86,11 @@ bool spoly_contains_point(const SPOLY *pg, const SPoint *sp);
*/
int8 poly_line_pos(const SPOLY *poly, const SLine *line);
+/*
+ * Input of a spherical from sequence of pairconsecutive numbers(lng, lat).
+ */
+Datum spherepoly_deg(PG_FUNCTION_ARGS);
+
/*
* Input of a spherical polygon.
*/
@@ -343,4 +353,14 @@ Datum spherepoly_add_point(PG_FUNCTION_ARGS);
*/
Datum spherepoly_add_points_finalize(PG_FUNCTION_ARGS);
+/*
+ * Returns spoly as array of points
+ */
+Datum spherepoly_get_array(PG_FUNCTION_ARGS);
+
+/*
+ * Checks whether a polygon is convex
+ */
+Datum spherepoly_is_convex(PG_FUNCTION_ARGS);
+
#endif
diff --git a/src/process_moc.cpp b/src/process_moc.cpp
index b2ba137..4a9e342 100644
--- a/src/process_moc.cpp
+++ b/src/process_moc.cpp
@@ -621,31 +621,31 @@ create_moc_release_context(void* moc_in_context, Smoc* moc,
for (size_t k = 1; k < depth; ++k)
{
rnode_iter z(moc_data, m.layout[k].level_end);
- rnode_iter n(moc_data, m.layout[k + 1].level_end);
+ rnode_iter b(moc_data, m.layout[k + 1].level_end);
rnode_iter last_z;
rnode_iter z_end = rend;
for ( ; z != z_end; ++z)
{
if (z.page_ready())
{
- n.set(make_node(z.index(), (*z).start));
- last_rend = n;
- rend = ++n;
+ b.set(make_node(z.index(), (*z).start));
+ last_rend = b;
+ rend = ++b;
}
last_z = z;
}
if (!last_z.page_ready())
{
- n.set(make_node(last_z.index(), (*last_z).start));
- last_rend = n;
- rend = ++n;
+ b.set(make_node(last_z.index(), (*last_z).start));
+ last_rend = b;
+ rend = ++b;
}
}
// The level-end section must be put relative to the actual beginning
// of the root node to prevent confusing redunancies.
int32 tree_begin = last_rend.index() - depth * MOC_INDEX_ALIGN;
-
+
// fill out level-end section
int32* level_ends = data_as(detoasted_offset(moc, tree_begin));
moc->depth = depth;
diff --git a/upgrade_scripts/pg_sphere--1.2.3--1.3.0.sql.in b/upgrade_scripts/pg_sphere--1.2.3--1.3.0.sql.in
new file mode 100644
index 0000000..6309349
--- /dev/null
+++ b/upgrade_scripts/pg_sphere--1.2.3--1.3.0.sql.in
@@ -0,0 +1,104 @@
+CREATE FUNCTION scircle_deg(spoint, float8)
+ RETURNS scircle
+ AS 'MODULE_PATHNAME' , 'spherecircle_by_center_deg'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT PARALLEL SAFE;
+
+COMMENT ON FUNCTION scircle_deg(spoint, float8) IS
+ 'spherical circle with spherical point as center and float8 as radius in degrees';
+
+CREATE FUNCTION spoint_deg(FLOAT8, FLOAT8)
+ RETURNS spoint
+ AS 'MODULE_PATHNAME', 'spherepoint_from_long_lat_deg'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT PARALLEL SAFE;
+
+COMMENT ON FUNCTION spoint_deg(FLOAT8, FLOAT8) IS
+ 'returns a spherical point from longitude (arg1, in degrees), latitude (arg2, in degrees)';
+
+CREATE FUNCTION spoly_deg(float8[])
+ RETURNS spoly
+ AS 'MODULE_PATHNAME', 'spherepoly_deg'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT;
+
+COMMENT ON FUNCTION spoly_deg(float8[]) IS
+ ' Create spoly from array of points.
+ Two consecutive numbers among those present
+ refer to the same occurrence and cover its
+ latitude and longitude, respectively.';
+
+CREATE FUNCTION spath_as_array(spath)
+ RETURNS spoint[]
+ AS 'MODULE_PATHNAME', 'spherepath_get_array'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT PARALLEL SAFE;
+
+COMMENT ON FUNCTION spath_as_array(spath) IS
+ 'returns spath as array of points';
+
+CREATE FUNCTION spoint(spoly, int4)
+ RETURNS spoint
+ AS 'MODULE_PATHNAME', 'spherepoly_get_point'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT PARALLEL SAFE;
+
+COMMENT ON FUNCTION spoint(spoly, int4) IS
+ 'returns n-th point of spherical polygon';
+
+CREATE FUNCTION spoly_as_array(spoly)
+ RETURNS spoint[]
+ AS 'MODULE_PATHNAME', 'spherepoly_get_array'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT PARALLEL SAFE;
+
+COMMENT ON FUNCTION spoly_as_array(spoly) IS
+ 'returns spoly as array of points';
+
+CREATE FUNCTION dist(sline, spoint)
+ RETURNS FLOAT8
+ AS 'MODULE_PATHNAME', 'sphereline_point_distance'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT;
+
+COMMENT ON FUNCTION dist(sline, spoint) IS
+ 'returns the distance between spherical line and spherical point';
+
+CREATE OPERATOR <-> (
+ LEFTARG = sline,
+ RIGHTARG = spoint,
+ COMMUTATOR = '<->',
+ PROCEDURE = dist
+);
+
+COMMENT ON OPERATOR <-> (sline, spoint) IS
+ 'returns the distance between spherical line and spherical point';
+
+CREATE FUNCTION dist(spoint, sline)
+ RETURNS FLOAT8
+ AS 'MODULE_PATHNAME', 'sphereline_point_distance_com'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT;
+
+COMMENT ON FUNCTION dist(spoint, sline) IS
+ 'returns the distance between spherical line and spherical point';
+
+
+CREATE OPERATOR <-> (
+ LEFTARG = spoint,
+ RIGHTARG = sline,
+ COMMUTATOR = '<->',
+ PROCEDURE = dist
+);
+
+COMMENT ON OPERATOR <-> (spoint, sline) IS
+ 'returns the distance between spherical line and spherical point';
+
+CREATE FUNCTION spoly_is_convex(spoly)
+ RETURNS BOOL
+ AS 'MODULE_PATHNAME', 'spherepoly_is_convex'
+ LANGUAGE 'c'
+ IMMUTABLE PARALLEL SAFE;
+
+COMMENT ON FUNCTION spoly_is_convex(spoly) IS
+ 'true if spherical polygon is convex';