From 118fe52b13cb13a170593830d4d769270cc016c2 Mon Sep 17 00:00:00 2001 From: stepan-neretin7 Date: Mon, 31 Jul 2023 17:22:11 +0700 Subject: [PATCH 01/19] [ISSUE #22] Created spoint_deg, scircle_deg functions. --- Makefile | 6 ++- expected/circle.out | 16 +++++++ expected/init_test.out.in | 22 ++++----- expected/init_test_healpix.out.in | 4 +- expected/points.out | 18 +++++++ expected/poly.out | 22 +++++++++ pgs_circle.sql.in | 8 ++++ pgs_point.sql.in | 9 ++++ pgs_polygon.sql.in | 12 +++++ pgs_types.sql.in | 1 - sql/circle.sql | 8 ++++ sql/points.sql | 6 +++ sql/poly.sql | 10 ++++ src/circle.c | 20 +++++++- src/circle.h | 5 ++ src/pgs_util.h | 5 ++ src/point.c | 28 +++++++++-- src/point.h | 10 ++++ src/polygon.c | 47 +++++++++++++++++++ src/polygon.h | 5 ++ .../pg_sphere--1.2.3--1.3.0.sql.in | 29 ++++++++++++ 21 files changed, 271 insertions(+), 20 deletions(-) create mode 100644 upgrade_scripts/pg_sphere--1.2.3--1.3.0.sql.in diff --git a/Makefile b/Makefile index dca3b7d..4e0f826 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,8 @@ 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 \ @@ -260,6 +261,9 @@ endif pg_sphere--1.2.2--1.2.3.sql: cat upgrade_scripts/$@.in > $@ +pg_sphere--1.2.3--1.3.0.sql: + cat upgrade_scripts/$@.in > $@ + # end of local stuff src/sscan.o : src/sparse.c 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/init_test.out.in b/expected/init_test.out.in index 129283c..4b0671c 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:8568: 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:8575: NOTICE: argument type spherekey is only a shell +psql:pg_sphere.test.sql:8589: 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:8596: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8602: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8608: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8614: 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..7e725f8 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:9181: NOTICE: return type smoc is only a shell +psql:pg_sphere.test.sql:9187: NOTICE: argument type smoc is only a shell 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..a705483 100644 --- a/expected/poly.out +++ b/expected/poly.out @@ -318,11 +318,33 @@ 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 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_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..df5a614 100644 --- a/pgs_polygon.sql.in +++ b/pgs_polygon.sql.in @@ -928,6 +928,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' 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/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..52cedd7 100644 --- a/sql/poly.sql +++ b/sql/poly.sql @@ -78,10 +78,20 @@ 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)}'; 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/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..c68ee71 100644 --- a/src/point.c +++ b/src/point.c @@ -1,9 +1,11 @@ #include "point.h" +#include "pgs_util.h" /* 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); @@ -141,18 +143,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..89197d0 100644 --- a/src/point.h +++ b/src/point.h @@ -45,11 +45,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..17f4841 100644 --- a/src/polygon.c +++ b/src/polygon.c @@ -1,9 +1,11 @@ #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); @@ -850,6 +852,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) { diff --git a/src/polygon.h b/src/polygon.h index 7f2aa80..eefd099 100644 --- a/src/polygon.h +++ b/src/polygon.h @@ -81,6 +81,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. */ 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..86cc233 --- /dev/null +++ b/upgrade_scripts/pg_sphere--1.2.3--1.3.0.sql.in @@ -0,0 +1,29 @@ +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.'; From 513e2d0e4845b4dd45660009773f0cc6e613f97a Mon Sep 17 00:00:00 2001 From: Vitaly Davydov Date: Fri, 4 Aug 2023 23:32:07 +0300 Subject: [PATCH 02/19] Updated the current version. --- Makefile | 2 +- expected/init.out | 2 +- pg_sphere--1.2.3.sql.in => pg_sphere--1.3.0.sql.in | 0 pg_sphere.control | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename pg_sphere--1.2.3.sql.in => pg_sphere--1.3.0.sql.in (100%) diff --git a/Makefile b/Makefile index 4e0f826..a954626 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 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/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 From cbf89a8300710c35f3dfda4794a80ff597a111f4 Mon Sep 17 00:00:00 2001 From: stepan-neretin7 Date: Sat, 5 Aug 2023 05:01:21 +0700 Subject: [PATCH 03/19] [ISSUE #42] Fix compiler warning --- src/process_moc.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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; From 5e7111ef27fa95d998465c7b3a5bb0c47e8b9ad2 Mon Sep 17 00:00:00 2001 From: ggnmstr Date: Sat, 29 Jul 2023 15:32:23 +0700 Subject: [PATCH 04/19] Fix sline_sline_pos, add tests for degenerate polygons --- expected/poly.out | 9 +++++++++ sql/poly.sql | 6 ++++++ src/line.c | 18 +++++++++--------- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/expected/poly.out b/expected/poly.out index a705483..180e06f 100644 --- a/expected/poly.out +++ b/expected/poly.out @@ -350,6 +350,15 @@ 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 diff --git a/sql/poly.sql b/sql/poly.sql index 52cedd7..bdfbef8 100644 --- a/sql/poly.sql +++ b/sql/poly.sql @@ -96,6 +96,12 @@ SELECT spoly_deg(NULL::float8[]); 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)}'); diff --git a/src/line.c b/src/line.c index 315adfb..b8d1195 100644 --- a/src/line.c +++ b/src/line.c @@ -494,15 +494,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 +518,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)) From cd82a4d963402510aacf7523c4f0d902a0bd7ccc Mon Sep 17 00:00:00 2001 From: Vitaly Davydov Date: Fri, 4 Aug 2023 12:29:35 +0300 Subject: [PATCH 05/19] Added simple description of versioning. --- README.pg_sphere | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.pg_sphere b/README.pg_sphere index 6d36fef..8a85c39 100644 --- a/README.pg_sphere +++ b/README.pg_sphere @@ -13,7 +13,21 @@ This is an R-Tree implementation using GiST for spherical objects like spherical points and spherical circles with useful functions and operators. 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: From d88c0597e18afee1dc6dd990ccfce6379c69ba2d Mon Sep 17 00:00:00 2001 From: stepan-neretin7 Date: Mon, 24 Jul 2023 10:22:23 +0700 Subject: [PATCH 06/19] [ISSUE #16] Implemented a function and tests to extract vertices from spoly by index --- doc/functions.sgm | 89 ++++++++++++++++++- expected/init_test.out.in | 14 +-- expected/init_test_healpix.out.in | 4 +- expected/path.out | 25 ++++++ expected/poly.out | 30 +++++++ pgs_path.sql.in | 8 ++ pgs_polygon.sql.in | 18 ++++ sql/path.sql | 6 ++ sql/poly.sql | 7 ++ src/path.c | 27 ++++++ src/path.h | 5 ++ src/point.c | 12 +++ src/point.h | 2 + src/polygon.c | 53 +++++++++++ src/polygon.h | 10 +++ .../pg_sphere--1.2.3--1.3.0.sql.in | 27 ++++++ 16 files changed, 326 insertions(+), 11 deletions(-) diff --git a/doc/functions.sgm b/doc/functions.sgm index 30118bf..5cdc3aa 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,58 @@ - + + 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)}' );]]> + + + + + + + diff --git a/expected/init_test.out.in b/expected/init_test.out.in index 4b0671c..1276622 100644 --- a/expected/init_test.out.in +++ b/expected/init_test.out.in @@ -24,12 +24,12 @@ 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:184: NOTICE: argument type sbox is only a shell -psql:pg_sphere.test.sql:8568: NOTICE: type "spherekey" is not yet defined +psql:pg_sphere.test.sql:8594: NOTICE: type "spherekey" is not yet defined DETAIL: Creating a shell type definition. -psql:pg_sphere.test.sql:8575: NOTICE: argument type spherekey is only a shell -psql:pg_sphere.test.sql:8589: NOTICE: type "pointkey" is not yet defined +psql:pg_sphere.test.sql:8601: NOTICE: argument type spherekey is only a shell +psql:pg_sphere.test.sql:8615: NOTICE: type "pointkey" is not yet defined DETAIL: Creating a shell type definition. -psql:pg_sphere.test.sql:8596: NOTICE: argument type pointkey is only a shell -psql:pg_sphere.test.sql:8602: NOTICE: argument type pointkey is only a shell -psql:pg_sphere.test.sql:8608: NOTICE: argument type pointkey is only a shell -psql:pg_sphere.test.sql:8614: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8622: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8628: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8634: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8640: 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 7e725f8..147d4f9 100644 --- a/expected/init_test_healpix.out.in +++ b/expected/init_test_healpix.out.in @@ -1,2 +1,2 @@ -psql:pg_sphere.test.sql:9181: NOTICE: return type smoc is only a shell -psql:pg_sphere.test.sql:9187: NOTICE: argument type smoc is only a shell +psql:pg_sphere.test.sql:9207: NOTICE: return type smoc is only a shell +psql:pg_sphere.test.sql:9213: NOTICE: argument type smoc is only a shell 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/poly.out b/expected/poly.out index a705483..bf7bc0b 100644 --- a/expected/poly.out +++ b/expected/poly.out @@ -1760,3 +1760,33 @@ 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) + 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_polygon.sql.in b/pgs_polygon.sql.in index df5a614..5db17c6 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' 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/poly.sql b/sql/poly.sql index 52cedd7..9d7b600 100644 --- a/sql/poly.sql +++ b/sql/poly.sql @@ -603,3 +603,10 @@ 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)}' ); 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..29c687b 100644 --- a/src/path.h +++ b/src/path.h @@ -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/point.c b/src/point.c index c68ee71..0cbfa00 100644 --- a/src/point.c +++ b/src/point.c @@ -1,5 +1,6 @@ #include "point.h" #include "pgs_util.h" +#include /* This file contains definitions for spherical point functions. */ @@ -15,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) { diff --git a/src/point.h b/src/point.h index 89197d0..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. */ diff --git a/src/polygon.c b/src/polygon.c index 17f4841..54eb2a6 100644 --- a/src/polygon.c +++ b/src/polygon.c @@ -11,6 +11,8 @@ 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); @@ -556,6 +558,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. * diff --git a/src/polygon.h b/src/polygon.h index eefd099..c7daf13 100644 --- a/src/polygon.h +++ b/src/polygon.h @@ -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. @@ -348,4 +353,9 @@ 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); + #endif 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 index 86cc233..3791852 100644 --- 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 @@ -27,3 +27,30 @@ COMMENT ON FUNCTION spoly_deg(float8[]) IS 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'; From 23ff77ef2e67bce357a15e2d952ac026c3219d91 Mon Sep 17 00:00:00 2001 From: 3Davydov Date: Fri, 4 Aug 2023 03:51:02 +0700 Subject: [PATCH 07/19] Created some tests for contains and overlap operations to check DE-9IM compliance --- Makefile | 5 +- expected/contains.out | 233 ++++++++++ expected/overlaps.out | 1017 +++++++++++++++++++++++++++++++++++++++++ sql/contains.sql | 123 +++++ sql/overlaps.sql | 484 ++++++++++++++++++++ 5 files changed, 1860 insertions(+), 2 deletions(-) create mode 100644 expected/contains.out create mode 100644 expected/overlaps.out create mode 100644 sql/contains.sql create mode 100644 sql/overlaps.sql diff --git a/Makefile b/Makefile index dca3b7d..5bd53f7 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,8 @@ DATA_built = $(RELEASE_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 ifneq ($(USE_HEALPIX),0) REGRESS += healpix moc mocautocast @@ -41,7 +42,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 ifneq ($(USE_HEALPIX),0) TESTS += healpix moc mocautocast 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/overlaps.out b/expected/overlaps.out new file mode 100644 index 0000000..5a7625f --- /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 | f +(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 | f +(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/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/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; From 75a7fb3c36192062a443425ce9870a4902a5ef57 Mon Sep 17 00:00:00 2001 From: Vitaly Davydov Date: Wed, 9 Aug 2023 10:00:33 +0300 Subject: [PATCH 08/19] Fix pgSphere version and the project url in the doc --- doc/pg_sphere.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 From 2f9fe2c10402a4676e7855851c66d970eba7321f Mon Sep 17 00:00:00 2001 From: Darya177777 Date: Fri, 11 Aug 2023 09:29:42 +0700 Subject: [PATCH 09/19] Add calculation of the distance between a line and a point --- doc/operators.sgm | 14 +++- expected/init_test.out.in | 14 ++-- expected/init_test_healpix.out.in | 4 +- expected/line.out | 34 ++++++++- pgs_line.sql.in | 50 +++++++++++++ sql/line.sql | 17 ++++- src/line.c | 72 +++++++++++++++++++ src/line.h | 15 ++++ .../pg_sphere--1.2.3--1.3.0.sql.in | 39 ++++++++++ 9 files changed, 247 insertions(+), 12 deletions(-) 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/expected/init_test.out.in b/expected/init_test.out.in index 1276622..b5ace10 100644 --- a/expected/init_test.out.in +++ b/expected/init_test.out.in @@ -24,12 +24,12 @@ 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:184: NOTICE: argument type sbox is only a shell -psql:pg_sphere.test.sql:8594: NOTICE: type "spherekey" is not yet defined +psql:pg_sphere.test.sql:8644: NOTICE: type "spherekey" is not yet defined DETAIL: Creating a shell type definition. -psql:pg_sphere.test.sql:8601: NOTICE: argument type spherekey is only a shell -psql:pg_sphere.test.sql:8615: NOTICE: type "pointkey" is not yet defined +psql:pg_sphere.test.sql:8651: NOTICE: argument type spherekey is only a shell +psql:pg_sphere.test.sql:8665: NOTICE: type "pointkey" is not yet defined DETAIL: Creating a shell type definition. -psql:pg_sphere.test.sql:8622: NOTICE: argument type pointkey is only a shell -psql:pg_sphere.test.sql:8628: NOTICE: argument type pointkey is only a shell -psql:pg_sphere.test.sql:8634: NOTICE: argument type pointkey is only a shell -psql:pg_sphere.test.sql:8640: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8672: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8678: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8684: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8690: 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 147d4f9..3b0cfbd 100644 --- a/expected/init_test_healpix.out.in +++ b/expected/init_test_healpix.out.in @@ -1,2 +1,2 @@ -psql:pg_sphere.test.sql:9207: NOTICE: return type smoc is only a shell -psql:pg_sphere.test.sql:9213: NOTICE: argument type smoc is only a shell +psql:pg_sphere.test.sql:9257: NOTICE: return type smoc is only a shell +psql:pg_sphere.test.sql:9263: 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/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/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/src/line.c b/src/line.c index b8d1195..6599e64 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. @@ -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/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 index 3791852..6eb9460 100644 --- 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 @@ -54,3 +54,42 @@ CREATE FUNCTION spoly_as_array(spoly) 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'; From d8470f8972864e556010b0fe3ed448c6a884db29 Mon Sep 17 00:00:00 2001 From: ggnmstr Date: Thu, 27 Jul 2023 16:58:33 +0700 Subject: [PATCH 10/19] Add spoly_is_convex --- doc/functions.sgm | 27 ++++++++++ expected/init_test.out.in | 14 ++--- expected/init_test_healpix.out.in | 4 +- expected/poly.out | 25 +++++++++ pgs_polygon.sql.in | 14 +++++ sql/poly.sql | 6 +++ src/polygon.c | 52 +++++++++++++++++++ src/polygon.h | 5 ++ .../pg_sphere--1.2.3--1.3.0.sql.in | 9 ++++ 9 files changed, 147 insertions(+), 9 deletions(-) diff --git a/doc/functions.sgm b/doc/functions.sgm index 5cdc3aa..d5bb457 100644 --- a/doc/functions.sgm +++ b/doc/functions.sgm @@ -618,6 +618,33 @@ + + + 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/expected/init_test.out.in b/expected/init_test.out.in index b5ace10..6fbd06b 100644 --- a/expected/init_test.out.in +++ b/expected/init_test.out.in @@ -24,12 +24,12 @@ 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:184: NOTICE: argument type sbox is only a shell -psql:pg_sphere.test.sql:8644: NOTICE: type "spherekey" is not yet defined +psql:pg_sphere.test.sql:8658: NOTICE: type "spherekey" is not yet defined DETAIL: Creating a shell type definition. -psql:pg_sphere.test.sql:8651: NOTICE: argument type spherekey is only a shell -psql:pg_sphere.test.sql:8665: 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:8672: NOTICE: argument type pointkey is only a shell -psql:pg_sphere.test.sql:8678: NOTICE: argument type pointkey is only a shell -psql:pg_sphere.test.sql:8684: NOTICE: argument type pointkey is only a shell -psql:pg_sphere.test.sql:8690: 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 3b0cfbd..4195603 100644 --- a/expected/init_test_healpix.out.in +++ b/expected/init_test_healpix.out.in @@ -1,2 +1,2 @@ -psql:pg_sphere.test.sql:9257: NOTICE: return type smoc is only a shell -psql:pg_sphere.test.sql:9263: NOTICE: argument type smoc is only a shell +psql:pg_sphere.test.sql:9271: NOTICE: return type smoc is only a shell +psql:pg_sphere.test.sql:9277: NOTICE: argument type smoc is only a shell diff --git a/expected/poly.out b/expected/poly.out index 9fcd234..50e510e 100644 --- a/expected/poly.out +++ b/expected/poly.out @@ -1799,3 +1799,28 @@ SELECT spoly_as_array( spoly '{(0,0),(1,0),(1,1)}' ); {"(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/pgs_polygon.sql.in b/pgs_polygon.sql.in index 5db17c6..fdd4277 100644 --- a/pgs_polygon.sql.in +++ b/pgs_polygon.sql.in @@ -973,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/sql/poly.sql b/sql/poly.sql index b185e50..2281aba 100644 --- a/sql/poly.sql +++ b/sql/poly.sql @@ -616,3 +616,9 @@ 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/src/polygon.c b/src/polygon.c index 54eb2a6..57786b8 100644 --- a/src/polygon.c +++ b/src/polygon.c @@ -59,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); /* @@ -1531,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 c7daf13..9d47f40 100644 --- a/src/polygon.h +++ b/src/polygon.h @@ -358,4 +358,9 @@ Datum spherepoly_add_points_finalize(PG_FUNCTION_ARGS); */ Datum spherepoly_get_array(PG_FUNCTION_ARGS); +/* + * Checks whether a polygon is convex + */ +Datum spherepoly_is_convex(PG_FUNCTION_ARGS); + #endif 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 index 6eb9460..6309349 100644 --- 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 @@ -93,3 +93,12 @@ CREATE OPERATOR <-> ( 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'; From 0becb8b2d7d1baf622fddc0045eb6346a60be1fb Mon Sep 17 00:00:00 2001 From: Vitaly Davydov Date: Sun, 13 Aug 2023 23:21:00 +0300 Subject: [PATCH 11/19] Fix warnings in output.c --- src/output.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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); From e10a8bb84a661be7b469ea83c09aab250e48ef28 Mon Sep 17 00:00:00 2001 From: Christoph Berg Date: Mon, 31 Jul 2023 16:20:12 +0000 Subject: [PATCH 12/19] Fix compatibility with PG16 * Replace Abs with fabs * Remove DatumGetPointer where PG16 got stricter typechecking * Annotate expected/moc100 output files with PG major and architecture bits they are meant for * Add expected output files for moc100 on PG16 --- expected/moc100.out | 11 ++ expected/moc100_1.out | 11 ++ expected/moc100_2.out | 11 ++ expected/moc100_3.out | 11 ++ expected/moc100_4.out | 309 ++++++++++++++++++++++++++++++++++++++++++ expected/moc100_5.out | 309 ++++++++++++++++++++++++++++++++++++++++++ sql/moc100.sql | 11 ++ src/ellipse.c | 4 +- src/gist.c | 4 +- src/path.h | 2 +- src/polygon.h | 2 +- 11 files changed, 679 insertions(+), 6 deletions(-) create mode 100644 expected/moc100_4.out create mode 100644 expected/moc100_5.out 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..13e2306 --- /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..6.26 rows=1 width=96) (actual rows=35 loops=1) + Filter: (coverage && '4/0'::smoc) + Rows Removed by Filter: 66 + Buffers: shared hit=114 + 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=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..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=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..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=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..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=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/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/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/path.h b/src/path.h index 29c687b..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. diff --git a/src/polygon.h b/src/polygon.h index 9d47f40..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. From 70810bd9c800fbb6428875125470252e69752b43 Mon Sep 17 00:00:00 2001 From: Christoph Berg Date: Tue, 1 Aug 2023 10:32:43 +0200 Subject: [PATCH 13/19] Test PG16 on travis-ci.com --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 758f119..24df3d0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ env: - PG_SUPPORTED_VERSIONS=13 - PG_SUPPORTED_VERSIONS=14 - PG_SUPPORTED_VERSIONS=15 + - PG_SUPPORTED_VERSIONS=16 language: C dist: bionic From ec4bd87c473fa7c8ab9c8b60fe664345a681a1b7 Mon Sep 17 00:00:00 2001 From: Christoph Berg Date: Tue, 1 Aug 2023 12:36:13 +0200 Subject: [PATCH 14/19] Travis: Change to run on Ubuntu focal --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 24df3d0..4df87d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ env: - 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) From 56ff36668bb4df17ab12c693bf6f01bf1de67517 Mon Sep 17 00:00:00 2001 From: Vitaly Davydov Date: Fri, 25 Aug 2023 16:50:25 +0300 Subject: [PATCH 15/19] Fix sphereline_circle_pos (uninitialized memory use) --- expected/overlaps.out | 4 ++-- src/line.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/expected/overlaps.out b/expected/overlaps.out index 5a7625f..5b1f885 100644 --- a/expected/overlaps.out +++ b/expected/overlaps.out @@ -835,14 +835,14 @@ select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (20d , 20d))' && sci select 'sbox && scircle', 'f' as expected, sbox'((0d , 0d), (0d , 0d))' && scircle'<(10d , 0d) , 10d>' as actual; ?column? | expected | actual -----------------+----------+-------- - sbox && scircle | f | f + 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 | f + sbox && scircle | f | t (1 row) -- the box and circle are degenerated into the point and coincide diff --git a/src/line.c b/src/line.c index 6599e64..ad02575 100644 --- a/src/line.c +++ b/src/line.c @@ -349,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; } From 21163102051cd905f4547de21e9bacd479e209af Mon Sep 17 00:00:00 2001 From: Vitaly Davydov Date: Fri, 25 Aug 2023 21:42:58 +0300 Subject: [PATCH 16/19] Fix diff in the test moc100 on PG16 --- expected/moc100_4.out | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/expected/moc100_4.out b/expected/moc100_4.out index 13e2306..0dc26bd 100644 --- a/expected/moc100_4.out +++ b/expected/moc100_4.out @@ -72,10 +72,10 @@ 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) + 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=114 + Buffers: shared hit=115 Planning: Buffers: shared hit=1 (6 rows) @@ -84,10 +84,10 @@ 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) + 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=59 + Buffers: shared hit=60 Planning: Buffers: shared hit=4 (6 rows) @@ -96,10 +96,10 @@ 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) + 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=59 + Buffers: shared hit=60 Planning: Buffers: shared hit=1 (6 rows) @@ -108,10 +108,10 @@ 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) + 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=59 + Buffers: shared hit=60 Planning: Buffers: shared hit=1 (6 rows) @@ -120,10 +120,10 @@ 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) + 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=59 + Buffers: shared hit=60 Planning: Buffers: shared hit=4 (6 rows) @@ -132,10 +132,10 @@ 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) + 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=59 + Buffers: shared hit=60 Planning: Buffers: shared hit=1 (6 rows) @@ -144,10 +144,10 @@ 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) + 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=59 + Buffers: shared hit=60 Planning: Buffers: shared hit=1 (6 rows) @@ -254,7 +254,7 @@ 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) + 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 @@ -273,7 +273,7 @@ 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) + 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 @@ -292,7 +292,7 @@ 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) + 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 From 6ebf5c2a9fb761a6657c6ebc6ababfbf088e87e7 Mon Sep 17 00:00:00 2001 From: Giuseppe Broccolo Date: Mon, 15 Jan 2018 11:00:18 +0100 Subject: [PATCH 17/19] Add BRIN support for spoint and sbox Adjust style using pgindent, execute regression test for BRIN code just for PG>9.5 --- Makefile | 6 +- README.pg_sphere | 1 + brin.c | 348 +++++++++++++++++++++++++++++++++ brin.h | 40 ++++ doc/indices.sgm | 45 ++++- expected/spoint_brin.out | 56 ++++++ pgs_brin.sql.in | 411 +++++++++++++++++++++++++++++++++++++++ sql/spoint_brin.sql | 136 +++++++++++++ 8 files changed, 1036 insertions(+), 7 deletions(-) create mode 100644 brin.c create mode 100644 brin.h create mode 100644 expected/spoint_brin.out create mode 100644 pgs_brin.sql.in create mode 100644 sql/spoint_brin.sql diff --git a/Makefile b/Makefile index 062aab6..bb5074f 100644 --- a/Makefile +++ b/Makefile @@ -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 brin.o ifneq ($(USE_HEALPIX),0) OBJS += src/healpix.o src/moc.o src/process_moc.o \ @@ -33,7 +33,7 @@ DATA_built = $(RELEASE_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 overlaps + contains overlaps spoint_brin ifneq ($(USE_HEALPIX),0) REGRESS += healpix moc mocautocast @@ -66,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 diff --git a/README.pg_sphere b/README.pg_sphere index 8a85c39..cccc8ca 100644 --- a/README.pg_sphere +++ b/README.pg_sphere @@ -11,6 +11,7 @@ It provides: This is an R-Tree implementation using GiST for spherical objects like spherical points and spherical circles with useful functions and operators. +It also support the Block Range INdexing (BRIN) for large datasets. NOTICE: This version will work only with PostgreSQL version 10 and above. diff --git a/brin.c b/brin.c new file mode 100644 index 0000000..5a5ae03 --- /dev/null +++ b/brin.c @@ -0,0 +1,348 @@ +/* + * 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/brin.h b/brin.h new file mode 100644 index 0000000..b1a1c2c --- /dev/null +++ b/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/doc/indices.sgm b/doc/indices.sgm index 8103072..7918ee0 100644 --- a/doc/indices.sgm +++ b/doc/indices.sgm @@ -8,15 +8,32 @@ pgSphere uses GiST - to create spherical indices. An index speeds up the execution - time of operators BRIN) algorithms to create + spherical indices. + GiST index represents the R-Tree implementation for + spherical objects, while BRINs are based on "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 BRINs). + As a consequence, BRINs result to be really small indexes (up to 1000 times + than GiST ones), generally with lower a 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 BRINs 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">!=. + + Codestin Search App + + You can create a GiST index with the following spherical data types: @@ -55,6 +72,10 @@ + + BRIN indexing supports just spherical points (spoint) + and spherical coordinates range (sbox) at the moment. + Codestin Search App @@ -65,6 +86,22 @@ + + BRINs can be created through the following syntax: + + + + + + By default, BRINs summarize block of 128 pages. The lower numbers + of pages are specified, the higher granularity is reached during + the searches, and performance's gap between GiST indexes and BRINs + is lower (consider that BRINs size increases as well). Different + summarizations can be used with the following command: + + + + diff --git a/expected/spoint_brin.out b/expected/spoint_brin.out new file mode 100644 index 0000000..4bb88b0 --- /dev/null +++ b/expected/spoint_brin.out @@ -0,0 +1,56 @@ +CREATE TABLE +COPY 77 +CREATE FUNCTION +CREATE INDEX +SET +SET +SET + ?column? | qnodes +----------+---------- + scan_seq | Seq Scan +(1 row) + + p +----------------------------------------- + (0.349065850398866 , 0.174532925199433) +(1 row) + + ?column? | qnodes +----------+---------- + scan_seq | Seq Scan +(1 row) + + p +----------------------------------------- + (0.349065850398866 , 0.174532925199433) +(1 row) + +SET +SET +SET + ?column? | qnodes +----------+------------------------------------ + scan_idx | Bitmap Heap Scan,Bitmap Index Scan +(1 row) + + p +----------------------------------------- + (0.349065850398866 , 0.174532925199433) +(1 row) + + ?column? | qnodes +----------+------------------------------------ + scan_idx | Bitmap Heap Scan,Bitmap Index Scan +(1 row) + + p +----------------------------------------- + (0.349065850398866 , 0.174532925199433) +(1 row) + +DROP INDEX +DROP TABLE +DROP FUNCTION +SET +SET +SET diff --git a/pgs_brin.sql.in b/pgs_brin.sql.in new file mode 100644 index 0000000..93fe8dd --- /dev/null +++ b/pgs_brin.sql.in @@ -0,0 +1,411 @@ + +-------------------------------------------------------------------- +-- 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); + + diff --git a/sql/spoint_brin.sql b/sql/spoint_brin.sql new file mode 100644 index 0000000..b03508d --- /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)'); + --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; From fa429a54177282ae1eb94465903154f5f514756a Mon Sep 17 00:00:00 2001 From: Vitaly Davydov Date: Tue, 15 Aug 2023 18:08:28 +0300 Subject: [PATCH 18/19] Prepare the original PR of @gbroccolo for the merge Move brin.c(h) files into src subdirectory Add brin support in upgrade script Fix some code problems Fix test_init Fix Indices section in the doc Add test for sbox BRIN index Fix found problems in the doc after review Fix BRIN support for sbox --- Makefile | 8 +- README.pg_sphere | 4 +- doc/indices.sgm | 30 +++---- expected/init_test_healpix.out.in | 4 +- expected/sbox_brin.out | 91 ++++++++++++++++++++ expected/spoint_brin.out | 99 +++++++++++++-------- pgs_brin.sql.in | 6 +- sql/sbox_brin.sql | 138 ++++++++++++++++++++++++++++++ sql/spoint_brin.sql | 2 +- brin.c => src/brin.c | 28 +++--- brin.h => src/brin.h | 0 11 files changed, 337 insertions(+), 73 deletions(-) create mode 100644 expected/sbox_brin.out create mode 100644 sql/sbox_brin.sql rename brin.c => src/brin.c (95%) rename brin.h => src/brin.h (100%) diff --git a/Makefile b/Makefile index bb5074f..2589494 100644 --- a/Makefile +++ b/Makefile @@ -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 brin.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 \ @@ -33,7 +33,7 @@ DATA_built = $(RELEASE_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 overlaps spoint_brin + contains overlaps spoint_brin sbox_brin ifneq ($(USE_HEALPIX),0) REGRESS += healpix moc mocautocast @@ -43,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 contains overlaps + epochprop contains overlaps spoint_brin sbox_brin ifneq ($(USE_HEALPIX),0) TESTS += healpix moc mocautocast @@ -262,7 +262,7 @@ endif pg_sphere--1.2.2--1.2.3.sql: cat upgrade_scripts/$@.in > $@ -pg_sphere--1.2.3--1.3.0.sql: +pg_sphere--1.2.3--1.3.0.sql: pgs_brin.sql.in cat upgrade_scripts/$@.in > $@ # end of local stuff diff --git a/README.pg_sphere b/README.pg_sphere index cccc8ca..95a2563 100644 --- a/README.pg_sphere +++ b/README.pg_sphere @@ -9,9 +9,9 @@ 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 support the Block Range INdexing (BRIN) for large datasets. +It also supports the Block Range INdexing (BRIN) for large datasets. NOTICE: This version will work only with PostgreSQL version 10 and above. diff --git a/doc/indices.sgm b/doc/indices.sgm index 7918ee0..11940c2 100644 --- a/doc/indices.sgm +++ b/doc/indices.sgm @@ -10,17 +10,17 @@ pgSphere uses GiST and Block Range INdexing (BRIN) algorithms to create spherical indices. - GiST index represents the R-Tree implementation for - spherical objects, while BRINs are based on "summarization" + 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 BRINs). - As a consequence, BRINs result to be really small indexes (up to 1000 times - than GiST ones), generally with lower a performance compared with a GiST one, + url="https://www.postgresql.org/docs/current/brin-intro.html"> + 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 BRINs are particularly suitable in a big data context. + 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 !=. - Codestin Search App You can create a GiST index with the following spherical data types: @@ -87,17 +84,18 @@ - BRINs can be created through the following syntax: + BRIN index can be created through the following syntax: - By default, BRINs summarize block of 128 pages. The lower numbers - of pages are specified, the higher granularity is reached during - the searches, and performance's gap between GiST indexes and BRINs - is lower (consider that BRINs size increases as well). Different - summarizations can be used with the following command: + 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/expected/init_test_healpix.out.in b/expected/init_test_healpix.out.in index 4195603..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:9271: NOTICE: return type smoc is only a shell -psql:pg_sphere.test.sql:9277: 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/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 index 4bb88b0..958c709 100644 --- a/expected/spoint_brin.out +++ b/expected/spoint_brin.out @@ -1,56 +1,87 @@ -CREATE TABLE -COPY 77 -CREATE FUNCTION -CREATE INDEX -SET -SET -SET - ?column? | qnodes -----------+---------- - scan_seq | Seq Scan -(1 row) - - p +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) - ?column? | qnodes -----------+---------- - scan_seq | Seq Scan +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) - p +SELECT * FROM test_points WHERE p && sbox '( (10d,10d), (20d,20d) )'; + p ----------------------------------------- (0.349065850398866 , 0.174532925199433) (1 row) -SET -SET -SET - ?column? | qnodes -----------+------------------------------------ - scan_idx | Bitmap Heap Scan,Bitmap Index Scan +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) - p +SELECT * FROM test_points WHERE p <@ sbox '( (10d,10d), (20d,20d) )'; + p ----------------------------------------- (0.349065850398866 , 0.174532925199433) (1 row) - ?column? | qnodes -----------+------------------------------------ - scan_idx | Bitmap Heap Scan,Bitmap Index Scan +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) - p +SELECT * FROM test_points WHERE p && sbox '( (10d,10d), (20d,20d) )'; + p ----------------------------------------- (0.349065850398866 , 0.174532925199433) (1 row) -DROP INDEX -DROP TABLE -DROP FUNCTION -SET -SET -SET +-- 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/pgs_brin.sql.in b/pgs_brin.sql.in index 93fe8dd..4b0fba5 100644 --- a/pgs_brin.sql.in +++ b/pgs_brin.sql.in @@ -406,6 +406,8 @@ ALTER OPERATOR FAMILY brin_inclusion_spheric_ops USING brin ADD OPERATOR 7 @>(sbox, spoint), OPERATOR 7 @>(spoint, sbox), OPERATOR 8 <@(sbox, spoint), - OPERATOR 8 <@(spoint, sbox); - + OPERATOR 8 <@(spoint, sbox), + OPERATOR 3 &&(sbox, sbox), + OPERATOR 7 @>(sbox, sbox), + OPERATOR 8 <@(sbox, sbox); 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 index b03508d..4a37f37 100644 --- a/sql/spoint_brin.sql +++ b/sql/spoint_brin.sql @@ -93,7 +93,7 @@ BEGIN FOR exp IN EXECUTE 'EXPLAIN ' || q LOOP --RAISE NOTICE 'EXP: %', exp; - mat := regexp_matches(exp, ' *(?:-> *)?(.*Scan)'); + 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]); diff --git a/brin.c b/src/brin.c similarity index 95% rename from brin.c rename to src/brin.c index 5a5ae03..1c5ae1b 100644 --- a/brin.c +++ b/src/brin.c @@ -53,7 +53,7 @@ spoint_brin_inclusion_add_value(PG_FUNCTION_ARGS) PG_RETURN_BOOL(true); } - spherepoint_gen_key(&spointkey, newval); + spherepoint_gen_key(spointkey, newval); /* * If spherekey pointer is NULL, we consider the spoint entry as 'empty'. @@ -61,6 +61,7 @@ spoint_brin_inclusion_add_value(PG_FUNCTION_ARGS) * 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])) @@ -71,6 +72,7 @@ spoint_brin_inclusion_add_value(PG_FUNCTION_ARGS) PG_RETURN_BOOL(false); } + */ /* if the recorded value is null, we just need to store the spherekey */ if (column->bv_allnulls) @@ -121,7 +123,7 @@ sbox_brin_inclusion_add_value(PG_FUNCTION_ARGS) PG_RETURN_BOOL(true); } - spherebox_gen_key(&sboxkey, newval); + spherebox_gen_key(sboxkey, newval); /* * If spherekey pointer is NULL, we consider the spoint entry as 'empty'. @@ -129,6 +131,7 @@ sbox_brin_inclusion_add_value(PG_FUNCTION_ARGS) * 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])) @@ -139,6 +142,7 @@ sbox_brin_inclusion_add_value(PG_FUNCTION_ARGS) PG_RETURN_BOOL(false); } + */ /* if the recorded value is null, we just need to store the spherekey */ if (column->bv_allnulls) @@ -178,7 +182,7 @@ spoint_overlaps_spherekey(PG_FUNCTION_ARGS) SPoint *p1 = (SPoint *) PG_GETARG_POINTER(0); int32 *k2 = (int32 *) PG_GETARG_POINTER(1); - spherepoint_gen_key(&k1, p1); + spherepoint_gen_key(k1, p1); if (spherekey_interleave(k1, k2) == SCKEY_OVERLAP) { PG_RETURN_BOOL(true); @@ -194,7 +198,7 @@ spoint_contains_spherekey(PG_FUNCTION_ARGS) SPoint *p1 = (SPoint *) PG_GETARG_POINTER(0); int32 *k2 = (int32 *) PG_GETARG_POINTER(1); - spherepoint_gen_key(&k1, p1); + spherepoint_gen_key(k1, p1); if (spherekey_interleave(k1, k2) == SCKEY_IN) { PG_RETURN_BOOL(true); @@ -210,7 +214,7 @@ spoint_iscontained_spherekey(PG_FUNCTION_ARGS) SPoint *p1 = (SPoint *) PG_GETARG_POINTER(0); int32 *k2 = (int32 *) PG_GETARG_POINTER(1); - spherepoint_gen_key(&k1, p1); + spherepoint_gen_key(k1, p1); if (spherekey_interleave(k2, k1) == SCKEY_IN) { PG_RETURN_BOOL(true); @@ -226,7 +230,7 @@ sbox_overlaps_spherekey(PG_FUNCTION_ARGS) SBOX *p1 = (SBOX *) PG_GETARG_POINTER(0); int32 *k2 = (int32 *) PG_GETARG_POINTER(1); - spherebox_gen_key(&k1, p1); + spherebox_gen_key(k1, p1); if (spherekey_interleave(k1, k2) == SCKEY_OVERLAP) { PG_RETURN_BOOL(true); @@ -242,7 +246,7 @@ sbox_contains_spherekey(PG_FUNCTION_ARGS) SBOX *p1 = (SBOX *) PG_GETARG_POINTER(0); int32 *k2 = (int32 *) PG_GETARG_POINTER(1); - spherebox_gen_key(&k1, p1); + spherebox_gen_key(k1, p1); if (spherekey_interleave(k1, k2) == SCKEY_IN) { PG_RETURN_BOOL(true); @@ -258,7 +262,7 @@ sbox_iscontained_spherekey(PG_FUNCTION_ARGS) SBOX *p1 = (SBOX *) PG_GETARG_POINTER(0); int32 *k2 = (int32 *) PG_GETARG_POINTER(1); - spherebox_gen_key(&k1, p1); + spherebox_gen_key(k1, p1); if (spherekey_interleave(k2, k1) == SCKEY_IN) { PG_RETURN_BOOL(true); @@ -317,8 +321,8 @@ spoint_overlaps_sbox(PG_FUNCTION_ARGS) int32 k2[6]; SBOX *p2 = (SBOX *) PG_GETARG_POINTER(1); - spherepoint_gen_key(&k1, p1); - spherebox_gen_key(&k2, p2); + spherepoint_gen_key(k1, p1); + spherebox_gen_key(k2, p2); if (spherekey_interleave(k1, k2) == SCKEY_OVERLAP) { @@ -336,8 +340,8 @@ sbox_iscontained_spoint(PG_FUNCTION_ARGS) int32 k2[6]; SPoint *p2 = (SPoint *) PG_GETARG_POINTER(1); - spherebox_gen_key(&k1, p1); - spherepoint_gen_key(&k2, p2); + spherebox_gen_key(k1, p1); + spherepoint_gen_key(k2, p2); if (spherekey_interleave(k1, k2) == SCKEY_IN) { diff --git a/brin.h b/src/brin.h similarity index 100% rename from brin.h rename to src/brin.h From 752900a42f7f87fe5cf1f54337fbbd406a65a6d7 Mon Sep 17 00:00:00 2001 From: Vitaly Davydov Date: Wed, 30 Aug 2023 18:23:05 +0300 Subject: [PATCH 19/19] Fix pg_sphere--1.2.3--1.3.0 upgrade script (add brin support) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2589494..c3351cb 100644 --- a/Makefile +++ b/Makefile @@ -263,7 +263,7 @@ 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 > $@ + cat upgrade_scripts/$@.in $^ > $@ # end of local stuff