├── healpix_bare ├── NEWS ├── README ├── LICENSE └── test.c ├── pgindent-excludes.list ├── expected ├── init_test.out ├── init.out ├── version.out ├── init_extended.out ├── moc_options.out ├── moc_options_1.out ├── knn.out ├── spoint_brin.out ├── sbox_brin.out ├── euler.out ├── line.out └── epochprop.out ├── doc ├── img │ ├── logo.png │ ├── logo.xcf │ ├── sbox.jpg │ ├── smoc.png │ ├── sline.jpg │ ├── spath.jpg │ ├── sphere.jpg │ ├── sphere.xcf │ ├── spoint.jpg │ ├── spoly.jpg │ ├── strans.jpg │ ├── scircle.jpg │ ├── sellipse.jpg │ └── Makefile ├── faq.sgm ├── stylesheets │ ├── stylesheet.css.xml │ ├── stylesheet-html-nochunk.xsl │ ├── stylesheet-text.xsl │ ├── stylesheet.css │ ├── stylesheet-common.xsl │ └── stylesheet-speedup-common.xsl ├── pg_sphere.xml ├── appendixes.sgm ├── whatis.sgm ├── install.sgm ├── Makefile └── examples.sgm ├── upgrade_scripts ├── pg_sphere--1.2.2--1.2.3.sql.in ├── pg_sphere--1.3.0--1.3.1.sql.in ├── pg_sphere--1.5.1--1.5.2.sql.in ├── pg_sphere--1.2.0--1.2.1.sql.in ├── pg_sphere--1.0--1.0_gavo.sql.in ├── pg_sphere--1.1.5--1.1.5.1.sql.in ├── pg_sphere--1.1.5beta4gavo--1.2.0.sql.in ├── pg_sphere--1.1.5_from_2015-08-31--1.1.5.sql.in ├── pg_sphere--1.1.5_from_2016-02-07--1.1.5.sql.in ├── pg_sphere--1.0_gavo--1.1.5beta0gavo.sql.in ├── pg_sphere--1.1.5beta0gavo--1.1.5beta2gavo.sql.in ├── pg_sphere--1.1.5beta2gavo--1.1.5beta4gavo.sql.in ├── pg_sphere--1.0--1.1.5_from_2015-08-31.sql.in ├── pg_sphere--1.0--1.1.5_from_2016-02-07.sql.in ├── pg_sphere--1.5.0--1.5.1.sql.in ├── pg_sphere--1.4.2--1.5.0.sql.in ├── pgs_gist_drop_spoint2.sql.in ├── contains-ops-fixes-2.sql.in ├── contains-ops-fixes-1.sql.in ├── pg_sphere--1.3.1--1.4.0.sql.in ├── pg_sphere--1.2.1--1.2.2-healpix.sql.in ├── pgs_gist_contains_ops.sql.in └── pg_sphere--1.2.3--1.3.0.sql.in ├── sql ├── init.sql ├── version.sql ├── init_test.sql ├── init_extended.sql ├── knn.sql ├── moc_options.sql ├── tables.sql ├── euler.sql ├── gist_support.sql ├── selectivity.sql ├── output_precision.sql ├── epochprop.sql ├── line.sql ├── index.sql ├── bounding_box_gist.sql ├── circle_extended.sql └── mocautocast.sql ├── pg_sphere_head.sql.in ├── pg_sphere.control ├── .editorconfig ├── src ├── gnomo.h ├── pgs_chealpix.h ├── epochprop.h ├── types.h ├── vector3d.c ├── pgs_healpix.h ├── vector3d.h ├── pgs_util.h ├── brin.h ├── sscan.l ├── gnomo.c ├── point.h ├── sparse.h ├── gq_cache.c ├── circle.h └── euler.h ├── Makefile.common.mk ├── pgs_moc_options.sql.in ├── .gitignore ├── pgs_gist_support.sql.in ├── pgs_hash.sql.in ├── gnomo.sql.in ├── .gitlab-ci.yml ├── testsuite ├── gen_box.pl ├── gen_point.pl ├── gen_circle.pl └── gen_poly.pl ├── CONTRIBUTING.md ├── pgs_gist_pointkey.sql.in ├── pgs_epochprop.sql.in ├── .github └── workflows │ ├── deploy-docs.yml │ ├── build-and-check.yml │ └── build-and-check-windows-latest.yml ├── COPYRIGHT.pg_sphere ├── HACKING ├── pgs_gist_spoint3.sql.in ├── README.pg_sphere ├── data ├── test_spherepath.data └── test_spherepolygon.data ├── pgindent-typedefs.list ├── pgs_moc_type.sql.in ├── pgs_types.sql.in ├── pgs_circle_sel.sql.in └── healpix.sql.in /healpix_bare/NEWS: -------------------------------------------------------------------------------- 1 | Version 1.0 (March 2019): 2 | initial release 3 | -------------------------------------------------------------------------------- /pgindent-excludes.list: -------------------------------------------------------------------------------- 1 | pgs_process_moc.h 2 | pgs_healpix.h 3 | pgs_moc.h 4 | -------------------------------------------------------------------------------- /expected/init_test.out: -------------------------------------------------------------------------------- 1 | SET client_min_messages TO WARNING; 2 | \set ECHO none 3 | -------------------------------------------------------------------------------- /doc/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postgrespro/pgsphere/HEAD/doc/img/logo.png -------------------------------------------------------------------------------- /doc/img/logo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postgrespro/pgsphere/HEAD/doc/img/logo.xcf -------------------------------------------------------------------------------- /doc/img/sbox.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postgrespro/pgsphere/HEAD/doc/img/sbox.jpg -------------------------------------------------------------------------------- /doc/img/smoc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postgrespro/pgsphere/HEAD/doc/img/smoc.png -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.2.2--1.2.3.sql.in: -------------------------------------------------------------------------------- 1 | -- Nothing to upgrade in the schema 2 | -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.3.0--1.3.1.sql.in: -------------------------------------------------------------------------------- 1 | -- Nothing to upgrade in the schema 2 | -------------------------------------------------------------------------------- /doc/img/sline.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postgrespro/pgsphere/HEAD/doc/img/sline.jpg -------------------------------------------------------------------------------- /doc/img/spath.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postgrespro/pgsphere/HEAD/doc/img/spath.jpg -------------------------------------------------------------------------------- /doc/img/sphere.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postgrespro/pgsphere/HEAD/doc/img/sphere.jpg -------------------------------------------------------------------------------- /doc/img/sphere.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postgrespro/pgsphere/HEAD/doc/img/sphere.xcf -------------------------------------------------------------------------------- /doc/img/spoint.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postgrespro/pgsphere/HEAD/doc/img/spoint.jpg -------------------------------------------------------------------------------- /doc/img/spoly.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postgrespro/pgsphere/HEAD/doc/img/spoly.jpg -------------------------------------------------------------------------------- /doc/img/strans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postgrespro/pgsphere/HEAD/doc/img/strans.jpg -------------------------------------------------------------------------------- /sql/init.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- Initialize the extension. 3 | -- 4 | CREATE EXTENSION pg_sphere; 5 | -------------------------------------------------------------------------------- /sql/version.sql: -------------------------------------------------------------------------------- 1 | -- Check current pgsphere version 2 | SELECT pg_sphere_version(); 3 | 4 | -------------------------------------------------------------------------------- /doc/img/scircle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postgrespro/pgsphere/HEAD/doc/img/scircle.jpg -------------------------------------------------------------------------------- /doc/img/sellipse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postgrespro/pgsphere/HEAD/doc/img/sellipse.jpg -------------------------------------------------------------------------------- /expected/init.out: -------------------------------------------------------------------------------- 1 | -- 2 | -- Initialize the extension. 3 | -- 4 | CREATE EXTENSION pg_sphere; 5 | -------------------------------------------------------------------------------- /sql/init_test.sql: -------------------------------------------------------------------------------- 1 | SET client_min_messages TO WARNING; 2 | \set ECHO none 3 | \i pg_sphere.test.sql 4 | -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.5.1--1.5.2.sql.in: -------------------------------------------------------------------------------- 1 | -- Upgrade: 1.5.1 -> 1.5.2 2 | -- Nothing to do yet 3 | -------------------------------------------------------------------------------- /pg_sphere_head.sql.in: -------------------------------------------------------------------------------- 1 | -- complain if this script is run via psql 2 | \echo Use "CREATE EXTENSION pg_sphere" to load this file. \quit 3 | -------------------------------------------------------------------------------- /doc/faq.sgm: -------------------------------------------------------------------------------- 1 | 2 | 3 | FAQ 4 | 5 | 6 | tbw 7 | 8 | 9 | -------------------------------------------------------------------------------- /expected/version.out: -------------------------------------------------------------------------------- 1 | -- Check current pgsphere version 2 | SELECT pg_sphere_version(); 3 | pg_sphere_version 4 | ------------------- 5 | 1.5.2 6 | (1 row) 7 | 8 | -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.2.0--1.2.1.sql.in: -------------------------------------------------------------------------------- 1 | -- complain if this upgrade script is run via psql 2 | \echo Use "ALTER EXTENSION pg_sphere UPDATE TO '1.2.1'" to load this file. \quit 3 | -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.0--1.0_gavo.sql.in: -------------------------------------------------------------------------------- 1 | -- complain if this upgrade script is run via psql 2 | \echo Use "ALTER EXTENSION pg_sphere UPDATE TO '1.0_gavo'" to load this file. \quit 3 | -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.1.5--1.1.5.1.sql.in: -------------------------------------------------------------------------------- 1 | -- complain if this upgrade script is run via psql 2 | \echo Use "ALTER EXTENSION pg_sphere UPDATE TO '1.1.5.1'" to load this file. \quit 3 | -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.1.5beta4gavo--1.2.0.sql.in: -------------------------------------------------------------------------------- 1 | -- complain if this upgrade script is run via psql 2 | \echo Use "ALTER EXTENSION pg_sphere UPDATE TO '1.2.0'" to load this file. \quit 3 | -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.1.5_from_2015-08-31--1.1.5.sql.in: -------------------------------------------------------------------------------- 1 | -- complain if this upgrade script is run via psql 2 | \echo Use "ALTER EXTENSION pg_sphere UPDATE TO '1.1.5'" to load this file. \quit 3 | -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.1.5_from_2016-02-07--1.1.5.sql.in: -------------------------------------------------------------------------------- 1 | -- complain if this upgrade script is run via psql 2 | \echo Use "ALTER EXTENSION pg_sphere UPDATE TO '1.1.5'" to load this file. \quit 3 | -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.0_gavo--1.1.5beta0gavo.sql.in: -------------------------------------------------------------------------------- 1 | -- complain if this upgrade script is run via psql 2 | \echo Use "ALTER EXTENSION pg_sphere UPDATE TO '1.1.5beta0gavo'" to load this file. \quit 3 | -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.1.5beta0gavo--1.1.5beta2gavo.sql.in: -------------------------------------------------------------------------------- 1 | -- complain if this upgrade script is run via psql 2 | \echo Use "ALTER EXTENSION pg_sphere UPDATE TO '1.1.5beta2gavo'" to load this file. \quit 3 | -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.1.5beta2gavo--1.1.5beta4gavo.sql.in: -------------------------------------------------------------------------------- 1 | -- complain if this upgrade script is run via psql 2 | \echo Use "ALTER EXTENSION pg_sphere UPDATE TO '1.1.5beta4gavo'" to load this file. \quit 3 | -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.0--1.1.5_from_2015-08-31.sql.in: -------------------------------------------------------------------------------- 1 | -- complain if this upgrade script is run via psql 2 | \echo Use "ALTER EXTENSION pg_sphere UPDATE TO '1.1.5_from_2015-08-31'" to load this file. \quit 3 | -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.0--1.1.5_from_2016-02-07.sql.in: -------------------------------------------------------------------------------- 1 | -- complain if this upgrade script is run via psql 2 | \echo Use "ALTER EXTENSION pg_sphere UPDATE TO '1.1.5_from_2016-02-07'" to load this file. \quit 3 | -------------------------------------------------------------------------------- /pg_sphere.control: -------------------------------------------------------------------------------- 1 | # pg_sphere extension 2 | comment = 'spherical objects with useful functions, operators and index support' 3 | default_version = '1.5.2' 4 | module_pathname = '$libdir/pg_sphere' 5 | relocatable = true 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{c,cpp,h,l,y,pl,pm}] 4 | indent_style = tab 5 | indent_size = tab 6 | tab_width = 4 7 | 8 | [*.{sgml,xml}] 9 | indent_style = space 10 | indent_size = 1 11 | 12 | [*.xsl] 13 | indent_style = space 14 | indent_size = 2 15 | -------------------------------------------------------------------------------- /doc/stylesheets/stylesheet.css.xml: -------------------------------------------------------------------------------- 1 | 5 | 7 | ]> 8 | 9 | -------------------------------------------------------------------------------- /src/gnomo.h: -------------------------------------------------------------------------------- 1 | #ifndef __GNOMO_H__ 2 | #define __GNOMO_H__ 3 | 4 | /* function prototypes for the direct and inverse gnomonic projections */ 5 | 6 | extern Datum gnomonic_proj(PG_FUNCTION_ARGS); 7 | extern Datum gnomonic_inv(PG_FUNCTION_ARGS); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /Makefile.common.mk: -------------------------------------------------------------------------------- 1 | #---------------------------------------------------------------------------- 2 | # 3 | # pgSphere common definitions 4 | # 5 | #---------------------------------------------------------------------------- 6 | 7 | EXTENSION := pg_sphere 8 | PGSPHERE_VERSION := 1.5.2 9 | -------------------------------------------------------------------------------- /pgs_moc_options.sql.in: -------------------------------------------------------------------------------- 1 | -- GIN opclass options 2 | 3 | CREATE FUNCTION smoc_gin_options (internal) 4 | RETURNS void 5 | AS 'MODULE_PATHNAME' 6 | LANGUAGE C 7 | PARALLEL SAFE 8 | IMMUTABLE 9 | STRICT; 10 | 11 | ALTER OPERATOR FAMILY smoc_gin_ops USING gin 12 | ADD FUNCTION 7 (smoc) smoc_gin_options (internal); 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.bc 2 | *.o 3 | *.so 4 | /*.sql 5 | /doc/html/ 6 | /doc/pg_sphere*.fo 7 | /doc/pg_sphere-*.html 8 | /doc/pg_sphere-*.pdf 9 | /doc/pg_sphere-full.xml 10 | /doc/pg_sphere.dsl 11 | /doc/version.xml 12 | /log 13 | /results/ 14 | regression.out 15 | regression.diffs 16 | tags 17 | /tmp_check 18 | buildpod 19 | .deps 20 | -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.5.0--1.5.1.sql.in: -------------------------------------------------------------------------------- 1 | -- Upgrade: 1.5.0 -> 1.5.1 2 | 3 | DO $$ 4 | BEGIN 5 | ALTER OPERATOR FAMILY spoint USING gist ADD 6 | OPERATOR 17 <-> (spoint, spoint) FOR ORDER BY float_ops; 7 | EXCEPTION 8 | WHEN duplicate_object THEN NULL; 9 | WHEN OTHERS THEN RAISE; 10 | END; 11 | $$; 12 | -------------------------------------------------------------------------------- /doc/img/Makefile: -------------------------------------------------------------------------------- 1 | # Graphics 2 | 3 | EPS = logo.eps sbox.eps scircle.eps sellipse.eps sline.eps spath.eps sphere.eps spoint.eps spoly.eps strans.eps 4 | 5 | CONVERT = convert 6 | 7 | all: eps 8 | 9 | eps : $(EPS) 10 | 11 | %.eps: %.jpg 12 | $(CONVERT) $< eps:$@ 13 | 14 | %.eps: %.png 15 | $(CONVERT) $< eps:$@ 16 | 17 | clean : 18 | rm -f $(EPS) 19 | -------------------------------------------------------------------------------- /src/pgs_chealpix.h: -------------------------------------------------------------------------------- 1 | #ifndef __PGS_CHEALPIX_H__ 2 | #define __PGS_CHEALPIX_H__ 3 | 4 | #include 5 | #include /* PostgreSQL type definitions */ 6 | /* 7 | * Actually, chealpix changed its API: thus, this file must be included first, 8 | * directly or indirectly. 9 | */ 10 | 11 | #define MOC_FORMAT_64 INT64_FORMAT 12 | #define MOC_FORMAT_64U UINT64_FORMAT 13 | 14 | typedef int64 hpint64; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /pgs_gist_support.sql.in: -------------------------------------------------------------------------------- 1 | -- PG12+ has support functions 2 | 3 | CREATE FUNCTION spoint_dwithin_supportfn (internal) 4 | RETURNS internal 5 | AS 'MODULE_PATHNAME', 'spherepoint_dwithin_supportfn' 6 | LANGUAGE 'c'; 7 | 8 | COMMENT ON FUNCTION spoint_dwithin_supportfn(internal) IS 9 | 'support function for spoint_dwithin'; 10 | 11 | ALTER FUNCTION spoint_dwithin(spoint, spoint, float8) 12 | SUPPORT spoint_dwithin_supportfn; 13 | -------------------------------------------------------------------------------- /sql/init_extended.sql: -------------------------------------------------------------------------------- 1 | -- indexed operations..... 2 | 3 | -- spoint_data and scircle_data tables have to be created and indexed using 4 | 5 | \! perl testsuite/gen_point.pl 1 > results/gen_point_1.sql 6 | \i results/gen_point_1.sql 7 | 8 | -- and 9 | 10 | \! perl testsuite/gen_circle.pl 1 0.1 > results/gen_circle_1_0.1.sql 11 | \i results/gen_circle_1_0.1.sql 12 | 13 | -- 14 | 15 | \! perl testsuite/gen_poly.pl 1 0.1 4 > results/gen_poly_1_0.1_4.sql 16 | \i results/gen_poly_1_0.1_4.sql 17 | -------------------------------------------------------------------------------- /src/epochprop.h: -------------------------------------------------------------------------------- 1 | /* Definitions for handling proper motions */ 2 | 3 | #include 4 | 5 | 6 | extern Datum epoch_prop(PG_FUNCTION_ARGS); 7 | 8 | 9 | typedef struct s_phasevec 10 | { 11 | SPoint pos; /* Position as an SPoint */ 12 | double pm[2]; /* Proper motion long/lat in rad/year, PM in 13 | * longitude has cos(lat) applied */ 14 | double parallax; /* in rad */ 15 | double rv; /* radial velocity in km/s */ 16 | int parallax_valid; /* 1 if we accept the parallax as physical */ 17 | } phasevec; 18 | -------------------------------------------------------------------------------- /pgs_hash.sql.in: -------------------------------------------------------------------------------- 1 | CREATE FUNCTION spoint_hash32 (spoint) 2 | RETURNS int 3 | IMMUTABLE STRICT 4 | PARALLEL SAFE 5 | LANGUAGE C 6 | AS 'MODULE_PATHNAME', 'spherepoint_hash32'; 7 | 8 | UPDATE pg_operator 9 | SET oprcanhash = true 10 | WHERE oprname = '=' AND 11 | oprleft = 'spoint'::regtype AND oprright = 'spoint'::regtype; 12 | 13 | /* PG17: ALTER OPERATOR = (spoint, spoint) SET (HASHES); */ 14 | 15 | CREATE OPERATOR CLASS spoint_hash_ops 16 | DEFAULT FOR TYPE spoint USING hash 17 | AS 18 | OPERATOR 1 = (spoint, spoint), 19 | FUNCTION 1 spoint_hash32(spoint); 20 | -------------------------------------------------------------------------------- /gnomo.sql.in: -------------------------------------------------------------------------------- 1 | -- gnomonic projection and its inverse 2 | 3 | CREATE OR REPLACE FUNCTION gnomonic_proj(spoint, spoint) 4 | RETURNS point 5 | AS 'MODULE_PATHNAME' 6 | LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; 7 | 8 | COMMENT ON FUNCTION gnomonic_proj(spoint, spoint) IS 9 | 'gnomonic projection, the second argument is the tangential point'; 10 | 11 | CREATE OR REPLACE FUNCTION gnomonic_inv(point, spoint) 12 | RETURNS spoint 13 | AS 'MODULE_PATHNAME' 14 | LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; 15 | 16 | COMMENT ON FUNCTION gnomonic_inv(point, spoint) IS 17 | 'inverse of gnomonic projection, the second argument is the tangential point'; 18 | -------------------------------------------------------------------------------- /src/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __PGS_TYPES_H__ 2 | #define __PGS_TYPES_H__ 3 | 4 | /* Include this file if you want to have access to all data types. */ 5 | 6 | /* 7 | * box was the last added data type 8 | */ 9 | #include "box.h" 10 | 11 | /* PGS_DATA_TYPES Data type IDs */ 12 | #define PGS_TYPE_SPoint 1 /* Spherical point */ 13 | #define PGS_TYPE_SCIRCLE 2 /* Spherical circle */ 14 | #define PGS_TYPE_SELLIPSE 3 /* Spherical ellipse */ 15 | #define PGS_TYPE_SLine 4 /* Spherical line */ 16 | #define PGS_TYPE_SPATH 5 /* Spherical path */ 17 | #define PGS_TYPE_SPOLY 6 /* Spherical polygon */ 18 | #define PGS_TYPE_SBOX 7 /* Spherical box */ 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.4.2--1.5.0.sql.in: -------------------------------------------------------------------------------- 1 | -- Upgrade: 1.4.2 -> 1.5.0 2 | 3 | CREATE OR REPLACE FUNCTION g_spoint_distance(internal, spoint, smallint, oid, internal) 4 | RETURNS internal 5 | AS 'MODULE_PATHNAME', 'g_spoint_distance' 6 | LANGUAGE 'c'; 7 | 8 | DO $$ 9 | BEGIN 10 | ALTER OPERATOR FAMILY spoint USING gist ADD 11 | FUNCTION 8 (spoint, spoint) g_spoint_distance (internal, spoint, smallint, oid, internal); 12 | EXCEPTION 13 | WHEN duplicate_object THEN NULL; 14 | WHEN OTHERS THEN RAISE; 15 | END; 16 | $$; 17 | 18 | CREATE FUNCTION reset_sphere_output_precision() 19 | RETURNS CSTRING 20 | AS 'MODULE_PATHNAME', 'reset_sphere_output_precision' 21 | LANGUAGE 'c'; 22 | -------------------------------------------------------------------------------- /sql/knn.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE points (id int, p spoint, pos int); 2 | INSERT INTO points (id, p) SELECT x, spoint(random()*6.28, (2*random()-1)*1.57) FROM generate_series(1,314159) x; 3 | CREATE INDEX i ON points USING gist (p); 4 | SET enable_indexscan = true; 5 | EXPLAIN (costs off) SELECT p <-> spoint (0.2, 0.3) FROM points ORDER BY 1 LIMIT 100; 6 | UPDATE points SET pos = n FROM 7 | (SELECT id, row_number() OVER (ORDER BY p <-> spoint (0.2, 0.3)) n FROM points ORDER BY p <-> spoint (0.2, 0.3) LIMIT 100) sel 8 | WHERE points.id = sel.id; 9 | SET enable_indexscan = false; 10 | SELECT pos, row_number() OVER (ORDER BY p <-> spoint (0.2, 0.3)) n FROM points ORDER BY p <-> spoint (0.2, 0.3) LIMIT 100; 11 | DROP TABLE points; 12 | 13 | -------------------------------------------------------------------------------- /sql/moc_options.sql: -------------------------------------------------------------------------------- 1 | create table moc_opt (m smoc); 2 | insert into moc_opt select format('9/%s', i)::smoc from generate_series(1, 1000) g(i); 3 | analyze moc_opt; 4 | 5 | create index moc_opt5 on moc_opt using gin (m); 6 | explain (analyze, costs off, timing off, summary off, buffers off) select * from moc_opt where m && '9/1'; 7 | drop index moc_opt5; 8 | 9 | create index moc_opt8 on moc_opt using gin (m smoc_gin_ops_fine); 10 | explain (analyze, costs off, timing off, summary off, buffers off) select * from moc_opt where m && '9/1'; 11 | drop index moc_opt8; 12 | 13 | create index moc_opt9 on moc_opt using gin (m smoc_gin_ops (order = 9)); 14 | explain (analyze, costs off, timing off, summary off, buffers off) select * from moc_opt where m && '9/1'; 15 | -------------------------------------------------------------------------------- /upgrade_scripts/pgs_gist_drop_spoint2.sql.in: -------------------------------------------------------------------------------- 1 | DROP OPERATOR CLASS IF EXISTS spoint2 USING gist CASCADE; 2 | DROP FUNCTION IF EXISTS g_spoint2_union(bytea, internal) CASCADE; 3 | DROP FUNCTION IF EXISTS g_spoint2_penalty (internal, internal, internal) CASCADE; 4 | DROP FUNCTION IF EXISTS g_spoint2_picksplit(internal, internal) CASCADE; 5 | DROP FUNCTION IF EXISTS g_spoint2_same (bytea, bytea, internal) CASCADE; 6 | DROP FUNCTION IF EXISTS g_spoint2_compress(internal) CASCADE; 7 | DROP FUNCTION IF EXISTS g_spoint2_consistent(internal, internal, int4, oid, internal) CASCADE; 8 | DROP FUNCTION IF EXISTS g_spoint2_distance(internal, internal, int4, oid) CASCADE; 9 | 10 | DROP FUNCTION IF EXISTS crossmatch(text, text, float8); 11 | DROP FUNCTION IF EXISTS crossmatch(text, text, float8, sbox); 12 | -------------------------------------------------------------------------------- /expected/init_extended.out: -------------------------------------------------------------------------------- 1 | -- indexed operations..... 2 | -- spoint_data and scircle_data tables have to be created and indexed using 3 | \! perl testsuite/gen_point.pl 1 > results/gen_point_1.sql 4 | \i results/gen_point_1.sql 5 | CREATE TABLE spoint_data (sp spoint); 6 | COPY spoint_data (sp) FROM stdin; 7 | CREATE INDEX sp_idx ON spoint_data USING gist (sp); 8 | -- and 9 | \! perl testsuite/gen_circle.pl 1 0.1 > results/gen_circle_1_0.1.sql 10 | \i results/gen_circle_1_0.1.sql 11 | CREATE TABLE scircle_data (sc scircle); 12 | COPY scircle_data (sc) FROM stdin; 13 | CREATE INDEX sc_idx ON scircle_data USING gist (sc); 14 | -- 15 | \! perl testsuite/gen_poly.pl 1 0.1 4 > results/gen_poly_1_0.1_4.sql 16 | \i results/gen_poly_1_0.1_4.sql 17 | CREATE TABLE spoly_data (sp spoly); 18 | COPY spoly_data (sp) FROM stdin; 19 | CREATE INDEX spl_idx ON spoly_data USING gist (sp); 20 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | - build 3 | 4 | .build: &build 5 | stage: build 6 | image: credativ/postgresql-build:${PGVERSION} 7 | before_script: 8 | - apt-get -y install libhealpix-cxx-dev docbook-dsssl docbook-xml openjade 9 | script: 10 | - make PROFILE="-Werror" 11 | - make install 12 | - if ! pg_virtualenv make installcheck; then cat regression.diffs; exit 1; fi 13 | - make -C doc 14 | - make -C doc install 15 | 16 | build:9.4: { <<: *build, variables: { PGVERSION: '9.4' } } 17 | build:9.5: { <<: *build, variables: { PGVERSION: '9.5' } } 18 | build:9.6: { <<: *build, variables: { PGVERSION: '9.6' } } 19 | build:10: { <<: *build, variables: { PGVERSION: '10' } } 20 | build:11: { <<: *build, variables: { PGVERSION: '11' } } 21 | build:12: { <<: *build, variables: { PGVERSION: '12' } } 22 | build:13: { <<: *build, variables: { PGVERSION: '13' } } 23 | -------------------------------------------------------------------------------- /testsuite/gen_box.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | my $diff=$ARGV[0]; 4 | 5 | if ($#ARGV < 0) { 6 | print "gen_box.pl: Generic pg_sphere \"sbox\" data generator\n"; 7 | print "usage:\n\tgen_box.pl | psql pgsphere_db\n\n"; 8 | 9 | print "Program generates not overlapping spherical boxes.\n"; 10 | print "Each box has a size of degrees in longitude and\n"; 11 | print "latitude\n"; 12 | exit(0); 13 | } 14 | 15 | print < 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | First off, thanks for taking the time to contribute! ❤️ 2 | 3 | All types of contributions are encouraged and valued. See the Table of Contents for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 4 | 5 | # Table of Contents 6 | - [Project Scope](#project-scope) 7 | - [Development Plans](#development-plans) 8 | 9 | # Project Scope 10 | - Types. 11 | - Operations on types (creating, searching, sorting, set operations and others). 12 | - Indexing structures and algorithms. 13 | 14 | # Development Plans 15 | - Move all source files into src folder. 16 | - Implement optional compilation with HEALPIX and SMOC. 17 | - Use pgindent to format sources. 18 | - Check compilation with newest postgrespro versions. 19 | - Add more tests including performance tests. 20 | - Add more documentation. 21 | -------------------------------------------------------------------------------- /src/vector3d.c: -------------------------------------------------------------------------------- 1 | #include "vector3d.h" 2 | 3 | /* Vector functions */ 4 | 5 | bool 6 | vector3d_eq(const Vector3D *v1, const Vector3D *v2) 7 | { 8 | return (FPeq(v1->x, v2->x) && 9 | FPeq(v1->y, v2->y) && 10 | FPeq(v1->z, v2->z)); 11 | } 12 | 13 | void 14 | vector3d_cross(Vector3D *out, const Vector3D *v1, const Vector3D *v2) 15 | { 16 | out->x = v1->y * v2->z - v1->z * v2->y; 17 | out->y = v1->z * v2->x - v1->x * v2->z; 18 | out->z = v1->x * v2->y - v1->y * v2->x; 19 | } 20 | 21 | void 22 | vector3d_addwithscalar(Vector3D *result, double scalar, const Vector3D *delta) 23 | { 24 | result->x = result->x + delta->x * scalar; 25 | result->y = result->y + delta->y * scalar; 26 | result->z = result->z + delta->z * scalar; 27 | } 28 | 29 | float8 30 | vector3d_scalar(Vector3D *v1, Vector3D *v2) 31 | { 32 | float8 out = 0; 33 | 34 | out += v1->x * v2->x; 35 | out += v1->y * v2->y; 36 | out += v1->z * v2->z; 37 | return (out); 38 | } 39 | 40 | float8 41 | vector3d_length(const Vector3D *v) 42 | { 43 | return sqrt(Sqr(v->x) + Sqr(v->y) + Sqr(v->z)); 44 | } 45 | -------------------------------------------------------------------------------- /upgrade_scripts/contains-ops-fixes-2.sql.in: -------------------------------------------------------------------------------- 1 | -- fix typo in commutator of OPERATOR !@>(spoly, sellipse) (a.k.a. !~) introduced in commits 2798ed96f9282ddeee21d5ddd3e256bbb9b4f36f and 244c1549c492426b62bc926c9ac2ad21f3ccd0c1 2 | 3 | DROP OPERATOR !@> (spoly, sellipse) CASCADE; 4 | DROP OPERATOR !~ (spoly, sellipse) CASCADE; 5 | 6 | CREATE OPERATOR !@> ( 7 | LEFTARG = spoly, 8 | RIGHTARG = sellipse, 9 | PROCEDURE = spoly_contains_ellipse_neg, 10 | COMMUTATOR = '!<@', 11 | NEGATOR = '@>', 12 | RESTRICT = contsel, 13 | JOIN = contjoinsel 14 | ); 15 | COMMENT ON OPERATOR !@> (spoly, sellipse) IS 'true if spherical polygon (LHS) does not contain spherical ellipse (RHS)'; 16 | 17 | CREATE OPERATOR !~ ( 18 | LEFTARG = spoly, 19 | RIGHTARG = sellipse, 20 | PROCEDURE = spoly_contains_ellipse_neg, 21 | COMMUTATOR = '!@', 22 | NEGATOR = '~', 23 | RESTRICT = contsel, 24 | JOIN = contjoinsel 25 | ); 26 | COMMENT ON OPERATOR !~ (spoly, sellipse) IS 'true if spherical polygon (LHS) does not contain spherical ellipse (RHS)'; 27 | -------------------------------------------------------------------------------- /pgs_gist_pointkey.sql.in: -------------------------------------------------------------------------------- 1 | CREATE FUNCTION pointkey_in(CSTRING) 2 | RETURNS pointkey 3 | AS 'MODULE_PATHNAME', 'pointkey_in' 4 | LANGUAGE 'c' 5 | IMMUTABLE STRICT PARALLEL SAFE; 6 | 7 | 8 | CREATE FUNCTION pointkey_out(pointkey) 9 | RETURNS CSTRING 10 | AS 'MODULE_PATHNAME', 'pointkey_out' 11 | LANGUAGE 'c' 12 | IMMUTABLE STRICT PARALLEL SAFE; 13 | 14 | CREATE FUNCTION pointkey_volume(pointkey) 15 | RETURNS float8 16 | AS 'MODULE_PATHNAME', 'pointkey_volume' 17 | LANGUAGE 'c' 18 | IMMUTABLE STRICT PARALLEL SAFE; 19 | 20 | CREATE FUNCTION pointkey_area(pointkey) 21 | RETURNS float8 22 | AS 'MODULE_PATHNAME', 'pointkey_area' 23 | LANGUAGE 'c' 24 | IMMUTABLE STRICT PARALLEL SAFE; 25 | 26 | CREATE FUNCTION pointkey_perimeter(pointkey) 27 | RETURNS float8 28 | AS 'MODULE_PATHNAME', 'pointkey_perimeter' 29 | LANGUAGE 'c' 30 | IMMUTABLE STRICT PARALLEL SAFE; 31 | 32 | CREATE TYPE pointkey ( 33 | input = pointkey_in, 34 | output = pointkey_out, 35 | internallength = VARIABLE, 36 | ALIGNMENT = double, 37 | STORAGE = PLAIN 38 | ); 39 | -------------------------------------------------------------------------------- /src/pgs_healpix.h: -------------------------------------------------------------------------------- 1 | #ifndef __PGS_HEALPIX_H__ 2 | #define __PGS_HEALPIX_H__ 3 | 4 | /* this goes in front to detect the chealpix API break */ 5 | #include "pgs_chealpix.h" 6 | 7 | #include 8 | #include 9 | 10 | #include "point.h" /* SPoint */ 11 | 12 | int order_invalid(int); 13 | hpint64 c_npix(int); 14 | void check_order(int order); 15 | 16 | /* function prototypes for the Healpix support functions */ 17 | 18 | Datum pg_nest2ring(PG_FUNCTION_ARGS); 19 | Datum pg_ring2nest(PG_FUNCTION_ARGS); 20 | hpint64 c_healpix_convert_nest(hpint64 idx, int32 from_order, int32 to_order); 21 | Datum healpix_convert_nest(PG_FUNCTION_ARGS); 22 | Datum healpix_convert_ring(PG_FUNCTION_ARGS); 23 | Datum pg_nside2order(PG_FUNCTION_ARGS); 24 | Datum pg_order2nside(PG_FUNCTION_ARGS); 25 | Datum pg_nside2npix(PG_FUNCTION_ARGS); 26 | Datum pg_npix2nside(PG_FUNCTION_ARGS); 27 | Datum healpix_nest(PG_FUNCTION_ARGS); 28 | Datum healpix_ring(PG_FUNCTION_ARGS); 29 | Datum inv_healpix_nest(PG_FUNCTION_ARGS); 30 | Datum inv_healpix_ring(PG_FUNCTION_ARGS); 31 | 32 | hpint64 healpix_nest_c(int32, SPoint*); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /pgs_epochprop.sql.in: -------------------------------------------------------------------------------- 1 | -- *********************************** 2 | -- 3 | -- functions for propagating positions 4 | -- 5 | -- *********************************** 6 | 7 | CREATE FUNCTION epoch_prop( 8 | pos spoint, 9 | parallax DOUBLE PRECISION, 10 | pmlng DOUBLE PRECISION, 11 | pmlat DOUBLE PRECISION, 12 | rv DOUBLE PRECISION, 13 | delta_t DOUBLE PRECISION) 14 | RETURNS double precision[6] 15 | AS 'MODULE_PATHNAME', 'epoch_prop' 16 | LANGUAGE 'c' 17 | IMMUTABLE PARALLEL SAFE; 18 | 19 | CREATE FUNCTION epoch_prop_pos( 20 | pos spoint, 21 | parallax DOUBLE PRECISION, 22 | pmlng DOUBLE PRECISION, 23 | pmlat DOUBLE PRECISION, 24 | rv DOUBLE PRECISION, 25 | delta_t DOUBLE PRECISION) 26 | RETURNS spoint 27 | AS $body$ 28 | SELECT spoint(pv[1], pv[2]) 29 | FROM epoch_prop(pos, parallax, pmlng, pmlat, rv, delta_t) as pv 30 | $body$ LANGUAGE SQL STABLE PARALLEL SAFE; 31 | 32 | CREATE FUNCTION epoch_prop_pos( 33 | pos spoint, 34 | pmlng DOUBLE PRECISION, 35 | pmlat DOUBLE PRECISION, 36 | delta_t DOUBLE PRECISION) 37 | RETURNS spoint 38 | AS $body$ 39 | SELECT spoint(pv[1], pv[2]) 40 | FROM epoch_prop(pos, 0, pmlng, pmlat, 0, delta_t) as pv 41 | $body$ LANGUAGE SQL STABLE PARALLEL SAFE; 42 | -------------------------------------------------------------------------------- /src/vector3d.h: -------------------------------------------------------------------------------- 1 | #ifndef __PGS_VECTOR3D_H__ 2 | #define __PGS_VECTOR3D_H__ 3 | 4 | #include "pg_sphere.h" 5 | 6 | /* Vector declarations */ 7 | 8 | /* 9 | * The definition of a three dimensional vector data structure. 10 | */ 11 | typedef struct 12 | { 13 | float8 x; /* x (-1.0 .. 1.0) */ 14 | float8 y; /* y (-1.0 .. 1.0) */ 15 | float8 z; /* z (-1.0 .. 1.0) */ 16 | } Vector3D; 17 | 18 | 19 | /* 20 | * Calculate the cross product of two vectors. Puts 21 | * cross product of v1 and v2 into out and returns it. 22 | */ 23 | extern void vector3d_cross(Vector3D *out, const Vector3D *v1, 24 | const Vector3D *v2); 25 | 26 | /* 27 | * Checks equality of two vectors. 28 | */ 29 | extern bool vector3d_eq(const Vector3D *a, const Vector3D *b); 30 | 31 | /* 32 | * Calculate the scalar product of two vectors. 33 | */ 34 | extern float8 vector3d_scalar(Vector3D *v1, Vector3D *v2); 35 | 36 | /* 37 | * Calculate the length of a vector. 38 | */ 39 | extern float8 vector3d_length(const Vector3D *v); 40 | 41 | /* 42 | * Calculate result + scalar*delta 43 | */ 44 | extern void vector3d_addwithscalar(Vector3D *result, double scalar, 45 | const Vector3D *delta); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /.github/workflows/deploy-docs.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy Docs 2 | 3 | # Deploy docs when a new release is published or manually 4 | on: 5 | release: 6 | types: [published] 7 | workflow_dispatch: 8 | 9 | # Allow deployment to GitHub Pages 10 | permissions: 11 | pages: write 12 | id-token: write 13 | 14 | jobs: 15 | deploy-docs: 16 | 17 | name: Deploy Docs 18 | 19 | environment: 20 | name: github-pages 21 | url: ${{ steps.deployment.outputs.page_url }} 22 | 23 | runs-on: ubuntu-latest 24 | 25 | steps: 26 | - name: Install dependencies 27 | run: | 28 | sudo apt update && sudo apt install -y \ 29 | docbook-xml \ 30 | docbook-xsl \ 31 | libxml2-utils \ 32 | xsltproc \ 33 | fop 34 | 35 | - name: Clone pgSphere 36 | uses: actions/checkout@v4 37 | 38 | - name: Build docs 39 | run: make -C doc 40 | 41 | - name: Setup Pages 42 | uses: actions/configure-pages@v3 43 | 44 | - name: Upload artifact 45 | uses: actions/upload-pages-artifact@v4 46 | with: 47 | path: 'doc/html' 48 | 49 | - name: Deploy to GitHub Pages 50 | id: deployment 51 | uses: actions/deploy-pages@v4 52 | -------------------------------------------------------------------------------- /src/pgs_util.h: -------------------------------------------------------------------------------- 1 | #ifndef __PGS_UTIL_H__ 2 | #define __PGS_UTIL_H__ 3 | 4 | #define PI 3.14159265358979323846 /* pi */ 5 | #define PIH 1.57079632679489661923 /* pi/2 */ 6 | #define PID 6.2831853071795864769 /* 2*pi */ 7 | #define RADIANS 57.295779513082320877 /* 180/pi */ 8 | #define PI_EPS 4.4408920985006261617e-16 /* 2 ** -51 */ 9 | 10 | #define Sqr(a) ( (a) * (a) ) /* square function as macro */ 11 | 12 | #ifdef EPSILON 13 | #undef EPSILON 14 | #endif 15 | #define EPSILON 1.0E-09 /* precision of floating point values */ 16 | 17 | /* spherical circle constants */ 18 | #define SPHERE_SURFACE (4 * PI) 19 | #define DEFAULT_SCIRCLE_SEL 1e-7 20 | 21 | /* convert pg_sphere theta [pi/2 .. -pi/2] to healpix theta [0 .. pi] ([north .. south pole]) */ 22 | static inline double 23 | conv_theta(double x) 24 | { 25 | double y = PIH - x; 26 | 27 | if (fabs(x) < PI_EPS / 2) 28 | return PIH; 29 | if (fabs(y) < PI_EPS / 2) 30 | return 0; 31 | return y; 32 | } 33 | 34 | static inline double 35 | deg_to_rad(double in) 36 | { 37 | return in * PI / 180; 38 | } 39 | 40 | /* 41 | * Area of circle on sphere 42 | */ 43 | static inline double 44 | spherecircle_area_float(double radius) 45 | { 46 | return PID * (1 - cos(radius)); 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/brin.h: -------------------------------------------------------------------------------- 1 | #ifndef __PGS_BRIN_H__ 2 | #define __PGS_BRIN_H__ 3 | 4 | /* 5 | * BRIN declarations 6 | */ 7 | 8 | #include "postgres.h" 9 | #include "fmgr.h" 10 | 11 | #include "key.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "access/brin_tuple.h" 18 | #include "utils/datum.h" 19 | 20 | #define INCLUSION_UNION 0 21 | #define INCLUSION_UNMERGEABLE 1 22 | #define INCLUSION_CONTAINS_EMPTY 2 23 | 24 | Datum spoint_brin_inclusion_add_value(PG_FUNCTION_ARGS); 25 | Datum sbox_brin_inclusion_add_value(PG_FUNCTION_ARGS); 26 | 27 | Datum spoint_overlaps_spherekey(PG_FUNCTION_ARGS); 28 | Datum spoint_contains_spherekey(PG_FUNCTION_ARGS); 29 | Datum spoint_iscontained_spherekey(PG_FUNCTION_ARGS); 30 | Datum sbox_overlaps_spherekey(PG_FUNCTION_ARGS); 31 | Datum sbox_contains_spherekey(PG_FUNCTION_ARGS); 32 | Datum sbox_iscontained_spherekey(PG_FUNCTION_ARGS); 33 | Datum spherekey_overlaps_spherekey(PG_FUNCTION_ARGS); 34 | Datum spherekey_contains_spherekey(PG_FUNCTION_ARGS); 35 | Datum spherekey_iscontained_spherekey(PG_FUNCTION_ARGS); 36 | 37 | Datum spoint_overlaps_sbox(PG_FUNCTION_ARGS); 38 | Datum sbox_iscontained_spoint(PG_FUNCTION_ARGS); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /upgrade_scripts/contains-ops-fixes-1.sql.in: -------------------------------------------------------------------------------- 1 | -- catch up with the operator definitions that were fixed by commit bcdef9dcd2a8406d384f0d2cedd3aa349fd63cf3 2 | 3 | DROP OPERATOR !~ (sline, spoint) CASCADE; 4 | DROP OPERATOR !@ (spoint, sline) CASCADE; 5 | DROP OPERATOR !~ (spoly, spoint) CASCADE; 6 | 7 | CREATE OPERATOR !~ ( 8 | LEFTARG = sline, 9 | RIGHTARG = spoint, 10 | PROCEDURE = sline_contains_point_neg, 11 | COMMUTATOR = '!@', 12 | NEGATOR = '~', 13 | RESTRICT = contsel, 14 | JOIN = contjoinsel 15 | ); 16 | COMMENT ON OPERATOR !~ (sline, spoint) IS 'true if spherical line (LHS) does not contain spherical point (RHS)'; 17 | 18 | CREATE OPERATOR !@ ( 19 | LEFTARG = spoint, 20 | RIGHTARG = sline, 21 | PROCEDURE = sline_contains_point_com_neg, 22 | COMMUTATOR = '!~', 23 | NEGATOR = '@', 24 | RESTRICT = contsel, 25 | JOIN = contjoinsel 26 | ); 27 | COMMENT ON OPERATOR !@ (spoint, sline) IS 'true if spherical point (LHS) is not contained by spherical line (RHS)'; 28 | 29 | CREATE OPERATOR !~ ( 30 | LEFTARG = spoly, 31 | RIGHTARG = spoint, 32 | PROCEDURE = spoly_contains_point_neg, 33 | COMMUTATOR = '!@', 34 | NEGATOR = '~', 35 | RESTRICT = contsel, 36 | JOIN = contjoinsel 37 | ); 38 | COMMENT ON OPERATOR !~ (spoly, spoint) IS 'true if spherical polygon (LHS) does not contain spherical point (RHS)'; 39 | 40 | -------------------------------------------------------------------------------- /src/sscan.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include "string.h" 4 | #include "sparse.h" 5 | #include "sbuffer.h" 6 | 7 | #define YY_DECL int sphere_yylex(void) 8 | YY_DECL; 9 | #define yylval sphere_yylval 10 | 11 | #undef YY_INPUT 12 | #define YY_NO_INPUT 13 | #define YY_INPUT(buf, result, max_size) \ 14 | { \ 15 | result = get_buffer(buf, max_size); \ 16 | result = (result > 0) ? (result) : (YY_NULL); \ 17 | } 18 | 19 | void sphere_flush_scanner_buffer(void) 20 | { 21 | YY_FLUSH_BUFFER; 22 | } 23 | %} 24 | 25 | %option 8bit 26 | %option never-interactive 27 | %option nounput 28 | %option noyywrap 29 | 30 | int [0-9]+ 31 | sign [+-] 32 | real ({int})?\.({int}) 33 | float ({int}|{real})([eE]{sign}{int})? 34 | 35 | %% 36 | {sign} sphere_yylval.i = (strcmp("-", yytext)) ? (1) : (-1); return TOK_SIGN; 37 | {int} sphere_yylval.i = atoi(yytext); return TOK_INT; 38 | {float} sphere_yylval.d = atof(yytext); return TOK_FLOAT; 39 | [x-zX-Z]{3} memcpy(&sphere_yylval.c[0], yytext, 3); return EULERAXIS; 40 | h return HOUR; 41 | d return DEG; 42 | ' return MIN; 43 | m return MIN; 44 | \" return SEC; 45 | s return SEC; 46 | , return COMMA; 47 | \< return OPENCIRC; 48 | \> return CLOSECIRC; 49 | \( return OPENPOINT; 50 | \) return CLOSEPOINT; 51 | \{ return OPENARR; 52 | \} return CLOSEARR; 53 | [ \n\t]+ /* discard spaces */ 54 | . /* alert parser of the garbage */ 55 | %% 56 | -------------------------------------------------------------------------------- /sql/tables.sql: -------------------------------------------------------------------------------- 1 | -- Create tables 2 | 3 | SET client_min_messages = 'warning'; 4 | 5 | CREATE TABLE spheretmp1 (p spoint); 6 | 7 | \copy spheretmp1 from 'data/test_spherepoint.data' 8 | \copy spheretmp1 from 'data/test_spherepoint.data' 9 | \copy spheretmp1 from 'data/test_spherepoint.data' 10 | \copy spheretmp1 from 'data/test_spherepoint.data' 11 | 12 | CREATE TABLE spheretmp2 (c scircle); 13 | 14 | \copy spheretmp2 from 'data/test_spherecircle.data' 15 | \copy spheretmp2 from 'data/test_spherecircle.data' 16 | \copy spheretmp2 from 'data/test_spherecircle.data' 17 | \copy spheretmp2 from 'data/test_spherecircle.data' 18 | 19 | CREATE TABLE spheretmp3 (b sbox); 20 | \copy spheretmp3 from 'data/test_spherebox.data' 21 | 22 | CREATE TABLE spheretmp4 AS 23 | SELECT sline ( p , p - strans '-15d,-15d,-15d,ZXZ' ) AS l 24 | FROM spheretmp1; 25 | 26 | CREATE TABLE spheretmp5 (id int PRIMARY KEY , p spoly ); 27 | \copy spheretmp5 from 'data/test_spherepolygon.data' 28 | 29 | CREATE TABLE spheretmp6 (id int PRIMARY KEY , p spath ); 30 | \copy spheretmp6 from 'data/test_spherepath.data' 31 | 32 | -- Aggregate data from tables 33 | 34 | SELECT set_sphere_output_precision(12); 35 | 36 | CREATE TABLE spheretmp7 (p spoint); 37 | \copy spheretmp7 from 'data/test_spherepolygon_aggregate.data' 38 | SELECT spoly(p) FROM spheretmp7; 39 | CREATE TABLE spheretmp8 (p spoint); 40 | \copy spheretmp8 from 'data/test_spherepoint.data' 41 | SELECT spath(p) FROM spheretmp8 WHERE p IS NOT NULL; 42 | -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.3.1--1.4.0.sql.in: -------------------------------------------------------------------------------- 1 | -- add "fetch" support function to enable index-only scans for spoint3 2 | 3 | -- g_spoint3_fetch was already part of the spoint3 opclass in older versions 4 | -- around 1.0, but later made optional (see bdc37d1) 5 | 6 | DO $$ 7 | BEGIN 8 | ALTER OPERATOR FAMILY spoint3 USING gist ADD 9 | FUNCTION 9 (spoint, spoint) g_spoint3_fetch (internal); 10 | EXCEPTION 11 | WHEN duplicate_object THEN NULL; 12 | WHEN OTHERS THEN RAISE; 13 | END; 14 | $$; 15 | 16 | -- remove legacy spellings of operators 17 | DROP OPERATOR IF EXISTS @(bigint, smoc); 18 | DROP OPERATOR IF EXISTS @(spoint, smoc); 19 | 20 | -- add spoly function that takes an array of float8 values in radians 21 | CREATE FUNCTION spoly(float8[]) 22 | RETURNS spoly 23 | AS 'MODULE_PATHNAME', 'spherepoly_rad' 24 | LANGUAGE 'c' 25 | IMMUTABLE STRICT PARALLEL SAFE; 26 | 27 | COMMENT ON FUNCTION spoly(float8[]) IS 28 | 'creates spoly from array of numbers in radians'; 29 | 30 | CREATE FUNCTION spoly(spoint[]) 31 | RETURNS spoly 32 | AS 'MODULE_PATHNAME', 'spherepoly_from_point_array' 33 | LANGUAGE 'c' 34 | IMMUTABLE STRICT PARALLEL SAFE; 35 | 36 | COMMENT ON FUNCTION spoly(spoint[]) IS 37 | 'creates spoly from an array of points'; 38 | 39 | -- add PARALLEL SAFE to spoly_deg(float8[]) 40 | ALTER FUNCTION spoly_deg(float8[]) IMMUTABLE STRICT PARALLEL SAFE; 41 | 42 | -- update comment on spoly_deg function 43 | COMMENT ON FUNCTION spoly_deg(float8[]) IS 44 | 'creates spoly from array of numbers in degrees'; 45 | -------------------------------------------------------------------------------- /testsuite/gen_point.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | my $dist=$ARGV[0]; 4 | if ($#ARGV == -1) { 5 | print "gen_point.pl: Generic pg_sphere \"spoint\" data generator\n"; 6 | print "usage:\n\tgen_point.pl | psql pgsphere_db\n\n"; 7 | 8 | print "Program generates spherical points located in the\n"; 9 | print "intersections of parallels and meridians and SQL script\n"; 10 | print "to load them into existing database. Distance\n"; 11 | print "between meridians is chosen equal to \"step\" in degrees\n"; 12 | print "The modulus of 360 and step should be equal to zero.\n\n"; 13 | print "Example: \"gen_point.pl 1\" generates dataset containing 64442\n"; 14 | print "spherical points with integer spherical coordinate values\n"; 15 | print "when written in degrees.\n\n"; 16 | print "Program automatically creates \"spoint_data\" table\n"; 17 | print "but does not DROP an existing table with this name.\n\n"; 18 | print "Program attempts to create index \"sp_idx\" on this table\n"; 19 | exit(0); 20 | } 21 | 22 | 23 | my $pi=3.1415926535897932; 24 | my $degra=$pi/180.0; 25 | 26 | if ((180 % $dist)!=0) { 27 | print STDERR "incorrect step, using 1 degree instead.\n"; 28 | $dist = 1; 29 | } 30 | 31 | print < '-40d,0d,40d,XXX' ; 10 | 11 | SELECT strans ( 20.0*pi()/180.0, -270.0*pi()/180.0, 70.5*pi()/180.0, 'XZY' ); 12 | 13 | SELECT theta( strans ( 20.0*pi()/180.0, -270.0*pi()/180.0, 70.5*pi()/180.0, 'XZY' ) ); 14 | 15 | SELECT psi( strans ( 20.0*pi()/180.0, -270.0*pi()/180.0, 70.5*pi()/180.0, 'XZY' ) ); 16 | 17 | SELECT phi( strans ( 20.0*pi()/180.0, -270.0*pi()/180.0, 70.5*pi()/180.0, 'XZY' ) ); 18 | 19 | SELECT theta( strans( '20d, 30d, 40d, XZY' ) ); 20 | 21 | SELECT psi( strans( '20d, 30d, 40d, XZY' ) ); 22 | 23 | SELECT phi( strans( '20d, 30d, 40d, XZY' ) ); 24 | 25 | SELECT strans( '2d 20m, 10d, 0' ); 26 | 27 | SELECT theta( strans( '2d 20m, 10d, 0' ) ); 28 | 29 | SELECT psi( strans( '2d 20m, 10d, 0' ) ); 30 | 31 | SELECT phi( strans( '2d 20m, 10d, 0' ) ); 32 | 33 | SELECT strans ( '10d, 90d, 270d, ZXZ' ); 34 | 35 | SELECT theta( strans ( '10d, 90d, 270d, ZXZ' ) ); 36 | 37 | SELECT psi( strans ( '10d, 90d, 270d, ZXZ' ) ); 38 | 39 | SELECT phi( strans ( '10d, 90d, 270d, ZXZ' ) ); 40 | 41 | SELECT - strans ( '20d, 50d, 80d, XYZ' ); 42 | 43 | SELECT theta( - strans ( '20d, 50d, 80d, XYZ' ) ); 44 | 45 | SELECT psi( - strans ( '20d, 50d, 80d, XYZ' ) ); 46 | 47 | SELECT phi( - strans ( '20d, 50d, 80d, XYZ' ) ); 48 | 49 | SELECT strans( '90d, 60d, 30d' ); 50 | 51 | SELECT theta( strans( '90d, 60d, 30d' ) ); 52 | 53 | SELECT psi( strans( '90d, 60d, 30d' ) ); 54 | 55 | SELECT phi( strans( '90d, 60d, 30d' ) ); 56 | -------------------------------------------------------------------------------- /healpix_bare/README: -------------------------------------------------------------------------------- 1 | This package implements a small subset of routines for working with the 2 | HEALPix tesselation of the sphere. 3 | 4 | For information about HEALPix, see the publication by 5 | K.M. Gorski et al., 2005, Ap.J., 622, p.759 6 | (http://adsabs.harvard.edu/abs/2005ApJ...622..759G) 7 | More comprehensive software packages supporting HEALPix, as well as extensive 8 | documentation and references, are available at 9 | https://healpix.sourceforge.io/. 10 | 11 | 12 | Compilation 13 | =========== 14 | 15 | gcc -O2 healpix_bare.c -std=c99 test.c -lm 16 | clang -O2 healpix_bare.c -std=c99 test.c -lm 17 | icc -O2 healpix_bare.c -std=c99 test.c -lm 18 | 19 | 20 | Notes 21 | ===== 22 | 23 | This package is designed to cover a small set of frequently used HEALPix-related 24 | routines, which are implemented with a focus on robustness, accuracy and clarity. 25 | They have good performance, but are not heavily tuned to keep the code simple - 26 | the full-featured, GPL-licensed Healpix Fortran and C++ libraries (available 27 | via the link above) will be more efficient in most situations. 28 | 29 | The motivation for this package is to give developers of BSD-licensed 30 | Healpix-related codes a reliable starting point, so that they don't have to 31 | re-implement the central algorithms (like conversions between pixel index and 32 | angular coordinates), which are nontrivial to do correctly for all corner cases. 33 | 34 | 35 | Acknowledgements 36 | ================ 37 | 38 | If you are using this code in your own packages, please consider citing 39 | the original paper in your publications: 40 | 41 | K.M. Gorski et al., 2005, Ap.J., 622, p.759 42 | (http://adsabs.harvard.edu/abs/2005ApJ...622..759G) 43 | -------------------------------------------------------------------------------- /healpix_bare/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 1997-2019 Krzysztof M. Gorski, Eric Hivon, Martin Reinecke, 2 | Benjamin D. Wandelt, Anthony J. Banday, 3 | Matthias Bartelmann, 4 | Reza Ansari & Kenneth M. Ganga 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | list of conditions and the following disclaimer in the documentation and/or 14 | other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its contributors may 17 | be used to endorse or promote products derived from this software without 18 | specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 24 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.2.1--1.2.2-healpix.sql.in: -------------------------------------------------------------------------------- 1 | -- healpix 2 | ALTER FUNCTION nest2ring(integer, bigint) PARALLEL SAFE; 3 | ALTER FUNCTION ring2nest(integer, bigint) PARALLEL SAFE; 4 | ALTER FUNCTION healpix_convert_nest(integer, integer, bigint) PARALLEL SAFE; 5 | ALTER FUNCTION healpix_convert_ring(integer, integer, bigint) PARALLEL SAFE; 6 | ALTER FUNCTION nside2order(bigint) PARALLEL SAFE; 7 | ALTER FUNCTION order2nside(integer) PARALLEL SAFE; 8 | ALTER FUNCTION nside2npix(bigint) PARALLEL SAFE; 9 | ALTER FUNCTION npix2nside(bigint) PARALLEL SAFE; 10 | ALTER FUNCTION healpix_nest(integer, spoint) PARALLEL SAFE; 11 | ALTER FUNCTION healpix_ring(integer, spoint) PARALLEL SAFE; 12 | ALTER FUNCTION centre_of_healpix_nest(integer, bigint) PARALLEL SAFE; 13 | ALTER FUNCTION centre_of_healpix_ring(integer, bigint) PARALLEL SAFE; 14 | ALTER FUNCTION center_of_healpix_nest(integer, bigint) PARALLEL SAFE; 15 | ALTER FUNCTION center_of_healpix_ring(integer, bigint) PARALLEL SAFE; 16 | 17 | -- moc_type 18 | ALTER FUNCTION smoc_in(cstring) PARALLEL SAFE; 19 | ALTER FUNCTION smoc_out(smoc) PARALLEL SAFE; 20 | ALTER FUNCTION moc_debug() PARALLEL SAFE; 21 | ALTER FUNCTION set_smoc_output_type(integer) PARALLEL SAFE; 22 | ALTER FUNCTION max_order(smoc) PARALLEL SAFE; 23 | ALTER FUNCTION healpix_subset_smoc(bigint, smoc) PARALLEL SAFE; 24 | ALTER FUNCTION healpix_not_subset_smoc(bigint, smoc) PARALLEL SAFE; 25 | ALTER FUNCTION smoc_superset_healpix(smoc, bigint) PARALLEL SAFE; 26 | ALTER FUNCTION smoc_not_superset_healpix(smoc, bigint) PARALLEL SAFE; 27 | ALTER FUNCTION spoint_subset_smoc(spoint, smoc) PARALLEL SAFE; 28 | ALTER FUNCTION spoint_not_subset_smoc(spoint, smoc) PARALLEL SAFE; 29 | ALTER FUNCTION smoc_superset_spoint(smoc, spoint) PARALLEL SAFE; 30 | ALTER FUNCTION smoc_not_superset_spoint(smoc, spoint) PARALLEL SAFE; 31 | -------------------------------------------------------------------------------- /sql/gist_support.sql: -------------------------------------------------------------------------------- 1 | -- spoint_dwithin function selectivity 2 | set jit = off; -- suppress extra planning output 3 | 4 | select explain('select * from spoint10k where spoint_dwithin(star, spoint(1,1), 1)'); 5 | select explain('select * from spoint10k where spoint_dwithin(star, spoint(1,1), .1)'); 6 | select explain('select * from spoint10k where spoint_dwithin(star, spoint(1,1), .01)'); 7 | 8 | select explain('select * from spoint10k where spoint_dwithin(spoint(1,1), star, 1)'); 9 | select explain('select * from spoint10k where spoint_dwithin(spoint(1,1), star, .1)'); 10 | select explain('select * from spoint10k where spoint_dwithin(spoint(1,1), star, .01)'); 11 | 12 | select explain('select * from spoint10k a join spoint10k b on spoint_dwithin(a.star, b.star, 1)', do_analyze := 'false'); 13 | select explain('select * from spoint10k a join spoint10k b on spoint_dwithin(a.star, b.star, .1)'); 14 | select explain('select * from spoint10k a join spoint10k b on spoint_dwithin(a.star, b.star, .01)'); 15 | 16 | -- spoint_dwithin is symmetric in the first two arguments 17 | select explain('select * from spoint10k a join spoint10k b on spoint_dwithin(a.star, b.star, .01) 18 | where spoint_dwithin(a.star, spoint(1,1), .1)'); 19 | select explain('select * from spoint10k a join spoint10k b on spoint_dwithin(b.star, a.star, .01) 20 | where spoint_dwithin(a.star, spoint(1,1), .1)'); 21 | 22 | -- both sides indexable, check if the planner figures out the better choice 23 | select explain('select * from spoint10k a join spoint10k b on spoint_dwithin(a.star, b.star, .01) 24 | where spoint_dwithin(a.star, spoint(1,1), .1) and spoint_dwithin(b.star, spoint(1,1), .05)'); 25 | select explain('select * from spoint10k a join spoint10k b on spoint_dwithin(a.star, b.star, .01) 26 | where spoint_dwithin(a.star, spoint(1,1), .05) and spoint_dwithin(b.star, spoint(1,1), .1)'); 27 | -------------------------------------------------------------------------------- /HACKING: -------------------------------------------------------------------------------- 1 | SQL definitions 2 | =============== 3 | 4 | Long version: 5 | . 6 | 7 | If you're writing new features that require SQL support, pick some 8 | descriptive name; let's say my_new_op. 9 | 10 | Put your new code into a file called pgs_my_new_op.sql.in. The .in 11 | extension here usually indicates "it's for copying stuff together"; 12 | usally, not much processing is done on such files. 13 | 14 | Then edit the Makefile. The PGS_SQL variable contains a list of the 15 | SQL files eventually copied together, without the .in. Add your new 16 | file there. 17 | 18 | You will also need to create an upgrade file. In order to tell postgres 19 | to execute it, increase PGSPHERE_VERSION as appropriate. As a 20 | consequence, you will have to:: 21 | 22 | git mv pg_sphere--.sql.in pg_sphere--.sql.in 23 | 24 | and also to update the version in pg_sphere.control. 25 | 26 | Then create a make rule:: 27 | 28 | pg_sphere----.sql: pgs_my_new_op.sql.in 29 | cat $^ > $@ 30 | 31 | (of course, this will extend to having multiple sql.in files). 32 | 33 | Finally, add the target of that rule to the DATA_built variable. 34 | 35 | 36 | Regression tests 37 | ================ 38 | 39 | Regressions tests are as per 40 | . 41 | 42 | In short, write queries executing your new features into a file 43 | sql/my_new_op.sql, and add "my_new_op" (without the extension or the 44 | directory name) to both REGRESS and TESTS in the Makefile. 45 | 46 | Then touch expected/my_new_op.out, run make test. This will of course 47 | fail, because your tests hopefully will output something. But then you 48 | can pick out the diff from 49 | /var/lib/postgresql/pgsphere/regression.diffs, have another critical 50 | look at it and generatoe your .out file from it. 51 | -------------------------------------------------------------------------------- /sql/selectivity.sql: -------------------------------------------------------------------------------- 1 | -- test selectivity estimator functions 2 | 3 | create table spoint10k (star spoint); 4 | insert into spoint10k select spoint(i, i*i) from generate_series(1, 10000) g(i); 5 | create index on spoint10k using gist (star); 6 | analyze spoint10k; 7 | 8 | -- "explain analyze" wrapper that removes 'cost=...' since it varies across architectures 9 | -- (we can't use "costs off" since that also removes the estimated row count) 10 | create or replace function explain(query text, do_analyze text default 'true') returns setof text language plpgsql as $$ 11 | declare 12 | line text; 13 | begin 14 | for line in execute format('explain (analyze %s, timing off, summary off, buffers off) %s', do_analyze, query) loop 15 | continue when (line ~ ' +Index Searches: .*'); 16 | return next regexp_replace(line, 'cost=\S+ ', ''); 17 | end loop; 18 | return; 19 | end; 20 | $$; 21 | 22 | -- <@ operator selectivity 23 | select explain('select * from spoint10k where star <@ scircle(spoint(1,1), 1)'); 24 | select explain('select * from spoint10k where star <@ scircle(spoint(1,1), .1)'); 25 | select explain('select * from spoint10k where star <@ scircle(spoint(1,1), .01)'); 26 | 27 | select explain('select * from spoint10k where scircle(spoint(1,1), 1) @> star'); 28 | select explain('select * from spoint10k where scircle(spoint(1,1), .1) @> star'); 29 | select explain('select * from spoint10k where scircle(spoint(1,1), .01) @> star'); 30 | 31 | select explain('select * from spoint10k where star !<@ scircle(spoint(1,1), 1)'); 32 | select explain('select * from spoint10k where star !<@ scircle(spoint(1,1), .1)'); 33 | select explain('select * from spoint10k where star !<@ scircle(spoint(1,1), .01)'); 34 | 35 | select explain('select * from spoint10k where scircle(spoint(1,1), 1) !@> star'); 36 | select explain('select * from spoint10k where scircle(spoint(1,1), .1) !@> star'); 37 | select explain('select * from spoint10k where scircle(spoint(1,1), .01) !@> star'); 38 | -------------------------------------------------------------------------------- /expected/moc_options.out: -------------------------------------------------------------------------------- 1 | create table moc_opt (m smoc); 2 | insert into moc_opt select format('9/%s', i)::smoc from generate_series(1, 1000) g(i); 3 | analyze moc_opt; 4 | create index moc_opt5 on moc_opt using gin (m); 5 | explain (analyze, costs off, timing off, summary off, buffers off) select * from moc_opt where m && '9/1'; 6 | QUERY PLAN 7 | --------------------------------------------------------------- 8 | Bitmap Heap Scan on moc_opt (actual rows=1 loops=1) 9 | Recheck Cond: (m && '9/1'::smoc) 10 | Rows Removed by Index Recheck: 254 11 | Heap Blocks: exact=4 12 | -> Bitmap Index Scan on moc_opt5 (actual rows=255 loops=1) 13 | Index Cond: (m && '9/1'::smoc) 14 | (6 rows) 15 | 16 | drop index moc_opt5; 17 | create index moc_opt8 on moc_opt using gin (m smoc_gin_ops_fine); 18 | explain (analyze, costs off, timing off, summary off, buffers off) select * from moc_opt where m && '9/1'; 19 | QUERY PLAN 20 | ------------------------------------------------------------- 21 | Bitmap Heap Scan on moc_opt (actual rows=1 loops=1) 22 | Recheck Cond: (m && '9/1'::smoc) 23 | Rows Removed by Index Recheck: 2 24 | Heap Blocks: exact=1 25 | -> Bitmap Index Scan on moc_opt8 (actual rows=3 loops=1) 26 | Index Cond: (m && '9/1'::smoc) 27 | (6 rows) 28 | 29 | drop index moc_opt8; 30 | create index moc_opt9 on moc_opt using gin (m smoc_gin_ops (order = 9)); 31 | explain (analyze, costs off, timing off, summary off, buffers off) select * from moc_opt where m && '9/1'; 32 | QUERY PLAN 33 | ------------------------------------------------------------- 34 | Bitmap Heap Scan on moc_opt (actual rows=1 loops=1) 35 | Recheck Cond: (m && '9/1'::smoc) 36 | Heap Blocks: exact=1 37 | -> Bitmap Index Scan on moc_opt9 (actual rows=1 loops=1) 38 | Index Cond: (m && '9/1'::smoc) 39 | (5 rows) 40 | 41 | -------------------------------------------------------------------------------- /testsuite/gen_circle.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | my $dist=$ARGV[0]; 4 | my $radius=$ARGV[1]; 5 | if ($#ARGV <= 0) { 6 | print "gen_circle.pl: Generic pg_sphere \"scircle\" data generator\n"; 7 | print "usage:\n\tgen_circle.pl | psql pgsphere_db\n\n"; 8 | 9 | print "Program generates spherical circles located in the\n"; 10 | print "intersections of parallels and meridians and SQL script\n"; 11 | print "to load them into existing database. Distance\n"; 12 | print "between meridians is chosen equal to \"step\" in degrees\n"; 13 | print "radii of circles are set equal to \"radius\" in degrees\n"; 14 | print "The modulus of 360 and step should be equal to zero.\n"; 15 | print "The radius should be between 0 and 90\n\n"; 16 | print "Example: \"gen_circle.pl 1 0.1\" generates dataset containing\n"; 17 | print "64442 spherical circles with integer spherical coordinate\n"; 18 | print "values when written in degrees and radii of 6 arcmins.\n\n"; 19 | print "Program automatically creates \"scircle_data\" table\n"; 20 | print "but does not DROP an table with this name.\n\n"; 21 | print "Program attempts to create index \"sc_idx\" on this table\n"; 22 | exit(0); 23 | } 24 | 25 | my $pi=3.1415926535897932; 26 | my $degra=$pi/180.0; 27 | 28 | if ($dist <= 0) {$dist = 1;} 29 | if ((180 % $dist)!=0) { 30 | print STDERR "incorrect step, using 1 degree instead.\n"; 31 | $dist = 1; 32 | } 33 | if (($radius > 90)||($radius<0)) { 34 | print STDERR "incorrect radius, using 6 arcmins instead.\n"; 35 | $radius = 0.1; 36 | } 37 | 38 | 39 | print <\n"; 47 | for (my $i=-90+$dist;$i<=90-$dist;$i+=$dist) { 48 | for (my $j=0; $j<360; $j+=$dist) { 49 | print "<(${j}d, ${i}d), ${radius}d>\n"; 50 | } 51 | } 52 | print "<(0, 90d), ${radius}d>\n"; 53 | 54 | print "\\.\n\n"; 55 | print "CREATE INDEX sc_idx ON scircle_data USING gist (sc);\n"; 56 | -------------------------------------------------------------------------------- /doc/pg_sphere.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | &ohgr;"> 27 | &OHgr;"> 28 | &pgr;"> 29 | HEALPix"> 30 | pgSphere"> 31 | PostgreSQL"> 32 | pg_config"> 33 | 34 | 35 | 36 | ]> 37 | 38 | 39 | 40 | 41 | pgSphere &pg_sphere_version; 42 | pgSphere Development Team 43 | pgSphere 44 | &pg_sphere_version; 45 | 46 | 47 | &capWhatis; 48 | &capInstall; 49 | &capTypes; 50 | &capConstr; 51 | &capOperators; 52 | &capFunctions; 53 | &capIndices; 54 | &capExamples; 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/gnomo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "gnomo.h" 5 | #include "point.h" /* SPoint from pgsphere */ 6 | 7 | #include 8 | 9 | PG_FUNCTION_INFO_V1(gnomonic_proj); 10 | PG_FUNCTION_INFO_V1(gnomonic_inv); 11 | 12 | /* 13 | * Direct gnomonic projection. 14 | * 15 | * point gnomonic_proj(spoint spherical_point, spoint tangential_point) 16 | */ 17 | Datum gnomonic_proj(PG_FUNCTION_ARGS) 18 | { 19 | Point* g = (Point*) palloc(sizeof(Point)); 20 | SPoint* p = (SPoint*) PG_GETARG_POINTER(0); 21 | SPoint* t = (SPoint*) PG_GETARG_POINTER(1); 22 | 23 | double delta_lng = p->lng - t->lng; 24 | double sin_lat = sin(p->lat); 25 | double cos_lat = cos(p->lat); 26 | double sin_lat_t = sin(t->lat); 27 | double cos_lat_t = cos(t->lat); 28 | double sin_delta = sin(delta_lng); 29 | double cos_delta = cos(delta_lng); 30 | 31 | double cos_lat__cos_delta = cos_lat * cos_delta; 32 | double cos_dist = sin_lat_t * sin_lat + cos_lat_t * cos_lat__cos_delta; 33 | 34 | g->x = cos_lat * sin_delta / cos_dist; 35 | g->y = (cos_lat_t * sin_lat - sin_lat_t * cos_lat__cos_delta) / cos_dist; 36 | 37 | if (p->lng == t->lng && p->lat == t->lat) 38 | { 39 | g->x = 0; 40 | g->y = 0; 41 | } 42 | PG_RETURN_POINTER(g); 43 | } 44 | 45 | /* 46 | * Inverse gnomonic projection. 47 | * 48 | * spoint gnomonic_inv(point plane_point, spoint tangential_point) 49 | */ 50 | Datum gnomonic_inv(PG_FUNCTION_ARGS) 51 | { 52 | SPoint* p = (SPoint*) palloc(sizeof(SPoint)); 53 | Point* g = (Point*) PG_GETARG_POINTER(0); 54 | SPoint* t = (SPoint*) PG_GETARG_POINTER(1); 55 | 56 | double rho_sq = g->x * g->x + g->y * g->y; 57 | double rho = sqrt(rho_sq); 58 | double cos_c = 1 / sqrt(1 + rho_sq); 59 | double sin_c = 1 / sqrt(1 + 1 / rho_sq); 60 | double cos_lat_t = cos(t->lat); 61 | double sin_lat_t = sin(t->lat); 62 | 63 | p->lng = t->lng + atan2(g->x * sin_c, 64 | rho * cos_lat_t * cos_c - g->y * sin_lat_t * sin_c); 65 | p->lat = asin(cos_c * sin_lat_t + g->y *sin_c * cos_lat_t / rho); 66 | 67 | PG_RETURN_POINTER(p); 68 | } 69 | -------------------------------------------------------------------------------- /expected/moc_options_1.out: -------------------------------------------------------------------------------- 1 | create table moc_opt (m smoc); 2 | insert into moc_opt select format('9/%s', i)::smoc from generate_series(1, 1000) g(i); 3 | analyze moc_opt; 4 | create index moc_opt5 on moc_opt using gin (m); 5 | explain (analyze, costs off, timing off, summary off, buffers off) select * from moc_opt where m && '9/1'; 6 | QUERY PLAN 7 | ------------------------------------------------------------------ 8 | Bitmap Heap Scan on moc_opt (actual rows=1.00 loops=1) 9 | Recheck Cond: (m && '9/1'::smoc) 10 | Rows Removed by Index Recheck: 254 11 | Heap Blocks: exact=4 12 | -> Bitmap Index Scan on moc_opt5 (actual rows=255.00 loops=1) 13 | Index Cond: (m && '9/1'::smoc) 14 | Index Searches: 1 15 | (7 rows) 16 | 17 | drop index moc_opt5; 18 | create index moc_opt8 on moc_opt using gin (m smoc_gin_ops_fine); 19 | explain (analyze, costs off, timing off, summary off, buffers off) select * from moc_opt where m && '9/1'; 20 | QUERY PLAN 21 | ---------------------------------------------------------------- 22 | Bitmap Heap Scan on moc_opt (actual rows=1.00 loops=1) 23 | Recheck Cond: (m && '9/1'::smoc) 24 | Rows Removed by Index Recheck: 2 25 | Heap Blocks: exact=1 26 | -> Bitmap Index Scan on moc_opt8 (actual rows=3.00 loops=1) 27 | Index Cond: (m && '9/1'::smoc) 28 | Index Searches: 1 29 | (7 rows) 30 | 31 | drop index moc_opt8; 32 | create index moc_opt9 on moc_opt using gin (m smoc_gin_ops (order = 9)); 33 | explain (analyze, costs off, timing off, summary off, buffers off) select * from moc_opt where m && '9/1'; 34 | QUERY PLAN 35 | ---------------------------------------------------------------- 36 | Bitmap Heap Scan on moc_opt (actual rows=1.00 loops=1) 37 | Recheck Cond: (m && '9/1'::smoc) 38 | Heap Blocks: exact=1 39 | -> Bitmap Index Scan on moc_opt9 (actual rows=1.00 loops=1) 40 | Index Cond: (m && '9/1'::smoc) 41 | Index Searches: 1 42 | (6 rows) 43 | 44 | -------------------------------------------------------------------------------- /testsuite/gen_poly.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | my $dist=$ARGV[0]; 4 | my $r=$ARGV[1]; 5 | my $N=$ARGV[2]; 6 | if ($#ARGV == -1) { 7 | print "gen_poly.pl: Generic pg_sphere \"spoly\" data generator\n"; 8 | print "usage:\n\tgen_poly.pl | psql pgsphere_db\n\n"; 9 | 10 | print "Program generates spherical N-side polygons located near the\n"; 11 | print "intersections of parallels and meridians and SQL script\n"; 12 | print "to load them into existing database. N have to be >=3. Distance\n"; 13 | print "between meridians is chosen equal to \"step\" in degrees\n"; 14 | print "The modulus of 360 and step should be equal to zero.\n\n"; 15 | print "Example: \"gen_poly.pl 1 0.1 3\" generates dataset containing 64442\n"; 16 | print "spherical triangles with integer spherical coordinate values\n"; 17 | print "when written in degrees.\n\n"; 18 | print "Program automatically creates \"spoly_data\" table\n"; 19 | print "but does not DROP an existing table with this name.\n\n"; 20 | print "Program attempts to create index \"spl_idx\" on this table\n"; 21 | exit(0); 22 | } 23 | 24 | 25 | my $pi=3.1415926535897932; 26 | my $degra=$pi/180.0; 27 | 28 | if ((180 % $dist)!=0) { 29 | print STDERR "incorrect step, using 1 degree instead.\n"; 30 | $dist = 1; 31 | } 32 | 33 | if ($r < 0) { 34 | print STDERR "incorrect size, using 0.1 degree instead.\n"; 35 | $r = 0.1; 36 | } 37 | 38 | if ($N < 3) { 39 | print STDERR "incorrect N, using 3 degree instead.\n"; 40 | $N = 3; 41 | } 42 | 43 | my @x; 44 | my @y; 45 | 46 | for ($i=0.0;$i<$N;$i+=1.0) { 47 | push @x,$r*sin(2.0*$pi*$i/$N); 48 | push @y,$r*cos(2.0*$pi*$i/$N); 49 | } 50 | 51 | print <[$nn],$i+$y->[$nn]); 74 | $spoly.="," unless ($nn>=($N-1)); 75 | } 76 | $spoly.="}"; 77 | return $spoly; 78 | } 79 | -------------------------------------------------------------------------------- /doc/appendixes.sgm: -------------------------------------------------------------------------------- 1 | 2 | 3 | Appendix 4 | 5 | 6 | 7 | Changes from version 1.0 to 1.1 8 | 9 | 10 | 11 | 12 | Speed up index query time. The index scan is much faster than in 1.0. 13 | 14 | 15 | 16 | 17 | Remove B-tree index. It was used to cluster the index. 18 | 19 | 20 | 21 | 22 | This version is compatible to PostgreSQL 8.4 23 | 24 | 25 | 26 | 27 | 28 | 29 | Changes from version 1.1 to 1.1.5 30 | 31 | 32 | 33 | 34 | Modify behavior of function set_sphere_output_precision. 35 | 36 | 37 | 38 | 39 | Compatibility with PostgreSQL 9.2 40 | and later. 41 | 42 | 43 | 44 | 45 | Creating spath and spolygon objects "as aggregate" 46 | from tables should now work. 47 | 48 | 49 | 50 | 51 | Improved accuracy of spoint (great circle) distance calculation. 52 | 53 | 54 | 55 | 56 | Add new contains operators consistent with the geometry operators 57 | of the plain used in PostgreSQL 8.2 58 | and later: 59 | <@ and @>, the old operators @ and ˜ still work. 60 | 61 | 62 | 63 | 64 | Improved correctness of spatial indexing. 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /sql/output_precision.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- Test default and custom output precisions for double values. 3 | -- 4 | 5 | SELECT set_sphere_output( 'RAD' ); 6 | 7 | -- 8 | -- Check default precision 9 | -- 10 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 11 | 12 | -- 13 | -- Check option extra_float_digits 14 | -- 15 | SET extra_float_digits TO -6; 16 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 17 | 18 | SET extra_float_digits TO -2; 19 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 20 | 21 | SET extra_float_digits TO 0; 22 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 23 | 24 | SET extra_float_digits TO 1; 25 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 26 | 27 | SET extra_float_digits TO 2; 28 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 29 | 30 | SET extra_float_digits TO 3; 31 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 32 | 33 | SET extra_float_digits TO 6; 34 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 35 | 36 | -- 37 | -- Check compatibility behaviour 38 | -- 39 | SELECT set_sphere_output_precision(10); 40 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 41 | 42 | SELECT set_sphere_output_precision(12); 43 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 44 | 45 | SELECT set_sphere_output_precision(15); 46 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 47 | 48 | SELECT set_sphere_output_precision(17); 49 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 50 | 51 | SELECT set_sphere_output_precision(20); 52 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 53 | 54 | SELECT set_sphere_output_precision(0); 55 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 56 | 57 | SELECT set_sphere_output_precision(-3); 58 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 59 | 60 | -- 61 | -- Check extra_float_digits after set_sphere_output_precision. 62 | -- The change of extra_float_digits should not affect the precision of pgsphere 63 | -- output because set_sphere_output_precision enables compatibility mode. 64 | -- 65 | SELECT set_sphere_output_precision(10); 66 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 67 | 68 | SET extra_float_digits TO -6; 69 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 70 | 71 | SET extra_float_digits TO -10; 72 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 73 | 74 | -- 75 | -- Check reset_sphere_output_precision. 76 | -- It should disable compatibility mode - extra_float_digits should work. 77 | -- 78 | SELECT reset_sphere_output_precision(); 79 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 80 | 81 | SET extra_float_digits TO -6; 82 | SELECT '( 1h 2m 30s , +1d 2m 30s)'::spoint; 83 | -------------------------------------------------------------------------------- /pgs_gist_spoint3.sql.in: -------------------------------------------------------------------------------- 1 | -- create the next generation operator class for spherical points 2 | 3 | CREATE FUNCTION g_spoint3_union(bytea, internal) 4 | RETURNS spherekey 5 | AS 'MODULE_PATHNAME', 'g_spoint3_union' 6 | LANGUAGE 'c'; 7 | 8 | CREATE FUNCTION g_spoint3_penalty (internal, internal, internal) 9 | RETURNS internal 10 | AS 'MODULE_PATHNAME', 'g_spoint3_penalty' 11 | LANGUAGE 'c' 12 | STRICT PARALLEL SAFE; 13 | 14 | CREATE FUNCTION g_spoint3_picksplit(internal, internal) 15 | RETURNS internal 16 | AS 'MODULE_PATHNAME', 'g_spoint3_picksplit' 17 | LANGUAGE 'c'; 18 | 19 | CREATE FUNCTION g_spoint3_same (bytea, bytea, internal) 20 | RETURNS internal 21 | AS 'MODULE_PATHNAME', 'g_spoint3_same' 22 | LANGUAGE 'c'; 23 | 24 | CREATE FUNCTION g_spoint3_compress(internal) 25 | RETURNS internal 26 | AS 'MODULE_PATHNAME', 'g_spoint3_compress' 27 | LANGUAGE 'c'; 28 | 29 | CREATE FUNCTION g_spoint3_consistent(internal, internal, int4, oid, internal) 30 | RETURNS internal 31 | AS 'MODULE_PATHNAME', 'g_spoint3_consistent' 32 | LANGUAGE 'c'; 33 | 34 | CREATE FUNCTION g_spoint3_distance(internal, internal, int4, oid) 35 | RETURNS float8 36 | AS 'MODULE_PATHNAME', 'g_spoint3_distance' 37 | LANGUAGE 'c'; 38 | 39 | CREATE FUNCTION g_spoint3_fetch(internal) 40 | RETURNS internal 41 | AS 'MODULE_PATHNAME', 'g_spoint3_fetch' 42 | LANGUAGE 'c' 43 | STRICT PARALLEL SAFE; 44 | 45 | CREATE OPERATOR CLASS spoint3 46 | FOR TYPE spoint USING gist AS 47 | OPERATOR 1 = (spoint, spoint), 48 | OPERATOR 11 @ (spoint, scircle), 49 | OPERATOR 12 @ (spoint, sline), 50 | OPERATOR 13 @ (spoint, spath), 51 | OPERATOR 14 @ (spoint, spoly), 52 | OPERATOR 15 @ (spoint, sellipse), 53 | OPERATOR 16 @ (spoint, sbox), 54 | OPERATOR 37 <@ (spoint, scircle), 55 | OPERATOR 38 <@ (spoint, sline), 56 | OPERATOR 39 <@ (spoint, spath), 57 | OPERATOR 40 <@ (spoint, spoly), 58 | OPERATOR 41 <@ (spoint, sellipse), 59 | OPERATOR 42 <@ (spoint, sbox), 60 | OPERATOR 100 <-> (spoint, spoint) FOR ORDER BY float_ops, 61 | FUNCTION 1 g_spoint3_consistent (internal, internal, int4, oid, internal), 62 | FUNCTION 2 g_spoint3_union (bytea, internal), 63 | FUNCTION 3 g_spoint3_compress (internal), 64 | FUNCTION 4 g_spherekey_decompress (internal), 65 | FUNCTION 5 g_spoint3_penalty (internal, internal, internal), 66 | FUNCTION 6 g_spoint3_picksplit (internal, internal), 67 | FUNCTION 7 g_spoint3_same (bytea, bytea, internal), 68 | FUNCTION 8 g_spoint3_distance (internal, internal, int4, oid), 69 | FUNCTION 9 (spoint, spoint) g_spoint3_fetch (internal), 70 | STORAGE pointkey; 71 | -------------------------------------------------------------------------------- /doc/whatis.sgm: -------------------------------------------------------------------------------- 1 | 2 | Overview 3 | 4 | 5 | 6 | What is pgSphere? 7 | 8 | 9 | pgSphere is an extra module for 10 | PostgreSQL which adds spherical data 11 | types. It provides: 12 | 13 | 14 | 15 | 16 | input and output of data 17 | 18 | 19 | 20 | 21 | containing, overlapping, and other operators 22 | 23 | 24 | 25 | 26 | various input and converting functions and operators 27 | 28 | 29 | 30 | 31 | circumference and area of an object 32 | 33 | 34 | 35 | 36 | spherical transformation 37 | 38 | 39 | 40 | 41 | indexing of spherical data types 42 | 43 | 44 | 45 | 46 | several input and output formats 47 | 48 | 49 | 50 | 51 | 52 | Hence, you can do a fast search and analysis for objects with 53 | spherical attributes as used in geographical, astronomical, or 54 | other applications using PostgreSQL. 55 | For instance, you can manage data of geographical objects around 56 | the world and astronomical data like star and other catalogs 57 | conveniently using an SQL interface. 58 | 59 | 60 | The aim of pgSphere is to provide 61 | uniform access to spherical data. Because 62 | PostgreSQL itself supports a lot of 63 | software interfaces, you can now use the same database 64 | with different utilities and applications. 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /expected/knn.out: -------------------------------------------------------------------------------- 1 | CREATE TABLE points (id int, p spoint, pos int); 2 | INSERT INTO points (id, p) SELECT x, spoint(random()*6.28, (2*random()-1)*1.57) FROM generate_series(1,314159) x; 3 | CREATE INDEX i ON points USING gist (p); 4 | SET enable_indexscan = true; 5 | EXPLAIN (costs off) SELECT p <-> spoint (0.2, 0.3) FROM points ORDER BY 1 LIMIT 100; 6 | QUERY PLAN 7 | ------------------------------------------------- 8 | Limit 9 | -> Index Scan using i on points 10 | Order By: (p <-> '(0.2 , 0.3)'::spoint) 11 | (3 rows) 12 | 13 | UPDATE points SET pos = n FROM 14 | (SELECT id, row_number() OVER (ORDER BY p <-> spoint (0.2, 0.3)) n FROM points ORDER BY p <-> spoint (0.2, 0.3) LIMIT 100) sel 15 | WHERE points.id = sel.id; 16 | SET enable_indexscan = false; 17 | SELECT pos, row_number() OVER (ORDER BY p <-> spoint (0.2, 0.3)) n FROM points ORDER BY p <-> spoint (0.2, 0.3) LIMIT 100; 18 | pos | n 19 | -----+----- 20 | 1 | 1 21 | 2 | 2 22 | 3 | 3 23 | 4 | 4 24 | 5 | 5 25 | 6 | 6 26 | 7 | 7 27 | 8 | 8 28 | 9 | 9 29 | 10 | 10 30 | 11 | 11 31 | 12 | 12 32 | 13 | 13 33 | 14 | 14 34 | 15 | 15 35 | 16 | 16 36 | 17 | 17 37 | 18 | 18 38 | 19 | 19 39 | 20 | 20 40 | 21 | 21 41 | 22 | 22 42 | 23 | 23 43 | 24 | 24 44 | 25 | 25 45 | 26 | 26 46 | 27 | 27 47 | 28 | 28 48 | 29 | 29 49 | 30 | 30 50 | 31 | 31 51 | 32 | 32 52 | 33 | 33 53 | 34 | 34 54 | 35 | 35 55 | 36 | 36 56 | 37 | 37 57 | 38 | 38 58 | 39 | 39 59 | 40 | 40 60 | 41 | 41 61 | 42 | 42 62 | 43 | 43 63 | 44 | 44 64 | 45 | 45 65 | 46 | 46 66 | 47 | 47 67 | 48 | 48 68 | 49 | 49 69 | 50 | 50 70 | 51 | 51 71 | 52 | 52 72 | 53 | 53 73 | 54 | 54 74 | 55 | 55 75 | 56 | 56 76 | 57 | 57 77 | 58 | 58 78 | 59 | 59 79 | 60 | 60 80 | 61 | 61 81 | 62 | 62 82 | 63 | 63 83 | 64 | 64 84 | 65 | 65 85 | 66 | 66 86 | 67 | 67 87 | 68 | 68 88 | 69 | 69 89 | 70 | 70 90 | 71 | 71 91 | 72 | 72 92 | 73 | 73 93 | 74 | 74 94 | 75 | 75 95 | 76 | 76 96 | 77 | 77 97 | 78 | 78 98 | 79 | 79 99 | 80 | 80 100 | 81 | 81 101 | 82 | 82 102 | 83 | 83 103 | 84 | 84 104 | 85 | 85 105 | 86 | 86 106 | 87 | 87 107 | 88 | 88 108 | 89 | 89 109 | 90 | 90 110 | 91 | 91 111 | 92 | 92 112 | 93 | 93 113 | 94 | 94 114 | 95 | 95 115 | 96 | 96 116 | 97 | 97 117 | 98 | 98 118 | 99 | 99 119 | 100 | 100 120 | (100 rows) 121 | 122 | DROP TABLE points; 123 | -------------------------------------------------------------------------------- /.github/workflows/build-and-check.yml: -------------------------------------------------------------------------------- 1 | name: Build and Check 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | schedule: 8 | - cron: '0 0 * * 5' 9 | 10 | jobs: 11 | build_and_test: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | pg_version: [10, 11, 12, 13, 14, 15, 16, 17, 18] 19 | use_healpix: [0, 1] 20 | 21 | name: PostgreSQL ${{ matrix.pg_version }} - USE_HEALPIX=${{ matrix.use_healpix }} 22 | 23 | steps: 24 | - name: Install dependencies 25 | run: | 26 | sudo apt update && sudo apt install -y \ 27 | postgresql-common \ 28 | libhealpix-cxx-dev \ 29 | docbook-xml \ 30 | docbook-xsl \ 31 | libxml2-utils \ 32 | xsltproc \ 33 | fop 34 | 35 | - name: Install PostgreSQL 36 | run: sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -p -v ${{ matrix.pg_version }} -i 37 | 38 | - name: Clone pgSphere 39 | uses: actions/checkout@v4 40 | 41 | - name: Set MAKE_CMD variable 42 | run: echo "MAKE_CMD=make --keep-going -j$(nproc) -l$(nproc) -O" >> $GITHUB_ENV 43 | 44 | - name: Build pgSphere 45 | run: ${MAKE_CMD} PROFILE="-Werror -Wall" USE_HEALPIX=${{ matrix.use_healpix }} 46 | 47 | - name: make test 48 | run: pg_virtualenv ${MAKE_CMD} USE_HEALPIX=${{ matrix.use_healpix }} test 49 | 50 | - name: Show test regression.diffs 51 | if: ${{ failure() }} 52 | run: cat regression.diffs 53 | 54 | - name: Install pgSphere 55 | run: sudo ${MAKE_CMD} USE_HEALPIX=${{ matrix.use_healpix }} install 56 | 57 | - name: make installcheck 58 | run: pg_virtualenv ${MAKE_CMD} USE_HEALPIX=${{ matrix.use_healpix }} installcheck 59 | 60 | - name: Show installcheck regression.diffs 61 | if: ${{ failure() }} 62 | run: cat regression.diffs 63 | 64 | - name: make crushtest 65 | run: pg_virtualenv ${MAKE_CMD} USE_HEALPIX=${{ matrix.use_healpix }} crushtest 66 | 67 | - name: Show crushtest regression.diffs 68 | if: ${{ failure() }} 69 | run: cat regression.diffs 70 | 71 | - name: Build docs 72 | run: ${MAKE_CMD} -C doc 73 | 74 | - name: Inject slug/short variables 75 | uses: rlespinasse/github-slug-action@v4 76 | 77 | - name: Upload artifacts 78 | uses: actions/upload-artifact@v4 79 | if: success() || failure() 80 | with: 81 | name: ${{ env.GITHUB_REF_SLUG_URL }}-pg${{ matrix.pg_version }}-use-healpix-${{ matrix.use_healpix }}-${{ github.run_id }} 82 | if-no-files-found: ignore 83 | path: | 84 | ./**/*.log 85 | ./**/*.diffs 86 | -------------------------------------------------------------------------------- /upgrade_scripts/pgs_gist_contains_ops.sql.in: -------------------------------------------------------------------------------- 1 | ALTER OPERATOR FAMILY spoint USING gist ADD 2 | OPERATOR 37 <@ (spoint, scircle), 3 | OPERATOR 38 <@ (spoint, sline), 4 | OPERATOR 39 <@ (spoint, spath), 5 | OPERATOR 40 <@ (spoint, spoly), 6 | OPERATOR 41 <@ (spoint, sellipse), 7 | OPERATOR 42 <@ (spoint, sbox); 8 | 9 | ALTER OPERATOR FAMILY scircle USING gist ADD 10 | OPERATOR 37 <@ (scircle, scircle), 11 | OPERATOR 38 <@ (scircle, spoly), 12 | OPERATOR 39 <@ (scircle, sellipse), 13 | OPERATOR 40 <@ (scircle, sbox), 14 | OPERATOR 43 @> (scircle, spoint), 15 | OPERATOR 44 @> (scircle, scircle), 16 | OPERATOR 45 @> (scircle, sline), 17 | OPERATOR 46 @> (scircle, spath), 18 | OPERATOR 47 @> (scircle, spoly), 19 | OPERATOR 48 @> (scircle, sellipse), 20 | OPERATOR 49 @> (scircle, sbox); 21 | 22 | ALTER OPERATOR FAMILY sline USING gist ADD 23 | OPERATOR 37 <@ (sline, scircle), 24 | OPERATOR 38 <@ (sline, spoly), 25 | OPERATOR 39 <@ (sline, sellipse), 26 | OPERATOR 40 <@ (sline, sbox), 27 | OPERATOR 43 @> (sline, spoint); 28 | 29 | ALTER OPERATOR FAMILY sellipse USING gist ADD 30 | OPERATOR 37 <@ (sellipse, scircle), 31 | OPERATOR 38 <@ (sellipse, spoly), 32 | OPERATOR 39 <@ (sellipse, sellipse), 33 | OPERATOR 40 <@ (sellipse, sbox), 34 | OPERATOR 43 @> (sellipse, spoint), 35 | OPERATOR 44 @> (sellipse, scircle), 36 | OPERATOR 45 @> (sellipse, sline), 37 | OPERATOR 46 @> (sellipse, spath), 38 | OPERATOR 47 @> (sellipse, spoly), 39 | OPERATOR 48 @> (sellipse, sellipse), 40 | OPERATOR 49 @> (sellipse, sbox); 41 | 42 | ALTER OPERATOR FAMILY spoly USING gist ADD 43 | OPERATOR 37 <@ (spoly, scircle), 44 | OPERATOR 38 <@ (spoly, spoly), 45 | OPERATOR 39 <@ (spoly, sellipse), 46 | OPERATOR 40 <@ (spoly, sbox), 47 | OPERATOR 43 @> (spoly, spoint), 48 | OPERATOR 44 @> (spoly, scircle), 49 | OPERATOR 45 @> (spoly, sline), 50 | OPERATOR 46 @> (spoly, spath), 51 | OPERATOR 47 @> (spoly, spoly), 52 | OPERATOR 48 @> (spoly, sellipse), 53 | OPERATOR 49 @> (spoly, sbox); 54 | 55 | ALTER OPERATOR FAMILY spath USING gist ADD 56 | OPERATOR 37 <@ (spath, scircle), 57 | OPERATOR 38 <@ (spath, spoly), 58 | OPERATOR 39 <@ (spath, sellipse), 59 | OPERATOR 40 <@ (spath, sbox), 60 | OPERATOR 43 @> (spath, spoint); 61 | 62 | ALTER OPERATOR FAMILY sbox USING gist ADD 63 | OPERATOR 37 <@ (sbox, scircle), 64 | OPERATOR 38 <@ (sbox, spoly), 65 | OPERATOR 39 <@ (sbox, sellipse), 66 | OPERATOR 40 <@ (sbox, sbox), 67 | OPERATOR 43 @> (sbox, spoint), 68 | OPERATOR 44 @> (sbox, scircle), 69 | OPERATOR 45 @> (sbox, sline), 70 | OPERATOR 46 @> (sbox, spath), 71 | OPERATOR 47 @> (sbox, spoly), 72 | OPERATOR 48 @> (sbox, sellipse), 73 | OPERATOR 49 @> (sbox, sbox); 74 | -------------------------------------------------------------------------------- /.github/workflows/build-and-check-windows-latest.yml: -------------------------------------------------------------------------------- 1 | name: Build and Check (windows-latest) 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | schedule: 8 | - cron: '0 0 * * 5' 9 | 10 | jobs: 11 | build_and_test: 12 | 13 | runs-on: windows-latest 14 | 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | pg_version: [10, 11, 12, 13, 14, 15, 16, 17, 18] 19 | use_healpix: [0] 20 | 21 | name: PostgreSQL ${{ matrix.pg_version }} - USE_HEALPIX=${{ matrix.use_healpix }} (windows-latest) 22 | 23 | defaults: 24 | run: 25 | shell: msys2 {0} 26 | 27 | steps: 28 | 29 | - name: Install MSYS2 30 | uses: msys2/setup-msys2@v2 31 | with: 32 | update: true 33 | msystem: mingw64 34 | install: >- 35 | base-devel 36 | curl 37 | git 38 | make 39 | perl 40 | flex 41 | bison 42 | diffutils 43 | mingw-w64-x86_64-zlib 44 | mingw-w64-x86_64-icu 45 | mingw-w64-x86_64-gcc 46 | 47 | - name: Install PostgreSQL 48 | run: | 49 | echo "Workspace: ${GITHUB_WORKSPACE}" 50 | git clone --single-branch -b "REL_${{ matrix.pg_version }}_STABLE" https://git.postgresql.org/git/postgresql.git 51 | cd ${GITHUB_WORKSPACE}/postgresql 52 | ./configure --enable-cassert --without-icu 53 | make -j$(nproc) 54 | make install 55 | 56 | - name: Clone pgSphere 57 | uses: actions/checkout@v4 58 | 59 | - name: Build pgSphere 60 | run: | 61 | make --keep-going -j$(nproc) PROFILE='-Werror -Wall' USE_HEALPIX=0 62 | make USE_HEALPIX=0 install 63 | 64 | - name: Test pgSphere (installcheck) 65 | run: | 66 | initdb -D pgdata -U postgres 67 | pg_ctl -D pgdata -l postgres_installcheck.log start 68 | make USE_HEALPIX=0 installcheck 69 | pg_ctl -D pgdata stop 70 | rm -rf pgdata 71 | 72 | - name: Show installcheck regression.diffs 73 | if: ${{ failure() }} 74 | run: cat regression.diffs 75 | 76 | - name: Test pgSphere (crushtest) 77 | run: | 78 | initdb -D pgdata -U postgres 79 | pg_ctl -D pgdata -l postgres_crushtest.log start 80 | make USE_HEALPIX=0 crushtest 81 | pg_ctl -D pgdata stop 82 | 83 | - name: Show crushtest regression.diffs 84 | if: ${{ failure() }} 85 | run: cat regression.diffs 86 | 87 | - name: Upload artifacts 88 | uses: actions/upload-artifact@v4 89 | if: success() || failure() 90 | with: 91 | name: ${{ env.GITHUB_REF_SLUG_URL }}-pg${{ matrix.pg_version }}-use-healpix-${{ matrix.use_healpix }}-${{ github.run_id }} 92 | if-no-files-found: ignore 93 | path: | 94 | ./**/*.log 95 | ./**/*.diffs 96 | -------------------------------------------------------------------------------- /src/point.h: -------------------------------------------------------------------------------- 1 | #ifndef __PGS_POINT_H__ 2 | #define __PGS_POINT_H__ 3 | 4 | #include "vector3d.h" 5 | #include "sbuffer.h" 6 | 7 | /* This file contains declarations for spherical point and functions. */ 8 | 9 | /* 10 | * The data structure definition of a spherical point. 11 | */ 12 | typedef struct 13 | { 14 | float8 lng; /* longitude value in radians */ 15 | float8 lat; /* latitude value in radians */ 16 | } SPoint; 17 | 18 | extern Oid get_spoint_type_oid(void); 19 | 20 | /* 21 | * Calculate the distance between two spherical points in radians. 22 | */ 23 | 24 | extern float8 spoint_dist(const SPoint *p1, const SPoint *p2); 25 | 26 | /* 27 | * Check whether two points are equal. 28 | */ 29 | 30 | extern bool spoint_eq(const SPoint *p1, const SPoint *p2); 31 | 32 | /* 33 | * Check the longitude and latitude values of a spherical point. 34 | */ 35 | 36 | extern void spoint_check(SPoint *spoint); 37 | 38 | /* 39 | * Transforms a 3d vector into a spherical point. 40 | */ 41 | 42 | extern void vector3d_spoint(SPoint *p, const Vector3D *v); 43 | 44 | /* 45 | * Transforms a spherical point into a 3d vector. 46 | */ 47 | 48 | extern void spoint_vector3d(Vector3D *v, const SPoint *p); 49 | 50 | /* 51 | * Take the input and store it as a spherical point. 52 | */ 53 | 54 | extern Datum spherepoint_in(PG_FUNCTION_ARGS); 55 | 56 | /* 57 | * Create spherical point from lat, lng and store to first argument(pointer) 58 | */ 59 | 60 | extern void create_spherepoint_from_long_lat(SPoint *p, float8 lng, float8 lat); 61 | 62 | /* 63 | * Create a spherical point from longitude and latitude both in radians. 64 | */ 65 | 66 | extern Datum spherepoint_from_long_lat(PG_FUNCTION_ARGS); 67 | 68 | /* 69 | * Create a spherical point from longitude and latitude both in degrees. 70 | */ 71 | 72 | extern Datum spherepoint_from_long_lat_deg(PG_FUNCTION_ARGS); 73 | 74 | /* 75 | * Calculate the distance between two spherical points. 76 | */ 77 | extern Datum spherepoint_distance(PG_FUNCTION_ARGS); 78 | 79 | /* 80 | * Longitude of a spherical point. 81 | */ 82 | extern Datum spherepoint_long(PG_FUNCTION_ARGS); 83 | 84 | /* 85 | * Latitude of a spherical point. 86 | */ 87 | extern Datum spherepoint_lat(PG_FUNCTION_ARGS); 88 | 89 | /* 90 | * Cartesian x-value of a spherical point. 91 | */ 92 | extern Datum spherepoint_x(PG_FUNCTION_ARGS); 93 | 94 | /* 95 | * Cartesian y-value of a spherical point. 96 | */ 97 | extern Datum spherepoint_y(PG_FUNCTION_ARGS); 98 | 99 | /* 100 | * Cartesian z-value of a spherical point. 101 | */ 102 | extern Datum spherepoint_z(PG_FUNCTION_ARGS); 103 | 104 | /* 105 | * Cartesian values of a spherical point as an array. 106 | */ 107 | extern Datum spherepoint_xyz(PG_FUNCTION_ARGS); 108 | 109 | /* 110 | * Check whether two points are equal. 111 | */ 112 | extern Datum spherepoint_equal(PG_FUNCTION_ARGS); 113 | 114 | /* 115 | * Compute a 32-bit hash value of a point. 116 | */ 117 | extern Datum spherepoint_hash32(PG_FUNCTION_ARGS); 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /README.pg_sphere: -------------------------------------------------------------------------------- 1 | pgSphere is a PostgreSQL extension for spherical geometry. 2 | 3 | It provides: 4 | 5 | * New data types (points, spherical polygons, paths, circles, ellipses, coordinate ranges) 6 | * Input and output of data in various formats 7 | * Membership, overlap, and other operators 8 | * Circumference and area of objects 9 | * Object rotation by Euler angles 10 | * Indexing of spherical data types 11 | 12 | This is an R-tree implementation using GiST for spherical objects like 13 | spherical points and spherical circles with useful functions and operators. 14 | It also supports the Block Range INdexing (BRIN) for large datasets. 15 | 16 | NOTICE: 17 | This version will work only with PostgreSQL version 10 and above. 18 | 19 | VERSIONING: 20 | 21 | Stable versions are marked with tags containing version numbers in the GitHub 22 | repository at https://github.com/postgrespro/pgsphere/. Each stable version 23 | contains upgrade scripts for updating an existing installation to the latest 24 | version using the ALTER EXTENSION UPDATE TO command. 25 | 26 | The master branch is intended for development purposes and may contain 27 | intermediate changes. The current version in the master branch and its 28 | functionality are subject to change. 29 | 30 | Note: The master branch should not be used in production because the upgrade 31 | scripts and the current version number may be changed. 32 | 33 | INSTALLATION: 34 | 35 | -- Build and install 36 | 37 | make 38 | make install 39 | 40 | -- HEALPix/MOC support is included by default. If your platform does not 41 | -- have the required libhealpix_cxx dependency, you can optionally build 42 | -- pgSphere without HEALPix/MOC support, like this: 43 | 44 | make USE_HEALPIX=0 45 | make USE_HEALPIX=0 install 46 | 47 | -- Load extension 48 | 49 | psql -c "CREATE EXTENSION pg_sphere;" 50 | 51 | UPDATING AN EXISTING INSTALLATION: 52 | 53 | -- If you are updating from a previous version of pgSphere, perform the 54 | -- same make and make install steps as above, but, instead of the CREATE 55 | -- EXTENSION step, you need to do: 56 | 57 | psql -c "ALTER EXTENSION pg_sphere UPDATE TO 'A.B.C';" 58 | 59 | -- where A.B.C is a placeholder for the current version. 60 | -- You also may want to check what version of pgSphere is installed using 61 | either or both of the following commands: 62 | 63 | psql -c "SELECT pg_sphere_version();" 64 | psql -c "SELECT * FROM pg_available_extension_versions WHERE name = 'pg_sphere';" 65 | 66 | REGRESSION TEST (as the same user as the currently running PostgreSQL server): 67 | 68 | make installcheck 69 | 70 | -- or -- 71 | 72 | make USE_HEALPIX=0 installcheck 73 | 74 | LONG REGRESSION TEST: 75 | 76 | make crushtest 77 | 78 | -- or -- 79 | 80 | make USE_HEALPIX=0 crushtest 81 | 82 | The 'make' program used in all of the above commands must be compatible with 83 | GNU make. 84 | 85 | For more information or to report issues or to help with development, please 86 | refer to https://github.com/postgrespro/pgsphere/ 87 | 88 | Original repository for pgSphere: https://github.com/akorotkov/pgsphere 89 | 90 | Have a lot of fun! 91 | -------------------------------------------------------------------------------- /doc/stylesheets/stylesheet-text.xsl: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
  • 23 | 24 | 25 | 28 | 29 |
  • 30 |
    31 | 32 | 33 | 34 | 35 | * 36 | 37 | * 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
    53 | 54 | 55 | 56 | 57 | 58 | 59 |

    60 | 61 | 62 | : 63 | 64 |

    65 |
    66 | 67 | 68 |
    69 |
    70 | 71 | 72 | 73 | 77 |
    78 | 79 |
    80 | 81 | 85 |
    86 | 87 |
    88 | 89 | 93 |
    94 | 95 |
    96 | 97 |
    98 | -------------------------------------------------------------------------------- /sql/epochprop.sql: -------------------------------------------------------------------------------- 1 | SET extra_float_digits = 1; 2 | 3 | SELECT 4 | to_char(DEGREES(tp[1]), '999D9999999999'), 5 | to_char(DEGREES(tp[2]), '999D9999999999'), 6 | to_char(tp[3], '999D999'), 7 | to_char(DEGREES(tp[4])*3.6e6, '999D999'), 8 | to_char(DEGREES(tp[5])*3.6e6, '99999D999'), 9 | to_char(tp[6], '999D999') 10 | FROM ( 11 | SELECT epoch_prop(spoint(radians(269.45207695), radians(4.693364966)), 12 | 546.9759, 13 | RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), -110, 14 | -100) AS tp) AS q; 15 | 16 | SELECT 17 | to_char(DEGREES(tp[1]), '999D9999999999'), 18 | to_char(DEGREES(tp[2]), '999D9999999999'), 19 | to_char(tp[3], '999D999'), 20 | to_char(DEGREES(tp[4])*3.6e6, '999D999'), 21 | to_char(DEGREES(tp[5])*3.6e6, '99999D999'), 22 | to_char(tp[6], '999D999') 23 | FROM ( 24 | SELECT epoch_prop(spoint(radians(269.45207695), radians(4.693364966)), 25 | 0, 26 | RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), -110, 27 | -100) AS tp) AS q; 28 | 29 | SELECT 30 | to_char(DEGREES(tp[1]), '999D9999999999'), 31 | to_char(DEGREES(tp[2]), '999D9999999999'), 32 | to_char(tp[3], '999D999'), 33 | to_char(DEGREES(tp[4])*3.6e6, '999D999'), 34 | to_char(DEGREES(tp[5])*3.6e6, '99999D999'), 35 | to_char(tp[6], '999D999') 36 | FROM ( 37 | SELECT epoch_prop(spoint(radians(269.45207695), radians(4.693364966)), 38 | NULL, 39 | RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), -110, 40 | -100) AS tp) AS q; 41 | 42 | SELECT 43 | to_char(DEGREES(tp[1]), '999D9999999999'), 44 | to_char(DEGREES(tp[2]), '999D9999999999'), 45 | to_char(tp[3], '999D999'), 46 | to_char(DEGREES(tp[4])*3.6e6, '999D999'), 47 | to_char(DEGREES(tp[5])*3.6e6, '99999D999'), 48 | to_char(tp[6], '999D999') 49 | FROM ( 50 | SELECT epoch_prop(spoint(radians(269.45207695), radians(4.693364966)), 51 | 23, 52 | RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), NULL, 53 | 20) AS tp) AS q; 54 | 55 | SELECT 56 | to_char(DEGREES(tp[1]), '999D9999999999'), 57 | to_char(DEGREES(tp[2]), '999D9999999999'), 58 | to_char(tp[3], '999D999'), 59 | to_char(DEGREES(tp[4])*3.6e6, '999D999'), 60 | to_char(DEGREES(tp[5])*3.6e6, '99999D999'), 61 | to_char(tp[6], '999D999') 62 | FROM ( 63 | SELECT epoch_prop(spoint(radians(269.45207695), radians(4.693364966)), 64 | 23, 65 | NULL, RADIANS(10362/3.6e6), -110, 66 | 120) AS tp) AS q; 67 | 68 | SELECT epoch_prop(NULL, 69 | 23, 70 | 0.01 , RADIANS(10362/3.6e6), -110, 71 | 120); 72 | 73 | SELECT epoch_prop_pos(spoint(radians(269.45207695), radians(4.693364966)), 74 | 23, 75 | RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), -110, 76 | 20) AS tp; 77 | 78 | SELECT epoch_prop_pos(spoint(radians(269.45207695), radians(4.693364966)), 79 | RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), 80 | 20) AS tp; 81 | -------------------------------------------------------------------------------- /expected/spoint_brin.out: -------------------------------------------------------------------------------- 1 | CREATE TABLE test_points ( 2 | p spoint 3 | ); 4 | COPY test_points (p) FROM stdin; 5 | CREATE OR REPLACE FUNCTION qnodes(q text) RETURNS text 6 | LANGUAGE 'plpgsql' AS 7 | $$ 8 | DECLARE 9 | exp TEXT; 10 | mat TEXT[]; 11 | ret TEXT[]; 12 | BEGIN 13 | FOR exp IN EXECUTE 'EXPLAIN ' || q 14 | LOOP 15 | --RAISE NOTICE 'EXP: %', exp; 16 | mat := regexp_matches(exp, ' *(?:-> *)?(.*Scan on (test_points|brin_spoint))'); 17 | --RAISE NOTICE 'MAT: %', mat; 18 | IF mat IS NOT NULL THEN 19 | ret := array_append(ret, mat[1]); 20 | END IF; 21 | --RAISE NOTICE 'RET: %', ret; 22 | END LOOP; 23 | RETURN array_to_string(ret,','); 24 | END; 25 | $$; 26 | CREATE INDEX brin_spoint ON test_points USING brin (p) WITH (pages_per_range = 16); 27 | set enable_indexscan = off; 28 | set enable_bitmapscan = off; 29 | set enable_seqscan = on; 30 | SELECT 'scan_seq', qnodes('SELECT * FROM test_points WHERE p <@ sbox ''( (10d,10d), (20d,20d) )'''); 31 | ?column? | qnodes 32 | ----------+------------------------- 33 | scan_seq | Seq Scan on test_points 34 | (1 row) 35 | 36 | SELECT * FROM test_points WHERE p <@ sbox '( (10d,10d), (20d,20d) )'; 37 | p 38 | ----------------------------------------- 39 | (0.349065850398866 , 0.174532925199433) 40 | (1 row) 41 | 42 | SELECT 'scan_seq', qnodes('SELECT * FROM test_points WHERE p && sbox ''( (10d,10d), (20d,20d) )'''); 43 | ?column? | qnodes 44 | ----------+------------------------- 45 | scan_seq | Seq Scan on test_points 46 | (1 row) 47 | 48 | SELECT * FROM test_points WHERE p && sbox '( (10d,10d), (20d,20d) )'; 49 | p 50 | ----------------------------------------- 51 | (0.349065850398866 , 0.174532925199433) 52 | (1 row) 53 | 54 | set enable_indexscan = off; 55 | set enable_bitmapscan = on; 56 | set enable_seqscan = off; 57 | SELECT 'scan_idx', qnodes('SELECT * FROM test_points WHERE p <@ sbox ''( (10d,10d), (20d,20d) )'''); 58 | ?column? | qnodes 59 | ----------+------------------------------------------------------------------ 60 | scan_idx | Bitmap Heap Scan on test_points,Bitmap Index Scan on brin_spoint 61 | (1 row) 62 | 63 | SELECT * FROM test_points WHERE p <@ sbox '( (10d,10d), (20d,20d) )'; 64 | p 65 | ----------------------------------------- 66 | (0.349065850398866 , 0.174532925199433) 67 | (1 row) 68 | 69 | SELECT 'scan_idx', qnodes('SELECT * FROM test_points WHERE p && sbox ''( (10d,10d), (20d,20d) )'''); 70 | ?column? | qnodes 71 | ----------+------------------------------------------------------------------ 72 | scan_idx | Bitmap Heap Scan on test_points,Bitmap Index Scan on brin_spoint 73 | (1 row) 74 | 75 | SELECT * FROM test_points WHERE p && sbox '( (10d,10d), (20d,20d) )'; 76 | p 77 | ----------------------------------------- 78 | (0.349065850398866 , 0.174532925199433) 79 | (1 row) 80 | 81 | -- cleanup 82 | DROP INDEX brin_spoint; 83 | DROP TABLE test_points; 84 | DROP FUNCTION qnodes(text); 85 | set enable_indexscan = on; 86 | set enable_bitmapscan = on; 87 | set enable_seqscan = on; 88 | -------------------------------------------------------------------------------- /expected/sbox_brin.out: -------------------------------------------------------------------------------- 1 | SELECT set_sphere_output_precision(8); 2 | set_sphere_output_precision 3 | ----------------------------- 4 | SET 8 5 | (1 row) 6 | 7 | CREATE TABLE test_boxes ( 8 | b sbox 9 | ); 10 | COPY test_boxes (b) FROM stdin; 11 | CREATE OR REPLACE FUNCTION qnodes(q text) RETURNS text 12 | LANGUAGE 'plpgsql' AS 13 | $$ 14 | DECLARE 15 | exp TEXT; 16 | mat TEXT[]; 17 | ret TEXT[]; 18 | BEGIN 19 | FOR exp IN EXECUTE 'EXPLAIN ' || q 20 | LOOP 21 | --RAISE NOTICE 'EXP: %', exp; 22 | mat := regexp_matches(exp, ' *(?:-> *)?(.*Scan on (test_boxes|test_boxes_brin_idx))'); 23 | --RAISE NOTICE 'MAT: %', mat; 24 | IF mat IS NOT NULL THEN 25 | ret := array_append(ret, mat[1]); 26 | END IF; 27 | --RAISE NOTICE 'RET: %', ret; 28 | END LOOP; 29 | RETURN array_to_string(ret,','); 30 | END; 31 | $$; 32 | CREATE INDEX test_boxes_brin_idx ON test_boxes USING brin (b); 33 | SET enable_indexscan = OFF; 34 | SET enable_bitmapscan = OFF; 35 | SET enable_seqscan = ON; 36 | SELECT 'scan_seq', qnodes('SELECT * FROM test_boxes WHERE b <@ sbox ''( (10d,10d), (20d,20d) )'''); 37 | ?column? | qnodes 38 | ----------+------------------------ 39 | scan_seq | Seq Scan on test_boxes 40 | (1 row) 41 | 42 | SELECT * FROM test_boxes WHERE b <@ sbox '( (10d,10d), (20d,20d) )'; 43 | b 44 | --- 45 | (0 rows) 46 | 47 | SELECT 'scan_seq', qnodes('SELECT * FROM test_boxes WHERE b && sbox ''( (10d,10d), (20d,20d) )'''); 48 | ?column? | qnodes 49 | ----------+------------------------ 50 | scan_seq | Seq Scan on test_boxes 51 | (1 row) 52 | 53 | SELECT * FROM test_boxes WHERE b && sbox '( (10d,10d), (20d,20d) )'; 54 | b 55 | -------------------------------------------------------- 56 | ((0.34906585 , 0.17453293), (0.35006585 , 0.17463293)) 57 | (1 row) 58 | 59 | SET enable_indexscan = OFF; 60 | SET enable_bitmapscan = ON; 61 | SET enable_seqscan = OFF; 62 | SELECT 'scan_idx', qnodes('SELECT * FROM test_boxes WHERE b <@ sbox ''( (10d,10d), (20d,20d) )'''); 63 | ?column? | qnodes 64 | ----------+------------------------------------------------------------------------- 65 | scan_idx | Bitmap Heap Scan on test_boxes,Bitmap Index Scan on test_boxes_brin_idx 66 | (1 row) 67 | 68 | SELECT * FROM test_boxes WHERE b <@ sbox '( (10d,10d), (20d,20d) )'; 69 | b 70 | --- 71 | (0 rows) 72 | 73 | SELECT 'scan_idx', qnodes('SELECT * FROM test_boxes WHERE b && sbox ''( (10d,10d), (20d,20d) )'''); 74 | ?column? | qnodes 75 | ----------+------------------------------------------------------------------------- 76 | scan_idx | Bitmap Heap Scan on test_boxes,Bitmap Index Scan on test_boxes_brin_idx 77 | (1 row) 78 | 79 | SELECT * FROM test_boxes WHERE b && sbox '( (10d,10d), (20d,20d) )'; 80 | b 81 | -------------------------------------------------------- 82 | ((0.34906585 , 0.17453293), (0.35006585 , 0.17463293)) 83 | (1 row) 84 | 85 | ---- cleanup 86 | DROP INDEX test_boxes_brin_idx; 87 | DROP TABLE test_boxes; 88 | DROP FUNCTION qnodes(text); 89 | SET enable_indexscan = ON; 90 | SET enable_bitmapscan = ON; 91 | SET enable_seqscan = ON; 92 | -------------------------------------------------------------------------------- /sql/line.sql: -------------------------------------------------------------------------------- 1 | \set ECHO none 2 | SELECT set_sphere_output_precision(8); 3 | \set ECHO all 4 | SET extra_float_digits TO -3; 5 | 6 | -- checking spherical line operators 7 | 8 | SELECT sline ( spoint '(0, 90d)', spoint '(0, -89d)' ) = 9 | sline ( spoint '(0, 90d)', spoint '(0, -89d)' ) ; 10 | SELECT sline ( spoint '(0, 90d)', spoint '(0, -89d)' ) <> 11 | sline ( spoint '(0, -89d)', spoint '(0, 90d)' ) ; 12 | 13 | 14 | 15 | SELECT sline ( spoint '(0, 0d)', spoint '(10d, 0d)' ) # 16 | sline ( spoint '(5d, 5d)', spoint '(5d, -5d)' ) ; 17 | 18 | SELECT sline ( spoint '(0, 0d)', spoint '(10d, 0d)' ) # 19 | sline ( spoint '(10d, 5d)', spoint '(10d, -5d)' ) ; 20 | 21 | SELECT sline ( spoint '(0, 0d)', spoint '(10d, 0d)' ) # 22 | sline ( spoint '(15d, 5d)', spoint '(15d, -5d)' ) ; 23 | 24 | SELECT sline ( spoint '(0, 0d)', spoint '(10d, 0d)' ) # 25 | sline ( spoint '(10d, 0d)', spoint '(10d, -5d)' ) ; 26 | 27 | 28 | 29 | SELECT sline ( spoint '(0, 0d)', spoint '(10d, 0d)' ) # 30 | sline ( spoint '(5d, -5d)', spoint '(5d, 5d)' ) ; 31 | 32 | SELECT sline ( spoint '(0, 0d)', spoint '(10d, 0d)' ) # 33 | sline ( spoint '(10d, -5d)', spoint '(10d, 5d)' ) ; 34 | 35 | SELECT sline ( spoint '(0, 0d)', spoint '(10d, 0d)' ) # 36 | sline ( spoint '(15d, -5d)', spoint '(15d, 5d)' ) ; 37 | 38 | SELECT sline ( spoint '(0, 0d)', spoint '(10d, 0d)' ) # 39 | sline ( spoint '(10d, 0d)', spoint '(10d, 5d)' ) ; 40 | 41 | 42 | -- check small lines 43 | 44 | 45 | SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # 46 | sline ( spoint '(0.0000005d, 0.0000005d)', spoint '(0.0000005d, -0.0000005d)' ) ; 47 | 48 | SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # 49 | sline ( spoint '(0.000001d, 0.0000005d)', spoint '(0.000001d, -0.0000005d)' ) ; 50 | 51 | SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # 52 | sline ( spoint '(0.0000015d, 0.0000005d)', spoint '(0.0000015d, -0.0000005d)' ) ; 53 | 54 | SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # 55 | sline ( spoint '(0.000001d, 0d)', spoint '(0.000001d, -0.0000005d)' ) ; 56 | 57 | 58 | 59 | SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # 60 | sline ( spoint '(0.0000005d, -0.0000005d)', spoint '(0.0000005d, 0.0000005d)' ) ; 61 | 62 | SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # 63 | sline ( spoint '(0.000001d, -0.0000005d)', spoint '(0.000001d, 0.0000005d)' ) ; 64 | 65 | SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # 66 | sline ( spoint '(0.0000015d, -0.0000005d)', spoint '(0.0000015d, 0.0000005d)' ) ; 67 | 68 | SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # 69 | sline ( spoint '(0.000001d, 0d)', spoint '(0.000001d, 0.0000005d)' ) ; 70 | 71 | 72 | -- checking the distance between a line and a point 73 | 74 | 75 | SELECT sline '( 90d, 0d, 0d, XYZ ), 40d ' <-> spoint '( 0d, 90d )'; 76 | 77 | SELECT sline '( 90d, 0d, 0d, XYZ ), 40d ' <-> spoint '( 0d, 90d )' = 78 | spoint '( 0d, 90d )' <-> sline '( 90d, 0d, 0d, XYZ ), 40d '; 79 | 80 | SELECT sline '( 0d, 0d, 0d, XYZ ), 0d ' <-> spoint '( 0d, 90d )'; 81 | 82 | SELECT sline '( 0d, 0d, 0d, XYZ ), 0d ' <-> spoint '( 0d, 0d )'; 83 | 84 | SELECT sline '( 0d, 0d, 0d, XYZ ), 30d ' <-> spoint '( 0d, 30d )'; 85 | -------------------------------------------------------------------------------- /sql/index.sql: -------------------------------------------------------------------------------- 1 | \set ECHO none 2 | SELECT set_sphere_output_precision(8); 3 | \set ECHO all 4 | 5 | -- without idx 6 | 7 | SELECT count(*) FROM spheretmp1 WHERE p @ scircle '<(1,1),0.3>'; 8 | 9 | SELECT count(*) FROM spheretmp1 WHERE p = spoint '(3.09 , 1.25)' ; 10 | 11 | SELECT count(*) FROM spheretmp2 WHERE c @ scircle '<(1,1),0.3>'; 12 | 13 | SELECT count(*) FROM spheretmp2 WHERE c && scircle '<(1,1),0.3>'; 14 | 15 | SELECT count(*) FROM spheretmp3 WHERE b && scircle '<(1,1),0.3>'; 16 | 17 | SELECT count(*) FROM spheretmp3 WHERE spoint '(3.09 , 1.25)' @ b ; 18 | 19 | SELECT count(*) FROM spheretmp4 WHERE l @ scircle '<(1,1),0.3>'; 20 | 21 | SELECT count(*) FROM spheretmp4 WHERE l && scircle '<(1,1),0.3>'; 22 | 23 | 24 | -- create idx 25 | 26 | CREATE TABLE spheretmp1b AS TABLE spheretmp1; 27 | ANALYZE spheretmp1; 28 | 29 | CREATE INDEX aaaidx ON spheretmp1 USING gist ( p ); 30 | 31 | CREATE INDEX spoint3_idx ON spheretmp1b USING gist (p spoint3); 32 | 33 | CREATE INDEX bbbidx ON spheretmp2 USING gist ( c ); 34 | 35 | CREATE INDEX cccidx ON spheretmp3 USING gist ( b ); 36 | 37 | CREATE INDEX dddidx ON spheretmp4 USING gist ( l ); 38 | 39 | --with idx 40 | 41 | SET enable_seqscan = OFF ; 42 | 43 | SELECT count(*) FROM spheretmp1 WHERE p @ scircle '<(1,1),0.3>'; 44 | SELECT count(*) FROM spheretmp1b WHERE p @ scircle '<(1,1),0.3>'; 45 | SELECT count(*) FROM spheretmp1 WHERE p <@ scircle '<(1,1),0.3>'; 46 | SELECT count(*) FROM spheretmp1b WHERE p <@ scircle '<(1,1),0.3>'; 47 | 48 | SELECT count(*) FROM spheretmp1 WHERE p = spoint '(3.09 , 1.25)' ; 49 | SELECT count(*) FROM spheretmp1b WHERE p = spoint '(3.09 , 1.25)' ; 50 | 51 | SELECT count(*) FROM spheretmp2 WHERE c @ scircle '<(1,1),0.3>' ; 52 | 53 | SELECT count(*) FROM spheretmp2 WHERE c && scircle '<(1,1),0.3>' ; 54 | 55 | SELECT count(*) FROM spheretmp3 WHERE b && scircle '<(1,1),0.3>'; 56 | 57 | SELECT count(*) FROM spheretmp3 WHERE spoint '(3.09 , 1.25)' @ b ; 58 | 59 | SELECT count(*) FROM spheretmp4 WHERE l @ scircle '<(1,1),0.3>' ; 60 | 61 | SELECT count(*) FROM spheretmp4 WHERE l && scircle '<(1,1),0.3>' ; 62 | 63 | -- test spoint3 operator class with and without index-only scan 64 | 65 | SET enable_bitmapscan = OFF; 66 | SET enable_indexonlyscan = ON; 67 | 68 | EXPLAIN (COSTS OFF) SELECT count(*) FROM spheretmp1b WHERE p <@ scircle '<(1,1),0.3>'; 69 | SELECT count(*) FROM spheretmp1b WHERE p <@ scircle '<(1,1),0.3>'; 70 | EXPLAIN (COSTS OFF) SELECT count(*) FROM spheretmp1b WHERE p = spoint '(3.09 , 1.25)'; 71 | SELECT count(*) FROM spheretmp1b WHERE p = spoint '(3.09 , 1.25)'; 72 | 73 | SET enable_indexonlyscan = OFF; 74 | 75 | EXPLAIN (COSTS OFF) SELECT count(*) FROM spheretmp1b WHERE p <@ scircle '<(1,1),0.3>'; 76 | SELECT count(*) FROM spheretmp1b WHERE p <@ scircle '<(1,1),0.3>'; 77 | EXPLAIN (COSTS OFF) SELECT count(*) FROM spheretmp1b WHERE p = spoint '(3.09 , 1.25)'; 78 | SELECT count(*) FROM spheretmp1b WHERE p = spoint '(3.09 , 1.25)'; 79 | 80 | -- test hash opclass 81 | 82 | CREATE TABLE spheretmp1c AS TABLE spheretmp1; 83 | 84 | SELECT p FROM spheretmp1c WHERE p <@ scircle '<(1,1),0.2>' ORDER BY p::text; 85 | WITH points AS (SELECT DISTINCT p FROM spheretmp1c WHERE p <@ scircle '<(1,1),0.2>') 86 | SELECT p FROM points ORDER BY p::text; 87 | 88 | CREATE INDEX spheretmp1c_hash_idx ON spheretmp1c USING hash(p); 89 | EXPLAIN (COSTS OFF) SELECT * FROM spheretmp1c WHERE p = '(0.67 , 0.97)'; 90 | -------------------------------------------------------------------------------- /upgrade_scripts/pg_sphere--1.2.3--1.3.0.sql.in: -------------------------------------------------------------------------------- 1 | CREATE FUNCTION scircle_deg(spoint, float8) 2 | RETURNS scircle 3 | AS 'MODULE_PATHNAME' , 'spherecircle_by_center_deg' 4 | LANGUAGE 'c' 5 | IMMUTABLE STRICT PARALLEL SAFE; 6 | 7 | COMMENT ON FUNCTION scircle_deg(spoint, float8) IS 8 | 'spherical circle with spherical point as center and float8 as radius in degrees'; 9 | 10 | CREATE FUNCTION spoint_deg(FLOAT8, FLOAT8) 11 | RETURNS spoint 12 | AS 'MODULE_PATHNAME', 'spherepoint_from_long_lat_deg' 13 | LANGUAGE 'c' 14 | IMMUTABLE STRICT PARALLEL SAFE; 15 | 16 | COMMENT ON FUNCTION spoint_deg(FLOAT8, FLOAT8) IS 17 | 'returns a spherical point from longitude (arg1, in degrees), latitude (arg2, in degrees)'; 18 | 19 | CREATE FUNCTION spoly_deg(float8[]) 20 | RETURNS spoly 21 | AS 'MODULE_PATHNAME', 'spherepoly_deg' 22 | LANGUAGE 'c' 23 | IMMUTABLE STRICT; 24 | 25 | COMMENT ON FUNCTION spoly_deg(float8[]) IS 26 | ' Create spoly from array of points. 27 | Two consecutive numbers among those present 28 | refer to the same occurrence and cover its 29 | latitude and longitude, respectively.'; 30 | 31 | CREATE FUNCTION spath_as_array(spath) 32 | RETURNS spoint[] 33 | AS 'MODULE_PATHNAME', 'spherepath_get_array' 34 | LANGUAGE 'c' 35 | IMMUTABLE STRICT PARALLEL SAFE; 36 | 37 | COMMENT ON FUNCTION spath_as_array(spath) IS 38 | 'returns spath as array of points'; 39 | 40 | CREATE FUNCTION spoint(spoly, int4) 41 | RETURNS spoint 42 | AS 'MODULE_PATHNAME', 'spherepoly_get_point' 43 | LANGUAGE 'c' 44 | IMMUTABLE STRICT PARALLEL SAFE; 45 | 46 | COMMENT ON FUNCTION spoint(spoly, int4) IS 47 | 'returns n-th point of spherical polygon'; 48 | 49 | CREATE FUNCTION spoly_as_array(spoly) 50 | RETURNS spoint[] 51 | AS 'MODULE_PATHNAME', 'spherepoly_get_array' 52 | LANGUAGE 'c' 53 | IMMUTABLE STRICT PARALLEL SAFE; 54 | 55 | COMMENT ON FUNCTION spoly_as_array(spoly) IS 56 | 'returns spoly as array of points'; 57 | 58 | CREATE FUNCTION dist(sline, spoint) 59 | RETURNS FLOAT8 60 | AS 'MODULE_PATHNAME', 'sphereline_point_distance' 61 | LANGUAGE 'c' 62 | IMMUTABLE STRICT; 63 | 64 | COMMENT ON FUNCTION dist(sline, spoint) IS 65 | 'returns the distance between spherical line and spherical point'; 66 | 67 | CREATE OPERATOR <-> ( 68 | LEFTARG = sline, 69 | RIGHTARG = spoint, 70 | COMMUTATOR = '<->', 71 | PROCEDURE = dist 72 | ); 73 | 74 | COMMENT ON OPERATOR <-> (sline, spoint) IS 75 | 'returns the distance between spherical line and spherical point'; 76 | 77 | CREATE FUNCTION dist(spoint, sline) 78 | RETURNS FLOAT8 79 | AS 'MODULE_PATHNAME', 'sphereline_point_distance_com' 80 | LANGUAGE 'c' 81 | IMMUTABLE STRICT; 82 | 83 | COMMENT ON FUNCTION dist(spoint, sline) IS 84 | 'returns the distance between spherical line and spherical point'; 85 | 86 | 87 | CREATE OPERATOR <-> ( 88 | LEFTARG = spoint, 89 | RIGHTARG = sline, 90 | COMMUTATOR = '<->', 91 | PROCEDURE = dist 92 | ); 93 | 94 | COMMENT ON OPERATOR <-> (spoint, sline) IS 95 | 'returns the distance between spherical line and spherical point'; 96 | 97 | CREATE FUNCTION spoly_is_convex(spoly) 98 | RETURNS BOOL 99 | AS 'MODULE_PATHNAME', 'spherepoly_is_convex' 100 | LANGUAGE 'c' 101 | IMMUTABLE PARALLEL SAFE; 102 | 103 | COMMENT ON FUNCTION spoly_is_convex(spoly) IS 104 | 'true if spherical polygon is convex'; 105 | -------------------------------------------------------------------------------- /src/sparse.h: -------------------------------------------------------------------------------- 1 | /* A Bison parser, made by GNU Bison 3.4.2. */ 2 | 3 | /* Bison interface for Yacc-like parsers in C 4 | 5 | Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation, 6 | Inc. 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . */ 20 | 21 | /* As a special exception, you may create a larger work that contains 22 | part or all of the Bison parser skeleton and distribute that work 23 | under terms of your choice, so long as that work isn't itself a 24 | parser generator using the skeleton or a modified version thereof 25 | as a parser skeleton. Alternatively, if you modify or redistribute 26 | the parser skeleton itself, you may (at your option) remove this 27 | special exception, which will cause the skeleton and the resulting 28 | Bison output files to be licensed under the GNU General Public 29 | License without this special exception. 30 | 31 | This special exception was added by the Free Software Foundation in 32 | version 2.2 of Bison. */ 33 | 34 | /* Undocumented macros, especially those whose name start with YY_, 35 | are private implementation details. Do not rely on them. */ 36 | 37 | #ifndef YY_SPHERE_YY_SRC_SPARSE_H_INCLUDED 38 | # define YY_SPHERE_YY_SRC_SPARSE_H_INCLUDED 39 | /* Debug traces. */ 40 | #ifndef YYDEBUG 41 | # define YYDEBUG 0 42 | #endif 43 | #if YYDEBUG 44 | extern int sphere_yydebug; 45 | #endif 46 | 47 | /* Token type. */ 48 | #ifndef YYTOKENTYPE 49 | # define YYTOKENTYPE 50 | enum yytokentype 51 | { 52 | HOUR = 258, 53 | DEG = 259, 54 | MIN = 260, 55 | SEC = 261, 56 | COMMA = 262, 57 | OPENCIRC = 263, 58 | CLOSECIRC = 264, 59 | OPENPOINT = 265, 60 | CLOSEPOINT = 266, 61 | OPENARR = 267, 62 | CLOSEARR = 268, 63 | TOK_SIGN = 269, 64 | TOK_INT = 270, 65 | TOK_FLOAT = 271, 66 | EULERAXIS = 272 67 | }; 68 | #endif 69 | /* Tokens. */ 70 | #define HOUR 258 71 | #define DEG 259 72 | #define MIN 260 73 | #define SEC 261 74 | #define COMMA 262 75 | #define OPENCIRC 263 76 | #define CLOSECIRC 264 77 | #define OPENPOINT 265 78 | #define CLOSEPOINT 266 79 | #define OPENARR 267 80 | #define CLOSEARR 268 81 | #define TOK_SIGN 269 82 | #define TOK_INT 270 83 | #define TOK_FLOAT 271 84 | #define EULERAXIS 272 85 | 86 | /* Value type. */ 87 | #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED 88 | union YYSTYPE 89 | { 90 | #line 41 "src/sparse.y" 91 | 92 | int i; 93 | double d; 94 | char c[3]; 95 | 96 | #line 97 "src/sparse.h" 97 | 98 | }; 99 | typedef union YYSTYPE YYSTYPE; 100 | # define YYSTYPE_IS_TRIVIAL 1 101 | # define YYSTYPE_IS_DECLARED 1 102 | #endif 103 | 104 | 105 | extern YYSTYPE sphere_yylval; 106 | 107 | int sphere_yyparse (void); 108 | 109 | #endif /* !YY_SPHERE_YY_SRC_SPARSE_H_INCLUDED */ 110 | -------------------------------------------------------------------------------- /sql/bounding_box_gist.sql: -------------------------------------------------------------------------------- 1 | SET extra_float_digits = 2; 2 | SET enable_seqscan=true; 3 | CREATE TABLE bbox_ellipse (e sellipse not null); 4 | INSERT INTO bbox_ellipse VALUES ('<{10d, 0.1d}, (0d,0d), 0d>'); 5 | SELECT spoint '(5d, 0d)' @ sellipse '<{10d, 0.1d}, (0d,0d), 0d>' AS inside; 6 | SELECT COUNT(*) FROM bbox_ellipse WHERE spoint '(5d, 0d)' @ e; 7 | SELECT COUNT(*) FROM bbox_ellipse WHERE spoint '(5d, 0d)' <@ e; 8 | EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_ellipse WHERE spoint '(5d, 0d)' @ e; 9 | EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_ellipse WHERE spoint '(5d, 0d)' <@ e; 10 | -- The ellipse has semi-major axis length of 10 degrees along the equator, 11 | -- so (lon,lat) = (5,0) should be inside. 12 | CREATE INDEX idx_bbox_ellipse ON bbox_ellipse USING gist (e); 13 | ANALYZE bbox_ellipse; 14 | SET enable_seqscan=false; 15 | SELECT COUNT(*) FROM bbox_ellipse WHERE spoint '(5d, 0d)' @ e; 16 | SELECT COUNT(*) FROM bbox_ellipse WHERE spoint '(5d, 0d)' <@ e; 17 | EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_ellipse WHERE spoint '(5d, 0d)' @ e; 18 | EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_ellipse WHERE spoint '(5d, 0d)' <@ e; 19 | 20 | SET enable_seqscan=true; 21 | CREATE TABLE bbox_poly (p spoly not null); 22 | INSERT INTO bbox_poly VALUES ('{(40d,-40d), (0d,80d), (-40d,-40d)}'); 23 | SELECT spoint '(0d, 0d)' @ spoly '{(40d,-40d), (0d,80d), (-40d,-40d)}' AS inside; 24 | SELECT COUNT(*) FROM bbox_poly WHERE spoint '(0d, 0d)' @ p; 25 | SELECT COUNT(*) FROM bbox_poly WHERE spoint '(0d, 0d)' <@ p; 26 | EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_poly WHERE spoint '(0d, 0d)' @ p; 27 | EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_poly WHERE spoint '(0d, 0d)' <@ p; 28 | CREATE INDEX idx_bbox_poly ON bbox_poly USING gist (p); 29 | ANALYZE bbox_poly; 30 | SET enable_seqscan=false; 31 | SELECT COUNT(*) FROM bbox_poly WHERE spoint '(0d, 0d)' @ p; 32 | SELECT COUNT(*) FROM bbox_poly WHERE spoint '(0d, 0d)' <@ p; 33 | EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_poly WHERE spoint '(0d, 0d)' @ p; 34 | EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_poly WHERE spoint '(0d, 0d)' <@ p; 35 | 36 | SET enable_seqscan=true; 37 | CREATE TABLE bbox_path (p spath not null); 38 | INSERT INTO bbox_path VALUES ('{(-46d,0d), (-45d,80d), (-45d,0d), (80d,0d)}'); 39 | SELECT sline(spoint '(0d, -10d)', spoint '(0d, 10d)') && spath '{(-46d,0d), (-45d,80d), (-45d,0d), (80d,0d)}' AS crossing; 40 | SELECT spoint '(0d, 0d)' @ spath '{(-46d,0d), (-45d,80d), (-45d,0d), (80d,0d)}' AS inside; 41 | SELECT COUNT(*) FROM bbox_path WHERE sline(spoint '(0d, -10d)', spoint '(0d, 10d)') && p; 42 | SELECT COUNT(*) FROM bbox_path WHERE spoint '(0d, 0d)' @ p; 43 | SELECT COUNT(*) FROM bbox_path WHERE spoint '(0d, 0d)' <@ p; 44 | EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_path WHERE sline(spoint '(0d, -10d)', spoint '(0d, 10d)') && p; 45 | EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_path WHERE spoint '(0d, 0d)' @ p; 46 | EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_path WHERE spoint '(0d, 0d)' <@ p; 47 | CREATE INDEX idx_bbox_path ON bbox_path USING gist (p); 48 | ANALYZE bbox_path; 49 | SET enable_seqscan=false; 50 | SELECT COUNT(*) FROM bbox_path WHERE sline(spoint '(0d, -10d)', spoint '(0d, 10d)') && p; 51 | SELECT COUNT(*) FROM bbox_path WHERE spoint '(0d, 0d)' @ p; 52 | SELECT COUNT(*) FROM bbox_path WHERE spoint '(0d, 0d)' <@ p; 53 | EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_path WHERE sline(spoint '(0d, -10d)', spoint '(0d, 10d)') && p; 54 | EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_path WHERE spoint '(0d, 0d)' @ p; 55 | EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_path WHERE spoint '(0d, 0d)' <@ p; 56 | -------------------------------------------------------------------------------- /doc/install.sgm: -------------------------------------------------------------------------------- 1 | 2 | Installation 3 | 4 | 5 | Download 6 | 7 | 8 | &pgsphere; is not the part of the &postgresql; software. You can download 9 | the latest release from the 10 | &pgsphere; Releases page. 11 | The source code can also be downloaded by cloning the repository with the 12 | appropriate release tag. The master branch is intended for development 13 | use and may contain the code in a transitional state. It is not recommended 14 | for use in production. 15 | 16 | 17 | 18 | 19 | Install 20 | 21 | It is assumed that &postgresql; is already installed. Depending on the 22 | system configuration, superuser (root) access rights may be required to 23 | complete the installation. 24 | 25 | 26 | 27 | The installation script uses &pg_config; utility. Make sure that the 28 | environment variable PATH includes path to &pg_config; utility. The path 29 | to &pg_config; can be also specified in make command: 30 | 31 | make PG_CONFIG=/path/to/pgconfig ...]]> 32 | 33 | 34 | 35 | Unpack the downloaded archive and enter the directory: 36 | 37 | tar -xzf path/to/pgsphere-X.X.X.tgz]]> 38 | cd pgsphere-X.X.X]]> 39 | 40 | 41 | 42 | Compile the code. By default, &pgsphere; is compiled with &healpix; support. 43 | 44 | 45 | make]]> 46 | 47 | or compile without &healpix; support: 48 | 49 | make USE_HEALPIX=0]]> 50 | 51 | 52 | 53 | Run regression tests optionally. If &pgsphere; was compiled without &healpix; 54 | support, USE_HEALPIX=0 should be specified in make command line. 55 | 56 | 57 | make test]]> 58 | 59 | 60 | 61 | Install &pgsphere; files to the installation directories. The installation 62 | directories are defined by &pg_config; utility. Superuser (root) access 63 | rights may be required. If &pgsphere; was compiled without &healpix; support, 64 | USE_HEALPIX=0 should be added after make. 65 | 66 | 67 | make install]]> 68 | 69 | 70 | 71 | 72 | 73 | Configure Extension 74 | 75 | 76 | We assume you have already created a database userdb, 77 | where userdb is the name of any database. Assume that 78 | the name of &postgresql;'s superuser is postgres. 79 | 80 | 81 | psql -U postgres -c 'CREATE EXTENSION pg_sphere' userdb]]> 82 | 83 | 84 | 85 | It may be necessary to give more psql options, like port 86 | or host name, depending on your system configuration. Please, take a look at 87 | the psql user manual for details. The psql user manual for the latest 88 | &postgresql; version can be found at 89 | 90 | &postgresql; site 91 | . 92 | 93 | 94 | To get the version of installed &pgsphere; software: 95 | 96 | SELECT pg_sphere_version();]]> 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | #---------------------------------------------------------------------------- 2 | # 3 | # pgSphere documentation generation 4 | # 5 | #---------------------------------------------------------------------------- 6 | 7 | ifndef PGSPHERE_VERSION 8 | include ../Makefile.common.mk 9 | ifndef PGSPHERE_VERSION 10 | $(error PGSPHERE_VERSION is not set) 11 | endif 12 | endif 13 | 14 | ifndef FOP 15 | FOP = fop 16 | endif 17 | 18 | ifdef XMLLINT 19 | XMLLINT := $(XMLLINT) --nonet 20 | else 21 | XMLLINT = xmllint --nonet 22 | endif 23 | 24 | ifdef XSLTPROC 25 | XSLTPROC := $(XSLTPROC) --nonet 26 | else 27 | XSLTPROC = xsltproc --nonet 28 | endif 29 | 30 | override XSLTPROCFLAGS += \ 31 | --path stylesheets --path img --path . \ 32 | --stringparam pg_sphere.version '$(PGSPHERE_VERSION)' \ 33 | --stringparam pg.version '$(PGSPHERE_VERSION)' 34 | 35 | XMLINCLUDE = --path . 36 | ALLSGML := $(wildcard *.sgm) 37 | ALLIMAGES := $(wildcard img/*.jpg) 38 | 39 | all: html pdf 40 | 41 | .PHONY: all html pdf clean 42 | 43 | # This line fixes the error like: 44 | # No rule to make target 'pg_sphere.control' 45 | .PHONY: pg_sphere.control 46 | 47 | version.xml: 48 | @echo $(PGSPHERE_VERSION) > version.xml 49 | 50 | pg_sphere-full.xml: version.xml 51 | pg_sphere-full.xml: pg_sphere.xml $(ALLSGML) 52 | $(XMLLINT) $(XMLINCLUDE) --output $@ --noent --valid $< 53 | 54 | #------------------------------------------------------------------------------ 55 | # HTML 56 | #------------------------------------------------------------------------------ 57 | 58 | XSLTPROC_HTML_MULTIPAGE_FLAGS := --stringparam img.src.path '' 59 | XSLTPROC_HTML_SINGLEPAGE_FLAGS := --stringparam img.src.path '' 60 | 61 | html: html-singlepage html-multipage 62 | 63 | html-multipage: stylesheets/stylesheet.xsl pg_sphere-full.xml version.xml $(ALLIMAGES) 64 | $(XSLTPROC) $(XMLINCLUDE) $(XSLTPROCFLAGS) $(XSLTPROC_HTML_MULTIPAGE_FLAGS) $(wordlist 1,2,$^) 65 | mkdir -p html/img 66 | cp $(ALLIMAGES) html/img 67 | 68 | html-singlepage: pg_sphere-$(PGSPHERE_VERSION).html 69 | 70 | pg_sphere-$(PGSPHERE_VERSION).html: stylesheets/stylesheet-html-nochunk.xsl pg_sphere-full.xml version.xml $(ALLIMAGES) 71 | $(XSLTPROC) $(XMLINCLUDE) $(XSLTPROCFLAGS) $(XSLTPROC_HTML_SINGLEPAGE_FLAGS) -o $@ $(wordlist 1,2,$^) 72 | 73 | #------------------------------------------------------------------------------ 74 | # PDF 75 | #------------------------------------------------------------------------------ 76 | 77 | pdf: pg_sphere-${PGSPHERE_VERSION}-A4.pdf pg_sphere-${PGSPHERE_VERSION}-US.pdf 78 | 79 | pg_sphere-$(PGSPHERE_VERSION)-A4.pdf: pg_sphere.A4.fo 80 | $(FOP) -v -fo $< -pdf $@ 81 | 82 | pg_sphere-$(PGSPHERE_VERSION)-US.pdf: pg_sphere.US.fo 83 | $(FOP) -v -fo $< -pdf $@ 84 | 85 | pg_sphere.A4.fo: stylesheets/stylesheet-fo.xsl pg_sphere-full.xml version.xml $(ALLIMAGES) 86 | $(XSLTPROC) $(XMLINCLUDE) $(XSLTPROCFLAGS) $(XSLTPROC_FO_FLAGS) --stringparam paper.type A4 -o $@ stylesheets/stylesheet-fo.xsl pg_sphere-full.xml 87 | 88 | pg_sphere.US.fo: stylesheets/stylesheet-fo.xsl pg_sphere-full.xml version.xml $(ALLIMAGES) 89 | $(XSLTPROC) $(XMLINCLUDE) $(XSLTPROCFLAGS) $(XSLTPROC_FO_FLAGS) --stringparam paper.type USLetter -o $@ stylesheets/stylesheet-fo.xsl pg_sphere-full.xml 90 | 91 | #------------------------------------------------------------------------------ 92 | # Cleanup 93 | #------------------------------------------------------------------------------ 94 | 95 | clean distclean: 96 | rm -rf ./html 97 | rm -f version.xml 98 | rm -f pg_sphere-full.xml 99 | rm -f pg_sphere.A4.fo 100 | rm -f pg_sphere.US.fo 101 | rm -f pg_sphere-$(PGSPHERE_VERSION).html 102 | rm -f pg_sphere-$(PGSPHERE_VERSION)-A4.pdf 103 | rm -f pg_sphere-$(PGSPHERE_VERSION)-US.pdf 104 | -------------------------------------------------------------------------------- /data/test_spherepath.data: -------------------------------------------------------------------------------- 1 | 1 {(0d,30d),(45d,30d),(90d,30d),(135d,30d),(180d,30d),(225d,30d),(270d,30d),(315d,30d)} 2 | 2 {(0d,-5d),(1d,-5d),(2d,-5d),(3d,-5d),(4d,-5d),(5d,-5d),(6d,-5d),(7d,-5d),(8d,-5d),(9d,-5d),(10d,-5d),(11d,-5d),(12d,-5d),(13d,-5d),(14d,-5d),(15d,-5d),(16d,-5d),(17d,-5d),(18d,-5d),(19d,-5d),(20d,-5d),(21d,-5d),(22d,-5d),(23d,-5d),(24d,-5d),(25d,-5d),(26d,-5d),(27d,-5d),(28d,-5d),(29d,-5d),(30d,-5d),(31d,-5d),(32d,-5d),(33d,-5d),(34d,-5d),(35d,-5d),(36d,-5d),(37d,-5d),(38d,-5d),(39d,-5d),(40d,-5d),(41d,-5d),(42d,-5d),(43d,-5d),(44d,-5d),(45d,-5d),(46d,-5d),(47d,-5d),(48d,-5d),(49d,-5d),(50d,-5d),(51d,-5d),(52d,-5d),(53d,-5d),(54d,-5d),(55d,-5d),(56d,-5d),(57d,-5d),(58d,-5d),(59d,-5d),(60d,-5d),(61d,-5d),(62d,-5d),(63d,-5d),(64d,-5d),(65d,-5d),(66d,-5d),(67d,-5d),(68d,-5d),(69d,-5d),(70d,-5d),(71d,-5d),(72d,-5d),(73d,-5d),(74d,-5d),(75d,-5d),(76d,-5d),(77d,-5d),(78d,-5d),(79d,-5d),(80d,-5d),(81d,-5d),(82d,-5d),(83d,-5d),(84d,-5d),(85d,-5d),(86d,-5d),(87d,-5d),(88d,-5d),(89d,-5d),(90d,-5d),(91d,-5d),(92d,-5d),(93d,-5d),(94d,-5d),(95d,-5d),(96d,-5d),(97d,-5d),(98d,-5d),(99d,-5d),(100d,-5d),(101d,-5d),(102d,-5d),(103d,-5d),(104d,-5d),(105d,-5d),(106d,-5d),(107d,-5d),(108d,-5d),(109d,-5d),(110d,-5d),(111d,-5d),(112d,-5d),(113d,-5d),(114d,-5d),(115d,-5d),(116d,-5d),(117d,-5d),(118d,-5d),(119d,-5d),(120d,-5d),(121d,-5d),(122d,-5d),(123d,-5d),(124d,-5d),(125d,-5d),(126d,-5d),(127d,-5d),(128d,-5d),(129d,-5d),(130d,-5d),(131d,-5d),(132d,-5d),(133d,-5d),(134d,-5d),(135d,-5d),(136d,-5d),(137d,-5d),(138d,-5d),(139d,-5d),(140d,-5d),(141d,-5d),(142d,-5d),(143d,-5d),(144d,-5d),(145d,-5d),(146d,-5d),(147d,-5d),(148d,-5d),(149d,-5d),(150d,-5d),(151d,-5d),(152d,-5d),(153d,-5d),(154d,-5d),(155d,-5d),(156d,-5d),(157d,-5d),(158d,-5d),(159d,-5d),(160d,-5d),(161d,-5d),(162d,-5d),(163d,-5d),(164d,-5d),(165d,-5d),(166d,-5d),(167d,-5d),(168d,-5d),(169d,-5d),(170d,-5d),(171d,-5d),(172d,-5d),(173d,-5d),(174d,-5d),(175d,-5d),(176d,-5d),(177d,-5d),(178d,-5d),(179d,-5d),(180d,-5d),(181d,-5d),(182d,-5d),(183d,-5d),(184d,-5d),(185d,-5d),(186d,-5d),(187d,-5d),(188d,-5d),(189d,-5d),(190d,-5d),(191d,-5d),(192d,-5d),(193d,-5d),(194d,-5d),(195d,-5d),(196d,-5d),(197d,-5d),(198d,-5d),(199d,-5d),(200d,-5d),(201d,-5d),(202d,-5d),(203d,-5d),(204d,-5d),(205d,-5d),(206d,-5d),(207d,-5d),(208d,-5d),(209d,-5d),(210d,-5d),(211d,-5d),(212d,-5d),(213d,-5d),(214d,-5d),(215d,-5d),(216d,-5d),(217d,-5d),(218d,-5d),(219d,-5d),(220d,-5d),(221d,-5d),(222d,-5d),(223d,-5d),(224d,-5d),(225d,-5d),(226d,-5d),(227d,-5d),(228d,-5d),(229d,-5d),(230d,-5d),(231d,-5d),(232d,-5d),(233d,-5d),(234d,-5d),(235d,-5d),(236d,-5d),(237d,-5d),(238d,-5d),(239d,-5d),(240d,-5d),(241d,-5d),(242d,-5d),(243d,-5d),(244d,-5d),(245d,-5d),(246d,-5d),(247d,-5d),(248d,-5d),(249d,-5d),(250d,-5d),(251d,-5d),(252d,-5d),(253d,-5d),(254d,-5d),(255d,-5d),(256d,-5d),(257d,-5d),(258d,-5d),(259d,-5d),(260d,-5d),(261d,-5d),(262d,-5d),(263d,-5d),(264d,-5d),(265d,-5d),(266d,-5d),(267d,-5d),(268d,-5d),(269d,-5d),(270d,-5d),(271d,-5d),(272d,-5d),(273d,-5d),(274d,-5d),(275d,-5d),(276d,-5d),(277d,-5d),(278d,-5d),(279d,-5d),(280d,-5d),(281d,-5d),(282d,-5d),(283d,-5d),(284d,-5d),(285d,-5d),(286d,-5d),(287d,-5d),(288d,-5d),(289d,-5d),(290d,-5d),(291d,-5d),(292d,-5d),(293d,-5d),(294d,-5d),(295d,-5d),(296d,-5d),(297d,-5d),(298d,-5d),(299d,-5d),(300d,-5d),(301d,-5d),(302d,-5d),(303d,-5d),(304d,-5d),(305d,-5d),(306d,-5d),(307d,-5d),(308d,-5d),(309d,-5d),(310d,-5d),(311d,-5d),(312d,-5d),(313d,-5d),(314d,-5d),(315d,-5d),(316d,-5d),(317d,-5d),(318d,-5d),(319d,-5d),(320d,-5d),(321d,-5d),(322d,-5d),(323d,-5d),(324d,-5d),(325d,-5d),(326d,-5d),(327d,-5d),(328d,-5d),(329d,-5d),(330d,-5d),(331d,-5d),(332d,-5d),(333d,-5d),(334d,-5d),(335d,-5d),(336d,-5d),(337d,-5d),(338d,-5d),(339d,-5d),(340d,-5d),(341d,-5d),(342d,-5d),(343d,-5d),(344d,-5d),(345d,-5d),(346d,-5d),(347d,-5d),(348d,-5d),(349d,-5d),(350d,-5d),(351d,-5d),(352d,-5d),(353d,-5d),(354d,-5d),(355d,-5d),(356d,-5d),(357d,-5d),(358d,-5d),(359d,-5d)} 3 | \. 4 | -------------------------------------------------------------------------------- /data/test_spherepolygon.data: -------------------------------------------------------------------------------- 1 | 1 {(0d,30d),(45d,30d),(90d,30d),(135d,30d),(180d,30d),(225d,30d),(270d,30d),(315d,30d)} 2 | 2 {(0d,-5d),(1d,-5d),(2d,-5d),(3d,-5d),(4d,-5d),(5d,-5d),(6d,-5d),(7d,-5d),(8d,-5d),(9d,-5d),(10d,-5d),(11d,-5d),(12d,-5d),(13d,-5d),(14d,-5d),(15d,-5d),(16d,-5d),(17d,-5d),(18d,-5d),(19d,-5d),(20d,-5d),(21d,-5d),(22d,-5d),(23d,-5d),(24d,-5d),(25d,-5d),(26d,-5d),(27d,-5d),(28d,-5d),(29d,-5d),(30d,-5d),(31d,-5d),(32d,-5d),(33d,-5d),(34d,-5d),(35d,-5d),(36d,-5d),(37d,-5d),(38d,-5d),(39d,-5d),(40d,-5d),(41d,-5d),(42d,-5d),(43d,-5d),(44d,-5d),(45d,-5d),(46d,-5d),(47d,-5d),(48d,-5d),(49d,-5d),(50d,-5d),(51d,-5d),(52d,-5d),(53d,-5d),(54d,-5d),(55d,-5d),(56d,-5d),(57d,-5d),(58d,-5d),(59d,-5d),(60d,-5d),(61d,-5d),(62d,-5d),(63d,-5d),(64d,-5d),(65d,-5d),(66d,-5d),(67d,-5d),(68d,-5d),(69d,-5d),(70d,-5d),(71d,-5d),(72d,-5d),(73d,-5d),(74d,-5d),(75d,-5d),(76d,-5d),(77d,-5d),(78d,-5d),(79d,-5d),(80d,-5d),(81d,-5d),(82d,-5d),(83d,-5d),(84d,-5d),(85d,-5d),(86d,-5d),(87d,-5d),(88d,-5d),(89d,-5d),(90d,-5d),(91d,-5d),(92d,-5d),(93d,-5d),(94d,-5d),(95d,-5d),(96d,-5d),(97d,-5d),(98d,-5d),(99d,-5d),(100d,-5d),(101d,-5d),(102d,-5d),(103d,-5d),(104d,-5d),(105d,-5d),(106d,-5d),(107d,-5d),(108d,-5d),(109d,-5d),(110d,-5d),(111d,-5d),(112d,-5d),(113d,-5d),(114d,-5d),(115d,-5d),(116d,-5d),(117d,-5d),(118d,-5d),(119d,-5d),(120d,-5d),(121d,-5d),(122d,-5d),(123d,-5d),(124d,-5d),(125d,-5d),(126d,-5d),(127d,-5d),(128d,-5d),(129d,-5d),(130d,-5d),(131d,-5d),(132d,-5d),(133d,-5d),(134d,-5d),(135d,-5d),(136d,-5d),(137d,-5d),(138d,-5d),(139d,-5d),(140d,-5d),(141d,-5d),(142d,-5d),(143d,-5d),(144d,-5d),(145d,-5d),(146d,-5d),(147d,-5d),(148d,-5d),(149d,-5d),(150d,-5d),(151d,-5d),(152d,-5d),(153d,-5d),(154d,-5d),(155d,-5d),(156d,-5d),(157d,-5d),(158d,-5d),(159d,-5d),(160d,-5d),(161d,-5d),(162d,-5d),(163d,-5d),(164d,-5d),(165d,-5d),(166d,-5d),(167d,-5d),(168d,-5d),(169d,-5d),(170d,-5d),(171d,-5d),(172d,-5d),(173d,-5d),(174d,-5d),(175d,-5d),(176d,-5d),(177d,-5d),(178d,-5d),(179d,-5d),(180d,-5d),(181d,-5d),(182d,-5d),(183d,-5d),(184d,-5d),(185d,-5d),(186d,-5d),(187d,-5d),(188d,-5d),(189d,-5d),(190d,-5d),(191d,-5d),(192d,-5d),(193d,-5d),(194d,-5d),(195d,-5d),(196d,-5d),(197d,-5d),(198d,-5d),(199d,-5d),(200d,-5d),(201d,-5d),(202d,-5d),(203d,-5d),(204d,-5d),(205d,-5d),(206d,-5d),(207d,-5d),(208d,-5d),(209d,-5d),(210d,-5d),(211d,-5d),(212d,-5d),(213d,-5d),(214d,-5d),(215d,-5d),(216d,-5d),(217d,-5d),(218d,-5d),(219d,-5d),(220d,-5d),(221d,-5d),(222d,-5d),(223d,-5d),(224d,-5d),(225d,-5d),(226d,-5d),(227d,-5d),(228d,-5d),(229d,-5d),(230d,-5d),(231d,-5d),(232d,-5d),(233d,-5d),(234d,-5d),(235d,-5d),(236d,-5d),(237d,-5d),(238d,-5d),(239d,-5d),(240d,-5d),(241d,-5d),(242d,-5d),(243d,-5d),(244d,-5d),(245d,-5d),(246d,-5d),(247d,-5d),(248d,-5d),(249d,-5d),(250d,-5d),(251d,-5d),(252d,-5d),(253d,-5d),(254d,-5d),(255d,-5d),(256d,-5d),(257d,-5d),(258d,-5d),(259d,-5d),(260d,-5d),(261d,-5d),(262d,-5d),(263d,-5d),(264d,-5d),(265d,-5d),(266d,-5d),(267d,-5d),(268d,-5d),(269d,-5d),(270d,-5d),(271d,-5d),(272d,-5d),(273d,-5d),(274d,-5d),(275d,-5d),(276d,-5d),(277d,-5d),(278d,-5d),(279d,-5d),(280d,-5d),(281d,-5d),(282d,-5d),(283d,-5d),(284d,-5d),(285d,-5d),(286d,-5d),(287d,-5d),(288d,-5d),(289d,-5d),(290d,-5d),(291d,-5d),(292d,-5d),(293d,-5d),(294d,-5d),(295d,-5d),(296d,-5d),(297d,-5d),(298d,-5d),(299d,-5d),(300d,-5d),(301d,-5d),(302d,-5d),(303d,-5d),(304d,-5d),(305d,-5d),(306d,-5d),(307d,-5d),(308d,-5d),(309d,-5d),(310d,-5d),(311d,-5d),(312d,-5d),(313d,-5d),(314d,-5d),(315d,-5d),(316d,-5d),(317d,-5d),(318d,-5d),(319d,-5d),(320d,-5d),(321d,-5d),(322d,-5d),(323d,-5d),(324d,-5d),(325d,-5d),(326d,-5d),(327d,-5d),(328d,-5d),(329d,-5d),(330d,-5d),(331d,-5d),(332d,-5d),(333d,-5d),(334d,-5d),(335d,-5d),(336d,-5d),(337d,-5d),(338d,-5d),(339d,-5d),(340d,-5d),(341d,-5d),(342d,-5d),(343d,-5d),(344d,-5d),(345d,-5d),(346d,-5d),(347d,-5d),(348d,-5d),(349d,-5d),(350d,-5d),(351d,-5d),(352d,-5d),(353d,-5d),(354d,-5d),(355d,-5d),(356d,-5d),(357d,-5d),(358d,-5d),(359d,-5d)} 3 | \. 4 | -------------------------------------------------------------------------------- /expected/euler.out: -------------------------------------------------------------------------------- 1 | \set ECHO none 2 | set_sphere_output_precision 3 | ----------------------------- 4 | SET 8 5 | (1 row) 6 | 7 | -- checking Euler transformation operators 8 | SELECT strans '-10d,0d,10d,ZZZ' = '-10d,0d,10d,XXX' ; 9 | ?column? 10 | ---------- 11 | t 12 | (1 row) 13 | 14 | SELECT strans '-40d,0d,40d,ZZZ' <> '-40d,0d,40d,XXX' ; 15 | ?column? 16 | ---------- 17 | f 18 | (1 row) 19 | 20 | SELECT strans ( 20.0*pi()/180.0, -270.0*pi()/180.0, 70.5*pi()/180.0, 'XZY' ); 21 | strans 22 | --------------------------------------- 23 | 0.34906585, 1.5707963, 1.2304571, XZY 24 | (1 row) 25 | 26 | SELECT theta( strans ( 20.0*pi()/180.0, -270.0*pi()/180.0, 70.5*pi()/180.0, 'XZY' ) ); 27 | theta 28 | --------------- 29 | 1.57079632679 30 | (1 row) 31 | 32 | SELECT psi( strans ( 20.0*pi()/180.0, -270.0*pi()/180.0, 70.5*pi()/180.0, 'XZY' ) ); 33 | psi 34 | --------------- 35 | 1.23045712266 36 | (1 row) 37 | 38 | SELECT phi( strans ( 20.0*pi()/180.0, -270.0*pi()/180.0, 70.5*pi()/180.0, 'XZY' ) ); 39 | phi 40 | ---------------- 41 | 0.349065850399 42 | (1 row) 43 | 44 | SELECT theta( strans( '20d, 30d, 40d, XZY' ) ); 45 | theta 46 | ---------------- 47 | 0.523598775598 48 | (1 row) 49 | 50 | SELECT psi( strans( '20d, 30d, 40d, XZY' ) ); 51 | psi 52 | ---------------- 53 | 0.698131700798 54 | (1 row) 55 | 56 | SELECT phi( strans( '20d, 30d, 40d, XZY' ) ); 57 | phi 58 | ---------------- 59 | 0.349065850399 60 | (1 row) 61 | 62 | SELECT strans( '2d 20m, 10d, 0' ); 63 | strans 64 | --------------------------------- 65 | 0.040724349, 0.17453293, 0, ZXZ 66 | (1 row) 67 | 68 | SELECT theta( strans( '2d 20m, 10d, 0' ) ); 69 | theta 70 | ---------------- 71 | 0.174532925199 72 | (1 row) 73 | 74 | SELECT psi( strans( '2d 20m, 10d, 0' ) ); 75 | psi 76 | ----- 77 | 0 78 | (1 row) 79 | 80 | SELECT phi( strans( '2d 20m, 10d, 0' ) ); 81 | phi 82 | ----------------- 83 | 0.0407243492132 84 | (1 row) 85 | 86 | SELECT strans ( '10d, 90d, 270d, ZXZ' ); 87 | strans 88 | -------------------------------------- 89 | 0.17453293, 1.5707963, 4.712389, ZXZ 90 | (1 row) 91 | 92 | SELECT theta( strans ( '10d, 90d, 270d, ZXZ' ) ); 93 | theta 94 | --------------- 95 | 1.57079632679 96 | (1 row) 97 | 98 | SELECT psi( strans ( '10d, 90d, 270d, ZXZ' ) ); 99 | psi 100 | --------------- 101 | 4.71238898038 102 | (1 row) 103 | 104 | SELECT phi( strans ( '10d, 90d, 270d, ZXZ' ) ); 105 | phi 106 | ---------------- 107 | 0.174532925199 108 | (1 row) 109 | 110 | SELECT - strans ( '20d, 50d, 80d, XYZ' ); 111 | ?column? 112 | -------------------------------------- 113 | 4.8869219, 5.4105207, 5.9341195, ZYX 114 | (1 row) 115 | 116 | SELECT theta( - strans ( '20d, 50d, 80d, XYZ' ) ); 117 | theta 118 | ----------------- 119 | -0.872664625997 120 | (1 row) 121 | 122 | SELECT psi( - strans ( '20d, 50d, 80d, XYZ' ) ); 123 | psi 124 | ----------------- 125 | -0.349065850399 126 | (1 row) 127 | 128 | SELECT phi( - strans ( '20d, 50d, 80d, XYZ' ) ); 129 | phi 130 | --------------- 131 | -1.3962634016 132 | (1 row) 133 | 134 | SELECT strans( '90d, 60d, 30d' ); 135 | strans 136 | --------------------------------------- 137 | 1.5707963, 1.0471976, 0.52359878, ZXZ 138 | (1 row) 139 | 140 | SELECT theta( strans( '90d, 60d, 30d' ) ); 141 | theta 142 | -------------- 143 | 1.0471975512 144 | (1 row) 145 | 146 | SELECT psi( strans( '90d, 60d, 30d' ) ); 147 | psi 148 | ---------------- 149 | 0.523598775598 150 | (1 row) 151 | 152 | SELECT phi( strans( '90d, 60d, 30d' ) ); 153 | phi 154 | --------------- 155 | 1.57079632679 156 | (1 row) 157 | 158 | -------------------------------------------------------------------------------- /pgindent-typedefs.list: -------------------------------------------------------------------------------- 1 | align_val_t 2 | allocator_type 3 | __alloc_rebind 4 | ArrayType 5 | AttrDefault 6 | AttrNumber 7 | _Base_ptr 8 | BlockNumber 9 | Box3D 10 | BpChar 11 | bpoint 12 | BrinDesc 13 | BrinOpcInfo 14 | brin_serialize_callback_type 15 | BrinValues 16 | __builtin_va_list 17 | _Char_alloc_type 18 | char_type 19 | CommonEntry 20 | __compar_fn_t 21 | ConsiderSplitContext 22 | _Const_Base_ptr 23 | __const_iterator 24 | const_iterator 25 | _Const_Link_type 26 | const_pointer 27 | ConstrCheck 28 | const_reference 29 | const_reverse_iterator 30 | const_void_pointer 31 | coord_t 32 | CPoint 33 | Datum 34 | difference_type 35 | _DistanceType 36 | div_t 37 | DomainConstraintCache 38 | double_t 39 | __dso_handle 40 | __enable_if_t 41 | false> 42 | false_type 43 | __FILE 44 | FILE 45 | first_type 46 | flex_int16_t 47 | flex_uint8_t 48 | float4 49 | float8 50 | float_t 51 | FmgrInfo 52 | fmNodePtr 53 | FormData_pg_attribute 54 | __fpos_t 55 | fpos_t 56 | FunctionCallInfo 57 | GISTENTRY 58 | GistEntryVector 59 | GISTPageOpaque 60 | GISTPageOpaqueData 61 | GIST_SPLITVEC 62 | GiSTSPointKey 63 | __gnuc_va_list 64 | Healpix_Base2 65 | hpint64 66 | insert_return_type 67 | int16 68 | __int16_t 69 | int16_t 70 | int32 71 | __int32_t 72 | int32_t 73 | int64 74 | __int64_t 75 | int64_t 76 | int8 77 | __int8_t 78 | int8_t 79 | int_fast16_t 80 | int_fast32_t 81 | int_fast64_t 82 | int_fast8_t 83 | __int_least16_t 84 | int_least16_t 85 | __int_least32_t 86 | int_least32_t 87 | __int_least64_t 88 | int_least64_t 89 | __int_least8_t 90 | int_least8_t 91 | __intmax_t 92 | intmax_t 93 | intptr_t 94 | int_type 95 | _IO_lock_t 96 | iostate 97 | ItemIdData 98 | iterator 99 | iterator_category 100 | iterator_type 101 | key_compare 102 | key_type 103 | layout_vec 104 | ldiv_t 105 | _Link_type 106 | lldiv_t 107 | LocationIndex 108 | __make_not_void 109 | map_const_iter 110 | map_iterator 111 | mapped_type 112 | map_rev_iter 113 | max_align_t 114 | __mbstate_t 115 | mbstate_t 116 | MemoryContext 117 | moc_interval 118 | moc_map 119 | moc_map_entry 120 | moc_out_data 121 | moc_tree_entry 122 | NameData 123 | _Node_allocator 124 | NodeTag 125 | node_type 126 | NullableDatum 127 | nullptr_t 128 | __off64_t 129 | OffsetNumber 130 | __off_t 131 | Oid 132 | ostream 133 | __ostream_type 134 | other 135 | output_map 136 | Page 137 | PageGistNSN 138 | PageHeader 139 | PageHeaderData 140 | PageXLogRecPtr 141 | Pg_finfo_record 142 | PGFunction 143 | Pg_magic_struct 144 | pgs_error_handler 145 | phasevec 146 | Point 147 | Point3D 148 | __pointer 149 | pointer 150 | Pointer 151 | ptrdiff_t 152 | __ptr_rebind 153 | rebind 154 | rebind_alloc 155 | reference 156 | Relation 157 | _Rep_type 158 | reverse_iterator 159 | rintv_iter 160 | rnode_iter 161 | rtype 162 | SBOX 163 | SCIRCLE 164 | second_type 165 | _Self 166 | SELLIPSE 167 | SEuler 168 | Size 169 | size_t 170 | size_type 171 | SLine 172 | Smoc 173 | SPATH 174 | SplitInterval 175 | SPoint 176 | SPOLY 177 | StrategyNumber 178 | streamsize 179 | string 180 | __sv_type 181 | t_ang 182 | tdiff 183 | text 184 | _Tp_alloc_type 185 | TransactionId 186 | true_type 187 | tsize 188 | TupleConstr 189 | TupleDesc 190 | __type 191 | type 192 | TypeCacheEntry 193 | uchar 194 | uint16 195 | __uint16_t 196 | uint16_t 197 | uint32 198 | __uint32_t 199 | uint32_t 200 | uint64 201 | __uint64_t 202 | uint64_t 203 | uint8 204 | __uint8_t 205 | uint8_t 206 | uint_fast16_t 207 | uint_fast32_t 208 | uint_fast64_t 209 | uint_fast8_t 210 | __uint_least16_t 211 | uint_least16_t 212 | __uint_least32_t 213 | uint_least32_t 214 | __uint_least64_t 215 | uint_least64_t 216 | __uint_least8_t 217 | uint_least8_t 218 | __uintmax_t 219 | uintmax_t 220 | uintptr_t 221 | va_list 222 | value_type 223 | varattrib_4b 224 | vec3 225 | Vector3D 226 | wctrans_t 227 | wctype_t 228 | wint_t 229 | YY_BUFFER_STATE 230 | YY_CHAR 231 | yy_size_t 232 | yy_state_type 233 | YYSTYPE 234 | yytype_int16 235 | yytype_int8 236 | yytype_uint8 237 | -------------------------------------------------------------------------------- /src/gq_cache.c: -------------------------------------------------------------------------------- 1 | #include "gist.h" 2 | 3 | /* 4 | * GIST's query cache 5 | */ 6 | 7 | /* Holds the parent type of PGS_DATA_TYPES for cached key. */ 8 | static unsigned keytype = 0; 9 | 10 | /* the cached key */ 11 | static int32 kcache[6]; 12 | 13 | /* pointer to cached query */ 14 | static void *cquery = NULL; 15 | 16 | /* Holds the count of points, if cached query is a path or polygon. */ 17 | static int32 npts = 0; 18 | 19 | /* If query type and value are equal, this value is true */ 20 | static bool res = false; 21 | 22 | /* 23 | * Depending on type of PGS_DATA_TYPES, compare current query and cached query. 24 | * If query cache and current query are equal, set ref to true. 25 | */ 26 | #define GQ_MEMCMP(type) \ 27 | do \ 28 | { \ 29 | if (keytype == PGS_TYPE_##type) \ 30 | { \ 31 | if (memcmp((void *) cquery, (void *) query, sizeof(type)) == 0) res = true; \ 32 | } \ 33 | } while(0); 34 | 35 | bool 36 | gq_cache_get_value(unsigned pgstype, const void *query, int32 **key) 37 | { 38 | if (keytype == 0) 39 | { 40 | return false; 41 | } 42 | else 43 | { 44 | res = false; 45 | 46 | switch (pgstype) 47 | { 48 | case PGS_TYPE_SPoint: 49 | GQ_MEMCMP(SPoint); 50 | break; 51 | case PGS_TYPE_SCIRCLE: 52 | GQ_MEMCMP(SCIRCLE); 53 | break; 54 | case PGS_TYPE_SELLIPSE: 55 | GQ_MEMCMP(SELLIPSE); 56 | break; 57 | case PGS_TYPE_SLine: 58 | GQ_MEMCMP(SLine); 59 | break; 60 | case PGS_TYPE_SBOX: 61 | GQ_MEMCMP(SBOX); 62 | break; 63 | case PGS_TYPE_SPATH: 64 | if (keytype == pgstype && ((SPATH *) query)->npts == npts) 65 | { 66 | if (memcmp((void *) cquery, 67 | (void *) &((SPATH *) query)->p, 68 | ((SPATH *) query)->npts * sizeof(SPoint)) == 0) 69 | res = true; 70 | } 71 | break; 72 | case PGS_TYPE_SPOLY: 73 | if (keytype == pgstype && ((SPOLY *) query)->npts == npts) 74 | { 75 | if (memcmp((void *) cquery, 76 | (void *) &((SPOLY *) query)->p, 77 | ((SPOLY *) query)->npts * sizeof(SPoint)) == 0) 78 | res = true; 79 | } 80 | break; 81 | default: 82 | res = false; 83 | break; 84 | } 85 | 86 | if (res) 87 | { 88 | *key = &kcache[0]; 89 | } 90 | return res; 91 | } 92 | return false; 93 | } 94 | 95 | /* 96 | * Depending on type of PGS_DATA_TYPES, copy current query to cache. 97 | */ 98 | #define GQ_MEMCPY(type) \ 99 | do \ 100 | { \ 101 | cquery = (void *) malloc(sizeof(type)); \ 102 | memcpy((void *) cquery, (void *) query, sizeof(type)); \ 103 | } while(0); 104 | 105 | 106 | void 107 | gq_cache_set_value(unsigned pgstype, const void *query, const int32 *key) 108 | { 109 | if (cquery) 110 | { 111 | free(cquery); 112 | cquery = NULL; 113 | } 114 | 115 | keytype = pgstype; 116 | 117 | switch (pgstype) 118 | { 119 | case PGS_TYPE_SPoint: 120 | GQ_MEMCPY(SPoint); 121 | break; 122 | case PGS_TYPE_SCIRCLE: 123 | GQ_MEMCPY(SCIRCLE); 124 | break; 125 | case PGS_TYPE_SELLIPSE: 126 | GQ_MEMCPY(SELLIPSE); 127 | break; 128 | case PGS_TYPE_SLine: 129 | GQ_MEMCPY(SLine); 130 | break; 131 | case PGS_TYPE_SBOX: 132 | GQ_MEMCPY(SBOX); 133 | break; 134 | case PGS_TYPE_SPATH: 135 | cquery = (void *) malloc(((SPATH *) query)->npts * sizeof(SPoint)); 136 | npts = ((SPATH *) query)->npts; 137 | memcpy((void *) cquery, 138 | (void *) &((SPATH *) query)->p, 139 | ((SPATH *) query)->npts * sizeof(SPoint)); 140 | break; 141 | case PGS_TYPE_SPOLY: 142 | cquery = (void *) malloc(((SPOLY *) query)->npts * sizeof(SPoint)); 143 | npts = ((SPOLY *) query)->npts; 144 | memcpy((void *) cquery, 145 | (void *) &((SPOLY *) query)->p, 146 | ((SPOLY *) query)->npts * sizeof(SPoint)); 147 | break; 148 | default: 149 | keytype = 0; 150 | } 151 | if (keytype > 0) 152 | { 153 | memcpy((void *) &kcache[0], (void *) key, KEYSIZE); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /doc/stylesheets/stylesheet.css: -------------------------------------------------------------------------------- 1 | /* doc/src/sgml/stylesheet.css */ 2 | 3 | /* color scheme similar to www.postgresql.org */ 4 | 5 | body { 6 | color: #000000; 7 | background: #FFFFFF; 8 | font-family: verdana, sans-serif; 9 | } 10 | 11 | a:link { color:#0066A2; } 12 | a:visited { color:#004E66; } 13 | a:active { color:#0066A2; } 14 | a:hover { color:#000000; } 15 | 16 | h1 { 17 | font-size: 1.4em; 18 | font-weight: bold; 19 | margin-top: 0em; 20 | margin-bottom: 0em; 21 | color: #EC5800; 22 | } 23 | 24 | h2 { 25 | font-size: 1.2em; 26 | margin: 1.2em 0em 1.2em 0em; 27 | font-weight: bold; 28 | color: #666; 29 | } 30 | 31 | .titlepage h2.title, 32 | .refnamediv h2 { 33 | color: #EC5800; 34 | } 35 | 36 | h3 { 37 | font-size: 1.1em; 38 | margin: 1.2em 0em 1.2em 0em; 39 | font-weight: bold; 40 | color: #666; 41 | } 42 | 43 | h4 { 44 | font-size: 0.95em; 45 | margin: 1.2em 0em 1.2em 0em; 46 | font-weight: normal; 47 | color: #666; 48 | } 49 | 50 | h5 { 51 | font-size: 0.9em; 52 | margin: 1.2em 0em 1.2em 0em; 53 | font-weight: normal; 54 | } 55 | 56 | h6 { 57 | font-size: 0.85em; 58 | margin: 1.2em 0em 1.2em 0em; 59 | font-weight: normal; 60 | } 61 | 62 | /* center some titles */ 63 | 64 | .book .title, .book .corpauthor, .book .copyright { 65 | text-align: center; 66 | } 67 | 68 | /* decoration for formal examples */ 69 | 70 | div.example { 71 | padding-left: 15px; 72 | border-style: solid; 73 | border-width: 0px; 74 | border-left-width: 2px; 75 | border-color: black; 76 | margin: 0.5ex; 77 | } 78 | 79 | /* Additional formatting for "simplelist" structures */ 80 | table.simplelist td { 81 | padding-left: 2em; 82 | padding-right: 2em; 83 | } 84 | 85 | /* formatting for entries in tables of functions: indent all but first line */ 86 | 87 | th.func_table_entry p, 88 | td.func_table_entry p { 89 | margin-top: 0.1em; 90 | margin-bottom: 0.1em; 91 | padding-left: 4em; 92 | text-align: left; 93 | } 94 | 95 | p.func_signature { 96 | text-indent: -3.5em; 97 | } 98 | 99 | td.func_table_entry pre.programlisting { 100 | margin-top: 0.1em; 101 | margin-bottom: 0.1em; 102 | padding-left: 4em; 103 | } 104 | 105 | /* formatting for entries in tables of catalog/view columns */ 106 | 107 | th.catalog_table_entry p, 108 | td.catalog_table_entry p { 109 | margin-top: 0.1em; 110 | margin-bottom: 0.1em; 111 | padding-left: 4em; 112 | text-align: left; 113 | } 114 | 115 | th.catalog_table_entry p.column_definition { 116 | text-indent: -3.5em; 117 | word-spacing: 0.25em; 118 | } 119 | 120 | td.catalog_table_entry p.column_definition { 121 | text-indent: -3.5em; 122 | } 123 | 124 | p.column_definition code.type { 125 | padding-left: 0.25em; 126 | padding-right: 0.25em; 127 | } 128 | 129 | td.catalog_table_entry pre.programlisting { 130 | margin-top: 0.1em; 131 | margin-bottom: 0.1em; 132 | padding-left: 4em; 133 | } 134 | 135 | /* Put these here instead of inside the HTML (see unsetting of 136 | admon.style in XSL) so that the web site stylesheet can set its own 137 | style. */ 138 | 139 | .tip, 140 | .note, 141 | .important, 142 | .caution, 143 | .warning { 144 | margin-left: 0.5in; 145 | margin-right: 0.5in; 146 | } 147 | 148 | /* miscellaneous */ 149 | 150 | pre.literallayout, .screen, .synopsis, .programlisting { 151 | margin-left: 4ex; 152 | } 153 | 154 | ul.itemizedlist { 155 | margin-left: 2.5rem; 156 | } 157 | 158 | .comment { color: red; } 159 | 160 | var { font-family: monospace; font-style: italic; } 161 | /* Konqueror's standard style for ACRONYM is italic. */ 162 | acronym { font-style: inherit; } 163 | 164 | .option { white-space: nowrap; } 165 | 166 | /* make images not too wide on larger screens */ 167 | @media (min-width: 800px) { 168 | .mediaobject { 169 | width: 75%; 170 | } 171 | } 172 | 173 | /* links to ids of headers and definition terms */ 174 | 175 | a.id_link { 176 | color: inherit; 177 | visibility: hidden; 178 | } 179 | 180 | *:hover > a.id_link { 181 | visibility: visible; 182 | } 183 | -------------------------------------------------------------------------------- /doc/examples.sgm: -------------------------------------------------------------------------------- 1 | 2 | Examples 3 | 4 | 5 | 6 | Astronomical 7 | 8 | 9 | Coordinates transformation 10 | 11 | A commonly used task is a coordinate transformation. With the 12 | parameters of a new 13 | coordinate system (plane) relative to an old one, 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | &pg_OHgr; 24 | 25 | 26 | longitude of the ascending node 27 | 28 | 29 | angle between line of nodes and the zero point of 30 | longitude in the old plane. 31 | 32 | 33 | 34 | 35 | &pg_ohgr; 36 | 37 | 38 | argument of pericenter 39 | 40 | 41 | the angle from the ascending node to the position in the new plane. 42 | 43 | 44 | 45 | 46 | i 47 | 48 | 49 | inclination 50 | 51 | 52 | angle between the new plane and the old plane. 53 | 54 | 55 | 56 | 57 | 58 | 59 | you can do a transformation of an object 60 | object from an old into a new coordinate 61 | system using: 62 | 63 | object - strans '&pg_ohgr;, i, &pg_OHgr;' 64 | or 65 | object - strans (&pg_ohgr;, i, &pg_OHgr;) 66 | 67 | Otherwise, for a transformation of an object 68 | object from the new into the old 69 | coordinate system, use the operator +: 70 | 71 | object + strans '&pg_ohgr;, i, &pg_OHgr;' 72 | or 73 | object + strans (&pg_ohgr;, i, &pg_OHgr;) 74 | 75 | perihelion and aphelion coordinates of a comet's orbit 76 | 77 | We are assuming the orbital elements of a comet are 78 | &pg_OHgr;=30°, i=60° and &pg_ohgr;=90°. We get the 79 | spherical position of perihelion and aphelion with: 80 | 81 | 82 | SELECT set_sphere_output('DEG');]]> 83 | 84 | 85 | 86 | 87 | 88 | SELECT spoint '(0,0)' + strans '90d,60d,30d' AS perihelion;]]> 89 | 90 | 91 | 92 | 93 | 94 | SELECT spoint '(180d,0)' + strans '90d,60d,30d' AS aphelion;]]> 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /pgs_moc_type.sql.in: -------------------------------------------------------------------------------- 1 | CREATE TYPE smoc; 2 | 3 | CREATE FUNCTION smoc_in(cstring) 4 | RETURNS smoc 5 | AS 'MODULE_PATHNAME' 6 | LANGUAGE C 7 | IMMUTABLE STRICT PARALLEL SAFE; 8 | 9 | CREATE FUNCTION smoc_out(smoc) 10 | RETURNS cstring 11 | AS 'MODULE_PATHNAME' 12 | LANGUAGE C 13 | IMMUTABLE STRICT PARALLEL SAFE; 14 | 15 | CREATE TYPE smoc ( 16 | input = smoc_in, 17 | output = smoc_out, 18 | delimiter = ';', 19 | internallength = VARIABLE, 20 | alignment = double, 21 | storage = EXTERNAL 22 | ); 23 | 24 | CREATE FUNCTION moc_debug() 25 | RETURNS text 26 | AS 'MODULE_PATHNAME' 27 | LANGUAGE C 28 | STRICT PARALLEL SAFE; 29 | 30 | CREATE FUNCTION set_smoc_output_type(integer) 31 | RETURNS cstring 32 | AS 'MODULE_PATHNAME' 33 | LANGUAGE C 34 | STRICT PARALLEL SAFE; 35 | 36 | CREATE FUNCTION max_order(smoc) 37 | RETURNS integer 38 | AS 'MODULE_PATHNAME', 'smoc_order' 39 | LANGUAGE C 40 | IMMUTABLE STRICT PARALLEL SAFE; 41 | 42 | CREATE FUNCTION healpix_subset_smoc(bigint, smoc) 43 | RETURNS bool 44 | AS 'MODULE_PATHNAME' 45 | LANGUAGE C 46 | STRICT PARALLEL SAFE; 47 | 48 | CREATE FUNCTION healpix_not_subset_smoc(bigint, smoc) 49 | RETURNS bool 50 | AS 'MODULE_PATHNAME' 51 | LANGUAGE C 52 | STRICT PARALLEL SAFE; 53 | 54 | CREATE FUNCTION smoc_superset_healpix(smoc, bigint) 55 | RETURNS bool 56 | AS 'MODULE_PATHNAME' 57 | LANGUAGE C 58 | STRICT PARALLEL SAFE; 59 | 60 | CREATE FUNCTION smoc_not_superset_healpix(smoc, bigint) 61 | RETURNS bool 62 | AS 'MODULE_PATHNAME' 63 | LANGUAGE C 64 | STRICT PARALLEL SAFE; 65 | 66 | CREATE FUNCTION spoint_subset_smoc(spoint, smoc) 67 | RETURNS bool 68 | AS 'MODULE_PATHNAME' 69 | LANGUAGE C 70 | STRICT PARALLEL SAFE; 71 | 72 | CREATE FUNCTION spoint_not_subset_smoc(spoint, smoc) 73 | RETURNS bool 74 | AS 'MODULE_PATHNAME' 75 | LANGUAGE C 76 | STRICT PARALLEL SAFE; 77 | 78 | CREATE FUNCTION smoc_superset_spoint(smoc, spoint) 79 | RETURNS bool 80 | AS 'MODULE_PATHNAME' 81 | LANGUAGE C 82 | STRICT PARALLEL SAFE; 83 | 84 | CREATE FUNCTION smoc_not_superset_spoint(smoc, spoint) 85 | RETURNS bool 86 | AS 'MODULE_PATHNAME' 87 | LANGUAGE C 88 | STRICT PARALLEL SAFE; 89 | 90 | CREATE OPERATOR <@ ( 91 | LEFTARG = bigint, 92 | RIGHTARG = smoc, 93 | PROCEDURE = healpix_subset_smoc, 94 | COMMUTATOR = '@>', 95 | NEGATOR = '!<@', 96 | RESTRICT = contsel, 97 | JOIN = contjoinsel 98 | ); 99 | 100 | CREATE OPERATOR !<@ ( 101 | LEFTARG = bigint, 102 | RIGHTARG = smoc, 103 | PROCEDURE = healpix_not_subset_smoc, 104 | COMMUTATOR = '!@>', 105 | NEGATOR = '<@', 106 | RESTRICT = contsel, 107 | JOIN = contjoinsel 108 | ); 109 | 110 | CREATE OPERATOR @> ( 111 | LEFTARG = smoc, 112 | RIGHTARG = bigint, 113 | PROCEDURE = smoc_superset_healpix, 114 | COMMUTATOR = '<@', 115 | NEGATOR = '!@>', 116 | RESTRICT = contsel, 117 | JOIN = contjoinsel 118 | ); 119 | 120 | CREATE OPERATOR !@> ( 121 | LEFTARG = smoc, 122 | RIGHTARG = bigint, 123 | PROCEDURE = smoc_not_superset_healpix, 124 | COMMUTATOR = '!<@', 125 | NEGATOR = '@>', 126 | RESTRICT = contsel, 127 | JOIN = contjoinsel 128 | ); 129 | 130 | CREATE OPERATOR <@ ( 131 | LEFTARG = spoint, 132 | RIGHTARG = smoc, 133 | PROCEDURE = spoint_subset_smoc, 134 | COMMUTATOR = '@>', 135 | NEGATOR = '!<@', 136 | RESTRICT = contsel, 137 | JOIN = contjoinsel 138 | ); 139 | 140 | CREATE OPERATOR !<@ ( 141 | LEFTARG = spoint, 142 | RIGHTARG = smoc, 143 | PROCEDURE = spoint_not_subset_smoc, 144 | COMMUTATOR = '!@>', 145 | NEGATOR = '<@', 146 | RESTRICT = contsel, 147 | JOIN = contjoinsel 148 | ); 149 | 150 | CREATE OPERATOR @> ( 151 | LEFTARG = smoc, 152 | RIGHTARG = spoint, 153 | PROCEDURE = smoc_superset_spoint, 154 | COMMUTATOR = '<@', 155 | NEGATOR = '!@>', 156 | RESTRICT = contsel, 157 | JOIN = contjoinsel 158 | ); 159 | 160 | CREATE OPERATOR !@> ( 161 | LEFTARG = smoc, 162 | RIGHTARG = spoint, 163 | PROCEDURE = smoc_not_superset_spoint, 164 | COMMUTATOR = '!<@', 165 | NEGATOR = '@>', 166 | RESTRICT = contsel, 167 | JOIN = contjoinsel 168 | ); 169 | 170 | -------------------------------------------------------------------------------- /pgs_types.sql.in: -------------------------------------------------------------------------------- 1 | 2 | -- Creates a type 'spherical point' 3 | 4 | 5 | CREATE FUNCTION spoint_in(CSTRING) 6 | RETURNS spoint 7 | AS 'MODULE_PATHNAME', 'spherepoint_in' 8 | LANGUAGE 'c' 9 | IMMUTABLE STRICT; 10 | 11 | 12 | CREATE FUNCTION spoint_out(spoint) 13 | RETURNS CSTRING 14 | AS 'MODULE_PATHNAME', 'spherepoint_out' 15 | LANGUAGE 'c' 16 | IMMUTABLE STRICT; 17 | 18 | 19 | CREATE TYPE spoint ( 20 | internallength = 16, 21 | input = spoint_in, 22 | output = spoint_out 23 | ); 24 | 25 | -- Creates a type 'spherical transformation' 26 | 27 | 28 | CREATE FUNCTION strans_in(CSTRING) 29 | RETURNS strans 30 | AS 'MODULE_PATHNAME', 'spheretrans_in' 31 | LANGUAGE 'c' 32 | IMMUTABLE STRICT; 33 | 34 | 35 | CREATE FUNCTION strans_out(strans) 36 | RETURNS CSTRING 37 | AS 'MODULE_PATHNAME', 'spheretrans_out' 38 | LANGUAGE 'c' 39 | IMMUTABLE STRICT; 40 | 41 | 42 | CREATE TYPE strans ( 43 | internallength = 32, 44 | input = strans_in, 45 | output = strans_out 46 | ); 47 | 48 | -- Creates a type 'spherical circle' 49 | 50 | 51 | CREATE FUNCTION scircle_in(CSTRING) 52 | RETURNS scircle 53 | AS 'MODULE_PATHNAME', 'spherecircle_in' 54 | LANGUAGE 'c' 55 | IMMUTABLE STRICT; 56 | 57 | 58 | CREATE FUNCTION scircle_out(scircle) 59 | RETURNS CSTRING 60 | AS 'MODULE_PATHNAME', 'spherecircle_out' 61 | LANGUAGE 'c' 62 | IMMUTABLE STRICT; 63 | 64 | 65 | CREATE TYPE scircle ( 66 | internallength = 24, 67 | input = scircle_in, 68 | output = scircle_out 69 | ); 70 | 71 | -- Creates a type 'spherical line' 72 | 73 | 74 | CREATE FUNCTION sline_in(CSTRING) 75 | RETURNS sline 76 | AS 'MODULE_PATHNAME', 'sphereline_in' 77 | LANGUAGE 'c' 78 | IMMUTABLE STRICT; 79 | 80 | 81 | CREATE FUNCTION sline_out(sline) 82 | RETURNS CSTRING 83 | AS 'MODULE_PATHNAME', 'sphereline_out' 84 | LANGUAGE 'c' 85 | IMMUTABLE STRICT; 86 | 87 | 88 | CREATE TYPE sline ( 89 | internallength = 32, 90 | input = sline_in, 91 | output = sline_out 92 | ); 93 | 94 | 95 | -- Creates a type 'spherical ellipse' 96 | 97 | CREATE FUNCTION sellipse_in(CSTRING) 98 | RETURNS sellipse 99 | AS 'MODULE_PATHNAME', 'sphereellipse_in' 100 | LANGUAGE 'c' 101 | IMMUTABLE STRICT; 102 | 103 | 104 | CREATE FUNCTION sellipse_out(sellipse) 105 | RETURNS CSTRING 106 | AS 'MODULE_PATHNAME', 'sphereellipse_out' 107 | LANGUAGE 'c' 108 | IMMUTABLE STRICT; 109 | 110 | 111 | CREATE TYPE sellipse ( 112 | internallength = 40, 113 | input = sellipse_in, 114 | output = sellipse_out 115 | ); 116 | 117 | 118 | 119 | -- Creates a type 'spherical polygon' 120 | 121 | 122 | CREATE FUNCTION spoly_in(CSTRING) 123 | RETURNS spoly 124 | AS 'MODULE_PATHNAME', 'spherepoly_in' 125 | LANGUAGE 'c' 126 | IMMUTABLE STRICT; 127 | 128 | 129 | CREATE FUNCTION spoly_out(spoly) 130 | RETURNS CSTRING 131 | AS 'MODULE_PATHNAME', 'spherepoly_out' 132 | LANGUAGE 'c' 133 | IMMUTABLE STRICT; 134 | 135 | CREATE TYPE spoly ( 136 | internallength = VARIABLE, 137 | input = spoly_in, 138 | output = spoly_out, 139 | storage = external 140 | ); 141 | 142 | 143 | 144 | -- Creates a type 'spherical path' 145 | 146 | 147 | CREATE FUNCTION spath_in(CSTRING) 148 | RETURNS spath 149 | AS 'MODULE_PATHNAME', 'spherepath_in' 150 | LANGUAGE 'c' 151 | IMMUTABLE STRICT; 152 | 153 | 154 | CREATE FUNCTION spath_out(spath) 155 | RETURNS CSTRING 156 | AS 'MODULE_PATHNAME', 'spherepath_out' 157 | LANGUAGE 'c' 158 | IMMUTABLE STRICT; 159 | 160 | 161 | CREATE TYPE spath ( 162 | internallength = VARIABLE, 163 | input = spath_in, 164 | output = spath_out, 165 | storage = external 166 | ); 167 | 168 | 169 | 170 | -- Creates a type 'spherical box' 171 | 172 | 173 | CREATE FUNCTION sbox_in(CSTRING) 174 | RETURNS sbox 175 | AS 'MODULE_PATHNAME', 'spherebox_in' 176 | LANGUAGE 'c' 177 | IMMUTABLE STRICT; 178 | 179 | 180 | CREATE FUNCTION sbox_out(sbox) 181 | RETURNS CSTRING 182 | AS 'MODULE_PATHNAME', 'spherebox_out' 183 | LANGUAGE 'c' 184 | IMMUTABLE STRICT; 185 | 186 | 187 | CREATE TYPE sbox ( 188 | internallength = 32, 189 | input = sbox_in, 190 | output = sbox_out 191 | ); 192 | -------------------------------------------------------------------------------- /sql/circle_extended.sql: -------------------------------------------------------------------------------- 1 | -- indexed operations..... 2 | 3 | SET enable_indexscan=off; 4 | 5 | select count(sp) from spoint_data where sp @ '<(0d,90d),1.0d>'::scircle; 6 | 7 | select count(sp) from spoint_data where '<(0d,90d),1.0d>'::scircle ~ sp; 8 | 9 | select count(sp) from spoint_data where sp @ '<(0d,90d),1.1d>'::scircle; 10 | 11 | select count(sp) from spoint_data where '<(0d,90d),1.1d>'::scircle ~ sp; 12 | 13 | select count(sp) from spoint_data where sp @ '<(0d,-90d),1.0d>'::scircle; 14 | 15 | select count(sp) from spoint_data where '<(0d,-90d),1.0d>'::scircle ~ sp; 16 | 17 | select count(sp) from spoint_data where sp @ '<(0d,-90d),1.1d>'::scircle; 18 | 19 | select count(sp) from spoint_data where '<(0d,-90d),1.1d>'::scircle ~ sp; 20 | 21 | select count(sp) from spoint_data where sp @ '<(0d,0d),2.1d>'::scircle; 22 | 23 | select count(sp) from spoint_data where '<(0d,0d),2.1d>'::scircle ~ sp; 24 | 25 | 26 | 27 | select count(sc) from scircle_data where sc && '<(0d,90d),1.0d>'; 28 | 29 | select count(sc) from scircle_data where sc @ '<(0d,90d),1.0d>'; 30 | 31 | select count(sc) from scircle_data where '<(0d,90d),1.0d>' ~ sc; 32 | 33 | select count(sc) from scircle_data where sc && '<(0d,90d),1.1d>'; 34 | 35 | select count(sc) from scircle_data where sc @ '<(0d,90d),1.1d>'; 36 | 37 | select count(sc) from scircle_data where '<(0d,90d),1.1d>' ~ sc; 38 | 39 | select count(sc) from scircle_data where sc && '<(0d,-90d),1.0d>'; 40 | 41 | select count(sc) from scircle_data where sc @ '<(0d,-90d),1.0d>'; 42 | 43 | select count(sc) from scircle_data where '<(0d,-90d),1.0d>' ~ sc; 44 | 45 | select count(sc) from scircle_data where sc && '<(0d,-90d),1.1d>'; 46 | 47 | select count(sc) from scircle_data where sc @ '<(0d,-90d),1.1d>'; 48 | 49 | select count(sc) from scircle_data where '<(0d,-90d),1.1d>' ~ sc; 50 | 51 | select count(sc) from scircle_data where sc && '<(0d,0d),2.1d>'::scircle; 52 | 53 | select count(sc) from scircle_data where sc @ '<(0d,0d),2.1d>'::scircle; 54 | 55 | select count(sc) from scircle_data where '<(0d,0d),2.1d>'::scircle ~ sc; 56 | 57 | 58 | 59 | SET enable_indexscan=on; 60 | 61 | select count(sp) from spoint_data where sp @ '<(0d,90d),1.0d>'::scircle; 62 | 63 | select count(sp) from spoint_data where '<(0d,90d),1.0d>'::scircle ~ sp; 64 | 65 | select count(sp) from spoint_data where sp @ '<(0d,90d),1.1d>'::scircle; 66 | 67 | select count(sp) from spoint_data where '<(0d,90d),1.1d>'::scircle ~ sp; 68 | 69 | select count(sp) from spoint_data where sp @ '<(0d,-90d),1.0d>'::scircle; 70 | 71 | select count(sp) from spoint_data where '<(0d,-90d),1.0d>'::scircle ~ sp; 72 | 73 | select count(sp) from spoint_data where sp @ '<(0d,-90d),1.1d>'::scircle; 74 | 75 | select count(sp) from spoint_data where '<(0d,-90d),1.1d>'::scircle ~ sp; 76 | 77 | select count(sp) from spoint_data where sp @ '<(0d,0d),2.1d>'::scircle; 78 | 79 | select count(sp) from spoint_data where '<(0d,0d),2.1d>'::scircle ~ sp; 80 | 81 | 82 | 83 | select count(sc) from scircle_data where sc && '<(0d,90d),1.0d>'; 84 | 85 | select count(sc) from scircle_data where sc @ '<(0d,90d),1.0d>'; 86 | 87 | select count(sc) from scircle_data where '<(0d,90d),1.0d>' ~ sc; 88 | 89 | select count(sc) from scircle_data where sc && '<(0d,90d),1.1d>'; 90 | 91 | select count(sc) from scircle_data where sc @ '<(0d,90d),1.1d>'; 92 | 93 | select count(sc) from scircle_data where '<(0d,90d),1.1d>' ~ sc; 94 | 95 | select count(sc) from scircle_data where sc && '<(0d,-90d),1.0d>'; 96 | 97 | select count(sc) from scircle_data where sc @ '<(0d,-90d),1.0d>'; 98 | 99 | select count(sc) from scircle_data where '<(0d,-90d),1.0d>' ~ sc; 100 | 101 | select count(sc) from scircle_data where sc && '<(0d,-90d),1.1d>'; 102 | 103 | select count(sc) from scircle_data where sc @ '<(0d,-90d),1.1d>'; 104 | 105 | select count(sc) from scircle_data where '<(0d,-90d),1.1d>' ~ sc; 106 | 107 | select count(sc) from scircle_data where sc && '<(0d,0d),2.1d>'::scircle; 108 | 109 | select count(sc) from scircle_data where sc @ '<(0d,0d),2.1d>'::scircle; 110 | 111 | select count(sc) from scircle_data where '<(0d,0d),2.1d>'::scircle ~ sc; 112 | 113 | 114 | -- "Cross-correlation" about 30 seconds on PIII-750 115 | select count(spoint_data.sp) from spoint_data,scircle_data where spoint_data.sp @ scircle_data.sc; 116 | -------------------------------------------------------------------------------- /src/circle.h: -------------------------------------------------------------------------------- 1 | #ifndef __PGS_CIRCLE_H__ 2 | #define __PGS_CIRCLE_H__ 3 | 4 | #include "euler.h" 5 | 6 | /* Spherical circle declarations */ 7 | 8 | /* 9 | * Spherical circle data structure: center and radius. 10 | */ 11 | typedef struct 12 | { 13 | SPoint center; /* the center of circle */ 14 | float8 radius; /* the circle radius in radians */ 15 | } SCIRCLE; 16 | 17 | /* 18 | * Checks whether two circles are equal. 19 | */ 20 | extern bool scircle_eq(const SCIRCLE *c1, const SCIRCLE *c2); 21 | 22 | /* 23 | * Checks whether a circle contains a point. 24 | */ 25 | extern bool spoint_in_circle(const SPoint *p, const SCIRCLE *c); 26 | 27 | /* 28 | * Transforms a circle using an Euler transformation. 29 | */ 30 | extern void euler_scircle_trans(SCIRCLE *out, const SCIRCLE *in, const SEuler *se); 31 | 32 | /* 33 | * Takes the input and stores it as a spherical circle. 34 | */ 35 | extern Datum spherecircle_in(PG_FUNCTION_ARGS); 36 | 37 | /* 38 | * Checks whether two circles are equal. 39 | */ 40 | extern Datum spherecircle_equal(PG_FUNCTION_ARGS); 41 | 42 | /* 43 | * Checks whether two circles are not equal. 44 | */ 45 | extern Datum spherecircle_equal_neg(PG_FUNCTION_ARGS); 46 | 47 | /* 48 | * Calculate the distance of two circles. If they overlap, this function 49 | * returns 0.0. 50 | */ 51 | extern Datum spherecircle_distance(PG_FUNCTION_ARGS); 52 | 53 | /* 54 | * Calculate the distance of a circle and a point. If a circle contains a point, 55 | * this function returns 0.0. 56 | */ 57 | extern Datum spherecircle_point_distance(PG_FUNCTION_ARGS); 58 | 59 | /* 60 | * Calculate the distance of a point and a circle. If a circle contains a point, 61 | * this function returns 0.0. 62 | */ 63 | extern Datum spherecircle_point_distance_com(PG_FUNCTION_ARGS); 64 | 65 | /* 66 | * Checks whether a circle contains a point. 67 | */ 68 | extern Datum spherepoint_in_circle(PG_FUNCTION_ARGS); 69 | 70 | /* 71 | * Checks whether a circle doesn't contain a point. 72 | */ 73 | extern Datum spherepoint_in_circle_neg(PG_FUNCTION_ARGS); 74 | 75 | /* 76 | * Checks whether a circle contains a point. 77 | */ 78 | extern Datum spherepoint_in_circle_com(PG_FUNCTION_ARGS); 79 | 80 | /* 81 | * Checks whether a circle doesn't contain a point. 82 | */ 83 | extern Datum spherepoint_in_circle_com_neg(PG_FUNCTION_ARGS); 84 | 85 | /* 86 | * Checks whether a circle is contained by other circle. 87 | */ 88 | extern Datum spherecircle_in_circle(PG_FUNCTION_ARGS); 89 | 90 | /* 91 | * Checks whether a circle is not contained by other circle. 92 | */ 93 | extern Datum spherecircle_in_circle_neg(PG_FUNCTION_ARGS); 94 | 95 | /* 96 | * Checks whether a circle contains other circle. 97 | */ 98 | extern Datum spherecircle_in_circle_com(PG_FUNCTION_ARGS); 99 | 100 | /* 101 | * Checks whether circle does not contain other circle. 102 | */ 103 | extern Datum spherecircle_in_circle_com_neg(PG_FUNCTION_ARGS); 104 | 105 | /* 106 | * Checks whether two circles overlap. 107 | */ 108 | extern Datum spherecircle_overlap(PG_FUNCTION_ARGS); 109 | 110 | /* 111 | * Checks whether two circles overlap. 112 | */ 113 | extern Datum spherecircle_overlap_neg(PG_FUNCTION_ARGS); 114 | 115 | /* 116 | * Returns the center of a circle. 117 | */ 118 | extern Datum spherecircle_center(PG_FUNCTION_ARGS); 119 | 120 | /* 121 | * Returns the radius of a circle. 122 | */ 123 | extern Datum spherecircle_radius(PG_FUNCTION_ARGS); 124 | 125 | /* 126 | * Converts a point to a circle. 127 | */ 128 | extern Datum spherepoint_to_circle(PG_FUNCTION_ARGS); 129 | 130 | /* 131 | * Creates a circle from center and radius. 132 | */ 133 | extern Datum spherecircle_by_center(PG_FUNCTION_ARGS); 134 | 135 | /* 136 | * Creates a circle from center and radius(in degrees). 137 | */ 138 | extern Datum spherecircle_by_center_deg(PG_FUNCTION_ARGS); 139 | 140 | /* 141 | * Calculates the area of a circle in square radians. 142 | */ 143 | extern Datum spherecircle_area(PG_FUNCTION_ARGS); 144 | 145 | /* 146 | * Calculates the circumference of a circle in radians. 147 | */ 148 | extern Datum spherecircle_circ(PG_FUNCTION_ARGS); 149 | 150 | /* 151 | * Transforms a circle using an Euler transformation. 152 | */ 153 | extern Datum spheretrans_circle(PG_FUNCTION_ARGS); 154 | 155 | /* 156 | * Inverse transformation of a circle using an Euler transformation. 157 | */ 158 | extern Datum spheretrans_circle_inverse(PG_FUNCTION_ARGS); 159 | 160 | #endif 161 | -------------------------------------------------------------------------------- /doc/stylesheets/stylesheet-common.xsl: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 22 | 23 | 24 | 25 | 1 26 | 0 27 | 28 | 29 | 30 | 31 | yes 32 | 2 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 1 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | ? 89 | 90 | ? 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /sql/mocautocast.sql: -------------------------------------------------------------------------------- 1 | -- These are MOCs generated by 2 | -- SELECT smoc(mocorder, scircle '<(27d, -43d), 0.1d>'); 3 | -- intended to check automatic casts of other geometries. 4 | 5 | CREATE TABLE varorders ( 6 | mocorder smallint, 7 | geo smoc); 8 | INSERT INTO varorders (mocorder, geo) VALUES 9 | (1, smoc('1/32 34 1/')), 10 | (-3, smoc('1/32 34 3/')), 11 | (3, smoc('3/547-548 550 553 3/')), 12 | (7, smoc('7/140857-140860 140862 140944-140945 7/')), 13 | (-7, smoc('1/32 34 7/')); 14 | 15 | -- OVERLAPS smoc/scircle 16 | 17 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) gsupc 18 | FROM varorders 19 | WHERE geo @> scircle '<(30d, -43d), 1d>'; 20 | 21 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) gnsupc 22 | FROM varorders 23 | WHERE geo !@> scircle '<(30d, -43d), 1d>'; 24 | 25 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) csubg 26 | FROM varorders 27 | WHERE scircle '<(30d, -43d), 1d>' <@ geo; 28 | 29 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) cnsubg 30 | FROM varorders 31 | WHERE scircle '<(30d, -43d), 1d>' !<@ geo; 32 | 33 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) gsubc 34 | FROM varorders 35 | WHERE geo <@ scircle '<(30d, -43d), 1d>'; 36 | 37 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) gnsubc 38 | FROM varorders 39 | WHERE geo !<@ scircle '<(30d, -43d), 1d>'; 40 | 41 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) csupg 42 | FROM varorders 43 | WHERE scircle '<(30d, -43d), 1d>' @> geo; 44 | 45 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) cnsupg 46 | FROM varorders 47 | WHERE scircle '<(30d, -43d), 1d>' !@> geo; 48 | 49 | 50 | -- OVERLAPS smoc/spoly 51 | 52 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) gsupp 53 | FROM varorders 54 | WHERE geo @> spoly('{(26d,-42d), (26d,-41d), (27d,-41d)}'); 55 | 56 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) gnsupp 57 | FROM varorders 58 | WHERE geo !@> spoly('{(26d,-42d), (26d,-41d), (27d,-41d)}'); 59 | 60 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) psubg 61 | FROM varorders 62 | WHERE spoly('{(26d,-42d), (26d,-41d), (27d,-41d)}') <@ geo; 63 | 64 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) pnsubg 65 | FROM varorders 66 | WHERE spoly('{(26d,-42d), (26d,-41d), (27d,-41d)}') !<@ geo; 67 | 68 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) gsubp 69 | FROM varorders 70 | WHERE geo <@ spoly('{(26d,-42d), (26d,-41d), (27d,-41d)}'); 71 | 72 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) gnsubp 73 | FROM varorders 74 | WHERE geo !<@ spoly('{(26d,-42d), (26d,-41d), (27d,-41d)}'); 75 | 76 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) psupg 77 | FROM varorders 78 | WHERE spoly('{(26d,-42d), (26d,-41d), (27d,-41d)}') @> geo; 79 | 80 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) pnsupg 81 | FROM varorders 82 | WHERE spoly('{(26d,-42d), (26d,-41d), (27d,-41d)}') !@> geo; 83 | 84 | 85 | -- INTERSECTS smoc/scircle 86 | 87 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) cgim 88 | FROM varorders 89 | WHERE scircle '<(45d, -40d), 1d>' && geo; 90 | 91 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) cgnim 92 | FROM varorders 93 | WHERE scircle '<(45d, -40d), 1d>' !&& geo; 94 | 95 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) cmig 96 | FROM varorders 97 | WHERE geo && scircle '<(45d, -40d), 1d>'; 98 | 99 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) cnim 100 | FROM varorders 101 | WHERE geo !&& scircle '<(45d, -40d), 1d>'; 102 | 103 | 104 | -- INTERSECTS smoc/spoly 105 | 106 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) cgim 107 | FROM varorders 108 | WHERE spoly '{(51.1d, -50.1d), (45.8d, -47.5), (46.7d, -43.7d)}' && geo; 109 | 110 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) cgnim 111 | FROM varorders 112 | WHERE spoly '{(51.1d, -50.1d), (45.8d, -47.5), (46.7d, -43.7d)}' !&& geo; 113 | 114 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) cmig 115 | FROM varorders 116 | WHERE geo && spoly '{(51.1d, -50.1d), (45.8d, -47.5), (46.7d, -43.7d)}'; 117 | 118 | SELECT string_agg(to_char(mocorder, '9'), '/' ORDER BY mocorder) cnim 119 | FROM varorders 120 | WHERE geo !&& spoly '{(51.1d, -50.1d), (45.8d, -47.5), (46.7d, -43.7d)}'; 121 | 122 | 123 | DROP TABLE varorders; 124 | -------------------------------------------------------------------------------- /doc/stylesheets/stylesheet-speedup-common.xsl: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 60 | 61 | 63 | 64 | 65 | 66 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | en 99 | 100 | 101 | -------------------------------------------------------------------------------- /pgs_circle_sel.sql.in: -------------------------------------------------------------------------------- 1 | CREATE FUNCTION spoint_contained_by_circle_sel(internal, oid, internal, integer) 2 | RETURNS double precision 3 | AS 'MODULE_PATHNAME' , 'spherepoint_in_circle_sel' 4 | LANGUAGE C 5 | IMMUTABLE STRICT PARALLEL SAFE; 6 | 7 | COMMENT ON FUNCTION spoint_contained_by_circle_sel(internal, oid, internal, integer) IS 8 | 'selectivity estimator function for spoint_contained_by_circle'; 9 | 10 | CREATE FUNCTION spoint_contained_by_circle_joinsel(internal, oid, internal, smallint, internal) 11 | RETURNS double precision 12 | AS 'MODULE_PATHNAME' , 'spherepoint_in_circle_joinsel' 13 | LANGUAGE C 14 | IMMUTABLE STRICT PARALLEL SAFE; 15 | 16 | COMMENT ON FUNCTION spoint_contained_by_circle_joinsel(internal, oid, internal, smallint, internal) IS 17 | 'join selectivity estimator function for spoint_contained_by_circle'; 18 | 19 | 20 | CREATE FUNCTION spoint_contained_by_circle_neg_sel(internal, oid, internal, integer) 21 | RETURNS double precision 22 | AS 'MODULE_PATHNAME' , 'spherepoint_in_circle_neg_sel' 23 | LANGUAGE C 24 | IMMUTABLE STRICT PARALLEL SAFE; 25 | 26 | COMMENT ON FUNCTION spoint_contained_by_circle_neg_sel(internal, oid, internal, integer) IS 27 | 'selectivity estimator function for spoint_contained_by_circle_neg'; 28 | 29 | CREATE FUNCTION spoint_contained_by_circle_neg_joinsel(internal, oid, internal, smallint, internal) 30 | RETURNS double precision 31 | AS 'MODULE_PATHNAME' , 'spherepoint_in_circle_neg_joinsel' 32 | LANGUAGE C 33 | IMMUTABLE STRICT PARALLEL SAFE; 34 | 35 | COMMENT ON FUNCTION spoint_contained_by_circle_neg_joinsel(internal, oid, internal, smallint, internal) IS 36 | 'join selectivity estimator function for spoint_contained_by_circle_neg'; 37 | 38 | 39 | CREATE FUNCTION spoint_contained_by_circle_com_sel(internal, oid, internal, integer) 40 | RETURNS double precision 41 | AS 'MODULE_PATHNAME' , 'spherepoint_in_circle_com_sel' 42 | LANGUAGE C 43 | IMMUTABLE STRICT PARALLEL SAFE; 44 | 45 | COMMENT ON FUNCTION spoint_contained_by_circle_com_sel(internal, oid, internal, integer) IS 46 | 'selectivity estimator function for spoint_contained_by_circle_com'; 47 | 48 | CREATE FUNCTION spoint_contained_by_circle_com_joinsel(internal, oid, internal, smallint, internal) 49 | RETURNS double precision 50 | AS 'MODULE_PATHNAME' , 'spherepoint_in_circle_com_joinsel' 51 | LANGUAGE C 52 | IMMUTABLE STRICT PARALLEL SAFE; 53 | 54 | COMMENT ON FUNCTION spoint_contained_by_circle_com_joinsel(internal, oid, internal, smallint, internal) IS 55 | 'join selectivity estimator function for spoint_contained_by_circle_com'; 56 | 57 | 58 | CREATE FUNCTION spoint_contained_by_circle_com_neg_sel(internal, oid, internal, integer) 59 | RETURNS double precision 60 | AS 'MODULE_PATHNAME' , 'spherepoint_in_circle_com_neg_sel' 61 | LANGUAGE C 62 | IMMUTABLE STRICT PARALLEL SAFE; 63 | 64 | COMMENT ON FUNCTION spoint_contained_by_circle_com_neg_sel(internal, oid, internal, integer) IS 65 | 'selectivity estimator function for spoint_contained_by_circle_com_neg'; 66 | 67 | CREATE FUNCTION spoint_contained_by_circle_com_neg_joinsel(internal, oid, internal, smallint, internal) 68 | RETURNS double precision 69 | AS 'MODULE_PATHNAME' , 'spherepoint_in_circle_com_neg_joinsel' 70 | LANGUAGE C 71 | IMMUTABLE STRICT PARALLEL SAFE; 72 | 73 | COMMENT ON FUNCTION spoint_contained_by_circle_com_neg_joinsel(internal, oid, internal, smallint, internal) IS 74 | 'join selectivity estimator function for spoint_contained_by_circle_com_neg'; 75 | 76 | 77 | ALTER OPERATOR @> (scircle, spoint) 78 | SET ( 79 | RESTRICT = spoint_contained_by_circle_com_sel, 80 | JOIN = spoint_contained_by_circle_com_joinsel 81 | ); 82 | 83 | ALTER OPERATOR <@ (spoint, scircle) 84 | SET ( 85 | RESTRICT = spoint_contained_by_circle_sel, 86 | JOIN = spoint_contained_by_circle_joinsel 87 | ); 88 | 89 | ALTER OPERATOR !@> (scircle, spoint) 90 | SET ( 91 | RESTRICT = spoint_contained_by_circle_com_neg_sel, 92 | JOIN = spoint_contained_by_circle_com_neg_joinsel 93 | ); 94 | 95 | ALTER OPERATOR !<@ (spoint, scircle) 96 | SET ( 97 | RESTRICT = spoint_contained_by_circle_neg_sel, 98 | JOIN = spoint_contained_by_circle_neg_joinsel 99 | ); 100 | 101 | 102 | CREATE FUNCTION spoint_dwithin(spoint, spoint, float8) 103 | RETURNS boolean 104 | AS 'MODULE_PATHNAME', 'spherepoint_dwithin' 105 | LANGUAGE C 106 | IMMUTABLE STRICT PARALLEL SAFE; 107 | 108 | COMMENT ON FUNCTION spoint_dwithin(spoint, spoint, float8) IS 109 | 'predicate matching spherical points less than a given distance apart'; 110 | -------------------------------------------------------------------------------- /healpix.sql.in: -------------------------------------------------------------------------------- 1 | -- conversions to / from Healpix indexing 2 | 3 | CREATE OR REPLACE FUNCTION nest2ring(integer, bigint) 4 | RETURNS bigint 5 | AS 'MODULE_PATHNAME', 'pg_nest2ring' 6 | LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; 7 | COMMENT ON FUNCTION nest2ring(integer, bigint) IS 8 | 'converts nested Healpix index to a ring Healpix index for the specified integer level (first argument)'; 9 | 10 | CREATE OR REPLACE FUNCTION ring2nest(integer, bigint) 11 | RETURNS bigint 12 | AS 'MODULE_PATHNAME', 'pg_ring2nest' 13 | LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; 14 | COMMENT ON FUNCTION ring2nest(integer, bigint) IS 15 | 'converts ringe Healpix index to a nested Healpix index for the specified integer level (first argument)'; 16 | 17 | CREATE OR REPLACE FUNCTION healpix_convert_nest(integer, integer, bigint) 18 | RETURNS bigint 19 | AS 'MODULE_PATHNAME' 20 | LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; 21 | COMMENT ON FUNCTION healpix_convert_nest(integer, integer, bigint) IS 22 | 'converts nested Healpix index (last argument) from level of second argument to level of first argument'; 23 | 24 | CREATE OR REPLACE FUNCTION healpix_convert_ring(integer, integer, bigint) 25 | RETURNS bigint 26 | AS 'MODULE_PATHNAME' 27 | LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; 28 | COMMENT ON FUNCTION healpix_convert_ring(integer, integer, bigint) IS 29 | 'converts ring Healpix index (last argument) from level of second argument to level of first argument'; 30 | 31 | CREATE OR REPLACE FUNCTION nside2order(bigint) 32 | RETURNS integer 33 | AS 'MODULE_PATHNAME', 'pg_nside2order' 34 | LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; 35 | COMMENT ON FUNCTION nside2order(bigint) IS 36 | 'returns integer part of base-two logarithm of argument for powers of two up to 29'; 37 | 38 | CREATE OR REPLACE FUNCTION order2nside(integer) 39 | RETURNS bigint 40 | AS 'MODULE_PATHNAME', 'pg_order2nside' 41 | LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; 42 | COMMENT ON FUNCTION order2nside(integer) IS 43 | 'returns power of two for non-negative values up to 29'; 44 | 45 | CREATE OR REPLACE FUNCTION nside2npix(bigint) 46 | RETURNS bigint 47 | AS 'MODULE_PATHNAME', 'pg_nside2npix' 48 | LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; 49 | COMMENT ON FUNCTION nside2npix(bigint) IS 50 | 'returns 12 * nside ^ 2, the number of Healpix elements for the nside parameter'; 51 | 52 | CREATE OR REPLACE FUNCTION npix2nside(bigint) 53 | RETURNS bigint 54 | AS 'MODULE_PATHNAME', 'pg_npix2nside' 55 | LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; 56 | COMMENT ON FUNCTION npix2nside(bigint) IS 57 | 'returns the nside parameter correspondig to the number of Healpix elements'; 58 | 59 | CREATE OR REPLACE FUNCTION healpix_nest(integer, spoint) 60 | RETURNS bigint 61 | AS 'MODULE_PATHNAME' 62 | LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; 63 | COMMENT ON FUNCTION healpix_nest(integer, spoint) IS 64 | 'nested Healpix index of a spherical point for the specified integer level (first argument)'; 65 | 66 | CREATE OR REPLACE FUNCTION healpix_ring(integer, spoint) 67 | RETURNS bigint 68 | AS 'MODULE_PATHNAME' 69 | LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; 70 | COMMENT ON FUNCTION healpix_ring(integer, spoint) IS 71 | 'Healpix ring index of a spherical point for the specified integer level (first argument)'; 72 | 73 | CREATE OR REPLACE FUNCTION centre_of_healpix_nest(integer, bigint) 74 | RETURNS spoint 75 | AS 'MODULE_PATHNAME', 'inv_healpix_nest' 76 | LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; 77 | COMMENT ON FUNCTION centre_of_healpix_nest(integer, bigint) IS 78 | 'spherical point designating the centre of a nested Healpix element for the specified integer level (first argument)'; 79 | 80 | CREATE OR REPLACE FUNCTION centre_of_healpix_ring(integer, bigint) 81 | RETURNS spoint 82 | AS 'MODULE_PATHNAME', 'inv_healpix_ring' 83 | LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; 84 | COMMENT ON FUNCTION centre_of_healpix_ring(integer, bigint) IS 85 | 'spherical point designating the centre of a ring Healpix element for the specified integer level (first argument)'; 86 | 87 | CREATE OR REPLACE FUNCTION center_of_healpix_nest(integer, bigint) 88 | RETURNS spoint 89 | AS 'MODULE_PATHNAME', 'inv_healpix_nest' 90 | LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; 91 | COMMENT ON FUNCTION center_of_healpix_nest(integer, bigint) IS 92 | 'spherical point designating the center of a nested Healpix element for the specified integer level (first argument)'; 93 | 94 | CREATE OR REPLACE FUNCTION center_of_healpix_ring(integer, bigint) 95 | RETURNS spoint 96 | AS 'MODULE_PATHNAME', 'inv_healpix_ring' 97 | LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; 98 | COMMENT ON FUNCTION center_of_healpix_ring(integer, bigint) IS 99 | 'spherical point designating the center of a ring Healpix element for the specified integer level (first argument)'; 100 | -------------------------------------------------------------------------------- /expected/line.out: -------------------------------------------------------------------------------- 1 | \set ECHO none 2 | set_sphere_output_precision 3 | ----------------------------- 4 | SET 8 5 | (1 row) 6 | 7 | SET extra_float_digits TO -3; 8 | -- checking spherical line operators 9 | SELECT sline ( spoint '(0, 90d)', spoint '(0, -89d)' ) = 10 | sline ( spoint '(0, 90d)', spoint '(0, -89d)' ) ; 11 | ?column? 12 | ---------- 13 | t 14 | (1 row) 15 | 16 | SELECT sline ( spoint '(0, 90d)', spoint '(0, -89d)' ) <> 17 | sline ( spoint '(0, -89d)', spoint '(0, 90d)' ) ; 18 | ?column? 19 | ---------- 20 | t 21 | (1 row) 22 | 23 | SELECT sline ( spoint '(0, 0d)', spoint '(10d, 0d)' ) # 24 | sline ( spoint '(5d, 5d)', spoint '(5d, -5d)' ) ; 25 | ?column? 26 | ---------- 27 | t 28 | (1 row) 29 | 30 | SELECT sline ( spoint '(0, 0d)', spoint '(10d, 0d)' ) # 31 | sline ( spoint '(10d, 5d)', spoint '(10d, -5d)' ) ; 32 | ?column? 33 | ---------- 34 | t 35 | (1 row) 36 | 37 | SELECT sline ( spoint '(0, 0d)', spoint '(10d, 0d)' ) # 38 | sline ( spoint '(15d, 5d)', spoint '(15d, -5d)' ) ; 39 | ?column? 40 | ---------- 41 | f 42 | (1 row) 43 | 44 | SELECT sline ( spoint '(0, 0d)', spoint '(10d, 0d)' ) # 45 | sline ( spoint '(10d, 0d)', spoint '(10d, -5d)' ) ; 46 | ?column? 47 | ---------- 48 | f 49 | (1 row) 50 | 51 | SELECT sline ( spoint '(0, 0d)', spoint '(10d, 0d)' ) # 52 | sline ( spoint '(5d, -5d)', spoint '(5d, 5d)' ) ; 53 | ?column? 54 | ---------- 55 | t 56 | (1 row) 57 | 58 | SELECT sline ( spoint '(0, 0d)', spoint '(10d, 0d)' ) # 59 | sline ( spoint '(10d, -5d)', spoint '(10d, 5d)' ) ; 60 | ?column? 61 | ---------- 62 | t 63 | (1 row) 64 | 65 | SELECT sline ( spoint '(0, 0d)', spoint '(10d, 0d)' ) # 66 | sline ( spoint '(15d, -5d)', spoint '(15d, 5d)' ) ; 67 | ?column? 68 | ---------- 69 | f 70 | (1 row) 71 | 72 | SELECT sline ( spoint '(0, 0d)', spoint '(10d, 0d)' ) # 73 | sline ( spoint '(10d, 0d)', spoint '(10d, 5d)' ) ; 74 | ?column? 75 | ---------- 76 | f 77 | (1 row) 78 | 79 | 80 | 81 | -- check small lines 82 | SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # 83 | sline ( spoint '(0.0000005d, 0.0000005d)', spoint '(0.0000005d, -0.0000005d)' ) ; 84 | ?column? 85 | ---------- 86 | t 87 | (1 row) 88 | 89 | SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # 90 | sline ( spoint '(0.000001d, 0.0000005d)', spoint '(0.000001d, -0.0000005d)' ) ; 91 | ?column? 92 | ---------- 93 | t 94 | (1 row) 95 | 96 | SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # 97 | sline ( spoint '(0.0000015d, 0.0000005d)', spoint '(0.0000015d, -0.0000005d)' ) ; 98 | ?column? 99 | ---------- 100 | f 101 | (1 row) 102 | 103 | SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # 104 | sline ( spoint '(0.000001d, 0d)', spoint '(0.000001d, -0.0000005d)' ) ; 105 | ?column? 106 | ---------- 107 | f 108 | (1 row) 109 | 110 | SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # 111 | sline ( spoint '(0.0000005d, -0.0000005d)', spoint '(0.0000005d, 0.0000005d)' ) ; 112 | ?column? 113 | ---------- 114 | t 115 | (1 row) 116 | 117 | SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # 118 | sline ( spoint '(0.000001d, -0.0000005d)', spoint '(0.000001d, 0.0000005d)' ) ; 119 | ?column? 120 | ---------- 121 | t 122 | (1 row) 123 | 124 | SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # 125 | sline ( spoint '(0.0000015d, -0.0000005d)', spoint '(0.0000015d, 0.0000005d)' ) ; 126 | ?column? 127 | ---------- 128 | f 129 | (1 row) 130 | 131 | SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # 132 | sline ( spoint '(0.000001d, 0d)', spoint '(0.000001d, 0.0000005d)' ) ; 133 | ?column? 134 | ---------- 135 | f 136 | (1 row) 137 | 138 | -- checking the distance between a line and a point 139 | SELECT sline '( 90d, 0d, 0d, XYZ ), 40d ' <-> spoint '( 0d, 90d )'; 140 | ?column? 141 | ---------------- 142 | 0.872664625997 143 | (1 row) 144 | 145 | SELECT sline '( 90d, 0d, 0d, XYZ ), 40d ' <-> spoint '( 0d, 90d )' = 146 | spoint '( 0d, 90d )' <-> sline '( 90d, 0d, 0d, XYZ ), 40d '; 147 | ?column? 148 | ---------- 149 | t 150 | (1 row) 151 | 152 | SELECT sline '( 0d, 0d, 0d, XYZ ), 0d ' <-> spoint '( 0d, 90d )'; 153 | ?column? 154 | --------------- 155 | 1.57079632679 156 | (1 row) 157 | 158 | SELECT sline '( 0d, 0d, 0d, XYZ ), 0d ' <-> spoint '( 0d, 0d )'; 159 | ?column? 160 | ---------- 161 | 0 162 | (1 row) 163 | 164 | SELECT sline '( 0d, 0d, 0d, XYZ ), 30d ' <-> spoint '( 0d, 30d )'; 165 | ?column? 166 | ---------------- 167 | 0.523598775598 168 | (1 row) 169 | 170 | -------------------------------------------------------------------------------- /src/euler.h: -------------------------------------------------------------------------------- 1 | #ifndef __PGS_EULER_H__ 2 | #define __PGS_EULER_H__ 3 | 4 | #include "point.h" 5 | 6 | /* 7 | * Euler transformation declarations 8 | */ 9 | 10 | /* 11 | * Data structure of spherical (Euler) transformation. 12 | */ 13 | typedef struct 14 | { 15 | unsigned char phi_a:2, /* first axis */ 16 | theta_a:2, /* second axis */ 17 | psi_a:2; /* third axis */ 18 | float8 phi, /* first rotation angle */ 19 | theta, /* second rotation angle */ 20 | psi; /* third rotation angle */ 21 | } SEuler; 22 | 23 | 24 | /* 25 | * Transforms a spherical point and returns the pointer to a transformed spherical 26 | * point. 27 | */ 28 | extern void euler_spoint_trans(SPoint *out, const SPoint *in, const SEuler *se); 29 | 30 | /* 31 | * Transforms a spherical vector from 'spb' to 'spe' into an Euler transformation. 32 | * Returns true if the transformation was successful. 33 | */ 34 | extern bool spherevector_to_euler(SEuler *se, const SPoint *spb, const SPoint *spe); 35 | 36 | /* 37 | * Sets the axes of transformation to ZXZ. 38 | */ 39 | extern void seuler_set_zxz(SEuler *se); 40 | 41 | /* 42 | * Checks equality of two transformations. 43 | */ 44 | extern bool strans_eq(const SEuler *e1, const SEuler *e2); 45 | 46 | /* 47 | * Transforms a vector using an Euler transformation. Returns the pointer to 48 | * the result vector. 49 | */ 50 | extern void euler_vector_trans(Vector3D *out, const Vector3D *in, const SEuler *se); 51 | 52 | /* 53 | * Inverts an Euler transformation. Returns the pointer to the 54 | * inverted transformation. 55 | */ 56 | extern void spheretrans_inverse(SEuler *se_out, const SEuler *se_in); 57 | 58 | /* 59 | * Inverts an Euler transformation replacing the original Euler transformation. 60 | * Returns the pointer to the inverted transformation. 61 | */ 62 | extern void spheretrans_inv(SEuler *se); 63 | 64 | /* 65 | * Converts an Euler transformation to a ZXZ-axis transformation. Returns 66 | * the pointer to the converted transformation. 67 | */ 68 | extern void strans_zxz(SEuler *ret, const SEuler *se); 69 | 70 | /* 71 | * Transforms an Euler transformation 'in' into 'out' using 'se'. The result 72 | * is always a ZXZ-axis transformation. Returns the pointer to the transformed 73 | * transformation. 74 | */ 75 | extern void seuler_trans_zxz(SEuler *out, const SEuler *in, const SEuler *se); 76 | 77 | /* 78 | * Input of an Euler transformation. 79 | */ 80 | extern Datum spheretrans_in(PG_FUNCTION_ARGS); 81 | 82 | /* 83 | * Input of an Euler transformation with axis Z,X,Z from three angles 84 | * (phi, theta, psi) in radians. 85 | */ 86 | extern Datum spheretrans_from_float8(PG_FUNCTION_ARGS); 87 | 88 | /* 89 | * Returns the first angle of an Euler transformation in radians. 90 | */ 91 | extern Datum spheretrans_phi(PG_FUNCTION_ARGS); 92 | 93 | /* 94 | * Returns the second angle of an Euler transformation in radians. 95 | */ 96 | extern Datum spheretrans_theta(PG_FUNCTION_ARGS); 97 | 98 | /* 99 | * Returns the third angle of an Euler transformation in radians. 100 | */ 101 | extern Datum spheretrans_psi(PG_FUNCTION_ARGS); 102 | 103 | /* 104 | * Returns the axis of an Euler transformation as three letter code. 105 | */ 106 | extern Datum spheretrans_type(PG_FUNCTION_ARGS); 107 | 108 | /* 109 | * Returns the Euler transformation (does nothing). This function is needed 110 | * for +strans operator. 111 | */ 112 | extern Datum spheretrans(PG_FUNCTION_ARGS); 113 | 114 | /* 115 | * Returns the inverse Euler transformation. 116 | */ 117 | extern Datum spheretrans_invert(PG_FUNCTION_ARGS); 118 | 119 | /* 120 | * Convert an Euler transformation to a ZXZ-axis transformation. 121 | */ 122 | extern Datum spheretrans_zxz(PG_FUNCTION_ARGS); 123 | 124 | /* 125 | * This function creates an Euler transformation from 3 angle values in 126 | * radians and three letter code used for axes. A letter can be X, Y or Z 127 | * (case-insensitive). 128 | */ 129 | extern Datum spheretrans_from_float8_and_type(PG_FUNCTION_ARGS); 130 | 131 | /* 132 | * Checks equality of two Euler transformations. 133 | */ 134 | extern Datum spheretrans_equal(PG_FUNCTION_ARGS); 135 | 136 | /* 137 | * Checks inequality of two Euler transformations. 138 | */ 139 | extern Datum spheretrans_not_equal(PG_FUNCTION_ARGS); 140 | 141 | /* 142 | * Transforms an Euler transformation. 143 | */ 144 | extern Datum spheretrans_trans(PG_FUNCTION_ARGS); 145 | 146 | /* 147 | * Transforms inverse an Euler transformations. 148 | */ 149 | extern Datum spheretrans_trans_inv(PG_FUNCTION_ARGS); 150 | 151 | /* 152 | * Transforms a spherical point. 153 | */ 154 | extern Datum spheretrans_point(PG_FUNCTION_ARGS); 155 | 156 | /* 157 | * Perform inverse transformation of a spherical point. 158 | */ 159 | extern Datum spheretrans_point_inverse(PG_FUNCTION_ARGS); 160 | 161 | #endif 162 | -------------------------------------------------------------------------------- /expected/epochprop.out: -------------------------------------------------------------------------------- 1 | SET extra_float_digits = 1; 2 | SELECT 3 | to_char(DEGREES(tp[1]), '999D9999999999'), 4 | to_char(DEGREES(tp[2]), '999D9999999999'), 5 | to_char(tp[3], '999D999'), 6 | to_char(DEGREES(tp[4])*3.6e6, '999D999'), 7 | to_char(DEGREES(tp[5])*3.6e6, '99999D999'), 8 | to_char(tp[6], '999D999') 9 | FROM ( 10 | SELECT epoch_prop(spoint(radians(269.45207695), radians(4.693364966)), 11 | 546.9759, 12 | RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), -110, 13 | -100) AS tp) AS q; 14 | to_char | to_char | to_char | to_char | to_char | to_char 15 | -----------------+-----------------+----------+----------+------------+---------- 16 | 269.4742714391 | 4.4072939987 | 543.624 | -791.442 | 10235.412 | -110.450 17 | (1 row) 18 | 19 | SELECT 20 | to_char(DEGREES(tp[1]), '999D9999999999'), 21 | to_char(DEGREES(tp[2]), '999D9999999999'), 22 | to_char(tp[3], '999D999'), 23 | to_char(DEGREES(tp[4])*3.6e6, '999D999'), 24 | to_char(DEGREES(tp[5])*3.6e6, '99999D999'), 25 | to_char(tp[6], '999D999') 26 | FROM ( 27 | SELECT epoch_prop(spoint(radians(269.45207695), radians(4.693364966)), 28 | 0, 29 | RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), -110, 30 | -100) AS tp) AS q; 31 | to_char | to_char | to_char | to_char | to_char | to_char 32 | -----------------+-----------------+----------+----------+------------+---------- 33 | 269.4744079540 | 4.4055337210 | .000 | -801.210 | 10361.762 | -110.000 34 | (1 row) 35 | 36 | SELECT 37 | to_char(DEGREES(tp[1]), '999D9999999999'), 38 | to_char(DEGREES(tp[2]), '999D9999999999'), 39 | to_char(tp[3], '999D999'), 40 | to_char(DEGREES(tp[4])*3.6e6, '999D999'), 41 | to_char(DEGREES(tp[5])*3.6e6, '99999D999'), 42 | to_char(tp[6], '999D999') 43 | FROM ( 44 | SELECT epoch_prop(spoint(radians(269.45207695), radians(4.693364966)), 45 | NULL, 46 | RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), -110, 47 | -100) AS tp) AS q; 48 | to_char | to_char | to_char | to_char | to_char | to_char 49 | -----------------+-----------------+---------+----------+------------+---------- 50 | 269.4744079540 | 4.4055337210 | | -801.210 | 10361.762 | -110.000 51 | (1 row) 52 | 53 | SELECT 54 | to_char(DEGREES(tp[1]), '999D9999999999'), 55 | to_char(DEGREES(tp[2]), '999D9999999999'), 56 | to_char(tp[3], '999D999'), 57 | to_char(DEGREES(tp[4])*3.6e6, '999D999'), 58 | to_char(DEGREES(tp[5])*3.6e6, '99999D999'), 59 | to_char(tp[6], '999D999') 60 | FROM ( 61 | SELECT epoch_prop(spoint(radians(269.45207695), radians(4.693364966)), 62 | 23, 63 | RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), NULL, 64 | 20) AS tp) AS q; 65 | to_char | to_char | to_char | to_char | to_char | to_char 66 | -----------------+-----------------+----------+----------+------------+--------- 67 | 269.4476085384 | 4.7509315989 | 23.000 | -801.617 | 10361.984 | 68 | (1 row) 69 | 70 | SELECT 71 | to_char(DEGREES(tp[1]), '999D9999999999'), 72 | to_char(DEGREES(tp[2]), '999D9999999999'), 73 | to_char(tp[3], '999D999'), 74 | to_char(DEGREES(tp[4])*3.6e6, '999D999'), 75 | to_char(DEGREES(tp[5])*3.6e6, '99999D999'), 76 | to_char(tp[6], '999D999') 77 | FROM ( 78 | SELECT epoch_prop(spoint(radians(269.45207695), radians(4.693364966)), 79 | 23, 80 | NULL, RADIANS(10362/3.6e6), -110, 81 | 120) AS tp) AS q; 82 | to_char | to_char | to_char | to_char | to_char | to_char 83 | -----------------+-----------------+----------+---------+---------+---------- 84 | 269.4520769500 | 4.6933649660 | 23.007 | | | -110.000 85 | (1 row) 86 | 87 | SELECT epoch_prop(NULL, 88 | 23, 89 | 0.01 , RADIANS(10362/3.6e6), -110, 90 | 120); 91 | ERROR: NULL position not supported in epoch propagation 92 | SELECT epoch_prop_pos(spoint(radians(269.45207695), radians(4.693364966)), 93 | 23, 94 | RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), -110, 95 | 20) AS tp; 96 | tp 97 | ------------------------------------------- 98 | (4.702747926583129 , 0.08291945093459933) 99 | (1 row) 100 | 101 | SELECT epoch_prop_pos(spoint(radians(269.45207695), radians(4.693364966)), 102 | RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), 103 | 20) AS tp; 104 | tp 105 | ------------------------------------------- 106 | (4.702747930619516 , 0.08291939893808763) 107 | (1 row) 108 | 109 | -------------------------------------------------------------------------------- /healpix_bare/test.c: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------------- 2 | * 3 | * Copyright (C) 1997-2019 Krzysztof M. Gorski, Eric Hivon, Martin Reinecke, 4 | * Benjamin D. Wandelt, Anthony J. Banday, 5 | * Matthias Bartelmann, 6 | * Reza Ansari & Kenneth M. Ganga 7 | * 8 | * Test for the Healpix bare bones C library 9 | * 10 | * Licensed under a 3-clause BSD style license - see LICENSE 11 | * 12 | * For more information on HEALPix and additional software packages, see 13 | * https://healpix.sourceforge.io/ 14 | * 15 | * If you are using this code in your own packages, please consider citing 16 | * the original paper in your publications: 17 | * K.M. Gorski et al., 2005, Ap.J., 622, p.759 18 | * (http://adsabs.harvard.edu/abs/2005ApJ...622..759G) 19 | * 20 | *----------------------------------------------------------------------------*/ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "healpix_bare.h" 29 | 30 | static void error_check(int64_t nside, int64_t ipix, int64_t ip1) 31 | { 32 | if (ip1 != ipix) { 33 | printf("Error0: %" PRId64 " %" PRId64 " %" PRId64 "\n", nside, ipix, ip1); 34 | abort(); 35 | } 36 | } 37 | 38 | static void test2_helper1 (int64_t nside, int64_t dpix, int64_t epix) 39 | { 40 | /* Find the number of pixels in the full map */ 41 | for (int64_t ipix = 0; ipix < epix; ipix +=dpix) 42 | error_check(nside, ipix, ring2nest(nside, nest2ring(nside, ipix))); 43 | for (int64_t ipix = 0; ipix < epix; ipix +=dpix) 44 | error_check(nside, ipix, ang2nest(nside, nest2ang(nside, ipix))); 45 | for (int64_t ipix = 0; ipix < epix; ipix +=dpix) 46 | error_check(nside, ipix, vec2nest(nside, nest2vec(nside, ipix))); 47 | } 48 | 49 | static void test2_helper2 (int64_t nside, int64_t dpix) 50 | { 51 | /* Find the number of pixels in the full map */ 52 | int64_t npix = nside2npix(nside); 53 | for (int64_t ipix = 0; ipix < npix; ipix +=dpix) 54 | error_check(nside, ipix, ang2ring(nside, ring2ang(nside, ipix))); 55 | for (int64_t ipix = 0; ipix < npix; ipix +=dpix) 56 | error_check(nside, ipix, vec2ring(nside, ring2vec(nside, ipix))); 57 | } 58 | 59 | static void test2(void) { 60 | printf("Starting basic C Healpix pixel routines test\n"); 61 | 62 | for (int i=0; i<=29; ++i) 63 | { 64 | int64_t nside = 1LL<12*nside*nside) epix = 12*nside*nside; 68 | printf("Nside: %" PRId64 "\n",nside); 69 | test2_helper1(nside,nside*nside/123456+1, npix); 70 | test2_helper1(nside, 1, epix); 71 | test2_helper2(nside,nside*nside/123456+1); 72 | } 73 | 74 | printf("test completed\n\n"); 75 | } 76 | 77 | static void test3(void) { 78 | printf("Starting nontrivial C Healpix pixel routines test\n"); 79 | 80 | int64_t nside = 1024; 81 | int64_t dpix = 23; 82 | 83 | /* Find the number of pixels in the full map */ 84 | int64_t npix = nside2npix(nside); 85 | printf("Number of pixels in full map: %ld\n", npix); 86 | 87 | printf("dpix: %ld\n", dpix); 88 | printf("Nest -> ang -> vec -> ang -> Ring -> Nest\n"); 89 | for (int64_t ipix = 0; ipix < npix; ipix +=dpix) 90 | error_check(nside, ipix, 91 | ring2nest(nside, ang2ring(nside, vec2ang(ang2vec(nest2ang(nside, ipix)))))); 92 | printf("Ring -> ang -> Nest -> Ring\n"); 93 | for (int64_t ipix = 0; ipix < npix; ipix +=dpix) 94 | error_check(nside, ipix, 95 | nest2ring(nside,ang2nest(nside, ring2ang(nside, ipix)))); 96 | 97 | printf("Nest -> vec -> Ring -> Nest\n"); 98 | for (int64_t ipix = 0; ipix < npix; ipix +=dpix) 99 | error_check(nside, ipix, 100 | ring2nest(nside,vec2ring(nside,nest2vec(nside, ipix)))); 101 | printf("Ring -> vec -> Nest -> Ring\n"); 102 | for (int64_t ipix = 0; ipix < npix; ipix +=dpix) 103 | error_check(nside, ipix, 104 | nest2ring(nside,vec2nest(nside,ring2vec(nside, ipix)))); 105 | 106 | printf("%" PRId64 "\n", nside); 107 | printf("test completed\n\n"); 108 | } 109 | 110 | static void test_ang(void) { 111 | printf("Starting vector angle test\n"); 112 | for (double i=0; i<10; i+=0.01) { 113 | t_vec v1 = { i,10-i,sin(i) }, v2 = { 3-1.5*i, sqrt(i), i*0.3 }; 114 | double dot = v1.x*v2.x + v1.y*v2.y + v1.z*v2.z, 115 | l1 = sqrt(v1.x*v1.x+v1.y*v1.y+v1.z*v1.z), 116 | l2 = sqrt(v2.x*v2.x+v2.y*v2.y+v2.z*v2.z); 117 | double ang = acos(dot/(l1*l2)); 118 | if (fabs(ang - vec_angle(v1,v2))>1e-13) 119 | printf("error in vector angle test: %e %e\n", ang, ang-vec_angle(v1, v2)); 120 | } 121 | printf("test completed\n\n"); 122 | } 123 | 124 | int main(void) { 125 | test2(); 126 | test3(); 127 | test_ang(); 128 | return 0; 129 | } 130 | --------------------------------------------------------------------------------