pgLatLon
changeset 16:e319679cefbd
Added more operators for clusters (including polygons); Bugfix regarding missing entries in ecluster_ops operator class (index was not used for nearest-neighbor searches)
author | jbe |
---|---|
date | Fri Sep 09 19:22:30 2016 +0200 (2016-09-09) |
parents | 95f185a648a4 |
children | c790cf162e04 |
files | GNUmakefile README.html README.mkd latlon--0.1--0.2.sql latlon--0.2--0.3.sql latlon--0.3--0.4.sql latlon--0.3.sql latlon--0.4.sql latlon-v0003.c latlon-v0004.c latlon.control |
line diff
1.1 --- a/GNUmakefile Sat Sep 03 16:00:22 2016 +0200 1.2 +++ b/GNUmakefile Fri Sep 09 19:22:30 2016 +0200 1.3 @@ -1,6 +1,6 @@ 1.4 EXTENSION = latlon 1.5 -DATA = latlon--0.1--0.2.sql latlon--0.2--0.3.sql latlon--0.3.sql latlon--0.4.sql 1.6 -MODULES = latlon-v0003 latlon-v0004 1.7 +DATA = latlon--0.3--0.4.sql latlon--0.4.sql 1.8 +MODULES = latlon-v0004 1.9 1.10 PG_CONFIG = pg_config 1.11 PGXS := $(shell $(PG_CONFIG) --pgxs)
2.1 --- a/README.html Sat Sep 03 16:00:22 2016 +0200 2.2 +++ b/README.html Fri Sep 09 19:22:30 2016 +0200 2.3 @@ -1,5 +1,5 @@ 2.4 -<html><head><title>pgLatLon v0.3 documentation</title></head><body> 2.5 -<h1>pgLatLon v0.3 documentation</h1> 2.6 +<html><head><title>pgLatLon v0.4 documentation</title></head><body> 2.7 +<h1>pgLatLon v0.4 documentation</h1> 2.8 2.9 <p>pgLatLon is a spatial database extension for the PostgreSQL object-relational 2.10 database management system providing geographic data types and spatial indexing 2.11 @@ -59,6 +59,39 @@ 2.12 test_database=# CREATE EXTENSION latlon; 2.13 </code></pre> 2.14 2.15 +<h3>Updating</h3> 2.16 + 2.17 +<p>Before updating your database cluster to a new version of pgLatLon, you may 2.18 +want to uninstall the old by calling "<code>make uninstall</code>" in the unpacked source 2.19 +code directory of your old pgLatLon version. You may also manually delete the 2.20 +<code>latlon-v????.so</code> files from your PostgreSQL library directory and the 2.21 +<code>latlon.control</code> and <code>latlon--*.sql</code> files from your PostgreSQL extension 2.22 +directory.</p> 2.23 + 2.24 +<p>The new version can be installed as described above. For altering an existing 2.25 +database to use the installed new version (mandatory if you removed the old 2.26 +version), execute the following SQL command in the respective databases:</p> 2.27 + 2.28 +<pre><code>ALTER EXTENSION latlon UPDATE; 2.29 +</code></pre> 2.30 + 2.31 +<p>If the update contains modifications to operator classes, it may be necessary 2.32 +to drop all indices on geographic data types first (you will get an error 2.33 +message in this case). These indices can be re-created after the update.</p> 2.34 + 2.35 +<p>Note that taking several update steps at once (e.g. updating from version 0.2 2.36 +directly to version 0.4) requires the intermediate versions to be installed 2.37 +(i.e. in this example version 0.3 would need to be installed). Whenever you 2.38 +install or uninstall an intermediate or old version, make sure to afterwards 2.39 +re-install the latest pgLatLon version to ensure that the <code>latlon.control</code> file 2.40 +is available and points to the latest version.</p> 2.41 + 2.42 +<p>If the update contains modifications to the internal data representation 2.43 +format, an update path might not be available. In this case, create a dump of 2.44 +your database, delete your database, and restore it from your dump.</p> 2.45 + 2.46 +<p>Be sure to always keep backups of all your data before attempting to update.</p> 2.47 + 2.48 <h2>Reference</h2> 2.49 2.50 <h3>1. Types</h3> 2.51 @@ -245,8 +278,11 @@ 2.52 <li><code>epoint && ecircle</code></li> 2.53 <li><code>epoint && ecluster</code></li> 2.54 <li><code>ebox && ebox</code></li> 2.55 +<li><code>ebox && ecircle</code></li> 2.56 +<li><code>ebox && ecluster</code></li> 2.57 <li><code>ecircle && ecircle</code></li> 2.58 <li><code>ecircle && ecluster</code></li> 2.59 +<li><code>ecluster && ecluster</code></li> 2.60 </ul> 2.61 2.62 <p>The <code>&&</code> operator is commutative, i.e. <code>a && b</code> is the same as <code>b && a</code>. Each 2.63 @@ -266,12 +302,28 @@ 2.64 <li><code>ecluster &&+ ecluster</code></li> 2.65 </ul> 2.66 2.67 -<p>The <code>&&+</code> operator is commutative, i.e. <code>a &&+ b</code> is the same as <code>b &&+ a</code>. Each 2.68 -commutation is supported as well.</p> 2.69 +<p>The <code>&&+</code> operator is commutative, i.e. <code>a &&+ b</code> is the same as <code>b &&+ a</code>. 2.70 +Each commutation is supported as well.</p> 2.71 2.72 <p>Where two data types support both the <code>&&</code> and the <code>&&+</code> operator, the <code>&&+</code> 2.73 operator computes faster.</p> 2.74 2.75 +<h4>Contains operator <code>@></code></h4> 2.76 + 2.77 +<p>Tests if the object right of the operator is contained in the object left of 2.78 +the operator. Currently implemented for:</p> 2.79 + 2.80 +<ul> 2.81 +<li><code>ebox @> epoint</code> (alias for <code>&&</code>)</li> 2.82 +<li><code>ebox @> ecluster</code></li> 2.83 +<li><code>ecluster @> epoint</code> (alias for <code>&&</code>)</li> 2.84 +<li><code>ecluster @> ebox</code></li> 2.85 +<li><code>ecluster @> ecluster</code></li> 2.86 +</ul> 2.87 + 2.88 +<p>The commutator of <code>@></code> ("contains") is <code><@</code> ("is contained in"), i.e. <code>a @> b</code> 2.89 +is the same as <code>b <@ a</code>.</p> 2.90 + 2.91 <h4>Distance operator <code><-></code></h4> 2.92 2.93 <p>Calculates the shortest distance between two geographic objects in meters (zero 2.94 @@ -279,10 +331,15 @@ 2.95 2.96 <ul> 2.97 <li><code>epoint <-> epoint</code></li> 2.98 +<li><code>epoint <-> ebox</code></li> 2.99 <li><code>epoint <-> ecircle</code></li> 2.100 <li><code>epoint <-> ecluster</code></li> 2.101 +<li><code>ebox <-> ebox</code></li> 2.102 +<li><code>ebox <-> ecircle</code></li> 2.103 +<li><code>ebox <-> ecluster</code></li> 2.104 <li><code>ecircle <-> ecircle</code></li> 2.105 <li><code>ecircle <-> ecluster</code></li> 2.106 +<li><code>ecluster <-> ecluster</code></li> 2.107 </ul> 2.108 2.109 <p>The <code><-></code> operator is commutative, i.e. <code>a <-> b</code> is the same as <code>b <-> a</code>.
3.1 --- a/README.mkd Sat Sep 03 16:00:22 2016 +0200 3.2 +++ b/README.mkd Fri Sep 09 19:22:30 2016 +0200 3.3 @@ -1,4 +1,4 @@ 3.4 -pgLatLon v0.3 documentation 3.5 +pgLatLon v0.4 documentation 3.6 =========================== 3.7 3.8 pgLatLon is a spatial database extension for the PostgreSQL object-relational 3.9 @@ -56,6 +56,38 @@ 3.10 3.11 test_database=# CREATE EXTENSION latlon; 3.12 3.13 +### Updating 3.14 + 3.15 +Before updating your database cluster to a new version of pgLatLon, you may 3.16 +want to uninstall the old by calling "`make uninstall`" in the unpacked source 3.17 +code directory of your old pgLatLon version. You may also manually delete the 3.18 +`latlon-v????.so` files from your PostgreSQL library directory and the 3.19 +`latlon.control` and `latlon--*.sql` files from your PostgreSQL extension 3.20 +directory. 3.21 + 3.22 +The new version can be installed as described above. For altering an existing 3.23 +database to use the installed new version (mandatory if you removed the old 3.24 +version), execute the following SQL command in the respective databases: 3.25 + 3.26 + ALTER EXTENSION latlon UPDATE; 3.27 + 3.28 +If the update contains modifications to operator classes, it may be necessary 3.29 +to drop all indices on geographic data types first (you will get an error 3.30 +message in this case). These indices can be re-created after the update. 3.31 + 3.32 +Note that taking several update steps at once (e.g. updating from version 0.2 3.33 +directly to version 0.4) requires the intermediate versions to be installed 3.34 +(i.e. in this example version 0.3 would need to be installed). Whenever you 3.35 +install or uninstall an intermediate or old version, make sure to afterwards 3.36 +re-install the latest pgLatLon version to ensure that the `latlon.control` file 3.37 +is available and points to the latest version. 3.38 + 3.39 +If the update contains modifications to the internal data representation 3.40 +format, an update path might not be available. In this case, create a dump of 3.41 +your database, delete your database, and restore it from your dump. 3.42 + 3.43 +Be sure to always keep backups of all your data before attempting to update. 3.44 + 3.45 3.46 Reference 3.47 --------- 3.48 @@ -236,8 +268,11 @@ 3.49 * `epoint && ecircle` 3.50 * `epoint && ecluster` 3.51 * `ebox && ebox` 3.52 +* `ebox && ecircle` 3.53 +* `ebox && ecluster` 3.54 * `ecircle && ecircle` 3.55 * `ecircle && ecluster` 3.56 +* `ecluster && ecluster` 3.57 3.58 The `&&` operator is commutative, i.e. `a && b` is the same as `b && a`. Each 3.59 commutation is supported as well. 3.60 @@ -254,22 +289,41 @@ 3.61 * `ecircle &&+ ecluster` 3.62 * `ecluster &&+ ecluster` 3.63 3.64 -The `&&+` operator is commutative, i.e. `a &&+ b` is the same as `b &&+ a`. Each 3.65 -commutation is supported as well. 3.66 +The `&&+` operator is commutative, i.e. `a &&+ b` is the same as `b &&+ a`. 3.67 +Each commutation is supported as well. 3.68 3.69 Where two data types support both the `&&` and the `&&+` operator, the `&&+` 3.70 operator computes faster. 3.71 3.72 +#### Contains operator `@>` 3.73 + 3.74 +Tests if the object right of the operator is contained in the object left of 3.75 +the operator. Currently implemented for: 3.76 + 3.77 +* `ebox @> epoint` (alias for `&&`) 3.78 +* `ebox @> ecluster` 3.79 +* `ecluster @> epoint` (alias for `&&`) 3.80 +* `ecluster @> ebox` 3.81 +* `ecluster @> ecluster` 3.82 + 3.83 +The commutator of `@>` ("contains") is `<@` ("is contained in"), i.e. `a @> b` 3.84 +is the same as `b <@ a`. 3.85 + 3.86 #### Distance operator `<->` 3.87 3.88 Calculates the shortest distance between two geographic objects in meters (zero 3.89 if the objects are overlapping). Currently implemented for: 3.90 3.91 * `epoint <-> epoint` 3.92 +* `epoint <-> ebox` 3.93 * `epoint <-> ecircle` 3.94 * `epoint <-> ecluster` 3.95 +* `ebox <-> ebox` 3.96 +* `ebox <-> ecircle` 3.97 +* `ebox <-> ecluster` 3.98 * `ecircle <-> ecircle` 3.99 * `ecircle <-> ecluster` 3.100 +* `ecluster <-> ecluster` 3.101 3.102 The `<->` operator is commutative, i.e. `a <-> b` is the same as `b <-> a`. 3.103 Each commutation is supported as well.
4.1 --- a/latlon--0.1--0.2.sql Sat Sep 03 16:00:22 2016 +0200 4.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 4.3 @@ -1,391 +0,0 @@ 4.4 - 4.5 -CREATE OR REPLACE FUNCTION ekey_point_in_dummy(cstring) 4.6 - RETURNS ekey_point 4.7 - LANGUAGE C IMMUTABLE STRICT 4.8 - AS '$libdir/latlon-v0002', 'pgl_notimpl'; 4.9 - 4.10 -CREATE OR REPLACE FUNCTION ekey_point_out_dummy(ekey_point) 4.11 - RETURNS cstring 4.12 - LANGUAGE C IMMUTABLE STRICT 4.13 - AS '$libdir/latlon-v0002', 'pgl_notimpl'; 4.14 - 4.15 -CREATE OR REPLACE FUNCTION ekey_area_in_dummy(cstring) 4.16 - RETURNS ekey_area 4.17 - LANGUAGE C IMMUTABLE STRICT 4.18 - AS '$libdir/latlon-v0002', 'pgl_notimpl'; 4.19 - 4.20 -CREATE OR REPLACE FUNCTION ekey_area_out_dummy(ekey_area) 4.21 - RETURNS cstring 4.22 - LANGUAGE C IMMUTABLE STRICT 4.23 - AS '$libdir/latlon-v0002', 'pgl_notimpl'; 4.24 - 4.25 -CREATE OR REPLACE FUNCTION epoint_in(cstring) 4.26 - RETURNS epoint 4.27 - LANGUAGE C IMMUTABLE STRICT 4.28 - AS '$libdir/latlon-v0002', 'pgl_epoint_in'; 4.29 - 4.30 -CREATE OR REPLACE FUNCTION ebox_in(cstring) 4.31 - RETURNS ebox 4.32 - LANGUAGE C IMMUTABLE STRICT 4.33 - AS '$libdir/latlon-v0002', 'pgl_ebox_in'; 4.34 - 4.35 -CREATE OR REPLACE FUNCTION ecircle_in(cstring) 4.36 - RETURNS ecircle 4.37 - LANGUAGE C IMMUTABLE STRICT 4.38 - AS '$libdir/latlon-v0002', 'pgl_ecircle_in'; 4.39 - 4.40 -CREATE OR REPLACE FUNCTION ecluster_in(cstring) 4.41 - RETURNS ecluster 4.42 - LANGUAGE C IMMUTABLE STRICT 4.43 - AS '$libdir/latlon-v0002', 'pgl_ecluster_in'; 4.44 - 4.45 -CREATE OR REPLACE FUNCTION epoint_out(epoint) 4.46 - RETURNS cstring 4.47 - LANGUAGE C IMMUTABLE STRICT 4.48 - AS '$libdir/latlon-v0002', 'pgl_epoint_out'; 4.49 - 4.50 -CREATE OR REPLACE FUNCTION ebox_out(ebox) 4.51 - RETURNS cstring 4.52 - LANGUAGE C IMMUTABLE STRICT 4.53 - AS '$libdir/latlon-v0002', 'pgl_ebox_out'; 4.54 - 4.55 -CREATE OR REPLACE FUNCTION ecircle_out(ecircle) 4.56 - RETURNS cstring 4.57 - LANGUAGE C IMMUTABLE STRICT 4.58 - AS '$libdir/latlon-v0002', 'pgl_ecircle_out'; 4.59 - 4.60 -CREATE OR REPLACE FUNCTION ecluster_out(ecluster) 4.61 - RETURNS cstring 4.62 - LANGUAGE C IMMUTABLE STRICT 4.63 - AS '$libdir/latlon-v0002', 'pgl_ecluster_out'; 4.64 - 4.65 -CREATE OR REPLACE FUNCTION epoint_recv(internal) 4.66 - RETURNS epoint 4.67 - LANGUAGE C IMMUTABLE STRICT 4.68 - AS '$libdir/latlon-v0002', 'pgl_epoint_recv'; 4.69 - 4.70 -CREATE OR REPLACE FUNCTION ebox_recv(internal) 4.71 - RETURNS ebox 4.72 - LANGUAGE C IMMUTABLE STRICT 4.73 - AS '$libdir/latlon-v0002', 'pgl_ebox_recv'; 4.74 - 4.75 -CREATE OR REPLACE FUNCTION ecircle_recv(internal) 4.76 - RETURNS ecircle 4.77 - LANGUAGE C IMMUTABLE STRICT 4.78 - AS '$libdir/latlon-v0002', 'pgl_ecircle_recv'; 4.79 - 4.80 -CREATE OR REPLACE FUNCTION epoint_send(epoint) 4.81 - RETURNS bytea 4.82 - LANGUAGE C IMMUTABLE STRICT 4.83 - AS '$libdir/latlon-v0002', 'pgl_epoint_send'; 4.84 - 4.85 -CREATE OR REPLACE FUNCTION ebox_send(ebox) 4.86 - RETURNS bytea 4.87 - LANGUAGE C IMMUTABLE STRICT 4.88 - AS '$libdir/latlon-v0002', 'pgl_ebox_send'; 4.89 - 4.90 -CREATE OR REPLACE FUNCTION ecircle_send(ecircle) 4.91 - RETURNS bytea 4.92 - LANGUAGE C IMMUTABLE STRICT 4.93 - AS '$libdir/latlon-v0002', 'pgl_ecircle_send'; 4.94 - 4.95 -CREATE OR REPLACE FUNCTION epoint_btree_lt(epoint, epoint) 4.96 - RETURNS boolean 4.97 - LANGUAGE C IMMUTABLE STRICT 4.98 - AS '$libdir/latlon-v0002', 'pgl_btree_epoint_lt'; 4.99 - 4.100 -CREATE OR REPLACE FUNCTION epoint_btree_le(epoint, epoint) 4.101 - RETURNS boolean 4.102 - LANGUAGE C IMMUTABLE STRICT 4.103 - AS '$libdir/latlon-v0002', 'pgl_btree_epoint_le'; 4.104 - 4.105 -CREATE OR REPLACE FUNCTION epoint_btree_eq(epoint, epoint) 4.106 - RETURNS boolean 4.107 - LANGUAGE C IMMUTABLE STRICT 4.108 - AS '$libdir/latlon-v0002', 'pgl_btree_epoint_eq'; 4.109 - 4.110 -CREATE OR REPLACE FUNCTION epoint_btree_ne(epoint, epoint) 4.111 - RETURNS boolean 4.112 - LANGUAGE C IMMUTABLE STRICT 4.113 - AS '$libdir/latlon-v0002', 'pgl_btree_epoint_ne'; 4.114 - 4.115 -CREATE OR REPLACE FUNCTION epoint_btree_ge(epoint, epoint) 4.116 - RETURNS boolean 4.117 - LANGUAGE C IMMUTABLE STRICT 4.118 - AS '$libdir/latlon-v0002', 'pgl_btree_epoint_ge'; 4.119 - 4.120 -CREATE OR REPLACE FUNCTION epoint_btree_gt(epoint, epoint) 4.121 - RETURNS boolean 4.122 - LANGUAGE C IMMUTABLE STRICT 4.123 - AS '$libdir/latlon-v0002', 'pgl_btree_epoint_gt'; 4.124 - 4.125 -CREATE OR REPLACE FUNCTION epoint_btree_cmp(epoint, epoint) 4.126 - RETURNS int4 4.127 - LANGUAGE C IMMUTABLE STRICT 4.128 - AS '$libdir/latlon-v0002', 'pgl_btree_epoint_cmp'; 4.129 - 4.130 -CREATE OR REPLACE FUNCTION ebox_btree_lt(ebox, ebox) 4.131 - RETURNS boolean 4.132 - LANGUAGE C IMMUTABLE STRICT 4.133 - AS '$libdir/latlon-v0002', 'pgl_btree_ebox_lt'; 4.134 - 4.135 -CREATE OR REPLACE FUNCTION ebox_btree_le(ebox, ebox) 4.136 - RETURNS boolean 4.137 - LANGUAGE C IMMUTABLE STRICT 4.138 - AS '$libdir/latlon-v0002', 'pgl_btree_ebox_le'; 4.139 - 4.140 -CREATE OR REPLACE FUNCTION ebox_btree_eq(ebox, ebox) 4.141 - RETURNS boolean 4.142 - LANGUAGE C IMMUTABLE STRICT 4.143 - AS '$libdir/latlon-v0002', 'pgl_btree_ebox_eq'; 4.144 - 4.145 -CREATE OR REPLACE FUNCTION ebox_btree_ne(ebox, ebox) 4.146 - RETURNS boolean 4.147 - LANGUAGE C IMMUTABLE STRICT 4.148 - AS '$libdir/latlon-v0002', 'pgl_btree_ebox_ne'; 4.149 - 4.150 -CREATE OR REPLACE FUNCTION ebox_btree_ge(ebox, ebox) 4.151 - RETURNS boolean 4.152 - LANGUAGE C IMMUTABLE STRICT 4.153 - AS '$libdir/latlon-v0002', 'pgl_btree_ebox_ge'; 4.154 - 4.155 -CREATE OR REPLACE FUNCTION ebox_btree_gt(ebox, ebox) 4.156 - RETURNS boolean 4.157 - LANGUAGE C IMMUTABLE STRICT 4.158 - AS '$libdir/latlon-v0002', 'pgl_btree_ebox_gt'; 4.159 - 4.160 -CREATE OR REPLACE FUNCTION ebox_btree_cmp(ebox, ebox) 4.161 - RETURNS int4 4.162 - LANGUAGE C IMMUTABLE STRICT 4.163 - AS '$libdir/latlon-v0002', 'pgl_btree_ebox_cmp'; 4.164 - 4.165 -CREATE OR REPLACE FUNCTION ecircle_btree_lt(ecircle, ecircle) 4.166 - RETURNS boolean 4.167 - LANGUAGE C IMMUTABLE STRICT 4.168 - AS '$libdir/latlon-v0002', 'pgl_btree_ecircle_lt'; 4.169 - 4.170 -CREATE OR REPLACE FUNCTION ecircle_btree_le(ecircle, ecircle) 4.171 - RETURNS boolean 4.172 - LANGUAGE C IMMUTABLE STRICT 4.173 - AS '$libdir/latlon-v0002', 'pgl_btree_ecircle_le'; 4.174 - 4.175 -CREATE OR REPLACE FUNCTION ecircle_btree_eq(ecircle, ecircle) 4.176 - RETURNS boolean 4.177 - LANGUAGE C IMMUTABLE STRICT 4.178 - AS '$libdir/latlon-v0002', 'pgl_btree_ecircle_eq'; 4.179 - 4.180 -CREATE OR REPLACE FUNCTION ecircle_btree_ne(ecircle, ecircle) 4.181 - RETURNS boolean 4.182 - LANGUAGE C IMMUTABLE STRICT 4.183 - AS '$libdir/latlon-v0002', 'pgl_btree_ecircle_ne'; 4.184 - 4.185 -CREATE OR REPLACE FUNCTION ecircle_btree_ge(ecircle, ecircle) 4.186 - RETURNS boolean 4.187 - LANGUAGE C IMMUTABLE STRICT 4.188 - AS '$libdir/latlon-v0002', 'pgl_btree_ecircle_ge'; 4.189 - 4.190 -CREATE OR REPLACE FUNCTION ecircle_btree_gt(ecircle, ecircle) 4.191 - RETURNS boolean 4.192 - LANGUAGE C IMMUTABLE STRICT 4.193 - AS '$libdir/latlon-v0002', 'pgl_btree_ecircle_gt'; 4.194 - 4.195 -CREATE OR REPLACE FUNCTION ecircle_btree_cmp(ecircle, ecircle) 4.196 - RETURNS int4 4.197 - LANGUAGE C IMMUTABLE STRICT 4.198 - AS '$libdir/latlon-v0002', 'pgl_btree_ecircle_cmp'; 4.199 - 4.200 -CREATE OR REPLACE FUNCTION cast_epoint_to_ebox(epoint) 4.201 - RETURNS ebox 4.202 - LANGUAGE C IMMUTABLE STRICT 4.203 - AS '$libdir/latlon-v0002', 'pgl_epoint_to_ebox'; 4.204 - 4.205 -CREATE OR REPLACE FUNCTION cast_epoint_to_ecircle(epoint) 4.206 - RETURNS ecircle 4.207 - LANGUAGE C IMMUTABLE STRICT 4.208 - AS '$libdir/latlon-v0002', 'pgl_epoint_to_ecircle'; 4.209 - 4.210 -CREATE OR REPLACE FUNCTION cast_epoint_to_ecluster(epoint) 4.211 - RETURNS ecluster 4.212 - LANGUAGE C IMMUTABLE STRICT 4.213 - AS '$libdir/latlon-v0002', 'pgl_epoint_to_ecluster'; 4.214 - 4.215 -CREATE OR REPLACE FUNCTION cast_ebox_to_ecluster(ebox) 4.216 - RETURNS ecluster 4.217 - LANGUAGE C IMMUTABLE STRICT 4.218 - AS '$libdir/latlon-v0002', 'pgl_ebox_to_ecluster'; 4.219 - 4.220 -CREATE OR REPLACE FUNCTION epoint(float8, float8) 4.221 - RETURNS epoint 4.222 - LANGUAGE C IMMUTABLE STRICT 4.223 - AS '$libdir/latlon-v0002', 'pgl_create_epoint'; 4.224 - 4.225 -CREATE OR REPLACE FUNCTION empty_ebox() 4.226 - RETURNS ebox 4.227 - LANGUAGE C IMMUTABLE STRICT 4.228 - AS '$libdir/latlon-v0002', 'pgl_create_empty_ebox'; 4.229 - 4.230 -CREATE OR REPLACE FUNCTION ebox(float8, float8, float8, float8) 4.231 - RETURNS ebox 4.232 - LANGUAGE C IMMUTABLE STRICT 4.233 - AS '$libdir/latlon-v0002', 'pgl_create_ebox'; 4.234 - 4.235 -CREATE OR REPLACE FUNCTION ebox(epoint, epoint) 4.236 - RETURNS ebox 4.237 - LANGUAGE C IMMUTABLE STRICT 4.238 - AS '$libdir/latlon-v0002', 'pgl_create_ebox_from_epoints'; 4.239 - 4.240 -CREATE OR REPLACE FUNCTION ecircle(float8, float8, float8) 4.241 - RETURNS ecircle 4.242 - LANGUAGE C IMMUTABLE STRICT 4.243 - AS '$libdir/latlon-v0002', 'pgl_create_ecircle'; 4.244 - 4.245 -CREATE OR REPLACE FUNCTION ecircle(epoint, float8) 4.246 - RETURNS ecircle 4.247 - LANGUAGE C IMMUTABLE STRICT 4.248 - AS '$libdir/latlon-v0002', 'pgl_create_ecircle_from_epoint'; 4.249 - 4.250 -CREATE OR REPLACE FUNCTION latitude(epoint) 4.251 - RETURNS float8 4.252 - LANGUAGE C IMMUTABLE STRICT 4.253 - AS '$libdir/latlon-v0002', 'pgl_epoint_lat'; 4.254 - 4.255 -CREATE OR REPLACE FUNCTION longitude(epoint) 4.256 - RETURNS float8 4.257 - LANGUAGE C IMMUTABLE STRICT 4.258 - AS '$libdir/latlon-v0002', 'pgl_epoint_lon'; 4.259 - 4.260 -CREATE OR REPLACE FUNCTION min_latitude(ebox) 4.261 - RETURNS float8 4.262 - LANGUAGE C IMMUTABLE STRICT 4.263 - AS '$libdir/latlon-v0002', 'pgl_ebox_lat_min'; 4.264 - 4.265 -CREATE OR REPLACE FUNCTION max_latitude(ebox) 4.266 - RETURNS float8 4.267 - LANGUAGE C IMMUTABLE STRICT 4.268 - AS '$libdir/latlon-v0002', 'pgl_ebox_lat_max'; 4.269 - 4.270 -CREATE OR REPLACE FUNCTION min_longitude(ebox) 4.271 - RETURNS float8 4.272 - LANGUAGE C IMMUTABLE STRICT 4.273 - AS '$libdir/latlon-v0002', 'pgl_ebox_lon_min'; 4.274 - 4.275 -CREATE OR REPLACE FUNCTION max_longitude(ebox) 4.276 - RETURNS float8 4.277 - LANGUAGE C IMMUTABLE STRICT 4.278 - AS '$libdir/latlon-v0002', 'pgl_ebox_lon_max'; 4.279 - 4.280 -CREATE OR REPLACE FUNCTION center(ecircle) 4.281 - RETURNS epoint 4.282 - LANGUAGE C IMMUTABLE STRICT 4.283 - AS '$libdir/latlon-v0002', 'pgl_ecircle_center'; 4.284 - 4.285 -CREATE OR REPLACE FUNCTION radius(ecircle) 4.286 - RETURNS float8 4.287 - LANGUAGE C IMMUTABLE STRICT 4.288 - AS '$libdir/latlon-v0002', 'pgl_ecircle_radius'; 4.289 - 4.290 -CREATE OR REPLACE FUNCTION epoint_ebox_overlap_proc(epoint, ebox) 4.291 - RETURNS boolean 4.292 - LANGUAGE C IMMUTABLE STRICT 4.293 - AS '$libdir/latlon-v0002', 'pgl_epoint_ebox_overlap'; 4.294 - 4.295 -CREATE OR REPLACE FUNCTION epoint_ecircle_overlap_proc(epoint, ecircle) 4.296 - RETURNS boolean 4.297 - LANGUAGE C IMMUTABLE STRICT 4.298 - AS '$libdir/latlon-v0002', 'pgl_epoint_ecircle_overlap'; 4.299 - 4.300 -CREATE OR REPLACE FUNCTION epoint_ecluster_overlap_proc(epoint, ecluster) 4.301 - RETURNS boolean 4.302 - LANGUAGE C IMMUTABLE STRICT 4.303 - AS '$libdir/latlon-v0002', 'pgl_epoint_ecluster_overlap'; 4.304 - 4.305 -CREATE OR REPLACE FUNCTION ebox_overlap_proc(ebox, ebox) 4.306 - RETURNS boolean 4.307 - LANGUAGE C IMMUTABLE STRICT 4.308 - AS '$libdir/latlon-v0002', 'pgl_ebox_overlap'; 4.309 - 4.310 -CREATE OR REPLACE FUNCTION ecircle_overlap_proc(ecircle, ecircle) 4.311 - RETURNS boolean 4.312 - LANGUAGE C IMMUTABLE STRICT 4.313 - AS '$libdir/latlon-v0002', 'pgl_ecircle_overlap'; 4.314 - 4.315 -CREATE OR REPLACE FUNCTION ecircle_ecluster_overlap_proc(ecircle, ecluster) 4.316 - RETURNS boolean 4.317 - LANGUAGE C IMMUTABLE STRICT 4.318 - AS '$libdir/latlon-v0002', 'pgl_ecircle_ecluster_overlap'; 4.319 - 4.320 -CREATE OR REPLACE FUNCTION epoint_distance_proc(epoint, epoint) 4.321 - RETURNS float8 4.322 - LANGUAGE C IMMUTABLE STRICT 4.323 - AS '$libdir/latlon-v0002', 'pgl_epoint_distance'; 4.324 - 4.325 -CREATE OR REPLACE FUNCTION epoint_ecircle_distance_proc(epoint, ecircle) 4.326 - RETURNS float8 4.327 - LANGUAGE C IMMUTABLE STRICT 4.328 - AS '$libdir/latlon-v0002', 'pgl_epoint_ecircle_distance'; 4.329 - 4.330 -CREATE OR REPLACE FUNCTION epoint_ecluster_distance_proc(epoint, ecluster) 4.331 - RETURNS float8 4.332 - LANGUAGE C IMMUTABLE STRICT 4.333 - AS '$libdir/latlon-v0002', 'pgl_epoint_ecluster_distance'; 4.334 - 4.335 -CREATE OR REPLACE FUNCTION ecircle_distance_proc(ecircle, ecircle) 4.336 - RETURNS float8 4.337 - LANGUAGE C IMMUTABLE STRICT 4.338 - AS '$libdir/latlon-v0002', 'pgl_ecircle_distance'; 4.339 - 4.340 -CREATE OR REPLACE FUNCTION ecircle_ecluster_distance_proc(ecircle, ecluster) 4.341 - RETURNS float8 4.342 - LANGUAGE C IMMUTABLE STRICT 4.343 - AS '$libdir/latlon-v0002', 'pgl_ecircle_ecluster_distance'; 4.344 - 4.345 -CREATE OR REPLACE FUNCTION pgl_gist_consistent(internal, internal, smallint, oid, internal) 4.346 - RETURNS boolean 4.347 - LANGUAGE C STRICT 4.348 - AS '$libdir/latlon-v0002', 'pgl_gist_consistent'; 4.349 - 4.350 -CREATE OR REPLACE FUNCTION pgl_gist_union(internal, internal) 4.351 - RETURNS internal 4.352 - LANGUAGE C STRICT 4.353 - AS '$libdir/latlon-v0002', 'pgl_gist_union'; 4.354 - 4.355 -CREATE OR REPLACE FUNCTION pgl_gist_compress_epoint(internal) 4.356 - RETURNS internal 4.357 - LANGUAGE C STRICT 4.358 - AS '$libdir/latlon-v0002', 'pgl_gist_compress_epoint'; 4.359 - 4.360 -CREATE OR REPLACE FUNCTION pgl_gist_compress_ecircle(internal) 4.361 - RETURNS internal 4.362 - LANGUAGE C STRICT 4.363 - AS '$libdir/latlon-v0002', 'pgl_gist_compress_ecircle'; 4.364 - 4.365 -CREATE OR REPLACE FUNCTION pgl_gist_compress_ecluster(internal) 4.366 - RETURNS internal 4.367 - LANGUAGE C STRICT 4.368 - AS '$libdir/latlon-v0002', 'pgl_gist_compress_ecluster'; 4.369 - 4.370 -CREATE OR REPLACE FUNCTION pgl_gist_decompress(internal) 4.371 - RETURNS internal 4.372 - LANGUAGE C STRICT 4.373 - AS '$libdir/latlon-v0002', 'pgl_gist_decompress'; 4.374 - 4.375 -CREATE OR REPLACE FUNCTION pgl_gist_penalty(internal, internal, internal) 4.376 - RETURNS internal 4.377 - LANGUAGE C STRICT 4.378 - AS '$libdir/latlon-v0002', 'pgl_gist_penalty'; 4.379 - 4.380 -CREATE OR REPLACE FUNCTION pgl_gist_picksplit(internal, internal) 4.381 - RETURNS internal 4.382 - LANGUAGE C STRICT 4.383 - AS '$libdir/latlon-v0002', 'pgl_gist_picksplit'; 4.384 - 4.385 -CREATE OR REPLACE FUNCTION pgl_gist_same(internal, internal, internal) 4.386 - RETURNS internal 4.387 - LANGUAGE C STRICT 4.388 - AS '$libdir/latlon-v0002', 'pgl_gist_same'; 4.389 - 4.390 -CREATE OR REPLACE FUNCTION pgl_gist_distance(internal, internal, smallint, oid) 4.391 - RETURNS internal 4.392 - LANGUAGE C STRICT 4.393 - AS '$libdir/latlon-v0002', 'pgl_gist_distance'; 4.394 -
5.1 --- a/latlon--0.2--0.3.sql Sat Sep 03 16:00:22 2016 +0200 5.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 5.3 @@ -1,575 +0,0 @@ 5.4 - 5.5 -CREATE OR REPLACE FUNCTION ekey_point_in_dummy(cstring) 5.6 - RETURNS ekey_point 5.7 - LANGUAGE C IMMUTABLE STRICT 5.8 - AS '$libdir/latlon-v0003', 'pgl_notimpl'; 5.9 - 5.10 -CREATE OR REPLACE FUNCTION ekey_point_out_dummy(ekey_point) 5.11 - RETURNS cstring 5.12 - LANGUAGE C IMMUTABLE STRICT 5.13 - AS '$libdir/latlon-v0003', 'pgl_notimpl'; 5.14 - 5.15 -CREATE OR REPLACE FUNCTION ekey_area_in_dummy(cstring) 5.16 - RETURNS ekey_area 5.17 - LANGUAGE C IMMUTABLE STRICT 5.18 - AS '$libdir/latlon-v0003', 'pgl_notimpl'; 5.19 - 5.20 -CREATE OR REPLACE FUNCTION ekey_area_out_dummy(ekey_area) 5.21 - RETURNS cstring 5.22 - LANGUAGE C IMMUTABLE STRICT 5.23 - AS '$libdir/latlon-v0003', 'pgl_notimpl'; 5.24 - 5.25 -CREATE OR REPLACE FUNCTION epoint_in(cstring) 5.26 - RETURNS epoint 5.27 - LANGUAGE C IMMUTABLE STRICT 5.28 - AS '$libdir/latlon-v0003', 'pgl_epoint_in'; 5.29 - 5.30 -CREATE OR REPLACE FUNCTION ebox_in(cstring) 5.31 - RETURNS ebox 5.32 - LANGUAGE C IMMUTABLE STRICT 5.33 - AS '$libdir/latlon-v0003', 'pgl_ebox_in'; 5.34 - 5.35 -CREATE OR REPLACE FUNCTION ecircle_in(cstring) 5.36 - RETURNS ecircle 5.37 - LANGUAGE C IMMUTABLE STRICT 5.38 - AS '$libdir/latlon-v0003', 'pgl_ecircle_in'; 5.39 - 5.40 -CREATE OR REPLACE FUNCTION ecluster_in(cstring) 5.41 - RETURNS ecluster 5.42 - LANGUAGE C IMMUTABLE STRICT 5.43 - AS '$libdir/latlon-v0003', 'pgl_ecluster_in'; 5.44 - 5.45 -CREATE OR REPLACE FUNCTION epoint_out(epoint) 5.46 - RETURNS cstring 5.47 - LANGUAGE C IMMUTABLE STRICT 5.48 - AS '$libdir/latlon-v0003', 'pgl_epoint_out'; 5.49 - 5.50 -CREATE OR REPLACE FUNCTION ebox_out(ebox) 5.51 - RETURNS cstring 5.52 - LANGUAGE C IMMUTABLE STRICT 5.53 - AS '$libdir/latlon-v0003', 'pgl_ebox_out'; 5.54 - 5.55 -CREATE OR REPLACE FUNCTION ecircle_out(ecircle) 5.56 - RETURNS cstring 5.57 - LANGUAGE C IMMUTABLE STRICT 5.58 - AS '$libdir/latlon-v0003', 'pgl_ecircle_out'; 5.59 - 5.60 -CREATE OR REPLACE FUNCTION ecluster_out(ecluster) 5.61 - RETURNS cstring 5.62 - LANGUAGE C IMMUTABLE STRICT 5.63 - AS '$libdir/latlon-v0003', 'pgl_ecluster_out'; 5.64 - 5.65 -CREATE OR REPLACE FUNCTION epoint_recv(internal) 5.66 - RETURNS epoint 5.67 - LANGUAGE C IMMUTABLE STRICT 5.68 - AS '$libdir/latlon-v0003', 'pgl_epoint_recv'; 5.69 - 5.70 -CREATE OR REPLACE FUNCTION ebox_recv(internal) 5.71 - RETURNS ebox 5.72 - LANGUAGE C IMMUTABLE STRICT 5.73 - AS '$libdir/latlon-v0003', 'pgl_ebox_recv'; 5.74 - 5.75 -CREATE OR REPLACE FUNCTION ecircle_recv(internal) 5.76 - RETURNS ecircle 5.77 - LANGUAGE C IMMUTABLE STRICT 5.78 - AS '$libdir/latlon-v0003', 'pgl_ecircle_recv'; 5.79 - 5.80 -CREATE OR REPLACE FUNCTION epoint_send(epoint) 5.81 - RETURNS bytea 5.82 - LANGUAGE C IMMUTABLE STRICT 5.83 - AS '$libdir/latlon-v0003', 'pgl_epoint_send'; 5.84 - 5.85 -CREATE OR REPLACE FUNCTION ebox_send(ebox) 5.86 - RETURNS bytea 5.87 - LANGUAGE C IMMUTABLE STRICT 5.88 - AS '$libdir/latlon-v0003', 'pgl_ebox_send'; 5.89 - 5.90 -CREATE OR REPLACE FUNCTION ecircle_send(ecircle) 5.91 - RETURNS bytea 5.92 - LANGUAGE C IMMUTABLE STRICT 5.93 - AS '$libdir/latlon-v0003', 'pgl_ecircle_send'; 5.94 - 5.95 -CREATE OR REPLACE FUNCTION epoint_btree_lt(epoint, epoint) 5.96 - RETURNS boolean 5.97 - LANGUAGE C IMMUTABLE STRICT 5.98 - AS '$libdir/latlon-v0003', 'pgl_btree_epoint_lt'; 5.99 - 5.100 -CREATE OR REPLACE FUNCTION epoint_btree_le(epoint, epoint) 5.101 - RETURNS boolean 5.102 - LANGUAGE C IMMUTABLE STRICT 5.103 - AS '$libdir/latlon-v0003', 'pgl_btree_epoint_le'; 5.104 - 5.105 -CREATE OR REPLACE FUNCTION epoint_btree_eq(epoint, epoint) 5.106 - RETURNS boolean 5.107 - LANGUAGE C IMMUTABLE STRICT 5.108 - AS '$libdir/latlon-v0003', 'pgl_btree_epoint_eq'; 5.109 - 5.110 -CREATE OR REPLACE FUNCTION epoint_btree_ne(epoint, epoint) 5.111 - RETURNS boolean 5.112 - LANGUAGE C IMMUTABLE STRICT 5.113 - AS '$libdir/latlon-v0003', 'pgl_btree_epoint_ne'; 5.114 - 5.115 -CREATE OR REPLACE FUNCTION epoint_btree_ge(epoint, epoint) 5.116 - RETURNS boolean 5.117 - LANGUAGE C IMMUTABLE STRICT 5.118 - AS '$libdir/latlon-v0003', 'pgl_btree_epoint_ge'; 5.119 - 5.120 -CREATE OR REPLACE FUNCTION epoint_btree_gt(epoint, epoint) 5.121 - RETURNS boolean 5.122 - LANGUAGE C IMMUTABLE STRICT 5.123 - AS '$libdir/latlon-v0003', 'pgl_btree_epoint_gt'; 5.124 - 5.125 -CREATE OR REPLACE FUNCTION epoint_btree_cmp(epoint, epoint) 5.126 - RETURNS int4 5.127 - LANGUAGE C IMMUTABLE STRICT 5.128 - AS '$libdir/latlon-v0003', 'pgl_btree_epoint_cmp'; 5.129 - 5.130 -CREATE OR REPLACE FUNCTION ebox_btree_lt(ebox, ebox) 5.131 - RETURNS boolean 5.132 - LANGUAGE C IMMUTABLE STRICT 5.133 - AS '$libdir/latlon-v0003', 'pgl_btree_ebox_lt'; 5.134 - 5.135 -CREATE OR REPLACE FUNCTION ebox_btree_le(ebox, ebox) 5.136 - RETURNS boolean 5.137 - LANGUAGE C IMMUTABLE STRICT 5.138 - AS '$libdir/latlon-v0003', 'pgl_btree_ebox_le'; 5.139 - 5.140 -CREATE OR REPLACE FUNCTION ebox_btree_eq(ebox, ebox) 5.141 - RETURNS boolean 5.142 - LANGUAGE C IMMUTABLE STRICT 5.143 - AS '$libdir/latlon-v0003', 'pgl_btree_ebox_eq'; 5.144 - 5.145 -CREATE OR REPLACE FUNCTION ebox_btree_ne(ebox, ebox) 5.146 - RETURNS boolean 5.147 - LANGUAGE C IMMUTABLE STRICT 5.148 - AS '$libdir/latlon-v0003', 'pgl_btree_ebox_ne'; 5.149 - 5.150 -CREATE OR REPLACE FUNCTION ebox_btree_ge(ebox, ebox) 5.151 - RETURNS boolean 5.152 - LANGUAGE C IMMUTABLE STRICT 5.153 - AS '$libdir/latlon-v0003', 'pgl_btree_ebox_ge'; 5.154 - 5.155 -CREATE OR REPLACE FUNCTION ebox_btree_gt(ebox, ebox) 5.156 - RETURNS boolean 5.157 - LANGUAGE C IMMUTABLE STRICT 5.158 - AS '$libdir/latlon-v0003', 'pgl_btree_ebox_gt'; 5.159 - 5.160 -CREATE OR REPLACE FUNCTION ebox_btree_cmp(ebox, ebox) 5.161 - RETURNS int4 5.162 - LANGUAGE C IMMUTABLE STRICT 5.163 - AS '$libdir/latlon-v0003', 'pgl_btree_ebox_cmp'; 5.164 - 5.165 -CREATE OR REPLACE FUNCTION ecircle_btree_lt(ecircle, ecircle) 5.166 - RETURNS boolean 5.167 - LANGUAGE C IMMUTABLE STRICT 5.168 - AS '$libdir/latlon-v0003', 'pgl_btree_ecircle_lt'; 5.169 - 5.170 -CREATE OR REPLACE FUNCTION ecircle_btree_le(ecircle, ecircle) 5.171 - RETURNS boolean 5.172 - LANGUAGE C IMMUTABLE STRICT 5.173 - AS '$libdir/latlon-v0003', 'pgl_btree_ecircle_le'; 5.174 - 5.175 -CREATE OR REPLACE FUNCTION ecircle_btree_eq(ecircle, ecircle) 5.176 - RETURNS boolean 5.177 - LANGUAGE C IMMUTABLE STRICT 5.178 - AS '$libdir/latlon-v0003', 'pgl_btree_ecircle_eq'; 5.179 - 5.180 -CREATE OR REPLACE FUNCTION ecircle_btree_ne(ecircle, ecircle) 5.181 - RETURNS boolean 5.182 - LANGUAGE C IMMUTABLE STRICT 5.183 - AS '$libdir/latlon-v0003', 'pgl_btree_ecircle_ne'; 5.184 - 5.185 -CREATE OR REPLACE FUNCTION ecircle_btree_ge(ecircle, ecircle) 5.186 - RETURNS boolean 5.187 - LANGUAGE C IMMUTABLE STRICT 5.188 - AS '$libdir/latlon-v0003', 'pgl_btree_ecircle_ge'; 5.189 - 5.190 -CREATE OR REPLACE FUNCTION ecircle_btree_gt(ecircle, ecircle) 5.191 - RETURNS boolean 5.192 - LANGUAGE C IMMUTABLE STRICT 5.193 - AS '$libdir/latlon-v0003', 'pgl_btree_ecircle_gt'; 5.194 - 5.195 -CREATE OR REPLACE FUNCTION ecircle_btree_cmp(ecircle, ecircle) 5.196 - RETURNS int4 5.197 - LANGUAGE C IMMUTABLE STRICT 5.198 - AS '$libdir/latlon-v0003', 'pgl_btree_ecircle_cmp'; 5.199 - 5.200 -CREATE OR REPLACE FUNCTION cast_epoint_to_ebox(epoint) 5.201 - RETURNS ebox 5.202 - LANGUAGE C IMMUTABLE STRICT 5.203 - AS '$libdir/latlon-v0003', 'pgl_epoint_to_ebox'; 5.204 - 5.205 -CREATE OR REPLACE FUNCTION cast_epoint_to_ecircle(epoint) 5.206 - RETURNS ecircle 5.207 - LANGUAGE C IMMUTABLE STRICT 5.208 - AS '$libdir/latlon-v0003', 'pgl_epoint_to_ecircle'; 5.209 - 5.210 -CREATE OR REPLACE FUNCTION cast_epoint_to_ecluster(epoint) 5.211 - RETURNS ecluster 5.212 - LANGUAGE C IMMUTABLE STRICT 5.213 - AS '$libdir/latlon-v0003', 'pgl_epoint_to_ecluster'; 5.214 - 5.215 -CREATE OR REPLACE FUNCTION cast_ebox_to_ecluster(ebox) 5.216 - RETURNS ecluster 5.217 - LANGUAGE C IMMUTABLE STRICT 5.218 - AS '$libdir/latlon-v0003', 'pgl_ebox_to_ecluster'; 5.219 - 5.220 -CREATE OR REPLACE FUNCTION epoint(float8, float8) 5.221 - RETURNS epoint 5.222 - LANGUAGE C IMMUTABLE STRICT 5.223 - AS '$libdir/latlon-v0003', 'pgl_create_epoint'; 5.224 - 5.225 -CREATE OR REPLACE FUNCTION empty_ebox() 5.226 - RETURNS ebox 5.227 - LANGUAGE C IMMUTABLE STRICT 5.228 - AS '$libdir/latlon-v0003', 'pgl_create_empty_ebox'; 5.229 - 5.230 -CREATE OR REPLACE FUNCTION ebox(float8, float8, float8, float8) 5.231 - RETURNS ebox 5.232 - LANGUAGE C IMMUTABLE STRICT 5.233 - AS '$libdir/latlon-v0003', 'pgl_create_ebox'; 5.234 - 5.235 -CREATE OR REPLACE FUNCTION ebox(epoint, epoint) 5.236 - RETURNS ebox 5.237 - LANGUAGE C IMMUTABLE STRICT 5.238 - AS '$libdir/latlon-v0003', 'pgl_create_ebox_from_epoints'; 5.239 - 5.240 -CREATE OR REPLACE FUNCTION ecircle(float8, float8, float8) 5.241 - RETURNS ecircle 5.242 - LANGUAGE C IMMUTABLE STRICT 5.243 - AS '$libdir/latlon-v0003', 'pgl_create_ecircle'; 5.244 - 5.245 -CREATE OR REPLACE FUNCTION ecircle(epoint, float8) 5.246 - RETURNS ecircle 5.247 - LANGUAGE C IMMUTABLE STRICT 5.248 - AS '$libdir/latlon-v0003', 'pgl_create_ecircle_from_epoint'; 5.249 - 5.250 -CREATE OR REPLACE FUNCTION latitude(epoint) 5.251 - RETURNS float8 5.252 - LANGUAGE C IMMUTABLE STRICT 5.253 - AS '$libdir/latlon-v0003', 'pgl_epoint_lat'; 5.254 - 5.255 -CREATE OR REPLACE FUNCTION longitude(epoint) 5.256 - RETURNS float8 5.257 - LANGUAGE C IMMUTABLE STRICT 5.258 - AS '$libdir/latlon-v0003', 'pgl_epoint_lon'; 5.259 - 5.260 -CREATE OR REPLACE FUNCTION min_latitude(ebox) 5.261 - RETURNS float8 5.262 - LANGUAGE C IMMUTABLE STRICT 5.263 - AS '$libdir/latlon-v0003', 'pgl_ebox_lat_min'; 5.264 - 5.265 -CREATE OR REPLACE FUNCTION max_latitude(ebox) 5.266 - RETURNS float8 5.267 - LANGUAGE C IMMUTABLE STRICT 5.268 - AS '$libdir/latlon-v0003', 'pgl_ebox_lat_max'; 5.269 - 5.270 -CREATE OR REPLACE FUNCTION min_longitude(ebox) 5.271 - RETURNS float8 5.272 - LANGUAGE C IMMUTABLE STRICT 5.273 - AS '$libdir/latlon-v0003', 'pgl_ebox_lon_min'; 5.274 - 5.275 -CREATE OR REPLACE FUNCTION max_longitude(ebox) 5.276 - RETURNS float8 5.277 - LANGUAGE C IMMUTABLE STRICT 5.278 - AS '$libdir/latlon-v0003', 'pgl_ebox_lon_max'; 5.279 - 5.280 -CREATE OR REPLACE FUNCTION center(ecircle) 5.281 - RETURNS epoint 5.282 - LANGUAGE C IMMUTABLE STRICT 5.283 - AS '$libdir/latlon-v0003', 'pgl_ecircle_center'; 5.284 - 5.285 -CREATE OR REPLACE FUNCTION radius(ecircle) 5.286 - RETURNS float8 5.287 - LANGUAGE C IMMUTABLE STRICT 5.288 - AS '$libdir/latlon-v0003', 'pgl_ecircle_radius'; 5.289 - 5.290 -CREATE OR REPLACE FUNCTION epoint_ebox_overlap_proc(epoint, ebox) 5.291 - RETURNS boolean 5.292 - LANGUAGE C IMMUTABLE STRICT 5.293 - AS '$libdir/latlon-v0003', 'pgl_epoint_ebox_overlap'; 5.294 - 5.295 -CREATE OR REPLACE FUNCTION epoint_ecircle_overlap_proc(epoint, ecircle) 5.296 - RETURNS boolean 5.297 - LANGUAGE C IMMUTABLE STRICT 5.298 - AS '$libdir/latlon-v0003', 'pgl_epoint_ecircle_overlap'; 5.299 - 5.300 -CREATE OR REPLACE FUNCTION epoint_ecluster_overlap_proc(epoint, ecluster) 5.301 - RETURNS boolean 5.302 - LANGUAGE C IMMUTABLE STRICT 5.303 - AS '$libdir/latlon-v0003', 'pgl_epoint_ecluster_overlap'; 5.304 - 5.305 -CREATE OR REPLACE FUNCTION epoint_ecluster_may_overlap_proc(epoint, ecluster) 5.306 - RETURNS boolean 5.307 - LANGUAGE C IMMUTABLE STRICT 5.308 - AS '$libdir/latlon-v0003', 'pgl_epoint_ecluster_may_overlap'; 5.309 - 5.310 -CREATE OR REPLACE FUNCTION ebox_overlap_proc(ebox, ebox) 5.311 - RETURNS boolean 5.312 - LANGUAGE C IMMUTABLE STRICT 5.313 - AS '$libdir/latlon-v0003', 'pgl_ebox_overlap'; 5.314 - 5.315 -CREATE OR REPLACE FUNCTION ebox_ecircle_may_overlap_proc(ebox, ecircle) 5.316 - RETURNS boolean 5.317 - LANGUAGE C IMMUTABLE STRICT 5.318 - AS '$libdir/latlon-v0003', 'pgl_ebox_ecircle_may_overlap'; 5.319 - 5.320 -CREATE OR REPLACE FUNCTION ebox_ecluster_may_overlap_proc(ebox, ecluster) 5.321 - RETURNS boolean 5.322 - LANGUAGE C IMMUTABLE STRICT 5.323 - AS '$libdir/latlon-v0003', 'pgl_ebox_ecluster_may_overlap'; 5.324 - 5.325 -CREATE OR REPLACE FUNCTION ecircle_overlap_proc(ecircle, ecircle) 5.326 - RETURNS boolean 5.327 - LANGUAGE C IMMUTABLE STRICT 5.328 - AS '$libdir/latlon-v0003', 'pgl_ecircle_overlap'; 5.329 - 5.330 -CREATE OR REPLACE FUNCTION ecircle_ecluster_overlap_proc(ecircle, ecluster) 5.331 - RETURNS boolean 5.332 - LANGUAGE C IMMUTABLE STRICT 5.333 - AS '$libdir/latlon-v0003', 'pgl_ecircle_ecluster_overlap'; 5.334 - 5.335 -CREATE OR REPLACE FUNCTION ecircle_ecluster_may_overlap_proc(ecircle, ecluster) 5.336 - RETURNS boolean 5.337 - LANGUAGE C IMMUTABLE STRICT 5.338 - AS '$libdir/latlon-v0003', 'pgl_ecircle_ecluster_may_overlap'; 5.339 - 5.340 -CREATE OR REPLACE FUNCTION ecluster_may_overlap_proc(ecluster, ecluster) 5.341 - RETURNS boolean 5.342 - LANGUAGE C IMMUTABLE STRICT 5.343 - AS '$libdir/latlon-v0003', 'pgl_ecluster_may_overlap'; 5.344 - 5.345 -CREATE OPERATOR &&+ ( 5.346 - leftarg = epoint, 5.347 - rightarg = ecluster, 5.348 - procedure = epoint_ecluster_may_overlap_proc, 5.349 - commutator = &&+, 5.350 - restrict = areasel, 5.351 - join = areajoinsel 5.352 -); 5.353 - 5.354 -CREATE FUNCTION epoint_ecluster_may_overlap_commutator(ecluster, epoint) 5.355 - RETURNS boolean 5.356 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 &&+ $1'; 5.357 - 5.358 -CREATE OPERATOR &&+ ( 5.359 - leftarg = ecluster, 5.360 - rightarg = epoint, 5.361 - procedure = epoint_ecluster_may_overlap_commutator, 5.362 - commutator = &&+, 5.363 - restrict = areasel, 5.364 - join = areajoinsel 5.365 -); 5.366 - 5.367 -CREATE OPERATOR &&+ ( 5.368 - leftarg = ebox, 5.369 - rightarg = ecircle, 5.370 - procedure = ebox_ecircle_may_overlap_proc, 5.371 - commutator = &&+, 5.372 - restrict = areasel, 5.373 - join = areajoinsel 5.374 -); 5.375 - 5.376 -CREATE FUNCTION ebox_ecircle_may_overlap_commutator(ecircle, ebox) 5.377 - RETURNS boolean 5.378 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 &&+ $1'; 5.379 - 5.380 -CREATE OPERATOR &&+ ( 5.381 - leftarg = ecircle, 5.382 - rightarg = ebox, 5.383 - procedure = ebox_ecircle_may_overlap_commutator, 5.384 - commutator = &&+, 5.385 - restrict = areasel, 5.386 - join = areajoinsel 5.387 -); 5.388 - 5.389 -CREATE OPERATOR &&+ ( 5.390 - leftarg = ebox, 5.391 - rightarg = ecluster, 5.392 - procedure = ebox_ecluster_may_overlap_proc, 5.393 - commutator = &&+, 5.394 - restrict = areasel, 5.395 - join = areajoinsel 5.396 -); 5.397 - 5.398 -CREATE FUNCTION ebox_ecluster_may_overlap_commutator(ecluster, ebox) 5.399 - RETURNS boolean 5.400 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 &&+ $1'; 5.401 - 5.402 -CREATE OPERATOR &&+ ( 5.403 - leftarg = ecluster, 5.404 - rightarg = ebox, 5.405 - procedure = ebox_ecluster_may_overlap_commutator, 5.406 - commutator = &&+, 5.407 - restrict = areasel, 5.408 - join = areajoinsel 5.409 -); 5.410 - 5.411 -CREATE OPERATOR &&+ ( 5.412 - leftarg = ecircle, 5.413 - rightarg = ecluster, 5.414 - procedure = ecircle_ecluster_may_overlap_proc, 5.415 - commutator = &&+, 5.416 - restrict = areasel, 5.417 - join = areajoinsel 5.418 -); 5.419 - 5.420 -CREATE FUNCTION ecircle_ecluster_may_overlap_commutator(ecluster, ecircle) 5.421 - RETURNS boolean 5.422 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 &&+ $1'; 5.423 - 5.424 -CREATE OPERATOR &&+ ( 5.425 - leftarg = ecluster, 5.426 - rightarg = ecircle, 5.427 - procedure = ecircle_ecluster_may_overlap_commutator, 5.428 - commutator = &&+, 5.429 - restrict = areasel, 5.430 - join = areajoinsel 5.431 -); 5.432 - 5.433 -CREATE OPERATOR &&+ ( 5.434 - leftarg = ecluster, 5.435 - rightarg = ecluster, 5.436 - procedure = ecluster_may_overlap_proc, 5.437 - commutator = &&+, 5.438 - restrict = areasel, 5.439 - join = areajoinsel 5.440 -); 5.441 - 5.442 -CREATE OR REPLACE FUNCTION epoint_distance_proc(epoint, epoint) 5.443 - RETURNS float8 5.444 - LANGUAGE C IMMUTABLE STRICT 5.445 - AS '$libdir/latlon-v0003', 'pgl_epoint_distance'; 5.446 - 5.447 -CREATE OR REPLACE FUNCTION epoint_ecircle_distance_proc(epoint, ecircle) 5.448 - RETURNS float8 5.449 - LANGUAGE C IMMUTABLE STRICT 5.450 - AS '$libdir/latlon-v0003', 'pgl_epoint_ecircle_distance'; 5.451 - 5.452 -CREATE OR REPLACE FUNCTION epoint_ecluster_distance_proc(epoint, ecluster) 5.453 - RETURNS float8 5.454 - LANGUAGE C IMMUTABLE STRICT 5.455 - AS '$libdir/latlon-v0003', 'pgl_epoint_ecluster_distance'; 5.456 - 5.457 -CREATE OR REPLACE FUNCTION ecircle_distance_proc(ecircle, ecircle) 5.458 - RETURNS float8 5.459 - LANGUAGE C IMMUTABLE STRICT 5.460 - AS '$libdir/latlon-v0003', 'pgl_ecircle_distance'; 5.461 - 5.462 -CREATE OR REPLACE FUNCTION ecircle_ecluster_distance_proc(ecircle, ecluster) 5.463 - RETURNS float8 5.464 - LANGUAGE C IMMUTABLE STRICT 5.465 - AS '$libdir/latlon-v0003', 'pgl_ecircle_ecluster_distance'; 5.466 - 5.467 -CREATE OR REPLACE FUNCTION pgl_gist_consistent(internal, internal, smallint, oid, internal) 5.468 - RETURNS boolean 5.469 - LANGUAGE C STRICT 5.470 - AS '$libdir/latlon-v0003', 'pgl_gist_consistent'; 5.471 - 5.472 -CREATE OR REPLACE FUNCTION pgl_gist_union(internal, internal) 5.473 - RETURNS internal 5.474 - LANGUAGE C STRICT 5.475 - AS '$libdir/latlon-v0003', 'pgl_gist_union'; 5.476 - 5.477 -CREATE OR REPLACE FUNCTION pgl_gist_compress_epoint(internal) 5.478 - RETURNS internal 5.479 - LANGUAGE C STRICT 5.480 - AS '$libdir/latlon-v0003', 'pgl_gist_compress_epoint'; 5.481 - 5.482 -CREATE OR REPLACE FUNCTION pgl_gist_compress_ecircle(internal) 5.483 - RETURNS internal 5.484 - LANGUAGE C STRICT 5.485 - AS '$libdir/latlon-v0003', 'pgl_gist_compress_ecircle'; 5.486 - 5.487 -CREATE OR REPLACE FUNCTION pgl_gist_compress_ecluster(internal) 5.488 - RETURNS internal 5.489 - LANGUAGE C STRICT 5.490 - AS '$libdir/latlon-v0003', 'pgl_gist_compress_ecluster'; 5.491 - 5.492 -CREATE OR REPLACE FUNCTION pgl_gist_decompress(internal) 5.493 - RETURNS internal 5.494 - LANGUAGE C STRICT 5.495 - AS '$libdir/latlon-v0003', 'pgl_gist_decompress'; 5.496 - 5.497 -CREATE OR REPLACE FUNCTION pgl_gist_penalty(internal, internal, internal) 5.498 - RETURNS internal 5.499 - LANGUAGE C STRICT 5.500 - AS '$libdir/latlon-v0003', 'pgl_gist_penalty'; 5.501 - 5.502 -CREATE OR REPLACE FUNCTION pgl_gist_picksplit(internal, internal) 5.503 - RETURNS internal 5.504 - LANGUAGE C STRICT 5.505 - AS '$libdir/latlon-v0003', 'pgl_gist_picksplit'; 5.506 - 5.507 -CREATE OR REPLACE FUNCTION pgl_gist_same(internal, internal, internal) 5.508 - RETURNS internal 5.509 - LANGUAGE C STRICT 5.510 - AS '$libdir/latlon-v0003', 'pgl_gist_same'; 5.511 - 5.512 -CREATE OR REPLACE FUNCTION pgl_gist_distance(internal, internal, smallint, oid) 5.513 - RETURNS internal 5.514 - LANGUAGE C STRICT 5.515 - AS '$libdir/latlon-v0003', 'pgl_gist_distance'; 5.516 - 5.517 -DROP OPERATOR CLASS epoint_ops USING gist; 5.518 -CREATE OPERATOR CLASS epoint_ops 5.519 - DEFAULT FOR TYPE epoint USING gist AS 5.520 - OPERATOR 11 = , 5.521 - OPERATOR 22 && (epoint, ebox), 5.522 - OPERATOR 23 && (epoint, ecircle), 5.523 - OPERATOR 24 && (epoint, ecluster), 5.524 - OPERATOR 124 &&+ (epoint, ecluster), 5.525 - OPERATOR 31 <-> (epoint, epoint) FOR ORDER BY float_ops, 5.526 - OPERATOR 33 <-> (epoint, ecircle) FOR ORDER BY float_ops, 5.527 - OPERATOR 34 <-> (epoint, ecluster) FOR ORDER BY float_ops, 5.528 - FUNCTION 1 pgl_gist_consistent(internal, internal, smallint, oid, internal), 5.529 - FUNCTION 2 pgl_gist_union(internal, internal), 5.530 - FUNCTION 3 pgl_gist_compress_epoint(internal), 5.531 - FUNCTION 4 pgl_gist_decompress(internal), 5.532 - FUNCTION 5 pgl_gist_penalty(internal, internal, internal), 5.533 - FUNCTION 6 pgl_gist_picksplit(internal, internal), 5.534 - FUNCTION 7 pgl_gist_same(internal, internal, internal), 5.535 - FUNCTION 8 pgl_gist_distance(internal, internal, smallint, oid), 5.536 - STORAGE ekey_point; 5.537 - 5.538 -DROP OPERATOR CLASS ecircle_ops USING gist; 5.539 -CREATE OPERATOR CLASS ecircle_ops 5.540 - DEFAULT FOR TYPE ecircle USING gist AS 5.541 - OPERATOR 13 = , 5.542 - OPERATOR 21 && (ecircle, epoint), 5.543 - OPERATOR 122 &&+ (ecircle, ebox), 5.544 - OPERATOR 23 && (ecircle, ecircle), 5.545 - OPERATOR 24 && (ecircle, ecluster), 5.546 - OPERATOR 124 &&+ (ecircle, ecluster), 5.547 - OPERATOR 31 <-> (ecircle, epoint) FOR ORDER BY float_ops, 5.548 - OPERATOR 33 <-> (ecircle, ecircle) FOR ORDER BY float_ops, 5.549 - OPERATOR 34 <-> (ecircle, ecluster) FOR ORDER BY float_ops, 5.550 - FUNCTION 1 pgl_gist_consistent(internal, internal, smallint, oid, internal), 5.551 - FUNCTION 2 pgl_gist_union(internal, internal), 5.552 - FUNCTION 3 pgl_gist_compress_ecircle(internal), 5.553 - FUNCTION 4 pgl_gist_decompress(internal), 5.554 - FUNCTION 5 pgl_gist_penalty(internal, internal, internal), 5.555 - FUNCTION 6 pgl_gist_picksplit(internal, internal), 5.556 - FUNCTION 7 pgl_gist_same(internal, internal, internal), 5.557 - FUNCTION 8 pgl_gist_distance(internal, internal, smallint, oid), 5.558 - STORAGE ekey_area; 5.559 - 5.560 -DROP OPERATOR CLASS ecluster_ops USING gist; 5.561 -CREATE OPERATOR CLASS ecluster_ops 5.562 - DEFAULT FOR TYPE ecluster USING gist AS 5.563 - OPERATOR 21 && (ecluster, epoint), 5.564 - OPERATOR 121 &&+ (ecluster, epoint), 5.565 - OPERATOR 122 &&+ (ecluster, ebox), 5.566 - OPERATOR 23 && (ecluster, ecircle), 5.567 - OPERATOR 123 &&+ (ecluster, ecircle), 5.568 - OPERATOR 124 &&+ (ecluster, ecluster), 5.569 - FUNCTION 1 pgl_gist_consistent(internal, internal, smallint, oid, internal), 5.570 - FUNCTION 2 pgl_gist_union(internal, internal), 5.571 - FUNCTION 3 pgl_gist_compress_ecluster(internal), 5.572 - FUNCTION 4 pgl_gist_decompress(internal), 5.573 - FUNCTION 5 pgl_gist_penalty(internal, internal, internal), 5.574 - FUNCTION 6 pgl_gist_picksplit(internal, internal), 5.575 - FUNCTION 7 pgl_gist_same(internal, internal, internal), 5.576 - FUNCTION 8 pgl_gist_distance(internal, internal, smallint, oid), 5.577 - STORAGE ekey_area; 5.578 -
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/latlon--0.3--0.4.sql Fri Sep 09 19:22:30 2016 +0200 6.3 @@ -0,0 +1,767 @@ 6.4 + 6.5 +CREATE OR REPLACE FUNCTION ekey_point_in_dummy(cstring) 6.6 + RETURNS ekey_point 6.7 + LANGUAGE C IMMUTABLE STRICT 6.8 + AS '$libdir/latlon-v0004', 'pgl_notimpl'; 6.9 + 6.10 +CREATE OR REPLACE FUNCTION ekey_point_out_dummy(ekey_point) 6.11 + RETURNS cstring 6.12 + LANGUAGE C IMMUTABLE STRICT 6.13 + AS '$libdir/latlon-v0004', 'pgl_notimpl'; 6.14 + 6.15 +CREATE OR REPLACE FUNCTION ekey_area_in_dummy(cstring) 6.16 + RETURNS ekey_area 6.17 + LANGUAGE C IMMUTABLE STRICT 6.18 + AS '$libdir/latlon-v0004', 'pgl_notimpl'; 6.19 + 6.20 +CREATE OR REPLACE FUNCTION ekey_area_out_dummy(ekey_area) 6.21 + RETURNS cstring 6.22 + LANGUAGE C IMMUTABLE STRICT 6.23 + AS '$libdir/latlon-v0004', 'pgl_notimpl'; 6.24 + 6.25 +CREATE OR REPLACE FUNCTION epoint_in(cstring) 6.26 + RETURNS epoint 6.27 + LANGUAGE C IMMUTABLE STRICT 6.28 + AS '$libdir/latlon-v0004', 'pgl_epoint_in'; 6.29 + 6.30 +CREATE OR REPLACE FUNCTION ebox_in(cstring) 6.31 + RETURNS ebox 6.32 + LANGUAGE C IMMUTABLE STRICT 6.33 + AS '$libdir/latlon-v0004', 'pgl_ebox_in'; 6.34 + 6.35 +CREATE OR REPLACE FUNCTION ecircle_in(cstring) 6.36 + RETURNS ecircle 6.37 + LANGUAGE C IMMUTABLE STRICT 6.38 + AS '$libdir/latlon-v0004', 'pgl_ecircle_in'; 6.39 + 6.40 +CREATE OR REPLACE FUNCTION ecluster_in(cstring) 6.41 + RETURNS ecluster 6.42 + LANGUAGE C IMMUTABLE STRICT 6.43 + AS '$libdir/latlon-v0004', 'pgl_ecluster_in'; 6.44 + 6.45 +CREATE OR REPLACE FUNCTION epoint_out(epoint) 6.46 + RETURNS cstring 6.47 + LANGUAGE C IMMUTABLE STRICT 6.48 + AS '$libdir/latlon-v0004', 'pgl_epoint_out'; 6.49 + 6.50 +CREATE OR REPLACE FUNCTION ebox_out(ebox) 6.51 + RETURNS cstring 6.52 + LANGUAGE C IMMUTABLE STRICT 6.53 + AS '$libdir/latlon-v0004', 'pgl_ebox_out'; 6.54 + 6.55 +CREATE OR REPLACE FUNCTION ecircle_out(ecircle) 6.56 + RETURNS cstring 6.57 + LANGUAGE C IMMUTABLE STRICT 6.58 + AS '$libdir/latlon-v0004', 'pgl_ecircle_out'; 6.59 + 6.60 +CREATE OR REPLACE FUNCTION ecluster_out(ecluster) 6.61 + RETURNS cstring 6.62 + LANGUAGE C IMMUTABLE STRICT 6.63 + AS '$libdir/latlon-v0004', 'pgl_ecluster_out'; 6.64 + 6.65 +CREATE OR REPLACE FUNCTION epoint_recv(internal) 6.66 + RETURNS epoint 6.67 + LANGUAGE C IMMUTABLE STRICT 6.68 + AS '$libdir/latlon-v0004', 'pgl_epoint_recv'; 6.69 + 6.70 +CREATE OR REPLACE FUNCTION ebox_recv(internal) 6.71 + RETURNS ebox 6.72 + LANGUAGE C IMMUTABLE STRICT 6.73 + AS '$libdir/latlon-v0004', 'pgl_ebox_recv'; 6.74 + 6.75 +CREATE OR REPLACE FUNCTION ecircle_recv(internal) 6.76 + RETURNS ecircle 6.77 + LANGUAGE C IMMUTABLE STRICT 6.78 + AS '$libdir/latlon-v0004', 'pgl_ecircle_recv'; 6.79 + 6.80 +CREATE OR REPLACE FUNCTION epoint_send(epoint) 6.81 + RETURNS bytea 6.82 + LANGUAGE C IMMUTABLE STRICT 6.83 + AS '$libdir/latlon-v0004', 'pgl_epoint_send'; 6.84 + 6.85 +CREATE OR REPLACE FUNCTION ebox_send(ebox) 6.86 + RETURNS bytea 6.87 + LANGUAGE C IMMUTABLE STRICT 6.88 + AS '$libdir/latlon-v0004', 'pgl_ebox_send'; 6.89 + 6.90 +CREATE OR REPLACE FUNCTION ecircle_send(ecircle) 6.91 + RETURNS bytea 6.92 + LANGUAGE C IMMUTABLE STRICT 6.93 + AS '$libdir/latlon-v0004', 'pgl_ecircle_send'; 6.94 + 6.95 +CREATE OR REPLACE FUNCTION epoint_btree_lt(epoint, epoint) 6.96 + RETURNS boolean 6.97 + LANGUAGE C IMMUTABLE STRICT 6.98 + AS '$libdir/latlon-v0004', 'pgl_btree_epoint_lt'; 6.99 + 6.100 +CREATE OR REPLACE FUNCTION epoint_btree_le(epoint, epoint) 6.101 + RETURNS boolean 6.102 + LANGUAGE C IMMUTABLE STRICT 6.103 + AS '$libdir/latlon-v0004', 'pgl_btree_epoint_le'; 6.104 + 6.105 +CREATE OR REPLACE FUNCTION epoint_btree_eq(epoint, epoint) 6.106 + RETURNS boolean 6.107 + LANGUAGE C IMMUTABLE STRICT 6.108 + AS '$libdir/latlon-v0004', 'pgl_btree_epoint_eq'; 6.109 + 6.110 +CREATE OR REPLACE FUNCTION epoint_btree_ne(epoint, epoint) 6.111 + RETURNS boolean 6.112 + LANGUAGE C IMMUTABLE STRICT 6.113 + AS '$libdir/latlon-v0004', 'pgl_btree_epoint_ne'; 6.114 + 6.115 +CREATE OR REPLACE FUNCTION epoint_btree_ge(epoint, epoint) 6.116 + RETURNS boolean 6.117 + LANGUAGE C IMMUTABLE STRICT 6.118 + AS '$libdir/latlon-v0004', 'pgl_btree_epoint_ge'; 6.119 + 6.120 +CREATE OR REPLACE FUNCTION epoint_btree_gt(epoint, epoint) 6.121 + RETURNS boolean 6.122 + LANGUAGE C IMMUTABLE STRICT 6.123 + AS '$libdir/latlon-v0004', 'pgl_btree_epoint_gt'; 6.124 + 6.125 +CREATE OR REPLACE FUNCTION epoint_btree_cmp(epoint, epoint) 6.126 + RETURNS int4 6.127 + LANGUAGE C IMMUTABLE STRICT 6.128 + AS '$libdir/latlon-v0004', 'pgl_btree_epoint_cmp'; 6.129 + 6.130 +CREATE OR REPLACE FUNCTION ebox_btree_lt(ebox, ebox) 6.131 + RETURNS boolean 6.132 + LANGUAGE C IMMUTABLE STRICT 6.133 + AS '$libdir/latlon-v0004', 'pgl_btree_ebox_lt'; 6.134 + 6.135 +CREATE OR REPLACE FUNCTION ebox_btree_le(ebox, ebox) 6.136 + RETURNS boolean 6.137 + LANGUAGE C IMMUTABLE STRICT 6.138 + AS '$libdir/latlon-v0004', 'pgl_btree_ebox_le'; 6.139 + 6.140 +CREATE OR REPLACE FUNCTION ebox_btree_eq(ebox, ebox) 6.141 + RETURNS boolean 6.142 + LANGUAGE C IMMUTABLE STRICT 6.143 + AS '$libdir/latlon-v0004', 'pgl_btree_ebox_eq'; 6.144 + 6.145 +CREATE OR REPLACE FUNCTION ebox_btree_ne(ebox, ebox) 6.146 + RETURNS boolean 6.147 + LANGUAGE C IMMUTABLE STRICT 6.148 + AS '$libdir/latlon-v0004', 'pgl_btree_ebox_ne'; 6.149 + 6.150 +CREATE OR REPLACE FUNCTION ebox_btree_ge(ebox, ebox) 6.151 + RETURNS boolean 6.152 + LANGUAGE C IMMUTABLE STRICT 6.153 + AS '$libdir/latlon-v0004', 'pgl_btree_ebox_ge'; 6.154 + 6.155 +CREATE OR REPLACE FUNCTION ebox_btree_gt(ebox, ebox) 6.156 + RETURNS boolean 6.157 + LANGUAGE C IMMUTABLE STRICT 6.158 + AS '$libdir/latlon-v0004', 'pgl_btree_ebox_gt'; 6.159 + 6.160 +CREATE OR REPLACE FUNCTION ebox_btree_cmp(ebox, ebox) 6.161 + RETURNS int4 6.162 + LANGUAGE C IMMUTABLE STRICT 6.163 + AS '$libdir/latlon-v0004', 'pgl_btree_ebox_cmp'; 6.164 + 6.165 +CREATE OR REPLACE FUNCTION ecircle_btree_lt(ecircle, ecircle) 6.166 + RETURNS boolean 6.167 + LANGUAGE C IMMUTABLE STRICT 6.168 + AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_lt'; 6.169 + 6.170 +CREATE OR REPLACE FUNCTION ecircle_btree_le(ecircle, ecircle) 6.171 + RETURNS boolean 6.172 + LANGUAGE C IMMUTABLE STRICT 6.173 + AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_le'; 6.174 + 6.175 +CREATE OR REPLACE FUNCTION ecircle_btree_eq(ecircle, ecircle) 6.176 + RETURNS boolean 6.177 + LANGUAGE C IMMUTABLE STRICT 6.178 + AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_eq'; 6.179 + 6.180 +CREATE OR REPLACE FUNCTION ecircle_btree_ne(ecircle, ecircle) 6.181 + RETURNS boolean 6.182 + LANGUAGE C IMMUTABLE STRICT 6.183 + AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_ne'; 6.184 + 6.185 +CREATE OR REPLACE FUNCTION ecircle_btree_ge(ecircle, ecircle) 6.186 + RETURNS boolean 6.187 + LANGUAGE C IMMUTABLE STRICT 6.188 + AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_ge'; 6.189 + 6.190 +CREATE OR REPLACE FUNCTION ecircle_btree_gt(ecircle, ecircle) 6.191 + RETURNS boolean 6.192 + LANGUAGE C IMMUTABLE STRICT 6.193 + AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_gt'; 6.194 + 6.195 +CREATE OR REPLACE FUNCTION ecircle_btree_cmp(ecircle, ecircle) 6.196 + RETURNS int4 6.197 + LANGUAGE C IMMUTABLE STRICT 6.198 + AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_cmp'; 6.199 + 6.200 +CREATE OR REPLACE FUNCTION cast_epoint_to_ebox(epoint) 6.201 + RETURNS ebox 6.202 + LANGUAGE C IMMUTABLE STRICT 6.203 + AS '$libdir/latlon-v0004', 'pgl_epoint_to_ebox'; 6.204 + 6.205 +CREATE OR REPLACE FUNCTION cast_epoint_to_ecircle(epoint) 6.206 + RETURNS ecircle 6.207 + LANGUAGE C IMMUTABLE STRICT 6.208 + AS '$libdir/latlon-v0004', 'pgl_epoint_to_ecircle'; 6.209 + 6.210 +CREATE OR REPLACE FUNCTION cast_epoint_to_ecluster(epoint) 6.211 + RETURNS ecluster 6.212 + LANGUAGE C IMMUTABLE STRICT 6.213 + AS '$libdir/latlon-v0004', 'pgl_epoint_to_ecluster'; 6.214 + 6.215 +CREATE OR REPLACE FUNCTION cast_ebox_to_ecluster(ebox) 6.216 + RETURNS ecluster 6.217 + LANGUAGE C IMMUTABLE STRICT 6.218 + AS '$libdir/latlon-v0004', 'pgl_ebox_to_ecluster'; 6.219 + 6.220 +CREATE OR REPLACE FUNCTION epoint(float8, float8) 6.221 + RETURNS epoint 6.222 + LANGUAGE C IMMUTABLE STRICT 6.223 + AS '$libdir/latlon-v0004', 'pgl_create_epoint'; 6.224 + 6.225 +CREATE OR REPLACE FUNCTION empty_ebox() 6.226 + RETURNS ebox 6.227 + LANGUAGE C IMMUTABLE STRICT 6.228 + AS '$libdir/latlon-v0004', 'pgl_create_empty_ebox'; 6.229 + 6.230 +CREATE OR REPLACE FUNCTION ebox(float8, float8, float8, float8) 6.231 + RETURNS ebox 6.232 + LANGUAGE C IMMUTABLE STRICT 6.233 + AS '$libdir/latlon-v0004', 'pgl_create_ebox'; 6.234 + 6.235 +CREATE OR REPLACE FUNCTION ebox(epoint, epoint) 6.236 + RETURNS ebox 6.237 + LANGUAGE C IMMUTABLE STRICT 6.238 + AS '$libdir/latlon-v0004', 'pgl_create_ebox_from_epoints'; 6.239 + 6.240 +CREATE OR REPLACE FUNCTION ecircle(float8, float8, float8) 6.241 + RETURNS ecircle 6.242 + LANGUAGE C IMMUTABLE STRICT 6.243 + AS '$libdir/latlon-v0004', 'pgl_create_ecircle'; 6.244 + 6.245 +CREATE OR REPLACE FUNCTION ecircle(epoint, float8) 6.246 + RETURNS ecircle 6.247 + LANGUAGE C IMMUTABLE STRICT 6.248 + AS '$libdir/latlon-v0004', 'pgl_create_ecircle_from_epoint'; 6.249 + 6.250 +CREATE OR REPLACE FUNCTION latitude(epoint) 6.251 + RETURNS float8 6.252 + LANGUAGE C IMMUTABLE STRICT 6.253 + AS '$libdir/latlon-v0004', 'pgl_epoint_lat'; 6.254 + 6.255 +CREATE OR REPLACE FUNCTION longitude(epoint) 6.256 + RETURNS float8 6.257 + LANGUAGE C IMMUTABLE STRICT 6.258 + AS '$libdir/latlon-v0004', 'pgl_epoint_lon'; 6.259 + 6.260 +CREATE OR REPLACE FUNCTION min_latitude(ebox) 6.261 + RETURNS float8 6.262 + LANGUAGE C IMMUTABLE STRICT 6.263 + AS '$libdir/latlon-v0004', 'pgl_ebox_lat_min'; 6.264 + 6.265 +CREATE OR REPLACE FUNCTION max_latitude(ebox) 6.266 + RETURNS float8 6.267 + LANGUAGE C IMMUTABLE STRICT 6.268 + AS '$libdir/latlon-v0004', 'pgl_ebox_lat_max'; 6.269 + 6.270 +CREATE OR REPLACE FUNCTION min_longitude(ebox) 6.271 + RETURNS float8 6.272 + LANGUAGE C IMMUTABLE STRICT 6.273 + AS '$libdir/latlon-v0004', 'pgl_ebox_lon_min'; 6.274 + 6.275 +CREATE OR REPLACE FUNCTION max_longitude(ebox) 6.276 + RETURNS float8 6.277 + LANGUAGE C IMMUTABLE STRICT 6.278 + AS '$libdir/latlon-v0004', 'pgl_ebox_lon_max'; 6.279 + 6.280 +CREATE OR REPLACE FUNCTION center(ecircle) 6.281 + RETURNS epoint 6.282 + LANGUAGE C IMMUTABLE STRICT 6.283 + AS '$libdir/latlon-v0004', 'pgl_ecircle_center'; 6.284 + 6.285 +CREATE OR REPLACE FUNCTION radius(ecircle) 6.286 + RETURNS float8 6.287 + LANGUAGE C IMMUTABLE STRICT 6.288 + AS '$libdir/latlon-v0004', 'pgl_ecircle_radius'; 6.289 + 6.290 +CREATE OR REPLACE FUNCTION epoint_ebox_overlap_proc(epoint, ebox) 6.291 + RETURNS boolean 6.292 + LANGUAGE C IMMUTABLE STRICT 6.293 + AS '$libdir/latlon-v0004', 'pgl_epoint_ebox_overlap'; 6.294 + 6.295 +CREATE OR REPLACE FUNCTION epoint_ecircle_overlap_proc(epoint, ecircle) 6.296 + RETURNS boolean 6.297 + LANGUAGE C IMMUTABLE STRICT 6.298 + AS '$libdir/latlon-v0004', 'pgl_epoint_ecircle_overlap'; 6.299 + 6.300 +CREATE OR REPLACE FUNCTION epoint_ecluster_overlap_proc(epoint, ecluster) 6.301 + RETURNS boolean 6.302 + LANGUAGE C IMMUTABLE STRICT 6.303 + AS '$libdir/latlon-v0004', 'pgl_epoint_ecluster_overlap'; 6.304 + 6.305 +CREATE OR REPLACE FUNCTION epoint_ecluster_may_overlap_proc(epoint, ecluster) 6.306 + RETURNS boolean 6.307 + LANGUAGE C IMMUTABLE STRICT 6.308 + AS '$libdir/latlon-v0004', 'pgl_epoint_ecluster_may_overlap'; 6.309 + 6.310 +CREATE OR REPLACE FUNCTION ebox_overlap_proc(ebox, ebox) 6.311 + RETURNS boolean 6.312 + LANGUAGE C IMMUTABLE STRICT 6.313 + AS '$libdir/latlon-v0004', 'pgl_ebox_overlap'; 6.314 + 6.315 +CREATE OR REPLACE FUNCTION ebox_ecircle_may_overlap_proc(ebox, ecircle) 6.316 + RETURNS boolean 6.317 + LANGUAGE C IMMUTABLE STRICT 6.318 + AS '$libdir/latlon-v0004', 'pgl_ebox_ecircle_may_overlap'; 6.319 + 6.320 +CREATE OR REPLACE FUNCTION ebox_ecluster_may_overlap_proc(ebox, ecluster) 6.321 + RETURNS boolean 6.322 + LANGUAGE C IMMUTABLE STRICT 6.323 + AS '$libdir/latlon-v0004', 'pgl_ebox_ecluster_may_overlap'; 6.324 + 6.325 +CREATE OR REPLACE FUNCTION ecircle_overlap_proc(ecircle, ecircle) 6.326 + RETURNS boolean 6.327 + LANGUAGE C IMMUTABLE STRICT 6.328 + AS '$libdir/latlon-v0004', 'pgl_ecircle_overlap'; 6.329 + 6.330 +CREATE OR REPLACE FUNCTION ecircle_ecluster_overlap_proc(ecircle, ecluster) 6.331 + RETURNS boolean 6.332 + LANGUAGE C IMMUTABLE STRICT 6.333 + AS '$libdir/latlon-v0004', 'pgl_ecircle_ecluster_overlap'; 6.334 + 6.335 +CREATE OR REPLACE FUNCTION ecircle_ecluster_may_overlap_proc(ecircle, ecluster) 6.336 + RETURNS boolean 6.337 + LANGUAGE C IMMUTABLE STRICT 6.338 + AS '$libdir/latlon-v0004', 'pgl_ecircle_ecluster_may_overlap'; 6.339 + 6.340 +CREATE FUNCTION ecluster_overlap_proc(ecluster, ecluster) 6.341 + RETURNS boolean 6.342 + LANGUAGE C IMMUTABLE STRICT 6.343 + AS '$libdir/latlon-v0004', 'pgl_ecluster_overlap'; 6.344 + 6.345 +CREATE OR REPLACE FUNCTION ecluster_may_overlap_proc(ecluster, ecluster) 6.346 + RETURNS boolean 6.347 + LANGUAGE C IMMUTABLE STRICT 6.348 + AS '$libdir/latlon-v0004', 'pgl_ecluster_may_overlap'; 6.349 + 6.350 +CREATE FUNCTION ecluster_contains_proc(ecluster, ecluster) 6.351 + RETURNS boolean 6.352 + LANGUAGE C IMMUTABLE STRICT 6.353 + AS '$libdir/latlon-v0004', 'pgl_ecluster_contains'; 6.354 + 6.355 +CREATE OR REPLACE FUNCTION epoint_distance_proc(epoint, epoint) 6.356 + RETURNS float8 6.357 + LANGUAGE C IMMUTABLE STRICT 6.358 + AS '$libdir/latlon-v0004', 'pgl_epoint_distance'; 6.359 + 6.360 +CREATE OR REPLACE FUNCTION epoint_ecircle_distance_proc(epoint, ecircle) 6.361 + RETURNS float8 6.362 + LANGUAGE C IMMUTABLE STRICT 6.363 + AS '$libdir/latlon-v0004', 'pgl_epoint_ecircle_distance'; 6.364 + 6.365 +CREATE OR REPLACE FUNCTION epoint_ecluster_distance_proc(epoint, ecluster) 6.366 + RETURNS float8 6.367 + LANGUAGE C IMMUTABLE STRICT 6.368 + AS '$libdir/latlon-v0004', 'pgl_epoint_ecluster_distance'; 6.369 + 6.370 +CREATE OR REPLACE FUNCTION ecircle_distance_proc(ecircle, ecircle) 6.371 + RETURNS float8 6.372 + LANGUAGE C IMMUTABLE STRICT 6.373 + AS '$libdir/latlon-v0004', 'pgl_ecircle_distance'; 6.374 + 6.375 +CREATE OR REPLACE FUNCTION ecircle_ecluster_distance_proc(ecircle, ecluster) 6.376 + RETURNS float8 6.377 + LANGUAGE C IMMUTABLE STRICT 6.378 + AS '$libdir/latlon-v0004', 'pgl_ecircle_ecluster_distance'; 6.379 + 6.380 +CREATE FUNCTION ecluster_distance_proc(ecluster, ecluster) 6.381 + RETURNS float8 6.382 + LANGUAGE C IMMUTABLE STRICT 6.383 + AS '$libdir/latlon-v0004', 'pgl_ecluster_distance'; 6.384 + 6.385 +CREATE OPERATOR && ( 6.386 + leftarg = ecluster, 6.387 + rightarg = ecluster, 6.388 + procedure = ecluster_overlap_proc, 6.389 + commutator = &&, 6.390 + restrict = areasel, 6.391 + join = areajoinsel 6.392 +); 6.393 + 6.394 +CREATE FUNCTION ebox_ecircle_overlap_castwrap(ebox, ecircle) 6.395 + RETURNS boolean 6.396 + LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster && $2'; 6.397 + 6.398 +CREATE OPERATOR && ( 6.399 + leftarg = ebox, 6.400 + rightarg = ecircle, 6.401 + procedure = ebox_ecircle_overlap_castwrap, 6.402 + commutator = &&, 6.403 + restrict = areasel, 6.404 + join = areajoinsel 6.405 +); 6.406 + 6.407 +CREATE FUNCTION ebox_ecircle_overlap_castwrap(ecircle, ebox) 6.408 + RETURNS boolean 6.409 + LANGUAGE sql IMMUTABLE AS 'SELECT $1 && $2::ecluster'; 6.410 + 6.411 +CREATE OPERATOR && ( 6.412 + leftarg = ecircle, 6.413 + rightarg = ebox, 6.414 + procedure = ebox_ecircle_overlap_castwrap, 6.415 + commutator = &&, 6.416 + restrict = areasel, 6.417 + join = areajoinsel 6.418 +); 6.419 + 6.420 +CREATE FUNCTION ebox_ecluster_overlap_castwrap(ebox, ecluster) 6.421 + RETURNS boolean 6.422 + LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster && $2'; 6.423 + 6.424 +CREATE OPERATOR && ( 6.425 + leftarg = ebox, 6.426 + rightarg = ecluster, 6.427 + procedure = ebox_ecluster_overlap_castwrap, 6.428 + commutator = &&, 6.429 + restrict = areasel, 6.430 + join = areajoinsel 6.431 +); 6.432 + 6.433 +CREATE FUNCTION ebox_ecluster_overlap_castwrap(ecluster, ebox) 6.434 + RETURNS boolean 6.435 + LANGUAGE sql IMMUTABLE AS 'SELECT $1 && $2::ecluster'; 6.436 + 6.437 +CREATE OPERATOR && ( 6.438 + leftarg = ecluster, 6.439 + rightarg = ebox, 6.440 + procedure = ebox_ecluster_overlap_castwrap, 6.441 + commutator = &&, 6.442 + restrict = areasel, 6.443 + join = areajoinsel 6.444 +); 6.445 + 6.446 + 6.447 +CREATE OPERATOR @> ( 6.448 + leftarg = ebox, 6.449 + rightarg = epoint, 6.450 + procedure = epoint_ebox_overlap_commutator, 6.451 + commutator = <@, 6.452 + restrict = areasel, 6.453 + join = areajoinsel 6.454 +); 6.455 + 6.456 +CREATE OPERATOR <@ ( 6.457 + leftarg = epoint, 6.458 + rightarg = ebox, 6.459 + procedure = epoint_ebox_overlap_proc, 6.460 + commutator = @>, 6.461 + restrict = areasel, 6.462 + join = areajoinsel 6.463 +); 6.464 + 6.465 +CREATE OPERATOR @> ( 6.466 + leftarg = ecluster, 6.467 + rightarg = epoint, 6.468 + procedure = epoint_ecluster_overlap_commutator, 6.469 + commutator = <@, 6.470 + restrict = areasel, 6.471 + join = areajoinsel 6.472 +); 6.473 + 6.474 +CREATE OPERATOR <@ ( 6.475 + leftarg = epoint, 6.476 + rightarg = ecluster, 6.477 + procedure = epoint_ecluster_overlap_proc, 6.478 + commutator = <@, 6.479 + restrict = areasel, 6.480 + join = areajoinsel 6.481 +); 6.482 + 6.483 +CREATE OPERATOR @> ( 6.484 + leftarg = ecluster, 6.485 + rightarg = ecluster, 6.486 + procedure = ecluster_contains_proc, 6.487 + commutator = <@, 6.488 + restrict = areasel, 6.489 + join = areajoinsel 6.490 +); 6.491 + 6.492 +CREATE FUNCTION ecluster_contains_commutator(ecluster, ecluster) 6.493 + RETURNS boolean 6.494 + LANGUAGE sql IMMUTABLE AS 'SELECT $2 @> $1'; 6.495 + 6.496 +CREATE OPERATOR <@ ( 6.497 + leftarg = ecluster, 6.498 + rightarg = ecluster, 6.499 + procedure = ecluster_contains_commutator, 6.500 + commutator = @>, 6.501 + restrict = areasel, 6.502 + join = areajoinsel 6.503 +); 6.504 + 6.505 +CREATE FUNCTION ebox_ecluster_contains_castwrap(ebox, ecluster) 6.506 + RETURNS boolean 6.507 + LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster @> $2'; 6.508 + 6.509 +CREATE OPERATOR @> ( 6.510 + leftarg = ebox, 6.511 + rightarg = ecluster, 6.512 + procedure = ebox_ecluster_contains_castwrap, 6.513 + commutator = <@, 6.514 + restrict = areasel, 6.515 + join = areajoinsel 6.516 +); 6.517 + 6.518 +CREATE FUNCTION ebox_ecluster_contains_castwrap(ecluster, ebox) 6.519 + RETURNS boolean 6.520 + LANGUAGE sql IMMUTABLE AS 'SELECT $2::ecluster @> $1'; 6.521 + 6.522 +CREATE OPERATOR <@ ( 6.523 + leftarg = ecluster, 6.524 + rightarg = ebox, 6.525 + procedure = ebox_ecluster_contains_castwrap, 6.526 + commutator = @>, 6.527 + restrict = areasel, 6.528 + join = areajoinsel 6.529 +); 6.530 + 6.531 +CREATE FUNCTION ecluster_ebox_contains_castwrap(ecluster, ebox) 6.532 + RETURNS boolean 6.533 + LANGUAGE sql IMMUTABLE AS 'SELECT $1 @> $2::ecluster'; 6.534 + 6.535 +CREATE OPERATOR @> ( 6.536 + leftarg = ecluster, 6.537 + rightarg = ebox, 6.538 + procedure = ecluster_ebox_contains_castwrap, 6.539 + commutator = <@, 6.540 + restrict = areasel, 6.541 + join = areajoinsel 6.542 +); 6.543 + 6.544 +CREATE FUNCTION ecluster_ebox_contains_castwrap(ebox, ecluster) 6.545 + RETURNS boolean 6.546 + LANGUAGE sql IMMUTABLE AS 'SELECT $2 @> $1::ecluster'; 6.547 + 6.548 +CREATE OPERATOR <@ ( 6.549 + leftarg = ebox, 6.550 + rightarg = ecluster, 6.551 + procedure = ecluster_ebox_contains_castwrap, 6.552 + commutator = @>, 6.553 + restrict = areasel, 6.554 + join = areajoinsel 6.555 +); 6.556 + 6.557 + 6.558 +CREATE OPERATOR <-> ( 6.559 + leftarg = ecluster, 6.560 + rightarg = ecluster, 6.561 + procedure = ecluster_distance_proc, 6.562 + commutator = <-> 6.563 +); 6.564 + 6.565 +CREATE FUNCTION epoint_ebox_distance_castwrap(epoint, ebox) 6.566 + RETURNS float8 6.567 + LANGUAGE sql IMMUTABLE AS 'SELECT $1 <-> $2::ecluster'; 6.568 + 6.569 +CREATE OPERATOR <-> ( 6.570 + leftarg = epoint, 6.571 + rightarg = ebox, 6.572 + procedure = epoint_ebox_distance_castwrap, 6.573 + commutator = <-> 6.574 +); 6.575 + 6.576 +CREATE FUNCTION epoint_ebox_distance_castwrap(ebox, epoint) 6.577 + RETURNS float8 6.578 + LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster <-> $2'; 6.579 + 6.580 +CREATE OPERATOR <-> ( 6.581 + leftarg = ebox, 6.582 + rightarg = epoint, 6.583 + procedure = epoint_ebox_distance_castwrap, 6.584 + commutator = <-> 6.585 +); 6.586 + 6.587 +CREATE FUNCTION ebox_distance_castwrap(ebox, ebox) 6.588 + RETURNS float8 6.589 + LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster <-> $2::ecluster'; 6.590 + 6.591 +CREATE OPERATOR <-> ( 6.592 + leftarg = ebox, 6.593 + rightarg = ebox, 6.594 + procedure = ebox_distance_castwrap, 6.595 + commutator = <-> 6.596 +); 6.597 + 6.598 +CREATE FUNCTION ebox_ecircle_distance_castwrap(ebox, ecircle) 6.599 + RETURNS float8 6.600 + LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster <-> $2'; 6.601 + 6.602 +CREATE OPERATOR <-> ( 6.603 + leftarg = ebox, 6.604 + rightarg = ecircle, 6.605 + procedure = ebox_ecircle_distance_castwrap, 6.606 + commutator = <-> 6.607 +); 6.608 + 6.609 +CREATE FUNCTION ebox_ecircle_distance_castwrap(ecircle, ebox) 6.610 + RETURNS float8 6.611 + LANGUAGE sql IMMUTABLE AS 'SELECT $1 <-> $2::ecluster'; 6.612 + 6.613 +CREATE OPERATOR <-> ( 6.614 + leftarg = ecircle, 6.615 + rightarg = ebox, 6.616 + procedure = ebox_ecircle_distance_castwrap, 6.617 + commutator = <-> 6.618 +); 6.619 + 6.620 +CREATE FUNCTION ebox_ecluster_distance_castwrap(ebox, ecluster) 6.621 + RETURNS float8 6.622 + LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster <-> $2'; 6.623 + 6.624 +CREATE OPERATOR <-> ( 6.625 + leftarg = ebox, 6.626 + rightarg = ecluster, 6.627 + procedure = ebox_ecluster_distance_castwrap, 6.628 + commutator = <-> 6.629 +); 6.630 + 6.631 +CREATE FUNCTION ebox_ecluster_distance_castwrap(ecluster, ebox) 6.632 + RETURNS float8 6.633 + LANGUAGE sql IMMUTABLE AS 'SELECT $1 <-> $2::ecluster'; 6.634 + 6.635 +CREATE OPERATOR <-> ( 6.636 + leftarg = ecluster, 6.637 + rightarg = ebox, 6.638 + procedure = ebox_ecluster_distance_castwrap, 6.639 + commutator = <-> 6.640 +); 6.641 + 6.642 +DROP OPERATOR CLASS epoint_ops USING gist; 6.643 +DROP OPERATOR CLASS ecircle_ops USING gist; 6.644 +DROP OPERATOR CLASS ecluster_ops USING gist; 6.645 + 6.646 +CREATE OR REPLACE FUNCTION pgl_gist_consistent(internal, internal, smallint, oid, internal) 6.647 + RETURNS boolean 6.648 + LANGUAGE C STRICT 6.649 + AS '$libdir/latlon-v0004', 'pgl_gist_consistent'; 6.650 + 6.651 +CREATE OR REPLACE FUNCTION pgl_gist_union(internal, internal) 6.652 + RETURNS internal 6.653 + LANGUAGE C STRICT 6.654 + AS '$libdir/latlon-v0004', 'pgl_gist_union'; 6.655 + 6.656 +CREATE OR REPLACE FUNCTION pgl_gist_compress_epoint(internal) 6.657 + RETURNS internal 6.658 + LANGUAGE C STRICT 6.659 + AS '$libdir/latlon-v0004', 'pgl_gist_compress_epoint'; 6.660 + 6.661 +CREATE OR REPLACE FUNCTION pgl_gist_compress_ecircle(internal) 6.662 + RETURNS internal 6.663 + LANGUAGE C STRICT 6.664 + AS '$libdir/latlon-v0004', 'pgl_gist_compress_ecircle'; 6.665 + 6.666 +CREATE OR REPLACE FUNCTION pgl_gist_compress_ecluster(internal) 6.667 + RETURNS internal 6.668 + LANGUAGE C STRICT 6.669 + AS '$libdir/latlon-v0004', 'pgl_gist_compress_ecluster'; 6.670 + 6.671 +CREATE OR REPLACE FUNCTION pgl_gist_decompress(internal) 6.672 + RETURNS internal 6.673 + LANGUAGE C STRICT 6.674 + AS '$libdir/latlon-v0004', 'pgl_gist_decompress'; 6.675 + 6.676 +CREATE OR REPLACE FUNCTION pgl_gist_penalty(internal, internal, internal) 6.677 + RETURNS internal 6.678 + LANGUAGE C STRICT 6.679 + AS '$libdir/latlon-v0004', 'pgl_gist_penalty'; 6.680 + 6.681 +CREATE OR REPLACE FUNCTION pgl_gist_picksplit(internal, internal) 6.682 + RETURNS internal 6.683 + LANGUAGE C STRICT 6.684 + AS '$libdir/latlon-v0004', 'pgl_gist_picksplit'; 6.685 + 6.686 +CREATE OR REPLACE FUNCTION pgl_gist_same(internal, internal, internal) 6.687 + RETURNS internal 6.688 + LANGUAGE C STRICT 6.689 + AS '$libdir/latlon-v0004', 'pgl_gist_same'; 6.690 + 6.691 +CREATE OR REPLACE FUNCTION pgl_gist_distance(internal, internal, smallint, oid) 6.692 + RETURNS internal 6.693 + LANGUAGE C STRICT 6.694 + AS '$libdir/latlon-v0004', 'pgl_gist_distance'; 6.695 + 6.696 +CREATE OPERATOR CLASS epoint_ops 6.697 + DEFAULT FOR TYPE epoint USING gist AS 6.698 + OPERATOR 11 = , 6.699 + OPERATOR 22 && (epoint, ebox), 6.700 + OPERATOR 222 <@ (epoint, ebox), 6.701 + OPERATOR 23 && (epoint, ecircle), 6.702 + OPERATOR 24 && (epoint, ecluster), 6.703 + OPERATOR 124 &&+ (epoint, ecluster), 6.704 + OPERATOR 224 <@ (epoint, ecluster), 6.705 + OPERATOR 31 <-> (epoint, epoint) FOR ORDER BY float_ops, 6.706 + OPERATOR 32 <-> (epoint, ebox) FOR ORDER BY float_ops, 6.707 + OPERATOR 33 <-> (epoint, ecircle) FOR ORDER BY float_ops, 6.708 + OPERATOR 34 <-> (epoint, ecluster) FOR ORDER BY float_ops, 6.709 + FUNCTION 1 pgl_gist_consistent(internal, internal, smallint, oid, internal), 6.710 + FUNCTION 2 pgl_gist_union(internal, internal), 6.711 + FUNCTION 3 pgl_gist_compress_epoint(internal), 6.712 + FUNCTION 4 pgl_gist_decompress(internal), 6.713 + FUNCTION 5 pgl_gist_penalty(internal, internal, internal), 6.714 + FUNCTION 6 pgl_gist_picksplit(internal, internal), 6.715 + FUNCTION 7 pgl_gist_same(internal, internal, internal), 6.716 + FUNCTION 8 pgl_gist_distance(internal, internal, smallint, oid), 6.717 + STORAGE ekey_point; 6.718 + 6.719 +CREATE OPERATOR CLASS ecircle_ops 6.720 + DEFAULT FOR TYPE ecircle USING gist AS 6.721 + OPERATOR 13 = , 6.722 + OPERATOR 21 && (ecircle, epoint), 6.723 + OPERATOR 22 && (ecircle, ebox), 6.724 + OPERATOR 122 &&+ (ecircle, ebox), 6.725 + OPERATOR 23 && (ecircle, ecircle), 6.726 + OPERATOR 24 && (ecircle, ecluster), 6.727 + OPERATOR 124 &&+ (ecircle, ecluster), 6.728 + OPERATOR 31 <-> (ecircle, epoint) FOR ORDER BY float_ops, 6.729 + OPERATOR 32 <-> (ecircle, ebox) FOR ORDER BY float_ops, 6.730 + OPERATOR 33 <-> (ecircle, ecircle) FOR ORDER BY float_ops, 6.731 + OPERATOR 34 <-> (ecircle, ecluster) FOR ORDER BY float_ops, 6.732 + FUNCTION 1 pgl_gist_consistent(internal, internal, smallint, oid, internal), 6.733 + FUNCTION 2 pgl_gist_union(internal, internal), 6.734 + FUNCTION 3 pgl_gist_compress_ecircle(internal), 6.735 + FUNCTION 4 pgl_gist_decompress(internal), 6.736 + FUNCTION 5 pgl_gist_penalty(internal, internal, internal), 6.737 + FUNCTION 6 pgl_gist_picksplit(internal, internal), 6.738 + FUNCTION 7 pgl_gist_same(internal, internal, internal), 6.739 + FUNCTION 8 pgl_gist_distance(internal, internal, smallint, oid), 6.740 + STORAGE ekey_area; 6.741 + 6.742 +CREATE OPERATOR CLASS ecluster_ops 6.743 + DEFAULT FOR TYPE ecluster USING gist AS 6.744 + OPERATOR 21 && (ecluster, epoint), 6.745 + OPERATOR 121 &&+ (ecluster, epoint), 6.746 + OPERATOR 221 @> (ecluster, epoint), 6.747 + OPERATOR 22 && (ecluster, ebox), 6.748 + OPERATOR 122 &&+ (ecluster, ebox), 6.749 + OPERATOR 222 @> (ecluster, ebox), 6.750 + OPERATOR 322 <@ (ecluster, ebox), 6.751 + OPERATOR 23 && (ecluster, ecircle), 6.752 + OPERATOR 123 &&+ (ecluster, ecircle), 6.753 + OPERATOR 24 && (ecluster, ecluster), 6.754 + OPERATOR 124 &&+ (ecluster, ecluster), 6.755 + OPERATOR 224 @> (ecluster, ecluster), 6.756 + OPERATOR 324 <@ (ecluster, ecluster), 6.757 + OPERATOR 31 <-> (ecluster, epoint) FOR ORDER BY float_ops, 6.758 + OPERATOR 32 <-> (ecluster, ebox) FOR ORDER BY float_ops, 6.759 + OPERATOR 33 <-> (ecluster, ecircle) FOR ORDER BY float_ops, 6.760 + OPERATOR 34 <-> (ecluster, ecluster) FOR ORDER BY float_ops, 6.761 + FUNCTION 1 pgl_gist_consistent(internal, internal, smallint, oid, internal), 6.762 + FUNCTION 2 pgl_gist_union(internal, internal), 6.763 + FUNCTION 3 pgl_gist_compress_ecluster(internal), 6.764 + FUNCTION 4 pgl_gist_decompress(internal), 6.765 + FUNCTION 5 pgl_gist_penalty(internal, internal, internal), 6.766 + FUNCTION 6 pgl_gist_picksplit(internal, internal), 6.767 + FUNCTION 7 pgl_gist_same(internal, internal, internal), 6.768 + FUNCTION 8 pgl_gist_distance(internal, internal, smallint, oid), 6.769 + STORAGE ekey_area; 6.770 +
7.1 --- a/latlon--0.3.sql Sat Sep 03 16:00:22 2016 +0200 7.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 7.3 @@ -1,1335 +0,0 @@ 7.4 - 7.5 ----------------------------------------- 7.6 --- forward declarations (shell types) -- 7.7 ----------------------------------------- 7.8 - 7.9 -CREATE TYPE epoint; 7.10 -CREATE TYPE ebox; 7.11 -CREATE TYPE ecircle; 7.12 -CREATE TYPE ecluster; 7.13 - 7.14 - 7.15 ------------------------------------------------------------- 7.16 --- dummy input/output functions for dummy index key types -- 7.17 ------------------------------------------------------------- 7.18 - 7.19 -CREATE FUNCTION ekey_point_in_dummy(cstring) 7.20 - RETURNS ekey_point 7.21 - LANGUAGE C IMMUTABLE STRICT 7.22 - AS '$libdir/latlon-v0003', 'pgl_notimpl'; 7.23 - 7.24 -CREATE FUNCTION ekey_point_out_dummy(ekey_point) 7.25 - RETURNS cstring 7.26 - LANGUAGE C IMMUTABLE STRICT 7.27 - AS '$libdir/latlon-v0003', 'pgl_notimpl'; 7.28 - 7.29 -CREATE FUNCTION ekey_area_in_dummy(cstring) 7.30 - RETURNS ekey_area 7.31 - LANGUAGE C IMMUTABLE STRICT 7.32 - AS '$libdir/latlon-v0003', 'pgl_notimpl'; 7.33 - 7.34 -CREATE FUNCTION ekey_area_out_dummy(ekey_area) 7.35 - RETURNS cstring 7.36 - LANGUAGE C IMMUTABLE STRICT 7.37 - AS '$libdir/latlon-v0003', 'pgl_notimpl'; 7.38 - 7.39 - 7.40 --------------------------- 7.41 --- text input functions -- 7.42 --------------------------- 7.43 - 7.44 -CREATE FUNCTION epoint_in(cstring) 7.45 - RETURNS epoint 7.46 - LANGUAGE C IMMUTABLE STRICT 7.47 - AS '$libdir/latlon-v0003', 'pgl_epoint_in'; 7.48 - 7.49 -CREATE FUNCTION ebox_in(cstring) 7.50 - RETURNS ebox 7.51 - LANGUAGE C IMMUTABLE STRICT 7.52 - AS '$libdir/latlon-v0003', 'pgl_ebox_in'; 7.53 - 7.54 -CREATE FUNCTION ecircle_in(cstring) 7.55 - RETURNS ecircle 7.56 - LANGUAGE C IMMUTABLE STRICT 7.57 - AS '$libdir/latlon-v0003', 'pgl_ecircle_in'; 7.58 - 7.59 -CREATE FUNCTION ecluster_in(cstring) 7.60 - RETURNS ecluster 7.61 - LANGUAGE C IMMUTABLE STRICT 7.62 - AS '$libdir/latlon-v0003', 'pgl_ecluster_in'; 7.63 - 7.64 - 7.65 ---------------------------- 7.66 --- text output functions -- 7.67 ---------------------------- 7.68 - 7.69 -CREATE FUNCTION epoint_out(epoint) 7.70 - RETURNS cstring 7.71 - LANGUAGE C IMMUTABLE STRICT 7.72 - AS '$libdir/latlon-v0003', 'pgl_epoint_out'; 7.73 - 7.74 -CREATE FUNCTION ebox_out(ebox) 7.75 - RETURNS cstring 7.76 - LANGUAGE C IMMUTABLE STRICT 7.77 - AS '$libdir/latlon-v0003', 'pgl_ebox_out'; 7.78 - 7.79 -CREATE FUNCTION ecircle_out(ecircle) 7.80 - RETURNS cstring 7.81 - LANGUAGE C IMMUTABLE STRICT 7.82 - AS '$libdir/latlon-v0003', 'pgl_ecircle_out'; 7.83 - 7.84 -CREATE FUNCTION ecluster_out(ecluster) 7.85 - RETURNS cstring 7.86 - LANGUAGE C IMMUTABLE STRICT 7.87 - AS '$libdir/latlon-v0003', 'pgl_ecluster_out'; 7.88 - 7.89 - 7.90 --------------------------- 7.91 --- binary I/O functions -- 7.92 --------------------------- 7.93 - 7.94 -CREATE FUNCTION epoint_recv(internal) 7.95 - RETURNS epoint 7.96 - LANGUAGE C IMMUTABLE STRICT 7.97 - AS '$libdir/latlon-v0003', 'pgl_epoint_recv'; 7.98 - 7.99 -CREATE FUNCTION ebox_recv(internal) 7.100 - RETURNS ebox 7.101 - LANGUAGE C IMMUTABLE STRICT 7.102 - AS '$libdir/latlon-v0003', 'pgl_ebox_recv'; 7.103 - 7.104 -CREATE FUNCTION ecircle_recv(internal) 7.105 - RETURNS ecircle 7.106 - LANGUAGE C IMMUTABLE STRICT 7.107 - AS '$libdir/latlon-v0003', 'pgl_ecircle_recv'; 7.108 - 7.109 -CREATE FUNCTION epoint_send(epoint) 7.110 - RETURNS bytea 7.111 - LANGUAGE C IMMUTABLE STRICT 7.112 - AS '$libdir/latlon-v0003', 'pgl_epoint_send'; 7.113 - 7.114 -CREATE FUNCTION ebox_send(ebox) 7.115 - RETURNS bytea 7.116 - LANGUAGE C IMMUTABLE STRICT 7.117 - AS '$libdir/latlon-v0003', 'pgl_ebox_send'; 7.118 - 7.119 -CREATE FUNCTION ecircle_send(ecircle) 7.120 - RETURNS bytea 7.121 - LANGUAGE C IMMUTABLE STRICT 7.122 - AS '$libdir/latlon-v0003', 'pgl_ecircle_send'; 7.123 - 7.124 - 7.125 ------------------------------------------------ 7.126 --- type definitions of dummy index key types -- 7.127 ------------------------------------------------ 7.128 - 7.129 -CREATE TYPE ekey_point ( 7.130 - internallength = 8, 7.131 - input = ekey_point_in_dummy, 7.132 - output = ekey_point_out_dummy, 7.133 - alignment = char ); 7.134 - 7.135 -CREATE TYPE ekey_area ( 7.136 - internallength = 9, 7.137 - input = ekey_area_in_dummy, 7.138 - output = ekey_area_out_dummy, 7.139 - alignment = char ); 7.140 - 7.141 - 7.142 ------------------------------------------- 7.143 --- definitions of geographic data types -- 7.144 ------------------------------------------- 7.145 - 7.146 -CREATE TYPE epoint ( 7.147 - internallength = 16, 7.148 - input = epoint_in, 7.149 - output = epoint_out, 7.150 - receive = epoint_recv, 7.151 - send = epoint_send, 7.152 - alignment = double ); 7.153 - 7.154 -CREATE TYPE ebox ( 7.155 - internallength = 32, 7.156 - input = ebox_in, 7.157 - output = ebox_out, 7.158 - receive = ebox_recv, 7.159 - send = ebox_send, 7.160 - alignment = double ); 7.161 - 7.162 -CREATE TYPE ecircle ( 7.163 - internallength = 24, 7.164 - input = ecircle_in, 7.165 - output = ecircle_out, 7.166 - receive = ecircle_recv, 7.167 - send = ecircle_send, 7.168 - alignment = double ); 7.169 - 7.170 -CREATE TYPE ecluster ( 7.171 - internallength = VARIABLE, 7.172 - input = ecluster_in, 7.173 - output = ecluster_out, 7.174 - alignment = double, 7.175 - storage = external ); 7.176 - 7.177 - 7.178 --------------------- 7.179 --- B-tree support -- 7.180 --------------------- 7.181 - 7.182 --- begin of B-tree support for epoint 7.183 - 7.184 -CREATE FUNCTION epoint_btree_lt(epoint, epoint) 7.185 - RETURNS boolean 7.186 - LANGUAGE C IMMUTABLE STRICT 7.187 - AS '$libdir/latlon-v0003', 'pgl_btree_epoint_lt'; 7.188 - 7.189 -CREATE FUNCTION epoint_btree_le(epoint, epoint) 7.190 - RETURNS boolean 7.191 - LANGUAGE C IMMUTABLE STRICT 7.192 - AS '$libdir/latlon-v0003', 'pgl_btree_epoint_le'; 7.193 - 7.194 -CREATE FUNCTION epoint_btree_eq(epoint, epoint) 7.195 - RETURNS boolean 7.196 - LANGUAGE C IMMUTABLE STRICT 7.197 - AS '$libdir/latlon-v0003', 'pgl_btree_epoint_eq'; 7.198 - 7.199 -CREATE FUNCTION epoint_btree_ne(epoint, epoint) 7.200 - RETURNS boolean 7.201 - LANGUAGE C IMMUTABLE STRICT 7.202 - AS '$libdir/latlon-v0003', 'pgl_btree_epoint_ne'; 7.203 - 7.204 -CREATE FUNCTION epoint_btree_ge(epoint, epoint) 7.205 - RETURNS boolean 7.206 - LANGUAGE C IMMUTABLE STRICT 7.207 - AS '$libdir/latlon-v0003', 'pgl_btree_epoint_ge'; 7.208 - 7.209 -CREATE FUNCTION epoint_btree_gt(epoint, epoint) 7.210 - RETURNS boolean 7.211 - LANGUAGE C IMMUTABLE STRICT 7.212 - AS '$libdir/latlon-v0003', 'pgl_btree_epoint_gt'; 7.213 - 7.214 -CREATE OPERATOR <<< ( 7.215 - leftarg = epoint, 7.216 - rightarg = epoint, 7.217 - procedure = epoint_btree_lt, 7.218 - commutator = >>>, 7.219 - negator = >>>=, 7.220 - restrict = scalarltsel, 7.221 - join = scalarltjoinsel 7.222 -); 7.223 - 7.224 -CREATE OPERATOR <<<= ( 7.225 - leftarg = epoint, 7.226 - rightarg = epoint, 7.227 - procedure = epoint_btree_le, 7.228 - commutator = >>>=, 7.229 - negator = >>>, 7.230 - restrict = scalarltsel, 7.231 - join = scalarltjoinsel 7.232 -); 7.233 - 7.234 -CREATE OPERATOR = ( 7.235 - leftarg = epoint, 7.236 - rightarg = epoint, 7.237 - procedure = epoint_btree_eq, 7.238 - commutator = =, 7.239 - negator = <>, 7.240 - restrict = eqsel, 7.241 - join = eqjoinsel, 7.242 - merges 7.243 -); 7.244 - 7.245 -CREATE OPERATOR <> ( 7.246 - leftarg = epoint, 7.247 - rightarg = epoint, 7.248 - procedure = epoint_btree_eq, 7.249 - commutator = <>, 7.250 - negator = =, 7.251 - restrict = neqsel, 7.252 - join = neqjoinsel 7.253 -); 7.254 - 7.255 -CREATE OPERATOR >>>= ( 7.256 - leftarg = epoint, 7.257 - rightarg = epoint, 7.258 - procedure = epoint_btree_ge, 7.259 - commutator = <<<=, 7.260 - negator = <<<, 7.261 - restrict = scalargtsel, 7.262 - join = scalargtjoinsel 7.263 -); 7.264 - 7.265 -CREATE OPERATOR >>> ( 7.266 - leftarg = epoint, 7.267 - rightarg = epoint, 7.268 - procedure = epoint_btree_gt, 7.269 - commutator = <<<, 7.270 - negator = <<<=, 7.271 - restrict = scalargtsel, 7.272 - join = scalargtjoinsel 7.273 -); 7.274 - 7.275 -CREATE FUNCTION epoint_btree_cmp(epoint, epoint) 7.276 - RETURNS int4 7.277 - LANGUAGE C IMMUTABLE STRICT 7.278 - AS '$libdir/latlon-v0003', 'pgl_btree_epoint_cmp'; 7.279 - 7.280 -CREATE OPERATOR CLASS epoint_btree_ops 7.281 - DEFAULT FOR TYPE epoint USING btree AS 7.282 - OPERATOR 1 <<< , 7.283 - OPERATOR 2 <<<= , 7.284 - OPERATOR 3 = , 7.285 - OPERATOR 4 >>>= , 7.286 - OPERATOR 5 >>> , 7.287 - FUNCTION 1 epoint_btree_cmp(epoint, epoint); 7.288 - 7.289 --- end of B-tree support for epoint 7.290 - 7.291 --- begin of B-tree support for ebox 7.292 - 7.293 -CREATE FUNCTION ebox_btree_lt(ebox, ebox) 7.294 - RETURNS boolean 7.295 - LANGUAGE C IMMUTABLE STRICT 7.296 - AS '$libdir/latlon-v0003', 'pgl_btree_ebox_lt'; 7.297 - 7.298 -CREATE FUNCTION ebox_btree_le(ebox, ebox) 7.299 - RETURNS boolean 7.300 - LANGUAGE C IMMUTABLE STRICT 7.301 - AS '$libdir/latlon-v0003', 'pgl_btree_ebox_le'; 7.302 - 7.303 -CREATE FUNCTION ebox_btree_eq(ebox, ebox) 7.304 - RETURNS boolean 7.305 - LANGUAGE C IMMUTABLE STRICT 7.306 - AS '$libdir/latlon-v0003', 'pgl_btree_ebox_eq'; 7.307 - 7.308 -CREATE FUNCTION ebox_btree_ne(ebox, ebox) 7.309 - RETURNS boolean 7.310 - LANGUAGE C IMMUTABLE STRICT 7.311 - AS '$libdir/latlon-v0003', 'pgl_btree_ebox_ne'; 7.312 - 7.313 -CREATE FUNCTION ebox_btree_ge(ebox, ebox) 7.314 - RETURNS boolean 7.315 - LANGUAGE C IMMUTABLE STRICT 7.316 - AS '$libdir/latlon-v0003', 'pgl_btree_ebox_ge'; 7.317 - 7.318 -CREATE FUNCTION ebox_btree_gt(ebox, ebox) 7.319 - RETURNS boolean 7.320 - LANGUAGE C IMMUTABLE STRICT 7.321 - AS '$libdir/latlon-v0003', 'pgl_btree_ebox_gt'; 7.322 - 7.323 -CREATE OPERATOR <<< ( 7.324 - leftarg = ebox, 7.325 - rightarg = ebox, 7.326 - procedure = ebox_btree_lt, 7.327 - commutator = >>>, 7.328 - negator = >>>=, 7.329 - restrict = scalarltsel, 7.330 - join = scalarltjoinsel 7.331 -); 7.332 - 7.333 -CREATE OPERATOR <<<= ( 7.334 - leftarg = ebox, 7.335 - rightarg = ebox, 7.336 - procedure = ebox_btree_le, 7.337 - commutator = >>>=, 7.338 - negator = >>>, 7.339 - restrict = scalarltsel, 7.340 - join = scalarltjoinsel 7.341 -); 7.342 - 7.343 -CREATE OPERATOR = ( 7.344 - leftarg = ebox, 7.345 - rightarg = ebox, 7.346 - procedure = ebox_btree_eq, 7.347 - commutator = =, 7.348 - negator = <>, 7.349 - restrict = eqsel, 7.350 - join = eqjoinsel, 7.351 - merges 7.352 -); 7.353 - 7.354 -CREATE OPERATOR <> ( 7.355 - leftarg = ebox, 7.356 - rightarg = ebox, 7.357 - procedure = ebox_btree_eq, 7.358 - commutator = <>, 7.359 - negator = =, 7.360 - restrict = neqsel, 7.361 - join = neqjoinsel 7.362 -); 7.363 - 7.364 -CREATE OPERATOR >>>= ( 7.365 - leftarg = ebox, 7.366 - rightarg = ebox, 7.367 - procedure = ebox_btree_ge, 7.368 - commutator = <<<=, 7.369 - negator = <<<, 7.370 - restrict = scalargtsel, 7.371 - join = scalargtjoinsel 7.372 -); 7.373 - 7.374 -CREATE OPERATOR >>> ( 7.375 - leftarg = ebox, 7.376 - rightarg = ebox, 7.377 - procedure = ebox_btree_gt, 7.378 - commutator = <<<, 7.379 - negator = <<<=, 7.380 - restrict = scalargtsel, 7.381 - join = scalargtjoinsel 7.382 -); 7.383 - 7.384 -CREATE FUNCTION ebox_btree_cmp(ebox, ebox) 7.385 - RETURNS int4 7.386 - LANGUAGE C IMMUTABLE STRICT 7.387 - AS '$libdir/latlon-v0003', 'pgl_btree_ebox_cmp'; 7.388 - 7.389 -CREATE OPERATOR CLASS ebox_btree_ops 7.390 - DEFAULT FOR TYPE ebox USING btree AS 7.391 - OPERATOR 1 <<< , 7.392 - OPERATOR 2 <<<= , 7.393 - OPERATOR 3 = , 7.394 - OPERATOR 4 >>>= , 7.395 - OPERATOR 5 >>> , 7.396 - FUNCTION 1 ebox_btree_cmp(ebox, ebox); 7.397 - 7.398 --- end of B-tree support for ebox 7.399 - 7.400 --- begin of B-tree support for ecircle 7.401 - 7.402 -CREATE FUNCTION ecircle_btree_lt(ecircle, ecircle) 7.403 - RETURNS boolean 7.404 - LANGUAGE C IMMUTABLE STRICT 7.405 - AS '$libdir/latlon-v0003', 'pgl_btree_ecircle_lt'; 7.406 - 7.407 -CREATE FUNCTION ecircle_btree_le(ecircle, ecircle) 7.408 - RETURNS boolean 7.409 - LANGUAGE C IMMUTABLE STRICT 7.410 - AS '$libdir/latlon-v0003', 'pgl_btree_ecircle_le'; 7.411 - 7.412 -CREATE FUNCTION ecircle_btree_eq(ecircle, ecircle) 7.413 - RETURNS boolean 7.414 - LANGUAGE C IMMUTABLE STRICT 7.415 - AS '$libdir/latlon-v0003', 'pgl_btree_ecircle_eq'; 7.416 - 7.417 -CREATE FUNCTION ecircle_btree_ne(ecircle, ecircle) 7.418 - RETURNS boolean 7.419 - LANGUAGE C IMMUTABLE STRICT 7.420 - AS '$libdir/latlon-v0003', 'pgl_btree_ecircle_ne'; 7.421 - 7.422 -CREATE FUNCTION ecircle_btree_ge(ecircle, ecircle) 7.423 - RETURNS boolean 7.424 - LANGUAGE C IMMUTABLE STRICT 7.425 - AS '$libdir/latlon-v0003', 'pgl_btree_ecircle_ge'; 7.426 - 7.427 -CREATE FUNCTION ecircle_btree_gt(ecircle, ecircle) 7.428 - RETURNS boolean 7.429 - LANGUAGE C IMMUTABLE STRICT 7.430 - AS '$libdir/latlon-v0003', 'pgl_btree_ecircle_gt'; 7.431 - 7.432 -CREATE OPERATOR <<< ( 7.433 - leftarg = ecircle, 7.434 - rightarg = ecircle, 7.435 - procedure = ecircle_btree_lt, 7.436 - commutator = >>>, 7.437 - negator = >>>=, 7.438 - restrict = scalarltsel, 7.439 - join = scalarltjoinsel 7.440 -); 7.441 - 7.442 -CREATE OPERATOR <<<= ( 7.443 - leftarg = ecircle, 7.444 - rightarg = ecircle, 7.445 - procedure = ecircle_btree_le, 7.446 - commutator = >>>=, 7.447 - negator = >>>, 7.448 - restrict = scalarltsel, 7.449 - join = scalarltjoinsel 7.450 -); 7.451 - 7.452 -CREATE OPERATOR = ( 7.453 - leftarg = ecircle, 7.454 - rightarg = ecircle, 7.455 - procedure = ecircle_btree_eq, 7.456 - commutator = =, 7.457 - negator = <>, 7.458 - restrict = eqsel, 7.459 - join = eqjoinsel, 7.460 - merges 7.461 -); 7.462 - 7.463 -CREATE OPERATOR <> ( 7.464 - leftarg = ecircle, 7.465 - rightarg = ecircle, 7.466 - procedure = ecircle_btree_eq, 7.467 - commutator = <>, 7.468 - negator = =, 7.469 - restrict = neqsel, 7.470 - join = neqjoinsel 7.471 -); 7.472 - 7.473 -CREATE OPERATOR >>>= ( 7.474 - leftarg = ecircle, 7.475 - rightarg = ecircle, 7.476 - procedure = ecircle_btree_ge, 7.477 - commutator = <<<=, 7.478 - negator = <<<, 7.479 - restrict = scalargtsel, 7.480 - join = scalargtjoinsel 7.481 -); 7.482 - 7.483 -CREATE OPERATOR >>> ( 7.484 - leftarg = ecircle, 7.485 - rightarg = ecircle, 7.486 - procedure = ecircle_btree_gt, 7.487 - commutator = <<<, 7.488 - negator = <<<=, 7.489 - restrict = scalargtsel, 7.490 - join = scalargtjoinsel 7.491 -); 7.492 - 7.493 -CREATE FUNCTION ecircle_btree_cmp(ecircle, ecircle) 7.494 - RETURNS int4 7.495 - LANGUAGE C IMMUTABLE STRICT 7.496 - AS '$libdir/latlon-v0003', 'pgl_btree_ecircle_cmp'; 7.497 - 7.498 -CREATE OPERATOR CLASS ecircle_btree_ops 7.499 - DEFAULT FOR TYPE ecircle USING btree AS 7.500 - OPERATOR 1 <<< , 7.501 - OPERATOR 2 <<<= , 7.502 - OPERATOR 3 = , 7.503 - OPERATOR 4 >>>= , 7.504 - OPERATOR 5 >>> , 7.505 - FUNCTION 1 ecircle_btree_cmp(ecircle, ecircle); 7.506 - 7.507 --- end of B-tree support for ecircle 7.508 - 7.509 - 7.510 ----------------- 7.511 --- type casts -- 7.512 ----------------- 7.513 - 7.514 -CREATE FUNCTION cast_epoint_to_ebox(epoint) 7.515 - RETURNS ebox 7.516 - LANGUAGE C IMMUTABLE STRICT 7.517 - AS '$libdir/latlon-v0003', 'pgl_epoint_to_ebox'; 7.518 - 7.519 -CREATE CAST (epoint AS ebox) WITH FUNCTION cast_epoint_to_ebox(epoint); 7.520 - 7.521 -CREATE FUNCTION cast_epoint_to_ecircle(epoint) 7.522 - RETURNS ecircle 7.523 - LANGUAGE C IMMUTABLE STRICT 7.524 - AS '$libdir/latlon-v0003', 'pgl_epoint_to_ecircle'; 7.525 - 7.526 -CREATE CAST (epoint AS ecircle) WITH FUNCTION cast_epoint_to_ecircle(epoint); 7.527 - 7.528 -CREATE FUNCTION cast_epoint_to_ecluster(epoint) 7.529 - RETURNS ecluster 7.530 - LANGUAGE C IMMUTABLE STRICT 7.531 - AS '$libdir/latlon-v0003', 'pgl_epoint_to_ecluster'; 7.532 - 7.533 -CREATE CAST (epoint AS ecluster) WITH FUNCTION cast_epoint_to_ecluster(epoint); 7.534 - 7.535 -CREATE FUNCTION cast_ebox_to_ecluster(ebox) 7.536 - RETURNS ecluster 7.537 - LANGUAGE C IMMUTABLE STRICT 7.538 - AS '$libdir/latlon-v0003', 'pgl_ebox_to_ecluster'; 7.539 - 7.540 -CREATE CAST (ebox AS ecluster) WITH FUNCTION cast_ebox_to_ecluster(ebox); 7.541 - 7.542 - 7.543 ---------------------------- 7.544 --- constructor functions -- 7.545 ---------------------------- 7.546 - 7.547 -CREATE FUNCTION epoint(float8, float8) 7.548 - RETURNS epoint 7.549 - LANGUAGE C IMMUTABLE STRICT 7.550 - AS '$libdir/latlon-v0003', 'pgl_create_epoint'; 7.551 - 7.552 -CREATE FUNCTION epoint_latlon(float8, float8) 7.553 - RETURNS epoint 7.554 - LANGUAGE SQL IMMUTABLE STRICT AS $$ 7.555 - SELECT epoint($1, $2) 7.556 - $$; 7.557 - 7.558 -CREATE FUNCTION epoint_lonlat(float8, float8) 7.559 - RETURNS epoint 7.560 - LANGUAGE SQL IMMUTABLE STRICT AS $$ 7.561 - SELECT epoint($2, $1) 7.562 - $$; 7.563 - 7.564 -CREATE FUNCTION empty_ebox() 7.565 - RETURNS ebox 7.566 - LANGUAGE C IMMUTABLE STRICT 7.567 - AS '$libdir/latlon-v0003', 'pgl_create_empty_ebox'; 7.568 - 7.569 -CREATE FUNCTION ebox(float8, float8, float8, float8) 7.570 - RETURNS ebox 7.571 - LANGUAGE C IMMUTABLE STRICT 7.572 - AS '$libdir/latlon-v0003', 'pgl_create_ebox'; 7.573 - 7.574 -CREATE FUNCTION ebox(epoint, epoint) 7.575 - RETURNS ebox 7.576 - LANGUAGE C IMMUTABLE STRICT 7.577 - AS '$libdir/latlon-v0003', 'pgl_create_ebox_from_epoints'; 7.578 - 7.579 -CREATE FUNCTION ecircle(float8, float8, float8) 7.580 - RETURNS ecircle 7.581 - LANGUAGE C IMMUTABLE STRICT 7.582 - AS '$libdir/latlon-v0003', 'pgl_create_ecircle'; 7.583 - 7.584 -CREATE FUNCTION ecircle(epoint, float8) 7.585 - RETURNS ecircle 7.586 - LANGUAGE C IMMUTABLE STRICT 7.587 - AS '$libdir/latlon-v0003', 'pgl_create_ecircle_from_epoint'; 7.588 - 7.589 -CREATE FUNCTION ecluster_concat(ecluster[]) 7.590 - RETURNS ecluster 7.591 - LANGUAGE sql IMMUTABLE STRICT AS $$ 7.592 - SELECT array_to_string($1, ' ')::ecluster 7.593 - $$; 7.594 - 7.595 -CREATE FUNCTION ecluster_concat(ecluster, ecluster) 7.596 - RETURNS ecluster 7.597 - LANGUAGE sql IMMUTABLE STRICT AS $$ 7.598 - SELECT ($1::text || ' ' || $2::text)::ecluster 7.599 - $$; 7.600 - 7.601 -CREATE FUNCTION ecluster_create_multipoint(epoint[]) 7.602 - RETURNS ecluster 7.603 - LANGUAGE sql IMMUTABLE STRICT AS $$ 7.604 - SELECT 7.605 - array_to_string(array_agg('point (' || unnest || ')'), ' ')::ecluster 7.606 - FROM unnest($1) 7.607 - $$; 7.608 - 7.609 -CREATE FUNCTION ecluster_create_path(epoint[]) 7.610 - RETURNS ecluster 7.611 - LANGUAGE sql IMMUTABLE STRICT AS $$ 7.612 - SELECT CASE WHEN "str" = '' THEN 'empty'::ecluster ELSE 7.613 - ('path (' || array_to_string($1, ' ') || ')')::ecluster 7.614 - END 7.615 - FROM array_to_string($1, ' ') AS "str" 7.616 - $$; 7.617 - 7.618 -CREATE FUNCTION ecluster_create_outline(epoint[]) 7.619 - RETURNS ecluster 7.620 - LANGUAGE sql IMMUTABLE STRICT AS $$ 7.621 - SELECT CASE WHEN "str" = '' THEN 'empty'::ecluster ELSE 7.622 - ('outline (' || array_to_string($1, ' ') || ')')::ecluster 7.623 - END 7.624 - FROM array_to_string($1, ' ') AS "str" 7.625 - $$; 7.626 - 7.627 -CREATE FUNCTION ecluster_create_polygon(epoint[]) 7.628 - RETURNS ecluster 7.629 - LANGUAGE sql IMMUTABLE STRICT AS $$ 7.630 - SELECT CASE WHEN "str" = '' THEN 'empty'::ecluster ELSE 7.631 - ('polygon (' || array_to_string($1, ' ') || ')')::ecluster 7.632 - END 7.633 - FROM array_to_string($1, ' ') AS "str" 7.634 - $$; 7.635 - 7.636 - 7.637 ----------------------- 7.638 --- getter functions -- 7.639 ----------------------- 7.640 - 7.641 -CREATE FUNCTION latitude(epoint) 7.642 - RETURNS float8 7.643 - LANGUAGE C IMMUTABLE STRICT 7.644 - AS '$libdir/latlon-v0003', 'pgl_epoint_lat'; 7.645 - 7.646 -CREATE FUNCTION longitude(epoint) 7.647 - RETURNS float8 7.648 - LANGUAGE C IMMUTABLE STRICT 7.649 - AS '$libdir/latlon-v0003', 'pgl_epoint_lon'; 7.650 - 7.651 -CREATE FUNCTION min_latitude(ebox) 7.652 - RETURNS float8 7.653 - LANGUAGE C IMMUTABLE STRICT 7.654 - AS '$libdir/latlon-v0003', 'pgl_ebox_lat_min'; 7.655 - 7.656 -CREATE FUNCTION max_latitude(ebox) 7.657 - RETURNS float8 7.658 - LANGUAGE C IMMUTABLE STRICT 7.659 - AS '$libdir/latlon-v0003', 'pgl_ebox_lat_max'; 7.660 - 7.661 -CREATE FUNCTION min_longitude(ebox) 7.662 - RETURNS float8 7.663 - LANGUAGE C IMMUTABLE STRICT 7.664 - AS '$libdir/latlon-v0003', 'pgl_ebox_lon_min'; 7.665 - 7.666 -CREATE FUNCTION max_longitude(ebox) 7.667 - RETURNS float8 7.668 - LANGUAGE C IMMUTABLE STRICT 7.669 - AS '$libdir/latlon-v0003', 'pgl_ebox_lon_max'; 7.670 - 7.671 -CREATE FUNCTION center(ecircle) 7.672 - RETURNS epoint 7.673 - LANGUAGE C IMMUTABLE STRICT 7.674 - AS '$libdir/latlon-v0003', 'pgl_ecircle_center'; 7.675 - 7.676 -CREATE FUNCTION radius(ecircle) 7.677 - RETURNS float8 7.678 - LANGUAGE C IMMUTABLE STRICT 7.679 - AS '$libdir/latlon-v0003', 'pgl_ecircle_radius'; 7.680 - 7.681 -CREATE FUNCTION ecluster_extract_points(ecluster) 7.682 - RETURNS SETOF epoint 7.683 - LANGUAGE sql IMMUTABLE STRICT AS $$ 7.684 - SELECT "match"[2]::epoint 7.685 - FROM regexp_matches($1::text, e'(^| )point \\(([^)]+)\\)', 'g') AS "match" 7.686 - $$; 7.687 - 7.688 -CREATE FUNCTION ecluster_extract_paths(ecluster) 7.689 - RETURNS SETOF epoint[] 7.690 - LANGUAGE sql IMMUTABLE STRICT AS $$ 7.691 - SELECT ( 7.692 - SELECT array_agg("m2"[1]::epoint) 7.693 - FROM regexp_matches("m1"[2], e'[^ ]+ [^ ]+', 'g') AS "m2" 7.694 - ) 7.695 - FROM regexp_matches($1::text, e'(^| )path \\(([^)]+)\\)', 'g') AS "m1" 7.696 - $$; 7.697 - 7.698 -CREATE FUNCTION ecluster_extract_outlines(ecluster) 7.699 - RETURNS SETOF epoint[] 7.700 - LANGUAGE sql IMMUTABLE STRICT AS $$ 7.701 - SELECT ( 7.702 - SELECT array_agg("m2"[1]::epoint) 7.703 - FROM regexp_matches("m1"[2], e'[^ ]+ [^ ]+', 'g') AS "m2" 7.704 - ) 7.705 - FROM regexp_matches($1::text, e'(^| )outline \\(([^)]+)\\)', 'g') AS "m1" 7.706 - $$; 7.707 - 7.708 -CREATE FUNCTION ecluster_extract_polygons(ecluster) 7.709 - RETURNS SETOF epoint[] 7.710 - LANGUAGE sql IMMUTABLE STRICT AS $$ 7.711 - SELECT ( 7.712 - SELECT array_agg("m2"[1]::epoint) 7.713 - FROM regexp_matches("m1"[2], e'[^ ]+ [^ ]+', 'g') AS "m2" 7.714 - ) 7.715 - FROM regexp_matches($1::text, e'(^| )polygon \\(([^)]+)\\)', 'g') AS "m1" 7.716 - $$; 7.717 - 7.718 - 7.719 ---------------- 7.720 --- operators -- 7.721 ---------------- 7.722 - 7.723 -CREATE FUNCTION epoint_ebox_overlap_proc(epoint, ebox) 7.724 - RETURNS boolean 7.725 - LANGUAGE C IMMUTABLE STRICT 7.726 - AS '$libdir/latlon-v0003', 'pgl_epoint_ebox_overlap'; 7.727 - 7.728 -CREATE FUNCTION epoint_ecircle_overlap_proc(epoint, ecircle) 7.729 - RETURNS boolean 7.730 - LANGUAGE C IMMUTABLE STRICT 7.731 - AS '$libdir/latlon-v0003', 'pgl_epoint_ecircle_overlap'; 7.732 - 7.733 -CREATE FUNCTION epoint_ecluster_overlap_proc(epoint, ecluster) 7.734 - RETURNS boolean 7.735 - LANGUAGE C IMMUTABLE STRICT 7.736 - AS '$libdir/latlon-v0003', 'pgl_epoint_ecluster_overlap'; 7.737 - 7.738 -CREATE FUNCTION epoint_ecluster_may_overlap_proc(epoint, ecluster) 7.739 - RETURNS boolean 7.740 - LANGUAGE C IMMUTABLE STRICT 7.741 - AS '$libdir/latlon-v0003', 'pgl_epoint_ecluster_may_overlap'; 7.742 - 7.743 -CREATE FUNCTION ebox_overlap_proc(ebox, ebox) 7.744 - RETURNS boolean 7.745 - LANGUAGE C IMMUTABLE STRICT 7.746 - AS '$libdir/latlon-v0003', 'pgl_ebox_overlap'; 7.747 - 7.748 -CREATE FUNCTION ebox_ecircle_may_overlap_proc(ebox, ecircle) 7.749 - RETURNS boolean 7.750 - LANGUAGE C IMMUTABLE STRICT 7.751 - AS '$libdir/latlon-v0003', 'pgl_ebox_ecircle_may_overlap'; 7.752 - 7.753 -CREATE FUNCTION ebox_ecluster_may_overlap_proc(ebox, ecluster) 7.754 - RETURNS boolean 7.755 - LANGUAGE C IMMUTABLE STRICT 7.756 - AS '$libdir/latlon-v0003', 'pgl_ebox_ecluster_may_overlap'; 7.757 - 7.758 -CREATE FUNCTION ecircle_overlap_proc(ecircle, ecircle) 7.759 - RETURNS boolean 7.760 - LANGUAGE C IMMUTABLE STRICT 7.761 - AS '$libdir/latlon-v0003', 'pgl_ecircle_overlap'; 7.762 - 7.763 -CREATE FUNCTION ecircle_ecluster_overlap_proc(ecircle, ecluster) 7.764 - RETURNS boolean 7.765 - LANGUAGE C IMMUTABLE STRICT 7.766 - AS '$libdir/latlon-v0003', 'pgl_ecircle_ecluster_overlap'; 7.767 - 7.768 -CREATE FUNCTION ecircle_ecluster_may_overlap_proc(ecircle, ecluster) 7.769 - RETURNS boolean 7.770 - LANGUAGE C IMMUTABLE STRICT 7.771 - AS '$libdir/latlon-v0003', 'pgl_ecircle_ecluster_may_overlap'; 7.772 - 7.773 -CREATE FUNCTION ecluster_may_overlap_proc(ecluster, ecluster) 7.774 - RETURNS boolean 7.775 - LANGUAGE C IMMUTABLE STRICT 7.776 - AS '$libdir/latlon-v0003', 'pgl_ecluster_may_overlap'; 7.777 - 7.778 -CREATE FUNCTION epoint_distance_proc(epoint, epoint) 7.779 - RETURNS float8 7.780 - LANGUAGE C IMMUTABLE STRICT 7.781 - AS '$libdir/latlon-v0003', 'pgl_epoint_distance'; 7.782 - 7.783 -CREATE FUNCTION epoint_ecircle_distance_proc(epoint, ecircle) 7.784 - RETURNS float8 7.785 - LANGUAGE C IMMUTABLE STRICT 7.786 - AS '$libdir/latlon-v0003', 'pgl_epoint_ecircle_distance'; 7.787 - 7.788 -CREATE FUNCTION epoint_ecluster_distance_proc(epoint, ecluster) 7.789 - RETURNS float8 7.790 - LANGUAGE C IMMUTABLE STRICT 7.791 - AS '$libdir/latlon-v0003', 'pgl_epoint_ecluster_distance'; 7.792 - 7.793 -CREATE FUNCTION ecircle_distance_proc(ecircle, ecircle) 7.794 - RETURNS float8 7.795 - LANGUAGE C IMMUTABLE STRICT 7.796 - AS '$libdir/latlon-v0003', 'pgl_ecircle_distance'; 7.797 - 7.798 -CREATE FUNCTION ecircle_ecluster_distance_proc(ecircle, ecluster) 7.799 - RETURNS float8 7.800 - LANGUAGE C IMMUTABLE STRICT 7.801 - AS '$libdir/latlon-v0003', 'pgl_ecircle_ecluster_distance'; 7.802 - 7.803 -CREATE OPERATOR && ( 7.804 - leftarg = epoint, 7.805 - rightarg = ebox, 7.806 - procedure = epoint_ebox_overlap_proc, 7.807 - commutator = &&, 7.808 - restrict = areasel, 7.809 - join = areajoinsel 7.810 -); 7.811 - 7.812 -CREATE FUNCTION epoint_ebox_overlap_commutator(ebox, epoint) 7.813 - RETURNS boolean 7.814 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 && $1'; 7.815 - 7.816 -CREATE OPERATOR && ( 7.817 - leftarg = ebox, 7.818 - rightarg = epoint, 7.819 - procedure = epoint_ebox_overlap_commutator, 7.820 - commutator = &&, 7.821 - restrict = areasel, 7.822 - join = areajoinsel 7.823 -); 7.824 - 7.825 -CREATE OPERATOR && ( 7.826 - leftarg = epoint, 7.827 - rightarg = ecircle, 7.828 - procedure = epoint_ecircle_overlap_proc, 7.829 - commutator = &&, 7.830 - restrict = areasel, 7.831 - join = areajoinsel 7.832 -); 7.833 - 7.834 -CREATE FUNCTION epoint_ecircle_overlap_commutator(ecircle, epoint) 7.835 - RETURNS boolean 7.836 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 && $1'; 7.837 - 7.838 -CREATE OPERATOR && ( 7.839 - leftarg = ecircle, 7.840 - rightarg = epoint, 7.841 - procedure = epoint_ecircle_overlap_commutator, 7.842 - commutator = &&, 7.843 - restrict = areasel, 7.844 - join = areajoinsel 7.845 -); 7.846 - 7.847 -CREATE OPERATOR && ( 7.848 - leftarg = epoint, 7.849 - rightarg = ecluster, 7.850 - procedure = epoint_ecluster_overlap_proc, 7.851 - commutator = &&, 7.852 - restrict = areasel, 7.853 - join = areajoinsel 7.854 -); 7.855 - 7.856 -CREATE FUNCTION epoint_ecluster_overlap_commutator(ecluster, epoint) 7.857 - RETURNS boolean 7.858 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 && $1'; 7.859 - 7.860 -CREATE OPERATOR && ( 7.861 - leftarg = ecluster, 7.862 - rightarg = epoint, 7.863 - procedure = epoint_ecluster_overlap_commutator, 7.864 - commutator = &&, 7.865 - restrict = areasel, 7.866 - join = areajoinsel 7.867 -); 7.868 - 7.869 -CREATE OPERATOR && ( 7.870 - leftarg = ebox, 7.871 - rightarg = ebox, 7.872 - procedure = ebox_overlap_proc, 7.873 - commutator = &&, 7.874 - restrict = areasel, 7.875 - join = areajoinsel 7.876 -); 7.877 - 7.878 -CREATE OPERATOR && ( 7.879 - leftarg = ecircle, 7.880 - rightarg = ecircle, 7.881 - procedure = ecircle_overlap_proc, 7.882 - commutator = &&, 7.883 - restrict = areasel, 7.884 - join = areajoinsel 7.885 -); 7.886 - 7.887 -CREATE OPERATOR && ( 7.888 - leftarg = ecircle, 7.889 - rightarg = ecluster, 7.890 - procedure = ecircle_ecluster_overlap_proc, 7.891 - commutator = &&, 7.892 - restrict = areasel, 7.893 - join = areajoinsel 7.894 -); 7.895 - 7.896 -CREATE FUNCTION ecircle_ecluster_overlap_commutator(ecluster, ecircle) 7.897 - RETURNS boolean 7.898 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 && $1'; 7.899 - 7.900 -CREATE OPERATOR && ( 7.901 - leftarg = ecluster, 7.902 - rightarg = ecircle, 7.903 - procedure = ecircle_ecluster_overlap_commutator, 7.904 - commutator = &&, 7.905 - restrict = areasel, 7.906 - join = areajoinsel 7.907 -); 7.908 - 7.909 -CREATE OPERATOR &&+ ( 7.910 - leftarg = epoint, 7.911 - rightarg = ecluster, 7.912 - procedure = epoint_ecluster_may_overlap_proc, 7.913 - commutator = &&+, 7.914 - restrict = areasel, 7.915 - join = areajoinsel 7.916 -); 7.917 - 7.918 -CREATE FUNCTION epoint_ecluster_may_overlap_commutator(ecluster, epoint) 7.919 - RETURNS boolean 7.920 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 &&+ $1'; 7.921 - 7.922 -CREATE OPERATOR &&+ ( 7.923 - leftarg = ecluster, 7.924 - rightarg = epoint, 7.925 - procedure = epoint_ecluster_may_overlap_commutator, 7.926 - commutator = &&+, 7.927 - restrict = areasel, 7.928 - join = areajoinsel 7.929 -); 7.930 - 7.931 -CREATE OPERATOR &&+ ( 7.932 - leftarg = ebox, 7.933 - rightarg = ecircle, 7.934 - procedure = ebox_ecircle_may_overlap_proc, 7.935 - commutator = &&+, 7.936 - restrict = areasel, 7.937 - join = areajoinsel 7.938 -); 7.939 - 7.940 -CREATE FUNCTION ebox_ecircle_may_overlap_commutator(ecircle, ebox) 7.941 - RETURNS boolean 7.942 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 &&+ $1'; 7.943 - 7.944 -CREATE OPERATOR &&+ ( 7.945 - leftarg = ecircle, 7.946 - rightarg = ebox, 7.947 - procedure = ebox_ecircle_may_overlap_commutator, 7.948 - commutator = &&+, 7.949 - restrict = areasel, 7.950 - join = areajoinsel 7.951 -); 7.952 - 7.953 -CREATE OPERATOR &&+ ( 7.954 - leftarg = ebox, 7.955 - rightarg = ecluster, 7.956 - procedure = ebox_ecluster_may_overlap_proc, 7.957 - commutator = &&+, 7.958 - restrict = areasel, 7.959 - join = areajoinsel 7.960 -); 7.961 - 7.962 -CREATE FUNCTION ebox_ecluster_may_overlap_commutator(ecluster, ebox) 7.963 - RETURNS boolean 7.964 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 &&+ $1'; 7.965 - 7.966 -CREATE OPERATOR &&+ ( 7.967 - leftarg = ecluster, 7.968 - rightarg = ebox, 7.969 - procedure = ebox_ecluster_may_overlap_commutator, 7.970 - commutator = &&+, 7.971 - restrict = areasel, 7.972 - join = areajoinsel 7.973 -); 7.974 - 7.975 -CREATE OPERATOR &&+ ( 7.976 - leftarg = ecircle, 7.977 - rightarg = ecluster, 7.978 - procedure = ecircle_ecluster_may_overlap_proc, 7.979 - commutator = &&+, 7.980 - restrict = areasel, 7.981 - join = areajoinsel 7.982 -); 7.983 - 7.984 -CREATE FUNCTION ecircle_ecluster_may_overlap_commutator(ecluster, ecircle) 7.985 - RETURNS boolean 7.986 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 &&+ $1'; 7.987 - 7.988 -CREATE OPERATOR &&+ ( 7.989 - leftarg = ecluster, 7.990 - rightarg = ecircle, 7.991 - procedure = ecircle_ecluster_may_overlap_commutator, 7.992 - commutator = &&+, 7.993 - restrict = areasel, 7.994 - join = areajoinsel 7.995 -); 7.996 - 7.997 -CREATE OPERATOR &&+ ( 7.998 - leftarg = ecluster, 7.999 - rightarg = ecluster, 7.1000 - procedure = ecluster_may_overlap_proc, 7.1001 - commutator = &&+, 7.1002 - restrict = areasel, 7.1003 - join = areajoinsel 7.1004 -); 7.1005 - 7.1006 -CREATE OPERATOR <-> ( 7.1007 - leftarg = epoint, 7.1008 - rightarg = epoint, 7.1009 - procedure = epoint_distance_proc, 7.1010 - commutator = <-> 7.1011 -); 7.1012 - 7.1013 -CREATE OPERATOR <-> ( 7.1014 - leftarg = epoint, 7.1015 - rightarg = ecircle, 7.1016 - procedure = epoint_ecircle_distance_proc, 7.1017 - commutator = <-> 7.1018 -); 7.1019 - 7.1020 -CREATE FUNCTION epoint_ecircle_distance_commutator(ecircle, epoint) 7.1021 - RETURNS float8 7.1022 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 <-> $1'; 7.1023 - 7.1024 -CREATE OPERATOR <-> ( 7.1025 - leftarg = ecircle, 7.1026 - rightarg = epoint, 7.1027 - procedure = epoint_ecircle_distance_commutator, 7.1028 - commutator = <-> 7.1029 -); 7.1030 - 7.1031 -CREATE OPERATOR <-> ( 7.1032 - leftarg = epoint, 7.1033 - rightarg = ecluster, 7.1034 - procedure = epoint_ecluster_distance_proc, 7.1035 - commutator = <-> 7.1036 -); 7.1037 - 7.1038 -CREATE FUNCTION epoint_ecluster_distance_commutator(ecluster, epoint) 7.1039 - RETURNS float8 7.1040 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 <-> $1'; 7.1041 - 7.1042 -CREATE OPERATOR <-> ( 7.1043 - leftarg = ecluster, 7.1044 - rightarg = epoint, 7.1045 - procedure = epoint_ecluster_distance_commutator, 7.1046 - commutator = <-> 7.1047 -); 7.1048 - 7.1049 -CREATE OPERATOR <-> ( 7.1050 - leftarg = ecircle, 7.1051 - rightarg = ecircle, 7.1052 - procedure = ecircle_distance_proc, 7.1053 - commutator = <-> 7.1054 -); 7.1055 - 7.1056 -CREATE OPERATOR <-> ( 7.1057 - leftarg = ecircle, 7.1058 - rightarg = ecluster, 7.1059 - procedure = ecircle_ecluster_distance_proc, 7.1060 - commutator = <-> 7.1061 -); 7.1062 - 7.1063 -CREATE FUNCTION ecircle_ecluster_distance_commutator(ecluster, ecircle) 7.1064 - RETURNS float8 7.1065 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 <-> $1'; 7.1066 - 7.1067 -CREATE OPERATOR <-> ( 7.1068 - leftarg = ecluster, 7.1069 - rightarg = ecircle, 7.1070 - procedure = ecircle_ecluster_distance_commutator, 7.1071 - commutator = <-> 7.1072 -); 7.1073 - 7.1074 - 7.1075 ----------------- 7.1076 --- GiST index -- 7.1077 ----------------- 7.1078 - 7.1079 -CREATE FUNCTION pgl_gist_consistent(internal, internal, smallint, oid, internal) 7.1080 - RETURNS boolean 7.1081 - LANGUAGE C STRICT 7.1082 - AS '$libdir/latlon-v0003', 'pgl_gist_consistent'; 7.1083 - 7.1084 -CREATE FUNCTION pgl_gist_union(internal, internal) 7.1085 - RETURNS internal 7.1086 - LANGUAGE C STRICT 7.1087 - AS '$libdir/latlon-v0003', 'pgl_gist_union'; 7.1088 - 7.1089 -CREATE FUNCTION pgl_gist_compress_epoint(internal) 7.1090 - RETURNS internal 7.1091 - LANGUAGE C STRICT 7.1092 - AS '$libdir/latlon-v0003', 'pgl_gist_compress_epoint'; 7.1093 - 7.1094 -CREATE FUNCTION pgl_gist_compress_ecircle(internal) 7.1095 - RETURNS internal 7.1096 - LANGUAGE C STRICT 7.1097 - AS '$libdir/latlon-v0003', 'pgl_gist_compress_ecircle'; 7.1098 - 7.1099 -CREATE FUNCTION pgl_gist_compress_ecluster(internal) 7.1100 - RETURNS internal 7.1101 - LANGUAGE C STRICT 7.1102 - AS '$libdir/latlon-v0003', 'pgl_gist_compress_ecluster'; 7.1103 - 7.1104 -CREATE FUNCTION pgl_gist_decompress(internal) 7.1105 - RETURNS internal 7.1106 - LANGUAGE C STRICT 7.1107 - AS '$libdir/latlon-v0003', 'pgl_gist_decompress'; 7.1108 - 7.1109 -CREATE FUNCTION pgl_gist_penalty(internal, internal, internal) 7.1110 - RETURNS internal 7.1111 - LANGUAGE C STRICT 7.1112 - AS '$libdir/latlon-v0003', 'pgl_gist_penalty'; 7.1113 - 7.1114 -CREATE FUNCTION pgl_gist_picksplit(internal, internal) 7.1115 - RETURNS internal 7.1116 - LANGUAGE C STRICT 7.1117 - AS '$libdir/latlon-v0003', 'pgl_gist_picksplit'; 7.1118 - 7.1119 -CREATE FUNCTION pgl_gist_same(internal, internal, internal) 7.1120 - RETURNS internal 7.1121 - LANGUAGE C STRICT 7.1122 - AS '$libdir/latlon-v0003', 'pgl_gist_same'; 7.1123 - 7.1124 -CREATE FUNCTION pgl_gist_distance(internal, internal, smallint, oid) 7.1125 - RETURNS internal 7.1126 - LANGUAGE C STRICT 7.1127 - AS '$libdir/latlon-v0003', 'pgl_gist_distance'; 7.1128 - 7.1129 -CREATE OPERATOR CLASS epoint_ops 7.1130 - DEFAULT FOR TYPE epoint USING gist AS 7.1131 - OPERATOR 11 = , 7.1132 - OPERATOR 22 && (epoint, ebox), 7.1133 - OPERATOR 23 && (epoint, ecircle), 7.1134 - OPERATOR 24 && (epoint, ecluster), 7.1135 - OPERATOR 124 &&+ (epoint, ecluster), 7.1136 - OPERATOR 31 <-> (epoint, epoint) FOR ORDER BY float_ops, 7.1137 - OPERATOR 33 <-> (epoint, ecircle) FOR ORDER BY float_ops, 7.1138 - OPERATOR 34 <-> (epoint, ecluster) FOR ORDER BY float_ops, 7.1139 - FUNCTION 1 pgl_gist_consistent(internal, internal, smallint, oid, internal), 7.1140 - FUNCTION 2 pgl_gist_union(internal, internal), 7.1141 - FUNCTION 3 pgl_gist_compress_epoint(internal), 7.1142 - FUNCTION 4 pgl_gist_decompress(internal), 7.1143 - FUNCTION 5 pgl_gist_penalty(internal, internal, internal), 7.1144 - FUNCTION 6 pgl_gist_picksplit(internal, internal), 7.1145 - FUNCTION 7 pgl_gist_same(internal, internal, internal), 7.1146 - FUNCTION 8 pgl_gist_distance(internal, internal, smallint, oid), 7.1147 - STORAGE ekey_point; 7.1148 - 7.1149 -CREATE OPERATOR CLASS ecircle_ops 7.1150 - DEFAULT FOR TYPE ecircle USING gist AS 7.1151 - OPERATOR 13 = , 7.1152 - OPERATOR 21 && (ecircle, epoint), 7.1153 - OPERATOR 122 &&+ (ecircle, ebox), 7.1154 - OPERATOR 23 && (ecircle, ecircle), 7.1155 - OPERATOR 24 && (ecircle, ecluster), 7.1156 - OPERATOR 124 &&+ (ecircle, ecluster), 7.1157 - OPERATOR 31 <-> (ecircle, epoint) FOR ORDER BY float_ops, 7.1158 - OPERATOR 33 <-> (ecircle, ecircle) FOR ORDER BY float_ops, 7.1159 - OPERATOR 34 <-> (ecircle, ecluster) FOR ORDER BY float_ops, 7.1160 - FUNCTION 1 pgl_gist_consistent(internal, internal, smallint, oid, internal), 7.1161 - FUNCTION 2 pgl_gist_union(internal, internal), 7.1162 - FUNCTION 3 pgl_gist_compress_ecircle(internal), 7.1163 - FUNCTION 4 pgl_gist_decompress(internal), 7.1164 - FUNCTION 5 pgl_gist_penalty(internal, internal, internal), 7.1165 - FUNCTION 6 pgl_gist_picksplit(internal, internal), 7.1166 - FUNCTION 7 pgl_gist_same(internal, internal, internal), 7.1167 - FUNCTION 8 pgl_gist_distance(internal, internal, smallint, oid), 7.1168 - STORAGE ekey_area; 7.1169 - 7.1170 -CREATE OPERATOR CLASS ecluster_ops 7.1171 - DEFAULT FOR TYPE ecluster USING gist AS 7.1172 - OPERATOR 21 && (ecluster, epoint), 7.1173 - OPERATOR 121 &&+ (ecluster, epoint), 7.1174 - OPERATOR 122 &&+ (ecluster, ebox), 7.1175 - OPERATOR 23 && (ecluster, ecircle), 7.1176 - OPERATOR 123 &&+ (ecluster, ecircle), 7.1177 - OPERATOR 124 &&+ (ecluster, ecluster), 7.1178 - FUNCTION 1 pgl_gist_consistent(internal, internal, smallint, oid, internal), 7.1179 - FUNCTION 2 pgl_gist_union(internal, internal), 7.1180 - FUNCTION 3 pgl_gist_compress_ecluster(internal), 7.1181 - FUNCTION 4 pgl_gist_decompress(internal), 7.1182 - FUNCTION 5 pgl_gist_penalty(internal, internal, internal), 7.1183 - FUNCTION 6 pgl_gist_picksplit(internal, internal), 7.1184 - FUNCTION 7 pgl_gist_same(internal, internal, internal), 7.1185 - FUNCTION 8 pgl_gist_distance(internal, internal, smallint, oid), 7.1186 - STORAGE ekey_area; 7.1187 - 7.1188 - 7.1189 ---------------------- 7.1190 --- alias functions -- 7.1191 ---------------------- 7.1192 - 7.1193 -CREATE FUNCTION distance(epoint, epoint) 7.1194 - RETURNS float8 7.1195 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 <-> $2'; 7.1196 - 7.1197 -CREATE FUNCTION distance(ecluster, epoint) 7.1198 - RETURNS float8 7.1199 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 <-> $2'; 7.1200 - 7.1201 -CREATE FUNCTION distance_within(epoint, epoint, float8) 7.1202 - RETURNS boolean 7.1203 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 && ecircle($2, $3)'; 7.1204 - 7.1205 -CREATE FUNCTION distance_within(ecluster, epoint, float8) 7.1206 - RETURNS boolean 7.1207 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 && ecircle($2, $3)'; 7.1208 - 7.1209 - 7.1210 --------------------------------- 7.1211 --- other data storage formats -- 7.1212 --------------------------------- 7.1213 - 7.1214 -CREATE FUNCTION coords_to_epoint(float8, float8, text = 'epoint_lonlat') 7.1215 - RETURNS epoint 7.1216 - LANGUAGE plpgsql IMMUTABLE STRICT AS $$ 7.1217 - DECLARE 7.1218 - "result" epoint; 7.1219 - BEGIN 7.1220 - IF $3 = 'epoint_lonlat' THEN 7.1221 - -- avoid dynamic command execution for better performance 7.1222 - RETURN epoint($2, $1); 7.1223 - END IF; 7.1224 - IF $3 = 'epoint' OR $3 = 'epoint_latlon' THEN 7.1225 - -- avoid dynamic command execution for better performance 7.1226 - RETURN epoint($1, $2); 7.1227 - END IF; 7.1228 - EXECUTE 'SELECT ' || $3 || '($1, $2)' INTO STRICT "result" USING $1, $2; 7.1229 - RETURN "result"; 7.1230 - END; 7.1231 - $$; 7.1232 - 7.1233 -CREATE FUNCTION GeoJSON_to_epoint(jsonb, text = 'epoint_lonlat') 7.1234 - RETURNS epoint 7.1235 - LANGUAGE sql IMMUTABLE STRICT AS $$ 7.1236 - SELECT CASE 7.1237 - WHEN $1->>'type' = 'Point' THEN 7.1238 - coords_to_epoint( 7.1239 - ($1->'coordinates'->>1)::float8, 7.1240 - ($1->'coordinates'->>0)::float8, 7.1241 - $2 7.1242 - ) 7.1243 - WHEN $1->>'type' = 'Feature' THEN 7.1244 - GeoJSON_to_epoint($1->'geometry', $2) 7.1245 - ELSE 7.1246 - NULL 7.1247 - END 7.1248 - $$; 7.1249 - 7.1250 -CREATE FUNCTION GeoJSON_to_ecluster(jsonb, text = 'epoint_lonlat') 7.1251 - RETURNS ecluster 7.1252 - LANGUAGE sql IMMUTABLE STRICT AS $$ 7.1253 - SELECT CASE $1->>'type' 7.1254 - WHEN 'Point' THEN 7.1255 - coords_to_epoint( 7.1256 - ($1->'coordinates'->>1)::float8, 7.1257 - ($1->'coordinates'->>0)::float8, 7.1258 - $2 7.1259 - )::ecluster 7.1260 - WHEN 'MultiPoint' THEN 7.1261 - ( SELECT ecluster_create_multipoint(array_agg( 7.1262 - coords_to_epoint( 7.1263 - ("coord"->>1)::float8, 7.1264 - ("coord"->>0)::float8, 7.1265 - $2 7.1266 - ) 7.1267 - )) 7.1268 - FROM jsonb_array_elements($1->'coordinates') AS "coord" 7.1269 - ) 7.1270 - WHEN 'LineString' THEN 7.1271 - ( SELECT ecluster_create_path(array_agg( 7.1272 - coords_to_epoint( 7.1273 - ("coord"->>1)::float8, 7.1274 - ("coord"->>0)::float8, 7.1275 - $2 7.1276 - ) 7.1277 - )) 7.1278 - FROM jsonb_array_elements($1->'coordinates') AS "coord" 7.1279 - ) 7.1280 - WHEN 'MultiLineString' THEN 7.1281 - ( SELECT ecluster_concat(array_agg( 7.1282 - ( SELECT ecluster_create_path(array_agg( 7.1283 - coords_to_epoint( 7.1284 - ("coord"->>1)::float8, 7.1285 - ("coord"->>0)::float8, 7.1286 - $2 7.1287 - ) 7.1288 - )) 7.1289 - FROM jsonb_array_elements("coord_array") AS "coord" 7.1290 - ) 7.1291 - )) 7.1292 - FROM jsonb_array_elements($1->'coordinates') AS "coord_array" 7.1293 - ) 7.1294 - WHEN 'Polygon' THEN 7.1295 - ( SELECT ecluster_concat(array_agg( 7.1296 - ( SELECT ecluster_create_polygon(array_agg( 7.1297 - coords_to_epoint( 7.1298 - ("coord"->>1)::float8, 7.1299 - ("coord"->>0)::float8, 7.1300 - $2 7.1301 - ) 7.1302 - )) 7.1303 - FROM jsonb_array_elements("coord_array") AS "coord" 7.1304 - ) 7.1305 - )) 7.1306 - FROM jsonb_array_elements($1->'coordinates') AS "coord_array" 7.1307 - ) 7.1308 - WHEN 'MultiPolygon' THEN 7.1309 - ( SELECT ecluster_concat(array_agg( 7.1310 - ( SELECT ecluster_concat(array_agg( 7.1311 - ( SELECT ecluster_create_polygon(array_agg( 7.1312 - coords_to_epoint( 7.1313 - ("coord"->>1)::float8, 7.1314 - ("coord"->>0)::float8, 7.1315 - $2 7.1316 - ) 7.1317 - )) 7.1318 - FROM jsonb_array_elements("coord_array") AS "coord" 7.1319 - ) 7.1320 - )) 7.1321 - FROM jsonb_array_elements("coord_array_array") AS "coord_array" 7.1322 - ) 7.1323 - )) 7.1324 - FROM jsonb_array_elements($1->'coordinates') AS "coord_array_array" 7.1325 - ) 7.1326 - WHEN 'Feature' THEN 7.1327 - GeoJSON_to_ecluster($1->'geometry', $2) 7.1328 - WHEN 'FeatureCollection' THEN 7.1329 - ( SELECT ecluster_concat(array_agg( 7.1330 - GeoJSON_to_ecluster("feature", $2) 7.1331 - )) 7.1332 - FROM jsonb_array_elements($1->'features') AS "feature" 7.1333 - ) 7.1334 - ELSE 7.1335 - NULL 7.1336 - END 7.1337 - $$; 7.1338 -
8.1 --- a/latlon--0.4.sql Sat Sep 03 16:00:22 2016 +0200 8.2 +++ b/latlon--0.4.sql Fri Sep 09 19:22:30 2016 +0200 8.3 @@ -767,11 +767,21 @@ 8.4 LANGUAGE C IMMUTABLE STRICT 8.5 AS '$libdir/latlon-v0004', 'pgl_ecircle_ecluster_may_overlap'; 8.6 8.7 +CREATE FUNCTION ecluster_overlap_proc(ecluster, ecluster) 8.8 + RETURNS boolean 8.9 + LANGUAGE C IMMUTABLE STRICT 8.10 + AS '$libdir/latlon-v0004', 'pgl_ecluster_overlap'; 8.11 + 8.12 CREATE FUNCTION ecluster_may_overlap_proc(ecluster, ecluster) 8.13 RETURNS boolean 8.14 LANGUAGE C IMMUTABLE STRICT 8.15 AS '$libdir/latlon-v0004', 'pgl_ecluster_may_overlap'; 8.16 8.17 +CREATE FUNCTION ecluster_contains_proc(ecluster, ecluster) 8.18 + RETURNS boolean 8.19 + LANGUAGE C IMMUTABLE STRICT 8.20 + AS '$libdir/latlon-v0004', 'pgl_ecluster_contains'; 8.21 + 8.22 CREATE FUNCTION epoint_distance_proc(epoint, epoint) 8.23 RETURNS float8 8.24 LANGUAGE C IMMUTABLE STRICT 8.25 @@ -797,6 +807,11 @@ 8.26 LANGUAGE C IMMUTABLE STRICT 8.27 AS '$libdir/latlon-v0004', 'pgl_ecircle_ecluster_distance'; 8.28 8.29 +CREATE FUNCTION ecluster_distance_proc(ecluster, ecluster) 8.30 + RETURNS float8 8.31 + LANGUAGE C IMMUTABLE STRICT 8.32 + AS '$libdir/latlon-v0004', 'pgl_ecluster_distance'; 8.33 + 8.34 CREATE OPERATOR && ( 8.35 leftarg = epoint, 8.36 rightarg = ebox, 8.37 @@ -903,6 +918,67 @@ 8.38 join = areajoinsel 8.39 ); 8.40 8.41 +CREATE OPERATOR && ( 8.42 + leftarg = ecluster, 8.43 + rightarg = ecluster, 8.44 + procedure = ecluster_overlap_proc, 8.45 + commutator = &&, 8.46 + restrict = areasel, 8.47 + join = areajoinsel 8.48 +); 8.49 + 8.50 +CREATE FUNCTION ebox_ecircle_overlap_castwrap(ebox, ecircle) 8.51 + RETURNS boolean 8.52 + LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster && $2'; 8.53 + 8.54 +CREATE OPERATOR && ( 8.55 + leftarg = ebox, 8.56 + rightarg = ecircle, 8.57 + procedure = ebox_ecircle_overlap_castwrap, 8.58 + commutator = &&, 8.59 + restrict = areasel, 8.60 + join = areajoinsel 8.61 +); 8.62 + 8.63 +CREATE FUNCTION ebox_ecircle_overlap_castwrap(ecircle, ebox) 8.64 + RETURNS boolean 8.65 + LANGUAGE sql IMMUTABLE AS 'SELECT $1 && $2::ecluster'; 8.66 + 8.67 +CREATE OPERATOR && ( 8.68 + leftarg = ecircle, 8.69 + rightarg = ebox, 8.70 + procedure = ebox_ecircle_overlap_castwrap, 8.71 + commutator = &&, 8.72 + restrict = areasel, 8.73 + join = areajoinsel 8.74 +); 8.75 + 8.76 +CREATE FUNCTION ebox_ecluster_overlap_castwrap(ebox, ecluster) 8.77 + RETURNS boolean 8.78 + LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster && $2'; 8.79 + 8.80 +CREATE OPERATOR && ( 8.81 + leftarg = ebox, 8.82 + rightarg = ecluster, 8.83 + procedure = ebox_ecluster_overlap_castwrap, 8.84 + commutator = &&, 8.85 + restrict = areasel, 8.86 + join = areajoinsel 8.87 +); 8.88 + 8.89 +CREATE FUNCTION ebox_ecluster_overlap_castwrap(ecluster, ebox) 8.90 + RETURNS boolean 8.91 + LANGUAGE sql IMMUTABLE AS 'SELECT $1 && $2::ecluster'; 8.92 + 8.93 +CREATE OPERATOR && ( 8.94 + leftarg = ecluster, 8.95 + rightarg = ebox, 8.96 + procedure = ebox_ecluster_overlap_castwrap, 8.97 + commutator = &&, 8.98 + restrict = areasel, 8.99 + join = areajoinsel 8.100 +); 8.101 + 8.102 CREATE OPERATOR &&+ ( 8.103 leftarg = epoint, 8.104 rightarg = ecluster, 8.105 @@ -1000,6 +1076,116 @@ 8.106 join = areajoinsel 8.107 ); 8.108 8.109 +CREATE OPERATOR @> ( 8.110 + leftarg = ebox, 8.111 + rightarg = epoint, 8.112 + procedure = epoint_ebox_overlap_commutator, 8.113 + commutator = <@, 8.114 + restrict = areasel, 8.115 + join = areajoinsel 8.116 +); 8.117 + 8.118 +CREATE OPERATOR <@ ( 8.119 + leftarg = epoint, 8.120 + rightarg = ebox, 8.121 + procedure = epoint_ebox_overlap_proc, 8.122 + commutator = @>, 8.123 + restrict = areasel, 8.124 + join = areajoinsel 8.125 +); 8.126 + 8.127 +CREATE OPERATOR @> ( 8.128 + leftarg = ecluster, 8.129 + rightarg = epoint, 8.130 + procedure = epoint_ecluster_overlap_commutator, 8.131 + commutator = <@, 8.132 + restrict = areasel, 8.133 + join = areajoinsel 8.134 +); 8.135 + 8.136 +CREATE OPERATOR <@ ( 8.137 + leftarg = epoint, 8.138 + rightarg = ecluster, 8.139 + procedure = epoint_ecluster_overlap_proc, 8.140 + commutator = <@, 8.141 + restrict = areasel, 8.142 + join = areajoinsel 8.143 +); 8.144 + 8.145 +CREATE OPERATOR @> ( 8.146 + leftarg = ecluster, 8.147 + rightarg = ecluster, 8.148 + procedure = ecluster_contains_proc, 8.149 + commutator = <@, 8.150 + restrict = areasel, 8.151 + join = areajoinsel 8.152 +); 8.153 + 8.154 +CREATE FUNCTION ecluster_contains_commutator(ecluster, ecluster) 8.155 + RETURNS boolean 8.156 + LANGUAGE sql IMMUTABLE AS 'SELECT $2 @> $1'; 8.157 + 8.158 +CREATE OPERATOR <@ ( 8.159 + leftarg = ecluster, 8.160 + rightarg = ecluster, 8.161 + procedure = ecluster_contains_commutator, 8.162 + commutator = @>, 8.163 + restrict = areasel, 8.164 + join = areajoinsel 8.165 +); 8.166 + 8.167 +CREATE FUNCTION ebox_ecluster_contains_castwrap(ebox, ecluster) 8.168 + RETURNS boolean 8.169 + LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster @> $2'; 8.170 + 8.171 +CREATE OPERATOR @> ( 8.172 + leftarg = ebox, 8.173 + rightarg = ecluster, 8.174 + procedure = ebox_ecluster_contains_castwrap, 8.175 + commutator = <@, 8.176 + restrict = areasel, 8.177 + join = areajoinsel 8.178 +); 8.179 + 8.180 +CREATE FUNCTION ebox_ecluster_contains_castwrap(ecluster, ebox) 8.181 + RETURNS boolean 8.182 + LANGUAGE sql IMMUTABLE AS 'SELECT $2::ecluster @> $1'; 8.183 + 8.184 +CREATE OPERATOR <@ ( 8.185 + leftarg = ecluster, 8.186 + rightarg = ebox, 8.187 + procedure = ebox_ecluster_contains_castwrap, 8.188 + commutator = @>, 8.189 + restrict = areasel, 8.190 + join = areajoinsel 8.191 +); 8.192 + 8.193 +CREATE FUNCTION ecluster_ebox_contains_castwrap(ecluster, ebox) 8.194 + RETURNS boolean 8.195 + LANGUAGE sql IMMUTABLE AS 'SELECT $1 @> $2::ecluster'; 8.196 + 8.197 +CREATE OPERATOR @> ( 8.198 + leftarg = ecluster, 8.199 + rightarg = ebox, 8.200 + procedure = ecluster_ebox_contains_castwrap, 8.201 + commutator = <@, 8.202 + restrict = areasel, 8.203 + join = areajoinsel 8.204 +); 8.205 + 8.206 +CREATE FUNCTION ecluster_ebox_contains_castwrap(ebox, ecluster) 8.207 + RETURNS boolean 8.208 + LANGUAGE sql IMMUTABLE AS 'SELECT $2 @> $1::ecluster'; 8.209 + 8.210 +CREATE OPERATOR <@ ( 8.211 + leftarg = ebox, 8.212 + rightarg = ecluster, 8.213 + procedure = ecluster_ebox_contains_castwrap, 8.214 + commutator = @>, 8.215 + restrict = areasel, 8.216 + join = areajoinsel 8.217 +); 8.218 + 8.219 CREATE OPERATOR <-> ( 8.220 leftarg = epoint, 8.221 rightarg = epoint, 8.222 @@ -1068,6 +1254,90 @@ 8.223 commutator = <-> 8.224 ); 8.225 8.226 +CREATE OPERATOR <-> ( 8.227 + leftarg = ecluster, 8.228 + rightarg = ecluster, 8.229 + procedure = ecluster_distance_proc, 8.230 + commutator = <-> 8.231 +); 8.232 + 8.233 +CREATE FUNCTION epoint_ebox_distance_castwrap(epoint, ebox) 8.234 + RETURNS float8 8.235 + LANGUAGE sql IMMUTABLE AS 'SELECT $1 <-> $2::ecluster'; 8.236 + 8.237 +CREATE OPERATOR <-> ( 8.238 + leftarg = epoint, 8.239 + rightarg = ebox, 8.240 + procedure = epoint_ebox_distance_castwrap, 8.241 + commutator = <-> 8.242 +); 8.243 + 8.244 +CREATE FUNCTION epoint_ebox_distance_castwrap(ebox, epoint) 8.245 + RETURNS float8 8.246 + LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster <-> $2'; 8.247 + 8.248 +CREATE OPERATOR <-> ( 8.249 + leftarg = ebox, 8.250 + rightarg = epoint, 8.251 + procedure = epoint_ebox_distance_castwrap, 8.252 + commutator = <-> 8.253 +); 8.254 + 8.255 +CREATE FUNCTION ebox_distance_castwrap(ebox, ebox) 8.256 + RETURNS float8 8.257 + LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster <-> $2::ecluster'; 8.258 + 8.259 +CREATE OPERATOR <-> ( 8.260 + leftarg = ebox, 8.261 + rightarg = ebox, 8.262 + procedure = ebox_distance_castwrap, 8.263 + commutator = <-> 8.264 +); 8.265 + 8.266 +CREATE FUNCTION ebox_ecircle_distance_castwrap(ebox, ecircle) 8.267 + RETURNS float8 8.268 + LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster <-> $2'; 8.269 + 8.270 +CREATE OPERATOR <-> ( 8.271 + leftarg = ebox, 8.272 + rightarg = ecircle, 8.273 + procedure = ebox_ecircle_distance_castwrap, 8.274 + commutator = <-> 8.275 +); 8.276 + 8.277 +CREATE FUNCTION ebox_ecircle_distance_castwrap(ecircle, ebox) 8.278 + RETURNS float8 8.279 + LANGUAGE sql IMMUTABLE AS 'SELECT $1 <-> $2::ecluster'; 8.280 + 8.281 +CREATE OPERATOR <-> ( 8.282 + leftarg = ecircle, 8.283 + rightarg = ebox, 8.284 + procedure = ebox_ecircle_distance_castwrap, 8.285 + commutator = <-> 8.286 +); 8.287 + 8.288 +CREATE FUNCTION ebox_ecluster_distance_castwrap(ebox, ecluster) 8.289 + RETURNS float8 8.290 + LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster <-> $2'; 8.291 + 8.292 +CREATE OPERATOR <-> ( 8.293 + leftarg = ebox, 8.294 + rightarg = ecluster, 8.295 + procedure = ebox_ecluster_distance_castwrap, 8.296 + commutator = <-> 8.297 +); 8.298 + 8.299 +CREATE FUNCTION ebox_ecluster_distance_castwrap(ecluster, ebox) 8.300 + RETURNS float8 8.301 + LANGUAGE sql IMMUTABLE AS 'SELECT $1 <-> $2::ecluster'; 8.302 + 8.303 +CREATE OPERATOR <-> ( 8.304 + leftarg = ecluster, 8.305 + rightarg = ebox, 8.306 + procedure = ebox_ecluster_distance_castwrap, 8.307 + commutator = <-> 8.308 +); 8.309 + 8.310 8.311 ---------------- 8.312 -- GiST index -- 8.313 @@ -1127,10 +1397,13 @@ 8.314 DEFAULT FOR TYPE epoint USING gist AS 8.315 OPERATOR 11 = , 8.316 OPERATOR 22 && (epoint, ebox), 8.317 + OPERATOR 222 <@ (epoint, ebox), 8.318 OPERATOR 23 && (epoint, ecircle), 8.319 OPERATOR 24 && (epoint, ecluster), 8.320 OPERATOR 124 &&+ (epoint, ecluster), 8.321 + OPERATOR 224 <@ (epoint, ecluster), 8.322 OPERATOR 31 <-> (epoint, epoint) FOR ORDER BY float_ops, 8.323 + OPERATOR 32 <-> (epoint, ebox) FOR ORDER BY float_ops, 8.324 OPERATOR 33 <-> (epoint, ecircle) FOR ORDER BY float_ops, 8.325 OPERATOR 34 <-> (epoint, ecluster) FOR ORDER BY float_ops, 8.326 FUNCTION 1 pgl_gist_consistent(internal, internal, smallint, oid, internal), 8.327 @@ -1147,11 +1420,13 @@ 8.328 DEFAULT FOR TYPE ecircle USING gist AS 8.329 OPERATOR 13 = , 8.330 OPERATOR 21 && (ecircle, epoint), 8.331 + OPERATOR 22 && (ecircle, ebox), 8.332 OPERATOR 122 &&+ (ecircle, ebox), 8.333 OPERATOR 23 && (ecircle, ecircle), 8.334 OPERATOR 24 && (ecircle, ecluster), 8.335 OPERATOR 124 &&+ (ecircle, ecluster), 8.336 OPERATOR 31 <-> (ecircle, epoint) FOR ORDER BY float_ops, 8.337 + OPERATOR 32 <-> (ecircle, ebox) FOR ORDER BY float_ops, 8.338 OPERATOR 33 <-> (ecircle, ecircle) FOR ORDER BY float_ops, 8.339 OPERATOR 34 <-> (ecircle, ecluster) FOR ORDER BY float_ops, 8.340 FUNCTION 1 pgl_gist_consistent(internal, internal, smallint, oid, internal), 8.341 @@ -1168,10 +1443,21 @@ 8.342 DEFAULT FOR TYPE ecluster USING gist AS 8.343 OPERATOR 21 && (ecluster, epoint), 8.344 OPERATOR 121 &&+ (ecluster, epoint), 8.345 + OPERATOR 221 @> (ecluster, epoint), 8.346 + OPERATOR 22 && (ecluster, ebox), 8.347 OPERATOR 122 &&+ (ecluster, ebox), 8.348 + OPERATOR 222 @> (ecluster, ebox), 8.349 + OPERATOR 322 <@ (ecluster, ebox), 8.350 OPERATOR 23 && (ecluster, ecircle), 8.351 OPERATOR 123 &&+ (ecluster, ecircle), 8.352 + OPERATOR 24 && (ecluster, ecluster), 8.353 OPERATOR 124 &&+ (ecluster, ecluster), 8.354 + OPERATOR 224 @> (ecluster, ecluster), 8.355 + OPERATOR 324 <@ (ecluster, ecluster), 8.356 + OPERATOR 31 <-> (ecluster, epoint) FOR ORDER BY float_ops, 8.357 + OPERATOR 32 <-> (ecluster, ebox) FOR ORDER BY float_ops, 8.358 + OPERATOR 33 <-> (ecluster, ecircle) FOR ORDER BY float_ops, 8.359 + OPERATOR 34 <-> (ecluster, ecluster) FOR ORDER BY float_ops, 8.360 FUNCTION 1 pgl_gist_consistent(internal, internal, smallint, oid, internal), 8.361 FUNCTION 2 pgl_gist_union(internal, internal), 8.362 FUNCTION 3 pgl_gist_compress_ecluster(internal),
9.1 --- a/latlon-v0003.c Sat Sep 03 16:00:22 2016 +0200 9.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 9.3 @@ -1,2768 +0,0 @@ 9.4 - 9.5 -/*-------------* 9.6 - * C prelude * 9.7 - *-------------*/ 9.8 - 9.9 -#include "postgres.h" 9.10 -#include "fmgr.h" 9.11 -#include "libpq/pqformat.h" 9.12 -#include "access/gist.h" 9.13 -#include "access/stratnum.h" 9.14 -#include "utils/array.h" 9.15 -#include <math.h> 9.16 - 9.17 -#ifdef PG_MODULE_MAGIC 9.18 -PG_MODULE_MAGIC; 9.19 -#endif 9.20 - 9.21 -#if INT_MAX < 2147483647 9.22 -#error Expected int type to be at least 32 bit wide 9.23 -#endif 9.24 - 9.25 - 9.26 -/*---------------------------------* 9.27 - * distance calculation on earth * 9.28 - * (using WGS-84 spheroid) * 9.29 - *---------------------------------*/ 9.30 - 9.31 -/* WGS-84 spheroid with following parameters: 9.32 - semi-major axis a = 6378137 9.33 - semi-minor axis b = a * (1 - 1/298.257223563) 9.34 - estimated diameter = 2 * (2*a+b)/3 9.35 -*/ 9.36 -#define PGL_SPHEROID_A 6378137.0 /* semi major axis */ 9.37 -#define PGL_SPHEROID_F (1.0/298.257223563) /* flattening */ 9.38 -#define PGL_SPHEROID_B (PGL_SPHEROID_A * (1.0-PGL_SPHEROID_F)) 9.39 -#define PGL_EPS2 ( ( PGL_SPHEROID_A * PGL_SPHEROID_A - \ 9.40 - PGL_SPHEROID_B * PGL_SPHEROID_B ) / \ 9.41 - ( PGL_SPHEROID_A * PGL_SPHEROID_A ) ) 9.42 -#define PGL_SUBEPS2 (1.0-PGL_EPS2) 9.43 -#define PGL_DIAMETER ((4.0*PGL_SPHEROID_A + 2.0*PGL_SPHEROID_B) / 3.0) 9.44 -#define PGL_SCALE (PGL_SPHEROID_A / PGL_DIAMETER) /* semi-major ref. */ 9.45 -#define PGL_FADELIMIT (PGL_DIAMETER * M_PI / 6.0) /* 1/6 circumference */ 9.46 -#define PGL_MAXDIST (PGL_DIAMETER * M_PI / 2.0) /* maximum distance */ 9.47 - 9.48 -/* calculate distance between two points on earth (given in degrees) */ 9.49 -static inline double pgl_distance( 9.50 - double lat1, double lon1, double lat2, double lon2 9.51 -) { 9.52 - float8 lat1cos, lat1sin, lat2cos, lat2sin, lon2cos, lon2sin; 9.53 - float8 nphi1, nphi2, x1, z1, x2, y2, z2, g, s, t; 9.54 - /* normalize delta longitude (lon2 > 0 && lon1 = 0) */ 9.55 - /* lon1 = 0 (not used anymore) */ 9.56 - lon2 = fabs(lon2-lon1); 9.57 - /* convert to radians (first divide, then multiply) */ 9.58 - lat1 = (lat1 / 180.0) * M_PI; 9.59 - lat2 = (lat2 / 180.0) * M_PI; 9.60 - lon2 = (lon2 / 180.0) * M_PI; 9.61 - /* make lat2 >= lat1 to ensure reversal-symmetry despite floating point 9.62 - operations (lon2 >= lon1 is already ensured in a previous step) */ 9.63 - if (lat2 < lat1) { float8 swap = lat1; lat1 = lat2; lat2 = swap; } 9.64 - /* calculate 3d coordinates on scaled ellipsoid which has an average diameter 9.65 - of 1.0 */ 9.66 - lat1cos = cos(lat1); lat1sin = sin(lat1); 9.67 - lat2cos = cos(lat2); lat2sin = sin(lat2); 9.68 - lon2cos = cos(lon2); lon2sin = sin(lon2); 9.69 - nphi1 = PGL_SCALE / sqrt(1 - PGL_EPS2 * lat1sin * lat1sin); 9.70 - nphi2 = PGL_SCALE / sqrt(1 - PGL_EPS2 * lat2sin * lat2sin); 9.71 - x1 = nphi1 * lat1cos; 9.72 - z1 = nphi1 * PGL_SUBEPS2 * lat1sin; 9.73 - x2 = nphi2 * lat2cos * lon2cos; 9.74 - y2 = nphi2 * lat2cos * lon2sin; 9.75 - z2 = nphi2 * PGL_SUBEPS2 * lat2sin; 9.76 - /* calculate tunnel distance through scaled (diameter 1.0) ellipsoid */ 9.77 - g = sqrt((x2-x1)*(x2-x1) + y2*y2 + (z2-z1)*(z2-z1)); 9.78 - /* convert tunnel distance through scaled ellipsoid to approximated surface 9.79 - distance on original ellipsoid */ 9.80 - if (g > 1.0) g = 1.0; 9.81 - s = PGL_DIAMETER * asin(g); 9.82 - /* return result only if small enough to be precise (less than 1/3 of 9.83 - maximum possible distance) */ 9.84 - if (s <= PGL_FADELIMIT) return s; 9.85 - /* calculate tunnel distance to antipodal point through scaled ellipsoid */ 9.86 - g = sqrt((x2+x1)*(x2+x1) + y2*y2 + (z2+z1)*(z2+z1)); 9.87 - /* convert tunnel distance to antipodal point through scaled ellipsoid to 9.88 - approximated surface distance to antipodal point on original ellipsoid */ 9.89 - if (g > 1.0) g = 1.0; 9.90 - t = PGL_DIAMETER * asin(g); 9.91 - /* surface distance between original points can now be approximated by 9.92 - substracting antipodal distance from maximum possible distance; 9.93 - return result only if small enough (less than 1/3 of maximum possible 9.94 - distance) */ 9.95 - if (t <= PGL_FADELIMIT) return PGL_MAXDIST-t; 9.96 - /* otherwise crossfade direct and antipodal result to ensure monotonicity */ 9.97 - return ( 9.98 - (s * (t-PGL_FADELIMIT) + (PGL_MAXDIST-t) * (s-PGL_FADELIMIT)) / 9.99 - (s + t - 2*PGL_FADELIMIT) 9.100 - ); 9.101 -} 9.102 - 9.103 -/* finite distance that can not be reached on earth */ 9.104 -#define PGL_ULTRA_DISTANCE (3 * PGL_MAXDIST) 9.105 - 9.106 - 9.107 -/*--------------------------------* 9.108 - * simple geographic data types * 9.109 - *--------------------------------*/ 9.110 - 9.111 -/* point on earth given by latitude and longitude in degrees */ 9.112 -/* (type "epoint" in SQL) */ 9.113 -typedef struct { 9.114 - double lat; /* between -90 and 90 (both inclusive) */ 9.115 - double lon; /* between -180 and 180 (both inclusive) */ 9.116 -} pgl_point; 9.117 - 9.118 -/* box delimited by two parallels and two meridians (all in degrees) */ 9.119 -/* (type "ebox" in SQL) */ 9.120 -typedef struct { 9.121 - double lat_min; /* between -90 and 90 (both inclusive) */ 9.122 - double lat_max; /* between -90 and 90 (both inclusive) */ 9.123 - double lon_min; /* between -180 and 180 (both inclusive) */ 9.124 - double lon_max; /* between -180 and 180 (both inclusive) */ 9.125 - /* if lat_min > lat_max, then box is empty */ 9.126 - /* if lon_min > lon_max, then 180th meridian is crossed */ 9.127 -} pgl_box; 9.128 - 9.129 -/* circle on earth surface (for radial searches with fixed radius) */ 9.130 -/* (type "ecircle" in SQL) */ 9.131 -typedef struct { 9.132 - pgl_point center; 9.133 - double radius; /* positive (including +0 but excluding -0), or -INFINITY */ 9.134 - /* A negative radius (i.e. -INFINITY) denotes nothing (i.e. no point), 9.135 - zero radius (0) denotes a single point, 9.136 - a finite radius (0 < radius < INFINITY) denotes a filled circle, and 9.137 - a radius of INFINITY is valid and means complete coverage of earth. */ 9.138 -} pgl_circle; 9.139 - 9.140 - 9.141 -/*----------------------------------* 9.142 - * geographic "cluster" data type * 9.143 - *----------------------------------*/ 9.144 - 9.145 -/* A cluster is a collection of points, paths, outlines, and polygons. If two 9.146 - polygons in a cluster overlap, the area covered by both polygons does not 9.147 - belong to the cluster. This way, a cluster can be used to describe complex 9.148 - shapes like polygons with holes. Outlines are non-filled polygons. Paths are 9.149 - open by default (i.e. the last point in the list is not connected with the 9.150 - first point in the list). Note that each outline or polygon in a cluster 9.151 - must cover a longitude range of less than 180 degrees to avoid ambiguities. 9.152 - Areas which are larger may be split into multiple polygons. */ 9.153 - 9.154 -/* maximum number of points in a cluster */ 9.155 -/* (limited to avoid integer overflows, e.g. when allocating memory) */ 9.156 -#define PGL_CLUSTER_MAXPOINTS 16777216 9.157 - 9.158 -/* types of cluster entries */ 9.159 -#define PGL_ENTRY_POINT 1 /* a point */ 9.160 -#define PGL_ENTRY_PATH 2 /* a path from first point to last point */ 9.161 -#define PGL_ENTRY_OUTLINE 3 /* a non-filled polygon with given vertices */ 9.162 -#define PGL_ENTRY_POLYGON 4 /* a filled polygon with given vertices */ 9.163 - 9.164 -/* Entries of a cluster are described by two different structs: pgl_newentry 9.165 - and pgl_entry. The first is used only during construction of a cluster, the 9.166 - second is used in all other cases (e.g. when reading clusters from the 9.167 - database, performing operations, etc). */ 9.168 - 9.169 -/* entry for new geographic cluster during construction of that cluster */ 9.170 -typedef struct { 9.171 - int32_t entrytype; 9.172 - int32_t npoints; 9.173 - pgl_point *points; /* pointer to an array of points (pgl_point) */ 9.174 -} pgl_newentry; 9.175 - 9.176 -/* entry of geographic cluster */ 9.177 -typedef struct { 9.178 - int32_t entrytype; /* type of entry: point, path, outline, polygon */ 9.179 - int32_t npoints; /* number of stored points (set to 1 for point entry) */ 9.180 - int32_t offset; /* offset of pgl_point array from cluster base address */ 9.181 - /* use macro PGL_ENTRY_POINTS to obtain a pointer to the array of points */ 9.182 -} pgl_entry; 9.183 - 9.184 -/* geographic cluster which is a collection of points, (open) paths, polygons, 9.185 - and outlines (non-filled polygons) */ 9.186 -typedef struct { 9.187 - char header[VARHDRSZ]; /* PostgreSQL header for variable size data types */ 9.188 - int32_t nentries; /* number of stored points */ 9.189 - pgl_circle bounding; /* bounding circle */ 9.190 - /* Note: bounding circle ensures alignment of pgl_cluster for points */ 9.191 - pgl_entry entries[FLEXIBLE_ARRAY_MEMBER]; /* var-length data */ 9.192 -} pgl_cluster; 9.193 - 9.194 -/* macro to determine memory alignment of points */ 9.195 -/* (needed to store pgl_point array after entries in pgl_cluster) */ 9.196 -typedef struct { char dummy; pgl_point aligned; } pgl_point_alignment; 9.197 -#define PGL_POINT_ALIGNMENT offsetof(pgl_point_alignment, aligned) 9.198 - 9.199 -/* macro to extract a pointer to the array of points of a cluster entry */ 9.200 -#define PGL_ENTRY_POINTS(cluster, idx) \ 9.201 - ((pgl_point *)(((intptr_t)cluster)+(cluster)->entries[idx].offset)) 9.202 - 9.203 -/* convert pgl_newentry array to pgl_cluster */ 9.204 -static pgl_cluster *pgl_new_cluster(int nentries, pgl_newentry *entries) { 9.205 - int i; /* index of current entry */ 9.206 - int npoints = 0; /* number of points in whole cluster */ 9.207 - int entry_npoints; /* number of points in current entry */ 9.208 - int points_offset = PGL_POINT_ALIGNMENT * ( 9.209 - ( offsetof(pgl_cluster, entries) + 9.210 - nentries * sizeof(pgl_entry) + 9.211 - PGL_POINT_ALIGNMENT - 1 9.212 - ) / PGL_POINT_ALIGNMENT 9.213 - ); /* offset of pgl_point array from base address (considering alignment) */ 9.214 - pgl_cluster *cluster; /* new cluster to be returned */ 9.215 - /* determine total number of points */ 9.216 - for (i=0; i<nentries; i++) npoints += entries[i].npoints; 9.217 - /* allocate memory for cluster (including entries and points) */ 9.218 - cluster = palloc(points_offset + npoints * sizeof(pgl_point)); 9.219 - /* re-count total number of points to determine offset for each entry */ 9.220 - npoints = 0; 9.221 - /* copy entries and points */ 9.222 - for (i=0; i<nentries; i++) { 9.223 - /* determine number of points in entry */ 9.224 - entry_npoints = entries[i].npoints; 9.225 - /* copy entry */ 9.226 - cluster->entries[i].entrytype = entries[i].entrytype; 9.227 - cluster->entries[i].npoints = entry_npoints; 9.228 - /* calculate offset (in bytes) of pgl_point array */ 9.229 - cluster->entries[i].offset = points_offset + npoints * sizeof(pgl_point); 9.230 - /* copy points */ 9.231 - memcpy( 9.232 - PGL_ENTRY_POINTS(cluster, i), 9.233 - entries[i].points, 9.234 - entry_npoints * sizeof(pgl_point) 9.235 - ); 9.236 - /* update total number of points processed */ 9.237 - npoints += entry_npoints; 9.238 - } 9.239 - /* set number of entries in cluster */ 9.240 - cluster->nentries = nentries; 9.241 - /* set PostgreSQL header for variable sized data */ 9.242 - SET_VARSIZE(cluster, points_offset + npoints * sizeof(pgl_point)); 9.243 - /* return newly created cluster */ 9.244 - return cluster; 9.245 -} 9.246 - 9.247 - 9.248 -/*----------------------------------------* 9.249 - * C functions on geographic data types * 9.250 - *----------------------------------------*/ 9.251 - 9.252 -/* round latitude or longitude to 12 digits after decimal point */ 9.253 -static inline double pgl_round(double val) { 9.254 - return round(val * 1e12) / 1e12; 9.255 -} 9.256 - 9.257 -/* compare two points */ 9.258 -/* (equality when same point on earth is described, otherwise an arbitrary 9.259 - linear order) */ 9.260 -static int pgl_point_cmp(pgl_point *point1, pgl_point *point2) { 9.261 - double lon1, lon2; /* modified longitudes for special cases */ 9.262 - /* use latitude as first ordering criterion */ 9.263 - if (point1->lat < point2->lat) return -1; 9.264 - if (point1->lat > point2->lat) return 1; 9.265 - /* determine modified longitudes (considering special case of poles and 9.266 - 180th meridian which can be described as W180 or E180) */ 9.267 - if (point1->lat == -90 || point1->lat == 90) lon1 = 0; 9.268 - else if (point1->lon == 180) lon1 = -180; 9.269 - else lon1 = point1->lon; 9.270 - if (point2->lat == -90 || point2->lat == 90) lon2 = 0; 9.271 - else if (point2->lon == 180) lon2 = -180; 9.272 - else lon2 = point2->lon; 9.273 - /* use (modified) longitude as secondary ordering criterion */ 9.274 - if (lon1 < lon2) return -1; 9.275 - if (lon1 > lon2) return 1; 9.276 - /* no difference found, points are equal */ 9.277 - return 0; 9.278 -} 9.279 - 9.280 -/* compare two boxes */ 9.281 -/* (equality when same box on earth is described, otherwise an arbitrary linear 9.282 - order) */ 9.283 -static int pgl_box_cmp(pgl_box *box1, pgl_box *box2) { 9.284 - /* two empty boxes are equal, and an empty box is always considered "less 9.285 - than" a non-empty box */ 9.286 - if (box1->lat_min> box1->lat_max && box2->lat_min<=box2->lat_max) return -1; 9.287 - if (box1->lat_min> box1->lat_max && box2->lat_min> box2->lat_max) return 0; 9.288 - if (box1->lat_min<=box1->lat_max && box2->lat_min> box2->lat_max) return 1; 9.289 - /* use southern border as first ordering criterion */ 9.290 - if (box1->lat_min < box2->lat_min) return -1; 9.291 - if (box1->lat_min > box2->lat_min) return 1; 9.292 - /* use northern border as second ordering criterion */ 9.293 - if (box1->lat_max < box2->lat_max) return -1; 9.294 - if (box1->lat_max > box2->lat_max) return 1; 9.295 - /* use western border as third ordering criterion */ 9.296 - if (box1->lon_min < box2->lon_min) return -1; 9.297 - if (box1->lon_min > box2->lon_min) return 1; 9.298 - /* use eastern border as fourth ordering criterion */ 9.299 - if (box1->lon_max < box2->lon_max) return -1; 9.300 - if (box1->lon_max > box2->lon_max) return 1; 9.301 - /* no difference found, boxes are equal */ 9.302 - return 0; 9.303 -} 9.304 - 9.305 -/* compare two circles */ 9.306 -/* (equality when same circle on earth is described, otherwise an arbitrary 9.307 - linear order) */ 9.308 -static int pgl_circle_cmp(pgl_circle *circle1, pgl_circle *circle2) { 9.309 - /* two circles with same infinite radius (positive or negative infinity) are 9.310 - considered equal independently of center point */ 9.311 - if ( 9.312 - !isfinite(circle1->radius) && !isfinite(circle2->radius) && 9.313 - circle1->radius == circle2->radius 9.314 - ) return 0; 9.315 - /* use radius as first ordering criterion */ 9.316 - if (circle1->radius < circle2->radius) return -1; 9.317 - if (circle1->radius > circle2->radius) return 1; 9.318 - /* use center point as secondary ordering criterion */ 9.319 - return pgl_point_cmp(&(circle1->center), &(circle2->center)); 9.320 -} 9.321 - 9.322 -/* set box to empty box*/ 9.323 -static void pgl_box_set_empty(pgl_box *box) { 9.324 - box->lat_min = INFINITY; 9.325 - box->lat_max = -INFINITY; 9.326 - box->lon_min = 0; 9.327 - box->lon_max = 0; 9.328 -} 9.329 - 9.330 -/* check if point is inside a box */ 9.331 -static bool pgl_point_in_box(pgl_point *point, pgl_box *box) { 9.332 - return ( 9.333 - point->lat >= box->lat_min && point->lat <= box->lat_max && ( 9.334 - (box->lon_min > box->lon_max) ? ( 9.335 - /* box crosses 180th meridian */ 9.336 - point->lon >= box->lon_min || point->lon <= box->lon_max 9.337 - ) : ( 9.338 - /* box does not cross the 180th meridian */ 9.339 - point->lon >= box->lon_min && point->lon <= box->lon_max 9.340 - ) 9.341 - ) 9.342 - ); 9.343 -} 9.344 - 9.345 -/* check if two boxes overlap */ 9.346 -static bool pgl_boxes_overlap(pgl_box *box1, pgl_box *box2) { 9.347 - return ( 9.348 - box2->lat_max >= box2->lat_min && /* ensure box2 is not empty */ 9.349 - ( box2->lat_min >= box1->lat_min || box2->lat_max >= box1->lat_min ) && 9.350 - ( box2->lat_min <= box1->lat_max || box2->lat_max <= box1->lat_max ) && ( 9.351 - ( 9.352 - /* check if one and only one box crosses the 180th meridian */ 9.353 - ((box1->lon_min > box1->lon_max) ? 1 : 0) ^ 9.354 - ((box2->lon_min > box2->lon_max) ? 1 : 0) 9.355 - ) ? ( 9.356 - /* exactly one box crosses the 180th meridian */ 9.357 - box2->lon_min >= box1->lon_min || box2->lon_max >= box1->lon_min || 9.358 - box2->lon_min <= box1->lon_max || box2->lon_max <= box1->lon_max 9.359 - ) : ( 9.360 - /* no box or both boxes cross the 180th meridian */ 9.361 - ( 9.362 - (box2->lon_min >= box1->lon_min || box2->lon_max >= box1->lon_min) && 9.363 - (box2->lon_min <= box1->lon_max || box2->lon_max <= box1->lon_max) 9.364 - ) || 9.365 - /* handle W180 == E180 */ 9.366 - ( box1->lon_min == -180 && box2->lon_max == 180 ) || 9.367 - ( box2->lon_min == -180 && box1->lon_max == 180 ) 9.368 - ) 9.369 - ) 9.370 - ); 9.371 -} 9.372 - 9.373 -/* check unambiguousness of east/west orientation of cluster entries and set 9.374 - bounding circle of cluster */ 9.375 -static bool pgl_finalize_cluster(pgl_cluster *cluster) { 9.376 - int i, j; /* i: index of entry, j: index of point in entry */ 9.377 - int npoints; /* number of points in entry */ 9.378 - int total_npoints = 0; /* total number of points in cluster */ 9.379 - pgl_point *points; /* points in entry */ 9.380 - int lon_dir; /* first point of entry west (-1) or east (+1) */ 9.381 - double lon_break = 0; /* antipodal longitude of first point in entry */ 9.382 - double lon_min, lon_max; /* covered longitude range of entry */ 9.383 - double value; /* temporary variable */ 9.384 - /* reset bounding circle center to empty circle at 0/0 coordinates */ 9.385 - cluster->bounding.center.lat = 0; 9.386 - cluster->bounding.center.lon = 0; 9.387 - cluster->bounding.radius = -INFINITY; 9.388 - /* if cluster is not empty */ 9.389 - if (cluster->nentries != 0) { 9.390 - /* iterate over all cluster entries and ensure they each cover a longitude 9.391 - range less than 180 degrees */ 9.392 - for (i=0; i<cluster->nentries; i++) { 9.393 - /* get properties of entry */ 9.394 - npoints = cluster->entries[i].npoints; 9.395 - points = PGL_ENTRY_POINTS(cluster, i); 9.396 - /* get longitude of first point of entry */ 9.397 - value = points[0].lon; 9.398 - /* initialize lon_min and lon_max with longitude of first point */ 9.399 - lon_min = value; 9.400 - lon_max = value; 9.401 - /* determine east/west orientation of first point and calculate antipodal 9.402 - longitude (Note: rounding required here) */ 9.403 - if (value < 0) { lon_dir = -1; lon_break = pgl_round(value + 180); } 9.404 - else if (value > 0) { lon_dir = 1; lon_break = pgl_round(value - 180); } 9.405 - else lon_dir = 0; 9.406 - /* iterate over all other points in entry */ 9.407 - for (j=1; j<npoints; j++) { 9.408 - /* consider longitude wrap-around */ 9.409 - value = points[j].lon; 9.410 - if (lon_dir<0 && value>lon_break) value = pgl_round(value - 360); 9.411 - else if (lon_dir>0 && value<lon_break) value = pgl_round(value + 360); 9.412 - /* update lon_min and lon_max */ 9.413 - if (value < lon_min) lon_min = value; 9.414 - else if (value > lon_max) lon_max = value; 9.415 - /* return false if 180 degrees or more are covered */ 9.416 - if (lon_max - lon_min >= 180) return false; 9.417 - } 9.418 - } 9.419 - /* iterate over all points of all entries and calculate arbitrary center 9.420 - point for bounding circle (best if center point minimizes the radius, 9.421 - but some error is allowed here) */ 9.422 - for (i=0; i<cluster->nentries; i++) { 9.423 - /* get properties of entry */ 9.424 - npoints = cluster->entries[i].npoints; 9.425 - points = PGL_ENTRY_POINTS(cluster, i); 9.426 - /* check if first entry */ 9.427 - if (i==0) { 9.428 - /* get longitude of first point of first entry in whole cluster */ 9.429 - value = points[0].lon; 9.430 - /* initialize lon_min and lon_max with longitude of first point of 9.431 - first entry in whole cluster (used to determine if whole cluster 9.432 - covers a longitude range of 180 degrees or more) */ 9.433 - lon_min = value; 9.434 - lon_max = value; 9.435 - /* determine east/west orientation of first point and calculate 9.436 - antipodal longitude (Note: rounding not necessary here) */ 9.437 - if (value < 0) { lon_dir = -1; lon_break = value + 180; } 9.438 - else if (value > 0) { lon_dir = 1; lon_break = value - 180; } 9.439 - else lon_dir = 0; 9.440 - } 9.441 - /* iterate over all points in entry */ 9.442 - for (j=0; j<npoints; j++) { 9.443 - /* longitude wrap-around (Note: rounding not necessary here) */ 9.444 - value = points[j].lon; 9.445 - if (lon_dir < 0 && value > lon_break) value -= 360; 9.446 - else if (lon_dir > 0 && value < lon_break) value += 360; 9.447 - if (value < lon_min) lon_min = value; 9.448 - else if (value > lon_max) lon_max = value; 9.449 - /* set bounding circle to cover whole earth if more than 180 degrees 9.450 - are covered */ 9.451 - if (lon_max - lon_min >= 180) { 9.452 - cluster->bounding.center.lat = 0; 9.453 - cluster->bounding.center.lon = 0; 9.454 - cluster->bounding.radius = INFINITY; 9.455 - return true; 9.456 - } 9.457 - /* add point to bounding circle center (for average calculation) */ 9.458 - cluster->bounding.center.lat += points[j].lat; 9.459 - cluster->bounding.center.lon += value; 9.460 - } 9.461 - /* count total number of points */ 9.462 - total_npoints += npoints; 9.463 - } 9.464 - /* determine average latitude and longitude of cluster */ 9.465 - cluster->bounding.center.lat /= total_npoints; 9.466 - cluster->bounding.center.lon /= total_npoints; 9.467 - /* normalize longitude of center of cluster bounding circle */ 9.468 - if (cluster->bounding.center.lon < -180) { 9.469 - cluster->bounding.center.lon += 360; 9.470 - } 9.471 - else if (cluster->bounding.center.lon > 180) { 9.472 - cluster->bounding.center.lon -= 360; 9.473 - } 9.474 - /* round bounding circle center (useful if it is used by other functions) */ 9.475 - cluster->bounding.center.lat = pgl_round(cluster->bounding.center.lat); 9.476 - cluster->bounding.center.lon = pgl_round(cluster->bounding.center.lon); 9.477 - /* calculate radius of bounding circle */ 9.478 - for (i=0; i<cluster->nentries; i++) { 9.479 - npoints = cluster->entries[i].npoints; 9.480 - points = PGL_ENTRY_POINTS(cluster, i); 9.481 - for (j=0; j<npoints; j++) { 9.482 - value = pgl_distance( 9.483 - cluster->bounding.center.lat, cluster->bounding.center.lon, 9.484 - points[j].lat, points[j].lon 9.485 - ); 9.486 - if (value > cluster->bounding.radius) cluster->bounding.radius = value; 9.487 - } 9.488 - } 9.489 - } 9.490 - /* return true (east/west orientation is unambiguous) */ 9.491 - return true; 9.492 -} 9.493 - 9.494 -/* check if point is inside cluster */ 9.495 -static bool pgl_point_in_cluster(pgl_point *point, pgl_cluster *cluster) { 9.496 - int i, j, k; /* i: entry, j: point in entry, k: next point in entry */ 9.497 - int entrytype; /* type of entry */ 9.498 - int npoints; /* number of points in entry */ 9.499 - pgl_point *points; /* array of points in entry */ 9.500 - int lon_dir = 0; /* first vertex west (-1) or east (+1) */ 9.501 - double lon_break = 0; /* antipodal longitude of first vertex */ 9.502 - double lat0 = point->lat; /* latitude of point */ 9.503 - double lon0; /* (adjusted) longitude of point */ 9.504 - double lat1, lon1; /* latitude and (adjusted) longitude of vertex */ 9.505 - double lat2, lon2; /* latitude and (adjusted) longitude of next vertex */ 9.506 - double lon; /* longitude of intersection */ 9.507 - int counter = 0; /* counter for intersections east of point */ 9.508 - /* points outside bounding circle are always assumed to be non-overlapping */ 9.509 - /* (necessary for consistent table and index scans) */ 9.510 - if ( 9.511 - pgl_distance( 9.512 - point->lat, point->lon, 9.513 - cluster->bounding.center.lat, cluster->bounding.center.lon 9.514 - ) > cluster->bounding.radius 9.515 - ) return false; 9.516 - /* iterate over all entries */ 9.517 - for (i=0; i<cluster->nentries; i++) { 9.518 - /* get properties of entry */ 9.519 - entrytype = cluster->entries[i].entrytype; 9.520 - npoints = cluster->entries[i].npoints; 9.521 - points = PGL_ENTRY_POINTS(cluster, i); 9.522 - /* determine east/west orientation of first point of entry and calculate 9.523 - antipodal longitude */ 9.524 - lon_break = points[0].lon; 9.525 - if (lon_break < 0) { lon_dir = -1; lon_break += 180; } 9.526 - else if (lon_break > 0) { lon_dir = 1; lon_break -= 180; } 9.527 - else lon_dir = 0; 9.528 - /* get longitude of point */ 9.529 - lon0 = point->lon; 9.530 - /* consider longitude wrap-around for point */ 9.531 - if (lon_dir < 0 && lon0 > lon_break) lon0 = pgl_round(lon0 - 360); 9.532 - else if (lon_dir > 0 && lon0 < lon_break) lon0 = pgl_round(lon0 + 360); 9.533 - /* iterate over all edges and vertices */ 9.534 - for (j=0; j<npoints; j++) { 9.535 - /* return true if point is on vertex of polygon */ 9.536 - if (pgl_point_cmp(point, &(points[j])) == 0) return true; 9.537 - /* calculate index of next vertex */ 9.538 - k = (j+1) % npoints; 9.539 - /* skip last edge unless entry is (closed) outline or polygon */ 9.540 - if ( 9.541 - k == 0 && 9.542 - entrytype != PGL_ENTRY_OUTLINE && 9.543 - entrytype != PGL_ENTRY_POLYGON 9.544 - ) continue; 9.545 - /* get latitude and longitude values of edge */ 9.546 - lat1 = points[j].lat; 9.547 - lat2 = points[k].lat; 9.548 - lon1 = points[j].lon; 9.549 - lon2 = points[k].lon; 9.550 - /* consider longitude wrap-around for edge */ 9.551 - if (lon_dir < 0 && lon1 > lon_break) lon1 = pgl_round(lon1 - 360); 9.552 - else if (lon_dir > 0 && lon1 < lon_break) lon1 = pgl_round(lon1 + 360); 9.553 - if (lon_dir < 0 && lon2 > lon_break) lon2 = pgl_round(lon2 - 360); 9.554 - else if (lon_dir > 0 && lon2 < lon_break) lon2 = pgl_round(lon2 + 360); 9.555 - /* return true if point is on horizontal (west to east) edge of polygon */ 9.556 - if ( 9.557 - lat0 == lat1 && lat0 == lat2 && 9.558 - ( (lon0 >= lon1 && lon0 <= lon2) || (lon0 >= lon2 && lon0 <= lon1) ) 9.559 - ) return true; 9.560 - /* check if edge crosses east/west line of point */ 9.561 - if ((lat1 < lat0 && lat2 >= lat0) || (lat2 < lat0 && lat1 >= lat0)) { 9.562 - /* calculate longitude of intersection */ 9.563 - lon = (lon1 * (lat2-lat0) + lon2 * (lat0-lat1)) / (lat2-lat1); 9.564 - /* return true if intersection goes (approximately) through point */ 9.565 - if (pgl_round(lon) == lon0) return true; 9.566 - /* count intersection if east of point and entry is polygon*/ 9.567 - if (entrytype == PGL_ENTRY_POLYGON && lon > lon0) counter++; 9.568 - } 9.569 - } 9.570 - } 9.571 - /* return true if number of intersections is odd */ 9.572 - return counter & 1; 9.573 -} 9.574 - 9.575 -/* calculate (approximate) distance between point and cluster */ 9.576 -static double pgl_point_cluster_distance(pgl_point *point, pgl_cluster *cluster) { 9.577 - int i, j, k; /* i: entry, j: point in entry, k: next point in entry */ 9.578 - int entrytype; /* type of entry */ 9.579 - int npoints; /* number of points in entry */ 9.580 - pgl_point *points; /* array of points in entry */ 9.581 - int lon_dir = 0; /* first vertex west (-1) or east (+1) */ 9.582 - double lon_break = 0; /* antipodal longitude of first vertex */ 9.583 - double lon_min = 0; /* minimum (adjusted) longitude of entry vertices */ 9.584 - double lon_max = 0; /* maximum (adjusted) longitude of entry vertices */ 9.585 - double lat0 = point->lat; /* latitude of point */ 9.586 - double lon0; /* (adjusted) longitude of point */ 9.587 - double lat1, lon1; /* latitude and (adjusted) longitude of vertex */ 9.588 - double lat2, lon2; /* latitude and (adjusted) longitude of next vertex */ 9.589 - double s; /* scalar for vector calculations */ 9.590 - double dist; /* distance calculated in one step */ 9.591 - double min_dist = INFINITY; /* minimum distance */ 9.592 - /* distance is zero if point is contained in cluster */ 9.593 - if (pgl_point_in_cluster(point, cluster)) return 0; 9.594 - /* iterate over all entries */ 9.595 - for (i=0; i<cluster->nentries; i++) { 9.596 - /* get properties of entry */ 9.597 - entrytype = cluster->entries[i].entrytype; 9.598 - npoints = cluster->entries[i].npoints; 9.599 - points = PGL_ENTRY_POINTS(cluster, i); 9.600 - /* determine east/west orientation of first point of entry and calculate 9.601 - antipodal longitude */ 9.602 - lon_break = points[0].lon; 9.603 - if (lon_break < 0) { lon_dir = -1; lon_break += 180; } 9.604 - else if (lon_break > 0) { lon_dir = 1; lon_break -= 180; } 9.605 - else lon_dir = 0; 9.606 - /* determine covered longitude range */ 9.607 - for (j=0; j<npoints; j++) { 9.608 - /* get longitude of vertex */ 9.609 - lon1 = points[j].lon; 9.610 - /* adjust longitude to fix potential wrap-around */ 9.611 - if (lon_dir < 0 && lon1 > lon_break) lon1 -= 360; 9.612 - else if (lon_dir > 0 && lon1 < lon_break) lon1 += 360; 9.613 - /* update minimum and maximum longitude of polygon */ 9.614 - if (j == 0 || lon1 < lon_min) lon_min = lon1; 9.615 - if (j == 0 || lon1 > lon_max) lon_max = lon1; 9.616 - } 9.617 - /* adjust longitude wrap-around according to full longitude range */ 9.618 - lon_break = (lon_max + lon_min) / 2; 9.619 - if (lon_break < 0) { lon_dir = -1; lon_break += 180; } 9.620 - else if (lon_break > 0) { lon_dir = 1; lon_break -= 180; } 9.621 - /* get longitude of point */ 9.622 - lon0 = point->lon; 9.623 - /* consider longitude wrap-around for point */ 9.624 - if (lon_dir < 0 && lon0 > lon_break) lon0 -= 360; 9.625 - else if (lon_dir > 0 && lon0 < lon_break) lon0 += 360; 9.626 - /* iterate over all edges and vertices */ 9.627 - for (j=0; j<npoints; j++) { 9.628 - /* get latitude and longitude values of current point */ 9.629 - lat1 = points[j].lat; 9.630 - lon1 = points[j].lon; 9.631 - /* consider longitude wrap-around for current point */ 9.632 - if (lon_dir < 0 && lon1 > lon_break) lon1 -= 360; 9.633 - else if (lon_dir > 0 && lon1 < lon_break) lon1 += 360; 9.634 - /* calculate distance to vertex */ 9.635 - dist = pgl_distance(lat0, lon0, lat1, lon1); 9.636 - /* store calculated distance if smallest */ 9.637 - if (dist < min_dist) min_dist = dist; 9.638 - /* calculate index of next vertex */ 9.639 - k = (j+1) % npoints; 9.640 - /* skip last edge unless entry is (closed) outline or polygon */ 9.641 - if ( 9.642 - k == 0 && 9.643 - entrytype != PGL_ENTRY_OUTLINE && 9.644 - entrytype != PGL_ENTRY_POLYGON 9.645 - ) continue; 9.646 - /* get latitude and longitude values of next point */ 9.647 - lat2 = points[k].lat; 9.648 - lon2 = points[k].lon; 9.649 - /* consider longitude wrap-around for next point */ 9.650 - if (lon_dir < 0 && lon2 > lon_break) lon2 -= 360; 9.651 - else if (lon_dir > 0 && lon2 < lon_break) lon2 += 360; 9.652 - /* go to next vertex and edge if edge is degenerated */ 9.653 - if (lat1 == lat2 && lon1 == lon2) continue; 9.654 - /* otherwise test if point can be projected onto edge of polygon */ 9.655 - s = ( 9.656 - ((lat0-lat1) * (lat2-lat1) + (lon0-lon1) * (lon2-lon1)) / 9.657 - ((lat2-lat1) * (lat2-lat1) + (lon2-lon1) * (lon2-lon1)) 9.658 - ); 9.659 - /* go to next vertex and edge if point cannot be projected */ 9.660 - if (!(s > 0 && s < 1)) continue; 9.661 - /* calculate distance from original point to projected point */ 9.662 - dist = pgl_distance( 9.663 - lat0, lon0, 9.664 - lat1 + s * (lat2-lat1), 9.665 - lon1 + s * (lon2-lon1) 9.666 - ); 9.667 - /* store calculated distance if smallest */ 9.668 - if (dist < min_dist) min_dist = dist; 9.669 - } 9.670 - } 9.671 - /* return minimum distance */ 9.672 - return min_dist; 9.673 -} 9.674 - 9.675 -/* estimator function for distance between box and point */ 9.676 -/* allowed to return smaller values than actually correct */ 9.677 -static double pgl_estimate_point_box_distance(pgl_point *point, pgl_box *box) { 9.678 - double dlon; /* longitude range of box (delta longitude) */ 9.679 - double h; /* half of distance along meridian */ 9.680 - double d; /* distance between both southern or both northern points */ 9.681 - double cur_dist; /* calculated distance */ 9.682 - double min_dist; /* minimum distance calculated */ 9.683 - /* return infinity if bounding box is empty */ 9.684 - if (box->lat_min > box->lat_max) return INFINITY; 9.685 - /* return zero if point is inside bounding box */ 9.686 - if (pgl_point_in_box(point, box)) return 0; 9.687 - /* calculate delta longitude */ 9.688 - dlon = box->lon_max - box->lon_min; 9.689 - if (dlon < 0) dlon += 360; /* 180th meridian crossed */ 9.690 - /* if delta longitude is greater than 180 degrees, perform safe fall-back */ 9.691 - if (dlon > 180) return 0; 9.692 - /* calculate half of distance along meridian */ 9.693 - h = pgl_distance(box->lat_min, 0, box->lat_max, 0) / 2; 9.694 - /* calculate full distance between southern points */ 9.695 - d = pgl_distance(box->lat_min, 0, box->lat_min, dlon); 9.696 - /* calculate maximum of full distance and half distance */ 9.697 - if (h > d) d = h; 9.698 - /* calculate distance from point to first southern vertex and substract 9.699 - maximum error */ 9.700 - min_dist = pgl_distance( 9.701 - point->lat, point->lon, box->lat_min, box->lon_min 9.702 - ) - d; 9.703 - /* return zero if estimated distance is smaller than zero */ 9.704 - if (min_dist <= 0) return 0; 9.705 - /* repeat procedure with second southern vertex */ 9.706 - cur_dist = pgl_distance( 9.707 - point->lat, point->lon, box->lat_min, box->lon_max 9.708 - ) - d; 9.709 - if (cur_dist <= 0) return 0; 9.710 - if (cur_dist < min_dist) min_dist = cur_dist; 9.711 - /* calculate full distance between northern points */ 9.712 - d = pgl_distance(box->lat_max, 0, box->lat_max, dlon); 9.713 - /* calculate maximum of full distance and half distance */ 9.714 - if (h > d) d = h; 9.715 - /* repeat procedure with northern vertices */ 9.716 - cur_dist = pgl_distance( 9.717 - point->lat, point->lon, box->lat_max, box->lon_max 9.718 - ) - d; 9.719 - if (cur_dist <= 0) return 0; 9.720 - if (cur_dist < min_dist) min_dist = cur_dist; 9.721 - cur_dist = pgl_distance( 9.722 - point->lat, point->lon, box->lat_max, box->lon_min 9.723 - ) - d; 9.724 - if (cur_dist <= 0) return 0; 9.725 - if (cur_dist < min_dist) min_dist = cur_dist; 9.726 - /* return smallest value (unless already returned zero) */ 9.727 - return min_dist; 9.728 -} 9.729 - 9.730 - 9.731 -/*----------------------------* 9.732 - * fractal geographic index * 9.733 - *----------------------------*/ 9.734 - 9.735 -/* number of bytes used for geographic (center) position in keys */ 9.736 -#define PGL_KEY_LATLON_BYTELEN 7 9.737 - 9.738 -/* maximum reference value for logarithmic size of geographic objects */ 9.739 -#define PGL_AREAKEY_REFOBJSIZE (PGL_DIAMETER/3.0) /* can be tweaked */ 9.740 - 9.741 -/* safety margin to avoid floating point errors in distance estimation */ 9.742 -#define PGL_FPE_SAFETY (1.0+1e-14) /* slightly greater than 1.0 */ 9.743 - 9.744 -/* pointer to index key (either pgl_pointkey or pgl_areakey) */ 9.745 -typedef unsigned char *pgl_keyptr; 9.746 - 9.747 -/* index key for points (objects with zero area) on the spheroid */ 9.748 -/* bit 0..55: interspersed bits of latitude and longitude, 9.749 - bit 56..57: always zero, 9.750 - bit 58..63: node depth in hypothetic (full) tree from 0 to 56 (incl.) */ 9.751 -typedef unsigned char pgl_pointkey[PGL_KEY_LATLON_BYTELEN+1]; 9.752 - 9.753 -/* index key for geographic objects on spheroid with area greater than zero */ 9.754 -/* bit 0..55: interspersed bits of latitude and longitude of center point, 9.755 - bit 56: always set to 1, 9.756 - bit 57..63: node depth in hypothetic (full) tree from 0 to (2*56)+1 (incl.), 9.757 - bit 64..71: logarithmic object size from 0 to 56+1 = 57 (incl.), but set to 9.758 - PGL_KEY_OBJSIZE_EMPTY (with interspersed bits = 0 and node depth 9.759 - = 113) for empty objects, and set to PGL_KEY_OBJSIZE_UNIVERSAL 9.760 - (with interspersed bits = 0 and node depth = 0) for keys which 9.761 - cover both empty and non-empty objects */ 9.762 - 9.763 -typedef unsigned char pgl_areakey[PGL_KEY_LATLON_BYTELEN+2]; 9.764 - 9.765 -/* helper macros for reading/writing index keys */ 9.766 -#define PGL_KEY_NODEDEPTH_OFFSET PGL_KEY_LATLON_BYTELEN 9.767 -#define PGL_KEY_OBJSIZE_OFFSET (PGL_KEY_NODEDEPTH_OFFSET+1) 9.768 -#define PGL_POINTKEY_MAXDEPTH (PGL_KEY_LATLON_BYTELEN*8) 9.769 -#define PGL_AREAKEY_MAXDEPTH (2*PGL_POINTKEY_MAXDEPTH+1) 9.770 -#define PGL_AREAKEY_MAXOBJSIZE (PGL_POINTKEY_MAXDEPTH+1) 9.771 -#define PGL_AREAKEY_TYPEMASK 0x80 9.772 -#define PGL_KEY_LATLONBIT(key, n) ((key)[(n)/8] & (0x80 >> ((n)%8))) 9.773 -#define PGL_KEY_LATLONBIT_DIFF(key1, key2, n) \ 9.774 - ( PGL_KEY_LATLONBIT(key1, n) ^ \ 9.775 - PGL_KEY_LATLONBIT(key2, n) ) 9.776 -#define PGL_KEY_IS_AREAKEY(key) ((key)[PGL_KEY_NODEDEPTH_OFFSET] & \ 9.777 - PGL_AREAKEY_TYPEMASK) 9.778 -#define PGL_KEY_NODEDEPTH(key) ((key)[PGL_KEY_NODEDEPTH_OFFSET] & \ 9.779 - (PGL_AREAKEY_TYPEMASK-1)) 9.780 -#define PGL_KEY_OBJSIZE(key) ((key)[PGL_KEY_OBJSIZE_OFFSET]) 9.781 -#define PGL_KEY_OBJSIZE_EMPTY 126 9.782 -#define PGL_KEY_OBJSIZE_UNIVERSAL 127 9.783 -#define PGL_KEY_IS_EMPTY(key) ( PGL_KEY_IS_AREAKEY(key) && \ 9.784 - (key)[PGL_KEY_OBJSIZE_OFFSET] == \ 9.785 - PGL_KEY_OBJSIZE_EMPTY ) 9.786 -#define PGL_KEY_IS_UNIVERSAL(key) ( PGL_KEY_IS_AREAKEY(key) && \ 9.787 - (key)[PGL_KEY_OBJSIZE_OFFSET] == \ 9.788 - PGL_KEY_OBJSIZE_UNIVERSAL ) 9.789 - 9.790 -/* set area key to match empty objects only */ 9.791 -static void pgl_key_set_empty(pgl_keyptr key) { 9.792 - memset(key, 0, sizeof(pgl_areakey)); 9.793 - /* Note: setting node depth to maximum is required for picksplit function */ 9.794 - key[PGL_KEY_NODEDEPTH_OFFSET] = PGL_AREAKEY_TYPEMASK | PGL_AREAKEY_MAXDEPTH; 9.795 - key[PGL_KEY_OBJSIZE_OFFSET] = PGL_KEY_OBJSIZE_EMPTY; 9.796 -} 9.797 - 9.798 -/* set area key to match any object (including empty objects) */ 9.799 -static void pgl_key_set_universal(pgl_keyptr key) { 9.800 - memset(key, 0, sizeof(pgl_areakey)); 9.801 - key[PGL_KEY_NODEDEPTH_OFFSET] = PGL_AREAKEY_TYPEMASK; 9.802 - key[PGL_KEY_OBJSIZE_OFFSET] = PGL_KEY_OBJSIZE_UNIVERSAL; 9.803 -} 9.804 - 9.805 -/* convert a point on earth into a max-depth key to be used in index */ 9.806 -static void pgl_point_to_key(pgl_point *point, pgl_keyptr key) { 9.807 - double lat = point->lat; 9.808 - double lon = point->lon; 9.809 - int i; 9.810 - /* clear latitude and longitude bits */ 9.811 - memset(key, 0, PGL_KEY_LATLON_BYTELEN); 9.812 - /* set node depth to maximum and type bit to zero */ 9.813 - key[PGL_KEY_NODEDEPTH_OFFSET] = PGL_POINTKEY_MAXDEPTH; 9.814 - /* iterate over all latitude/longitude bit pairs */ 9.815 - for (i=0; i<PGL_POINTKEY_MAXDEPTH/2; i++) { 9.816 - /* determine latitude bit */ 9.817 - if (lat >= 0) { 9.818 - key[i/4] |= 0x80 >> (2*(i%4)); 9.819 - lat *= 2; lat -= 90; 9.820 - } else { 9.821 - lat *= 2; lat += 90; 9.822 - } 9.823 - /* determine longitude bit */ 9.824 - if (lon >= 0) { 9.825 - key[i/4] |= 0x80 >> (2*(i%4)+1); 9.826 - lon *= 2; lon -= 180; 9.827 - } else { 9.828 - lon *= 2; lon += 180; 9.829 - } 9.830 - } 9.831 -} 9.832 - 9.833 -/* convert a circle on earth into a max-depth key to be used in an index */ 9.834 -static void pgl_circle_to_key(pgl_circle *circle, pgl_keyptr key) { 9.835 - /* handle special case of empty circle */ 9.836 - if (circle->radius < 0) { 9.837 - pgl_key_set_empty(key); 9.838 - return; 9.839 - } 9.840 - /* perform same action as for point keys */ 9.841 - pgl_point_to_key(&(circle->center), key); 9.842 - /* but overwrite type and node depth to fit area index key */ 9.843 - key[PGL_KEY_NODEDEPTH_OFFSET] = PGL_AREAKEY_TYPEMASK | PGL_AREAKEY_MAXDEPTH; 9.844 - /* check if radius is greater than (or equal to) reference size */ 9.845 - /* (treat equal values as greater values for numerical safety) */ 9.846 - if (circle->radius >= PGL_AREAKEY_REFOBJSIZE) { 9.847 - /* if yes, set logarithmic size to zero */ 9.848 - key[PGL_KEY_OBJSIZE_OFFSET] = 0; 9.849 - } else { 9.850 - /* otherwise, determine logarithmic size iteratively */ 9.851 - /* (one step is equivalent to a factor of sqrt(2)) */ 9.852 - double reference = PGL_AREAKEY_REFOBJSIZE / M_SQRT2; 9.853 - int objsize = 1; 9.854 - while (objsize < PGL_AREAKEY_MAXOBJSIZE) { 9.855 - /* stop when radius is greater than (or equal to) adjusted reference */ 9.856 - /* (treat equal values as greater values for numerical safety) */ 9.857 - if (circle->radius >= reference) break; 9.858 - reference /= M_SQRT2; 9.859 - objsize++; 9.860 - } 9.861 - /* set logarithmic size to determined value */ 9.862 - key[PGL_KEY_OBJSIZE_OFFSET] = objsize; 9.863 - } 9.864 -} 9.865 - 9.866 -/* check if one key is subkey of another key or vice versa */ 9.867 -static bool pgl_keys_overlap(pgl_keyptr key1, pgl_keyptr key2) { 9.868 - int i; /* key bit offset (includes both lat/lon and log. obj. size bits) */ 9.869 - /* determine smallest depth */ 9.870 - int depth1 = PGL_KEY_NODEDEPTH(key1); 9.871 - int depth2 = PGL_KEY_NODEDEPTH(key2); 9.872 - int depth = (depth1 < depth2) ? depth1 : depth2; 9.873 - /* check if keys are area keys (assuming that both keys have same type) */ 9.874 - if (PGL_KEY_IS_AREAKEY(key1)) { 9.875 - int j = 0; /* bit offset for logarithmic object size bits */ 9.876 - int k = 0; /* bit offset for latitude and longitude */ 9.877 - /* fetch logarithmic object size information */ 9.878 - int objsize1 = PGL_KEY_OBJSIZE(key1); 9.879 - int objsize2 = PGL_KEY_OBJSIZE(key2); 9.880 - /* handle special cases for empty objects (universal and empty keys) */ 9.881 - if ( 9.882 - objsize1 == PGL_KEY_OBJSIZE_UNIVERSAL || 9.883 - objsize2 == PGL_KEY_OBJSIZE_UNIVERSAL 9.884 - ) return true; 9.885 - if ( 9.886 - objsize1 == PGL_KEY_OBJSIZE_EMPTY || 9.887 - objsize2 == PGL_KEY_OBJSIZE_EMPTY 9.888 - ) return objsize1 == objsize2; 9.889 - /* iterate through key bits */ 9.890 - for (i=0; i<depth; i++) { 9.891 - /* every second bit is a bit describing the object size */ 9.892 - if (i%2 == 0) { 9.893 - /* check if object size bit is different in both keys (objsize1 and 9.894 - objsize2 describe the minimum index when object size bit is set) */ 9.895 - if ( 9.896 - (objsize1 <= j && objsize2 > j) || 9.897 - (objsize2 <= j && objsize1 > j) 9.898 - ) { 9.899 - /* bit differs, therefore keys are in separate branches */ 9.900 - return false; 9.901 - } 9.902 - /* increase bit counter for object size bits */ 9.903 - j++; 9.904 - } 9.905 - /* all other bits describe latitude and longitude */ 9.906 - else { 9.907 - /* check if bit differs in both keys */ 9.908 - if (PGL_KEY_LATLONBIT_DIFF(key1, key2, k)) { 9.909 - /* bit differs, therefore keys are in separate branches */ 9.910 - return false; 9.911 - } 9.912 - /* increase bit counter for latitude/longitude bits */ 9.913 - k++; 9.914 - } 9.915 - } 9.916 - } 9.917 - /* if not, keys are point keys */ 9.918 - else { 9.919 - /* iterate through key bits */ 9.920 - for (i=0; i<depth; i++) { 9.921 - /* check if bit differs in both keys */ 9.922 - if (PGL_KEY_LATLONBIT_DIFF(key1, key2, i)) { 9.923 - /* bit differs, therefore keys are in separate branches */ 9.924 - return false; 9.925 - } 9.926 - } 9.927 - } 9.928 - /* return true because keys are in the same branch */ 9.929 - return true; 9.930 -} 9.931 - 9.932 -/* combine two keys into new key which covers both original keys */ 9.933 -/* (result stored in first argument) */ 9.934 -static void pgl_unite_keys(pgl_keyptr dst, pgl_keyptr src) { 9.935 - int i; /* key bit offset (includes both lat/lon and log. obj. size bits) */ 9.936 - /* determine smallest depth */ 9.937 - int depth1 = PGL_KEY_NODEDEPTH(dst); 9.938 - int depth2 = PGL_KEY_NODEDEPTH(src); 9.939 - int depth = (depth1 < depth2) ? depth1 : depth2; 9.940 - /* check if keys are area keys (assuming that both keys have same type) */ 9.941 - if (PGL_KEY_IS_AREAKEY(dst)) { 9.942 - pgl_areakey dstbuf = { 0, }; /* destination buffer (cleared) */ 9.943 - int j = 0; /* bit offset for logarithmic object size bits */ 9.944 - int k = 0; /* bit offset for latitude and longitude */ 9.945 - /* fetch logarithmic object size information */ 9.946 - int objsize1 = PGL_KEY_OBJSIZE(dst); 9.947 - int objsize2 = PGL_KEY_OBJSIZE(src); 9.948 - /* handle special cases for empty objects (universal and empty keys) */ 9.949 - if ( 9.950 - objsize1 > PGL_AREAKEY_MAXOBJSIZE || 9.951 - objsize2 > PGL_AREAKEY_MAXOBJSIZE 9.952 - ) { 9.953 - if ( 9.954 - objsize1 == PGL_KEY_OBJSIZE_EMPTY && 9.955 - objsize2 == PGL_KEY_OBJSIZE_EMPTY 9.956 - ) pgl_key_set_empty(dst); 9.957 - else pgl_key_set_universal(dst); 9.958 - return; 9.959 - } 9.960 - /* iterate through key bits */ 9.961 - for (i=0; i<depth; i++) { 9.962 - /* every second bit is a bit describing the object size */ 9.963 - if (i%2 == 0) { 9.964 - /* increase bit counter for object size bits first */ 9.965 - /* (handy when setting objsize variable) */ 9.966 - j++; 9.967 - /* check if object size bit is set in neither key */ 9.968 - if (objsize1 >= j && objsize2 >= j) { 9.969 - /* set objsize in destination buffer to indicate that size bit is 9.970 - unset in destination buffer at the current bit position */ 9.971 - dstbuf[PGL_KEY_OBJSIZE_OFFSET] = j; 9.972 - } 9.973 - /* break if object size bit is set in one key only */ 9.974 - else if (objsize1 >= j || objsize2 >= j) break; 9.975 - } 9.976 - /* all other bits describe latitude and longitude */ 9.977 - else { 9.978 - /* break if bit differs in both keys */ 9.979 - if (PGL_KEY_LATLONBIT(dst, k)) { 9.980 - if (!PGL_KEY_LATLONBIT(src, k)) break; 9.981 - /* but set bit in destination buffer if bit is set in both keys */ 9.982 - dstbuf[k/8] |= 0x80 >> (k%8); 9.983 - } else if (PGL_KEY_LATLONBIT(src, k)) break; 9.984 - /* increase bit counter for latitude/longitude bits */ 9.985 - k++; 9.986 - } 9.987 - } 9.988 - /* set common node depth and type bit (type bit = 1) */ 9.989 - dstbuf[PGL_KEY_NODEDEPTH_OFFSET] = PGL_AREAKEY_TYPEMASK | i; 9.990 - /* copy contents of destination buffer to first key */ 9.991 - memcpy(dst, dstbuf, sizeof(pgl_areakey)); 9.992 - } 9.993 - /* if not, keys are point keys */ 9.994 - else { 9.995 - pgl_pointkey dstbuf = { 0, }; /* destination buffer (cleared) */ 9.996 - /* iterate through key bits */ 9.997 - for (i=0; i<depth; i++) { 9.998 - /* break if bit differs in both keys */ 9.999 - if (PGL_KEY_LATLONBIT(dst, i)) { 9.1000 - if (!PGL_KEY_LATLONBIT(src, i)) break; 9.1001 - /* but set bit in destination buffer if bit is set in both keys */ 9.1002 - dstbuf[i/8] |= 0x80 >> (i%8); 9.1003 - } else if (PGL_KEY_LATLONBIT(src, i)) break; 9.1004 - } 9.1005 - /* set common node depth (type bit = 0) */ 9.1006 - dstbuf[PGL_KEY_NODEDEPTH_OFFSET] = i; 9.1007 - /* copy contents of destination buffer to first key */ 9.1008 - memcpy(dst, dstbuf, sizeof(pgl_pointkey)); 9.1009 - } 9.1010 -} 9.1011 - 9.1012 -/* determine center(!) boundaries and radius estimation of index key */ 9.1013 -static double pgl_key_to_box(pgl_keyptr key, pgl_box *box) { 9.1014 - int i; 9.1015 - /* determine node depth */ 9.1016 - int depth = PGL_KEY_NODEDEPTH(key); 9.1017 - /* center point of possible result */ 9.1018 - double lat = 0; 9.1019 - double lon = 0; 9.1020 - /* maximum distance of real center point from key center */ 9.1021 - double dlat = 90; 9.1022 - double dlon = 180; 9.1023 - /* maximum radius of contained objects */ 9.1024 - double radius = 0; /* always return zero for point index keys */ 9.1025 - /* check if key is area key */ 9.1026 - if (PGL_KEY_IS_AREAKEY(key)) { 9.1027 - /* get logarithmic object size */ 9.1028 - int objsize = PGL_KEY_OBJSIZE(key); 9.1029 - /* handle special cases for empty objects (universal and empty keys) */ 9.1030 - if (objsize == PGL_KEY_OBJSIZE_EMPTY) { 9.1031 - pgl_box_set_empty(box); 9.1032 - return 0; 9.1033 - } else if (objsize == PGL_KEY_OBJSIZE_UNIVERSAL) { 9.1034 - box->lat_min = -90; 9.1035 - box->lat_max = 90; 9.1036 - box->lon_min = -180; 9.1037 - box->lon_max = 180; 9.1038 - return 0; /* any value >= 0 would do */ 9.1039 - } 9.1040 - /* calculate maximum possible radius of objects covered by the given key */ 9.1041 - if (objsize == 0) radius = INFINITY; 9.1042 - else { 9.1043 - radius = PGL_AREAKEY_REFOBJSIZE; 9.1044 - while (--objsize) radius /= M_SQRT2; 9.1045 - } 9.1046 - /* iterate over latitude and longitude bits in key */ 9.1047 - /* (every second bit is a latitude or longitude bit) */ 9.1048 - for (i=0; i<depth/2; i++) { 9.1049 - /* check if latitude bit */ 9.1050 - if (i%2 == 0) { 9.1051 - /* cut latitude dimension in half */ 9.1052 - dlat /= 2; 9.1053 - /* increase center latitude if bit is 1, otherwise decrease */ 9.1054 - if (PGL_KEY_LATLONBIT(key, i)) lat += dlat; 9.1055 - else lat -= dlat; 9.1056 - } 9.1057 - /* otherwise longitude bit */ 9.1058 - else { 9.1059 - /* cut longitude dimension in half */ 9.1060 - dlon /= 2; 9.1061 - /* increase center longitude if bit is 1, otherwise decrease */ 9.1062 - if (PGL_KEY_LATLONBIT(key, i)) lon += dlon; 9.1063 - else lon -= dlon; 9.1064 - } 9.1065 - } 9.1066 - } 9.1067 - /* if not, keys are point keys */ 9.1068 - else { 9.1069 - /* iterate over all bits in key */ 9.1070 - for (i=0; i<depth; i++) { 9.1071 - /* check if latitude bit */ 9.1072 - if (i%2 == 0) { 9.1073 - /* cut latitude dimension in half */ 9.1074 - dlat /= 2; 9.1075 - /* increase center latitude if bit is 1, otherwise decrease */ 9.1076 - if (PGL_KEY_LATLONBIT(key, i)) lat += dlat; 9.1077 - else lat -= dlat; 9.1078 - } 9.1079 - /* otherwise longitude bit */ 9.1080 - else { 9.1081 - /* cut longitude dimension in half */ 9.1082 - dlon /= 2; 9.1083 - /* increase center longitude if bit is 1, otherwise decrease */ 9.1084 - if (PGL_KEY_LATLONBIT(key, i)) lon += dlon; 9.1085 - else lon -= dlon; 9.1086 - } 9.1087 - } 9.1088 - } 9.1089 - /* calculate boundaries from center point and remaining dlat and dlon */ 9.1090 - /* (return values through pointer to box) */ 9.1091 - box->lat_min = lat - dlat; 9.1092 - box->lat_max = lat + dlat; 9.1093 - box->lon_min = lon - dlon; 9.1094 - box->lon_max = lon + dlon; 9.1095 - /* return radius (as a function return value) */ 9.1096 - return radius; 9.1097 -} 9.1098 - 9.1099 -/* estimator function for distance between point and index key */ 9.1100 -/* allowed to return smaller values than actually correct */ 9.1101 -static double pgl_estimate_key_distance(pgl_keyptr key, pgl_point *point) { 9.1102 - pgl_box box; /* center(!) bounding box of area index key */ 9.1103 - /* calculate center(!) bounding box and maximum radius of objects covered 9.1104 - by area index key (radius is zero for point index keys) */ 9.1105 - double distance = pgl_key_to_box(key, &box); 9.1106 - /* calculate estimated distance between bounding box of center point of 9.1107 - indexed object and point passed as second argument, then substract maximum 9.1108 - radius of objects covered by index key */ 9.1109 - /* (use PGL_FPE_SAFETY factor to cope with minor floating point errors) */ 9.1110 - distance = ( 9.1111 - pgl_estimate_point_box_distance(point, &box) / PGL_FPE_SAFETY - 9.1112 - distance * PGL_FPE_SAFETY 9.1113 - ); 9.1114 - /* truncate negative results to zero */ 9.1115 - if (distance <= 0) distance = 0; 9.1116 - /* return result */ 9.1117 - return distance; 9.1118 -} 9.1119 - 9.1120 - 9.1121 -/*---------------------------------* 9.1122 - * helper functions for text I/O * 9.1123 - *---------------------------------*/ 9.1124 - 9.1125 -#define PGL_NUMBUFLEN 64 /* buffer size for number to string conversion */ 9.1126 - 9.1127 -/* convert floating point number to string (round-trip safe) */ 9.1128 -static void pgl_print_float(char *buf, double flt) { 9.1129 - /* check if number is integral */ 9.1130 - if (trunc(flt) == flt) { 9.1131 - /* for integral floats use maximum precision */ 9.1132 - snprintf(buf, PGL_NUMBUFLEN, "%.17g", flt); 9.1133 - } else { 9.1134 - /* otherwise check if 15, 16, or 17 digits needed (round-trip safety) */ 9.1135 - snprintf(buf, PGL_NUMBUFLEN, "%.15g", flt); 9.1136 - if (strtod(buf, NULL) != flt) snprintf(buf, PGL_NUMBUFLEN, "%.16g", flt); 9.1137 - if (strtod(buf, NULL) != flt) snprintf(buf, PGL_NUMBUFLEN, "%.17g", flt); 9.1138 - } 9.1139 -} 9.1140 - 9.1141 -/* convert latitude floating point number (in degrees) to string */ 9.1142 -static void pgl_print_lat(char *buf, double lat) { 9.1143 - if (signbit(lat)) { 9.1144 - /* treat negative latitudes (including -0) as south */ 9.1145 - snprintf(buf, PGL_NUMBUFLEN, "S%015.12f", -lat); 9.1146 - } else { 9.1147 - /* treat positive latitudes (including +0) as north */ 9.1148 - snprintf(buf, PGL_NUMBUFLEN, "N%015.12f", lat); 9.1149 - } 9.1150 -} 9.1151 - 9.1152 -/* convert longitude floating point number (in degrees) to string */ 9.1153 -static void pgl_print_lon(char *buf, double lon) { 9.1154 - if (signbit(lon)) { 9.1155 - /* treat negative longitudes (including -0) as west */ 9.1156 - snprintf(buf, PGL_NUMBUFLEN, "W%016.12f", -lon); 9.1157 - } else { 9.1158 - /* treat positive longitudes (including +0) as east */ 9.1159 - snprintf(buf, PGL_NUMBUFLEN, "E%016.12f", lon); 9.1160 - } 9.1161 -} 9.1162 - 9.1163 -/* bit masks used as return value of pgl_scan() function */ 9.1164 -#define PGL_SCAN_NONE 0 /* no value has been parsed */ 9.1165 -#define PGL_SCAN_LAT (1<<0) /* latitude has been parsed */ 9.1166 -#define PGL_SCAN_LON (1<<1) /* longitude has been parsed */ 9.1167 -#define PGL_SCAN_LATLON (PGL_SCAN_LAT | PGL_SCAN_LON) /* bitwise OR of both */ 9.1168 - 9.1169 -/* parse a coordinate (can be latitude or longitude) */ 9.1170 -static int pgl_scan(char **str, double *lat, double *lon) { 9.1171 - double val; 9.1172 - int len; 9.1173 - if ( 9.1174 - sscanf(*str, " N %lf %n", &val, &len) || 9.1175 - sscanf(*str, " n %lf %n", &val, &len) 9.1176 - ) { 9.1177 - *str += len; *lat = val; return PGL_SCAN_LAT; 9.1178 - } 9.1179 - if ( 9.1180 - sscanf(*str, " S %lf %n", &val, &len) || 9.1181 - sscanf(*str, " s %lf %n", &val, &len) 9.1182 - ) { 9.1183 - *str += len; *lat = -val; return PGL_SCAN_LAT; 9.1184 - } 9.1185 - if ( 9.1186 - sscanf(*str, " E %lf %n", &val, &len) || 9.1187 - sscanf(*str, " e %lf %n", &val, &len) 9.1188 - ) { 9.1189 - *str += len; *lon = val; return PGL_SCAN_LON; 9.1190 - } 9.1191 - if ( 9.1192 - sscanf(*str, " W %lf %n", &val, &len) || 9.1193 - sscanf(*str, " w %lf %n", &val, &len) 9.1194 - ) { 9.1195 - *str += len; *lon = -val; return PGL_SCAN_LON; 9.1196 - } 9.1197 - return PGL_SCAN_NONE; 9.1198 -} 9.1199 - 9.1200 - 9.1201 -/*-----------------* 9.1202 - * SQL functions * 9.1203 - *-----------------*/ 9.1204 - 9.1205 -/* Note: These function names use "epoint", "ebox", etc. notation here instead 9.1206 - of "point", "box", etc. in order to distinguish them from any previously 9.1207 - defined functions. */ 9.1208 - 9.1209 -/* function needed for dummy types and/or not implemented features */ 9.1210 -PG_FUNCTION_INFO_V1(pgl_notimpl); 9.1211 -Datum pgl_notimpl(PG_FUNCTION_ARGS) { 9.1212 - ereport(ERROR, (errmsg("not implemented by pgLatLon"))); 9.1213 -} 9.1214 - 9.1215 -/* set point to latitude and longitude (including checks) */ 9.1216 -static void pgl_epoint_set_latlon(pgl_point *point, double lat, double lon) { 9.1217 - /* reject infinite or NaN values */ 9.1218 - if (!isfinite(lat) || !isfinite(lon)) { 9.1219 - ereport(ERROR, ( 9.1220 - errcode(ERRCODE_DATA_EXCEPTION), 9.1221 - errmsg("epoint requires finite coordinates") 9.1222 - )); 9.1223 - } 9.1224 - /* check latitude bounds */ 9.1225 - if (lat < -90) { 9.1226 - ereport(WARNING, (errmsg("latitude exceeds south pole"))); 9.1227 - lat = -90; 9.1228 - } else if (lat > 90) { 9.1229 - ereport(WARNING, (errmsg("latitude exceeds north pole"))); 9.1230 - lat = 90; 9.1231 - } 9.1232 - /* check longitude bounds */ 9.1233 - if (lon < -180) { 9.1234 - ereport(NOTICE, (errmsg("longitude west of 180th meridian normalized"))); 9.1235 - lon += 360 - trunc(lon / 360) * 360; 9.1236 - } else if (lon > 180) { 9.1237 - ereport(NOTICE, (errmsg("longitude east of 180th meridian normalized"))); 9.1238 - lon -= 360 + trunc(lon / 360) * 360; 9.1239 - } 9.1240 - /* store rounded latitude/longitude values for round-trip safety */ 9.1241 - point->lat = pgl_round(lat); 9.1242 - point->lon = pgl_round(lon); 9.1243 -} 9.1244 - 9.1245 -/* create point ("epoint" in SQL) from latitude and longitude */ 9.1246 -PG_FUNCTION_INFO_V1(pgl_create_epoint); 9.1247 -Datum pgl_create_epoint(PG_FUNCTION_ARGS) { 9.1248 - pgl_point *point = (pgl_point *)palloc(sizeof(pgl_point)); 9.1249 - pgl_epoint_set_latlon(point, PG_GETARG_FLOAT8(0), PG_GETARG_FLOAT8(1)); 9.1250 - PG_RETURN_POINTER(point); 9.1251 -} 9.1252 - 9.1253 -/* parse point ("epoint" in SQL) */ 9.1254 -/* format: '[NS]<float> [EW]<float>' */ 9.1255 -PG_FUNCTION_INFO_V1(pgl_epoint_in); 9.1256 -Datum pgl_epoint_in(PG_FUNCTION_ARGS) { 9.1257 - char *str = PG_GETARG_CSTRING(0); /* input string */ 9.1258 - char *strptr = str; /* current position within string */ 9.1259 - int done = 0; /* bit mask storing if latitude or longitude was read */ 9.1260 - double lat, lon; /* parsed values as double precision floats */ 9.1261 - pgl_point *point; /* return value (to be palloc'ed) */ 9.1262 - /* parse two floats (each latitude or longitude) separated by white-space */ 9.1263 - done |= pgl_scan(&strptr, &lat, &lon); 9.1264 - if (strptr != str && isspace(strptr[-1])) { 9.1265 - done |= pgl_scan(&strptr, &lat, &lon); 9.1266 - } 9.1267 - /* require end of string, and latitude and longitude parsed successfully */ 9.1268 - if (strptr[0] || done != PGL_SCAN_LATLON) { 9.1269 - ereport(ERROR, ( 9.1270 - errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 9.1271 - errmsg("invalid input syntax for type epoint: \"%s\"", str) 9.1272 - )); 9.1273 - } 9.1274 - /* allocate memory for result */ 9.1275 - point = (pgl_point *)palloc(sizeof(pgl_point)); 9.1276 - /* set latitude and longitude (and perform checks) */ 9.1277 - pgl_epoint_set_latlon(point, lat, lon); 9.1278 - /* return result */ 9.1279 - PG_RETURN_POINTER(point); 9.1280 -} 9.1281 - 9.1282 -/* create box ("ebox" in SQL) that is empty */ 9.1283 -PG_FUNCTION_INFO_V1(pgl_create_empty_ebox); 9.1284 -Datum pgl_create_empty_ebox(PG_FUNCTION_ARGS) { 9.1285 - pgl_box *box = (pgl_box *)palloc(sizeof(pgl_box)); 9.1286 - pgl_box_set_empty(box); 9.1287 - PG_RETURN_POINTER(box); 9.1288 -} 9.1289 - 9.1290 -/* set box to given boundaries (including checks) */ 9.1291 -static void pgl_ebox_set_boundaries( 9.1292 - pgl_box *box, 9.1293 - double lat_min, double lat_max, double lon_min, double lon_max 9.1294 -) { 9.1295 - /* if minimum latitude is greater than maximum latitude, return empty box */ 9.1296 - if (lat_min > lat_max) { 9.1297 - pgl_box_set_empty(box); 9.1298 - return; 9.1299 - } 9.1300 - /* otherwise reject infinite or NaN values */ 9.1301 - if ( 9.1302 - !isfinite(lat_min) || !isfinite(lat_max) || 9.1303 - !isfinite(lon_min) || !isfinite(lon_max) 9.1304 - ) { 9.1305 - ereport(ERROR, ( 9.1306 - errcode(ERRCODE_DATA_EXCEPTION), 9.1307 - errmsg("ebox requires finite coordinates") 9.1308 - )); 9.1309 - } 9.1310 - /* check latitude bounds */ 9.1311 - if (lat_max < -90) { 9.1312 - ereport(WARNING, (errmsg("northern latitude exceeds south pole"))); 9.1313 - lat_max = -90; 9.1314 - } else if (lat_max > 90) { 9.1315 - ereport(WARNING, (errmsg("northern latitude exceeds north pole"))); 9.1316 - lat_max = 90; 9.1317 - } 9.1318 - if (lat_min < -90) { 9.1319 - ereport(WARNING, (errmsg("southern latitude exceeds south pole"))); 9.1320 - lat_min = -90; 9.1321 - } else if (lat_min > 90) { 9.1322 - ereport(WARNING, (errmsg("southern latitude exceeds north pole"))); 9.1323 - lat_min = 90; 9.1324 - } 9.1325 - /* check if all longitudes are included */ 9.1326 - if (lon_max - lon_min >= 360) { 9.1327 - if (lon_max - lon_min > 360) ereport(WARNING, ( 9.1328 - errmsg("longitude coverage greater than 360 degrees") 9.1329 - )); 9.1330 - lon_min = -180; 9.1331 - lon_max = 180; 9.1332 - } else { 9.1333 - /* normalize longitude bounds */ 9.1334 - if (lon_min < -180) lon_min += 360 - trunc(lon_min / 360) * 360; 9.1335 - else if (lon_min > 180) lon_min -= 360 + trunc(lon_min / 360) * 360; 9.1336 - if (lon_max < -180) lon_max += 360 - trunc(lon_max / 360) * 360; 9.1337 - else if (lon_max > 180) lon_max -= 360 + trunc(lon_max / 360) * 360; 9.1338 - } 9.1339 - /* store rounded latitude/longitude values for round-trip safety */ 9.1340 - box->lat_min = pgl_round(lat_min); 9.1341 - box->lat_max = pgl_round(lat_max); 9.1342 - box->lon_min = pgl_round(lon_min); 9.1343 - box->lon_max = pgl_round(lon_max); 9.1344 - /* ensure that rounding does not change orientation */ 9.1345 - if (lon_min > lon_max && box->lon_min == box->lon_max) { 9.1346 - box->lon_min = -180; 9.1347 - box->lon_max = 180; 9.1348 - } 9.1349 -} 9.1350 - 9.1351 -/* create box ("ebox" in SQL) from min/max latitude and min/max longitude */ 9.1352 -PG_FUNCTION_INFO_V1(pgl_create_ebox); 9.1353 -Datum pgl_create_ebox(PG_FUNCTION_ARGS) { 9.1354 - pgl_box *box = (pgl_box *)palloc(sizeof(pgl_box)); 9.1355 - pgl_ebox_set_boundaries( 9.1356 - box, 9.1357 - PG_GETARG_FLOAT8(0), PG_GETARG_FLOAT8(1), 9.1358 - PG_GETARG_FLOAT8(2), PG_GETARG_FLOAT8(3) 9.1359 - ); 9.1360 - PG_RETURN_POINTER(box); 9.1361 -} 9.1362 - 9.1363 -/* create box ("ebox" in SQL) from two points ("epoint"s) */ 9.1364 -/* (can not be used to cover a longitude range of more than 120 degrees) */ 9.1365 -PG_FUNCTION_INFO_V1(pgl_create_ebox_from_epoints); 9.1366 -Datum pgl_create_ebox_from_epoints(PG_FUNCTION_ARGS) { 9.1367 - pgl_point *point1 = (pgl_point *)PG_GETARG_POINTER(0); 9.1368 - pgl_point *point2 = (pgl_point *)PG_GETARG_POINTER(1); 9.1369 - pgl_box *box = (pgl_box *)palloc(sizeof(pgl_box)); 9.1370 - double lat_min, lat_max, lon_min, lon_max; 9.1371 - double dlon; /* longitude range (delta longitude) */ 9.1372 - /* order latitude and longitude boundaries */ 9.1373 - if (point2->lat < point1->lat) { 9.1374 - lat_min = point2->lat; 9.1375 - lat_max = point1->lat; 9.1376 - } else { 9.1377 - lat_min = point1->lat; 9.1378 - lat_max = point2->lat; 9.1379 - } 9.1380 - if (point2->lon < point1->lon) { 9.1381 - lon_min = point2->lon; 9.1382 - lon_max = point1->lon; 9.1383 - } else { 9.1384 - lon_min = point1->lon; 9.1385 - lon_max = point2->lon; 9.1386 - } 9.1387 - /* calculate longitude range (round to avoid floating point errors) */ 9.1388 - dlon = pgl_round(lon_max - lon_min); 9.1389 - /* determine east-west direction */ 9.1390 - if (dlon >= 240) { 9.1391 - /* assume that 180th meridian is crossed and swap min/max longitude */ 9.1392 - double swap = lon_min; lon_min = lon_max; lon_max = swap; 9.1393 - } else if (dlon > 120) { 9.1394 - /* unclear orientation since delta longitude > 120 */ 9.1395 - ereport(ERROR, ( 9.1396 - errcode(ERRCODE_DATA_EXCEPTION), 9.1397 - errmsg("can not determine east/west orientation for ebox") 9.1398 - )); 9.1399 - } 9.1400 - /* use boundaries to setup box (and perform checks) */ 9.1401 - pgl_ebox_set_boundaries(box, lat_min, lat_max, lon_min, lon_max); 9.1402 - /* return result */ 9.1403 - PG_RETURN_POINTER(box); 9.1404 -} 9.1405 - 9.1406 -/* parse box ("ebox" in SQL) */ 9.1407 -/* format: '[NS]<float> [EW]<float> [NS]<float> [EW]<float>' 9.1408 - or: '[NS]<float> [NS]<float> [EW]<float> [EW]<float>' */ 9.1409 -PG_FUNCTION_INFO_V1(pgl_ebox_in); 9.1410 -Datum pgl_ebox_in(PG_FUNCTION_ARGS) { 9.1411 - char *str = PG_GETARG_CSTRING(0); /* input string */ 9.1412 - char *str_lower; /* lower case version of input string */ 9.1413 - char *strptr; /* current position within string */ 9.1414 - int valid; /* number of valid chars */ 9.1415 - int done; /* specifies if latitude or longitude was read */ 9.1416 - double val; /* temporary variable */ 9.1417 - int lat_count = 0; /* count of latitude values parsed */ 9.1418 - int lon_count = 0; /* count of longitufde values parsed */ 9.1419 - double lat_min, lat_max, lon_min, lon_max; /* see pgl_box struct */ 9.1420 - pgl_box *box; /* return value (to be palloc'ed) */ 9.1421 - /* lowercase input */ 9.1422 - str_lower = psprintf("%s", str); 9.1423 - for (strptr=str_lower; *strptr; strptr++) { 9.1424 - if (*strptr >= 'A' && *strptr <= 'Z') *strptr += 'a' - 'A'; 9.1425 - } 9.1426 - /* reset reading position to start of (lowercase) string */ 9.1427 - strptr = str_lower; 9.1428 - /* check if empty box */ 9.1429 - valid = 0; 9.1430 - sscanf(strptr, " empty %n", &valid); 9.1431 - if (valid && strptr[valid] == 0) { 9.1432 - /* allocate and return empty box */ 9.1433 - box = (pgl_box *)palloc(sizeof(pgl_box)); 9.1434 - pgl_box_set_empty(box); 9.1435 - PG_RETURN_POINTER(box); 9.1436 - } 9.1437 - /* demand four blocks separated by whitespace */ 9.1438 - valid = 0; 9.1439 - sscanf(strptr, " %*s %*s %*s %*s %n", &valid); 9.1440 - /* if four blocks separated by whitespace exist, parse those blocks */ 9.1441 - if (strptr[valid] == 0) while (strptr[0]) { 9.1442 - /* parse either latitude or longitude (whichever found in input string) */ 9.1443 - done = pgl_scan(&strptr, &val, &val); 9.1444 - /* store latitude or longitude in lat_min, lat_max, lon_min, or lon_max */ 9.1445 - if (done == PGL_SCAN_LAT) { 9.1446 - if (!lat_count) lat_min = val; else lat_max = val; 9.1447 - lat_count++; 9.1448 - } else if (done == PGL_SCAN_LON) { 9.1449 - if (!lon_count) lon_min = val; else lon_max = val; 9.1450 - lon_count++; 9.1451 - } else { 9.1452 - break; 9.1453 - } 9.1454 - } 9.1455 - /* require end of string, and two latitude and two longitude values */ 9.1456 - if (strptr[0] || lat_count != 2 || lon_count != 2) { 9.1457 - ereport(ERROR, ( 9.1458 - errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 9.1459 - errmsg("invalid input syntax for type ebox: \"%s\"", str) 9.1460 - )); 9.1461 - } 9.1462 - /* free lower case string */ 9.1463 - pfree(str_lower); 9.1464 - /* order boundaries (maximum greater than minimum) */ 9.1465 - if (lat_min > lat_max) { val = lat_min; lat_min = lat_max; lat_max = val; } 9.1466 - if (lon_min > lon_max) { val = lon_min; lon_min = lon_max; lon_max = val; } 9.1467 - /* allocate memory for result */ 9.1468 - box = (pgl_box *)palloc(sizeof(pgl_box)); 9.1469 - /* set boundaries (and perform checks) */ 9.1470 - pgl_ebox_set_boundaries(box, lat_min, lat_max, lon_min, lon_max); 9.1471 - /* return result */ 9.1472 - PG_RETURN_POINTER(box); 9.1473 -} 9.1474 - 9.1475 -/* set circle to given latitude, longitude, and radius (including checks) */ 9.1476 -static void pgl_ecircle_set_latlon_radius( 9.1477 - pgl_circle *circle, double lat, double lon, double radius 9.1478 -) { 9.1479 - /* set center point (including checks) */ 9.1480 - pgl_epoint_set_latlon(&(circle->center), lat, lon); 9.1481 - /* handle non-positive radius */ 9.1482 - if (isnan(radius)) { 9.1483 - ereport(ERROR, ( 9.1484 - errcode(ERRCODE_DATA_EXCEPTION), 9.1485 - errmsg("invalid radius for ecircle") 9.1486 - )); 9.1487 - } 9.1488 - if (radius == 0) radius = 0; /* avoids -0 */ 9.1489 - else if (radius < 0) { 9.1490 - if (isfinite(radius)) { 9.1491 - ereport(NOTICE, (errmsg("negative radius converted to minus infinity"))); 9.1492 - } 9.1493 - radius = -INFINITY; 9.1494 - } 9.1495 - /* store radius (round-trip safety is ensured by pgl_print_float) */ 9.1496 - circle->radius = radius; 9.1497 -} 9.1498 - 9.1499 -/* create circle ("ecircle" in SQL) from latitude, longitude, and radius */ 9.1500 -PG_FUNCTION_INFO_V1(pgl_create_ecircle); 9.1501 -Datum pgl_create_ecircle(PG_FUNCTION_ARGS) { 9.1502 - pgl_circle *circle = (pgl_circle *)palloc(sizeof(pgl_circle)); 9.1503 - pgl_ecircle_set_latlon_radius( 9.1504 - circle, PG_GETARG_FLOAT8(0), PG_GETARG_FLOAT8(1), PG_GETARG_FLOAT8(2) 9.1505 - ); 9.1506 - PG_RETURN_POINTER(circle); 9.1507 -} 9.1508 - 9.1509 -/* create circle ("ecircle" in SQL) from point ("epoint"), and radius */ 9.1510 -PG_FUNCTION_INFO_V1(pgl_create_ecircle_from_epoint); 9.1511 -Datum pgl_create_ecircle_from_epoint(PG_FUNCTION_ARGS) { 9.1512 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 9.1513 - double radius = PG_GETARG_FLOAT8(1); 9.1514 - pgl_circle *circle = (pgl_circle *)palloc(sizeof(pgl_circle)); 9.1515 - /* set latitude, longitude, radius (and perform checks) */ 9.1516 - pgl_ecircle_set_latlon_radius(circle, point->lat, point->lon, radius); 9.1517 - /* return result */ 9.1518 - PG_RETURN_POINTER(circle); 9.1519 -} 9.1520 - 9.1521 -/* parse circle ("ecircle" in SQL) */ 9.1522 -/* format: '[NS]<float> [EW]<float> <float>' */ 9.1523 -PG_FUNCTION_INFO_V1(pgl_ecircle_in); 9.1524 -Datum pgl_ecircle_in(PG_FUNCTION_ARGS) { 9.1525 - char *str = PG_GETARG_CSTRING(0); /* input string */ 9.1526 - char *strptr = str; /* current position within string */ 9.1527 - double lat, lon, radius; /* parsed values as double precision flaots */ 9.1528 - int valid = 0; /* number of valid chars */ 9.1529 - int done = 0; /* stores if latitude and/or longitude was read */ 9.1530 - pgl_circle *circle; /* return value (to be palloc'ed) */ 9.1531 - /* demand three blocks separated by whitespace */ 9.1532 - sscanf(strptr, " %*s %*s %*s %n", &valid); 9.1533 - /* if three blocks separated by whitespace exist, parse those blocks */ 9.1534 - if (strptr[valid] == 0) { 9.1535 - /* parse latitude and longitude */ 9.1536 - done |= pgl_scan(&strptr, &lat, &lon); 9.1537 - done |= pgl_scan(&strptr, &lat, &lon); 9.1538 - /* parse radius (while incrementing strptr by number of bytes parsed) */ 9.1539 - valid = 0; 9.1540 - if (sscanf(strptr, " %lf %n", &radius, &valid) == 1) strptr += valid; 9.1541 - } 9.1542 - /* require end of string and both latitude and longitude being parsed */ 9.1543 - if (strptr[0] || done != PGL_SCAN_LATLON) { 9.1544 - ereport(ERROR, ( 9.1545 - errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 9.1546 - errmsg("invalid input syntax for type ecircle: \"%s\"", str) 9.1547 - )); 9.1548 - } 9.1549 - /* allocate memory for result */ 9.1550 - circle = (pgl_circle *)palloc(sizeof(pgl_circle)); 9.1551 - /* set latitude, longitude, radius (and perform checks) */ 9.1552 - pgl_ecircle_set_latlon_radius(circle, lat, lon, radius); 9.1553 - /* return result */ 9.1554 - PG_RETURN_POINTER(circle); 9.1555 -} 9.1556 - 9.1557 -/* parse cluster ("ecluster" in SQL) */ 9.1558 -PG_FUNCTION_INFO_V1(pgl_ecluster_in); 9.1559 -Datum pgl_ecluster_in(PG_FUNCTION_ARGS) { 9.1560 - int i; 9.1561 - char *str = PG_GETARG_CSTRING(0); /* input string */ 9.1562 - char *str_lower; /* lower case version of input string */ 9.1563 - char *strptr; /* pointer to current reading position of input */ 9.1564 - int npoints_total = 0; /* total number of points in cluster */ 9.1565 - int nentries = 0; /* total number of entries */ 9.1566 - pgl_newentry *entries; /* array of pgl_newentry to create pgl_cluster */ 9.1567 - int entries_buflen = 4; /* maximum number of elements in entries array */ 9.1568 - int valid; /* number of valid chars processed */ 9.1569 - double lat, lon; /* latitude and longitude of parsed point */ 9.1570 - int entrytype; /* current entry type */ 9.1571 - int npoints; /* number of points in current entry */ 9.1572 - pgl_point *points; /* array of pgl_point for pgl_newentry */ 9.1573 - int points_buflen; /* maximum number of elements in points array */ 9.1574 - int done; /* return value of pgl_scan function */ 9.1575 - pgl_cluster *cluster; /* created cluster */ 9.1576 - /* lowercase input */ 9.1577 - str_lower = psprintf("%s", str); 9.1578 - for (strptr=str_lower; *strptr; strptr++) { 9.1579 - if (*strptr >= 'A' && *strptr <= 'Z') *strptr += 'a' - 'A'; 9.1580 - } 9.1581 - /* reset reading position to start of (lowercase) string */ 9.1582 - strptr = str_lower; 9.1583 - /* allocate initial buffer for entries */ 9.1584 - entries = palloc(entries_buflen * sizeof(pgl_newentry)); 9.1585 - /* parse until end of string */ 9.1586 - while (strptr[0]) { 9.1587 - /* require previous white-space or closing parenthesis before next token */ 9.1588 - if (strptr != str_lower && !isspace(strptr[-1]) && strptr[-1] != ')') { 9.1589 - goto pgl_ecluster_in_error; 9.1590 - } 9.1591 - /* ignore token "empty" */ 9.1592 - valid = 0; sscanf(strptr, " empty %n", &valid); 9.1593 - if (valid) { strptr += valid; continue; } 9.1594 - /* test for "point" token */ 9.1595 - valid = 0; sscanf(strptr, " point ( %n", &valid); 9.1596 - if (valid) { 9.1597 - strptr += valid; 9.1598 - entrytype = PGL_ENTRY_POINT; 9.1599 - goto pgl_ecluster_in_type_ok; 9.1600 - } 9.1601 - /* test for "path" token */ 9.1602 - valid = 0; sscanf(strptr, " path ( %n", &valid); 9.1603 - if (valid) { 9.1604 - strptr += valid; 9.1605 - entrytype = PGL_ENTRY_PATH; 9.1606 - goto pgl_ecluster_in_type_ok; 9.1607 - } 9.1608 - /* test for "outline" token */ 9.1609 - valid = 0; sscanf(strptr, " outline ( %n", &valid); 9.1610 - if (valid) { 9.1611 - strptr += valid; 9.1612 - entrytype = PGL_ENTRY_OUTLINE; 9.1613 - goto pgl_ecluster_in_type_ok; 9.1614 - } 9.1615 - /* test for "polygon" token */ 9.1616 - valid = 0; sscanf(strptr, " polygon ( %n", &valid); 9.1617 - if (valid) { 9.1618 - strptr += valid; 9.1619 - entrytype = PGL_ENTRY_POLYGON; 9.1620 - goto pgl_ecluster_in_type_ok; 9.1621 - } 9.1622 - /* error if no valid token found */ 9.1623 - goto pgl_ecluster_in_error; 9.1624 - pgl_ecluster_in_type_ok: 9.1625 - /* check if pgl_newentry array needs to grow */ 9.1626 - if (nentries == entries_buflen) { 9.1627 - pgl_newentry *newbuf; 9.1628 - entries_buflen *= 2; 9.1629 - newbuf = palloc(entries_buflen * sizeof(pgl_newentry)); 9.1630 - memcpy(newbuf, entries, nentries * sizeof(pgl_newentry)); 9.1631 - pfree(entries); 9.1632 - entries = newbuf; 9.1633 - } 9.1634 - /* reset number of points for current entry */ 9.1635 - npoints = 0; 9.1636 - /* allocate array for points */ 9.1637 - points_buflen = 4; 9.1638 - points = palloc(points_buflen * sizeof(pgl_point)); 9.1639 - /* parse until closing parenthesis */ 9.1640 - while (strptr[0] != ')') { 9.1641 - /* error on unexpected end of string */ 9.1642 - if (strptr[0] == 0) goto pgl_ecluster_in_error; 9.1643 - /* mark neither latitude nor longitude as read */ 9.1644 - done = PGL_SCAN_NONE; 9.1645 - /* require white-space before second, third, etc. point */ 9.1646 - if (npoints != 0 && !isspace(strptr[-1])) goto pgl_ecluster_in_error; 9.1647 - /* scan latitude (or longitude) */ 9.1648 - done |= pgl_scan(&strptr, &lat, &lon); 9.1649 - /* require white-space before second coordinate */ 9.1650 - if (strptr != str && !isspace(strptr[-1])) goto pgl_ecluster_in_error; 9.1651 - /* scan longitude (or latitude) */ 9.1652 - done |= pgl_scan(&strptr, &lat, &lon); 9.1653 - /* error unless both latitude and longitude were parsed */ 9.1654 - if (done != PGL_SCAN_LATLON) goto pgl_ecluster_in_error; 9.1655 - /* throw error if number of points is too high */ 9.1656 - if (npoints_total == PGL_CLUSTER_MAXPOINTS) { 9.1657 - ereport(ERROR, ( 9.1658 - errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 9.1659 - errmsg( 9.1660 - "too many points for ecluster entry (maximum %i)", 9.1661 - PGL_CLUSTER_MAXPOINTS 9.1662 - ) 9.1663 - )); 9.1664 - } 9.1665 - /* check if pgl_point array needs to grow */ 9.1666 - if (npoints == points_buflen) { 9.1667 - pgl_point *newbuf; 9.1668 - points_buflen *= 2; 9.1669 - newbuf = palloc(points_buflen * sizeof(pgl_point)); 9.1670 - memcpy(newbuf, points, npoints * sizeof(pgl_point)); 9.1671 - pfree(points); 9.1672 - points = newbuf; 9.1673 - } 9.1674 - /* append point to pgl_point array (includes checks) */ 9.1675 - pgl_epoint_set_latlon(&(points[npoints++]), lat, lon); 9.1676 - /* increase total number of points */ 9.1677 - npoints_total++; 9.1678 - } 9.1679 - /* error if entry has no points */ 9.1680 - if (!npoints) goto pgl_ecluster_in_error; 9.1681 - /* entries with one point are automatically of type "point" */ 9.1682 - if (npoints == 1) entrytype = PGL_ENTRY_POINT; 9.1683 - /* if entries have more than one point */ 9.1684 - else { 9.1685 - /* throw error if entry type is "point" */ 9.1686 - if (entrytype == PGL_ENTRY_POINT) { 9.1687 - ereport(ERROR, ( 9.1688 - errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 9.1689 - errmsg("invalid input syntax for type ecluster (point entry with more than one point)") 9.1690 - )); 9.1691 - } 9.1692 - /* coerce outlines and polygons with more than 2 points to be a path */ 9.1693 - if (npoints == 2) entrytype = PGL_ENTRY_PATH; 9.1694 - } 9.1695 - /* append entry to pgl_newentry array */ 9.1696 - entries[nentries].entrytype = entrytype; 9.1697 - entries[nentries].npoints = npoints; 9.1698 - entries[nentries].points = points; 9.1699 - nentries++; 9.1700 - /* consume closing parenthesis */ 9.1701 - strptr++; 9.1702 - /* consume white-space */ 9.1703 - while (isspace(strptr[0])) strptr++; 9.1704 - } 9.1705 - /* free lower case string */ 9.1706 - pfree(str_lower); 9.1707 - /* create cluster from pgl_newentry array */ 9.1708 - cluster = pgl_new_cluster(nentries, entries); 9.1709 - /* free pgl_newentry array */ 9.1710 - for (i=0; i<nentries; i++) pfree(entries[i].points); 9.1711 - pfree(entries); 9.1712 - /* set bounding circle of cluster and check east/west orientation */ 9.1713 - if (!pgl_finalize_cluster(cluster)) { 9.1714 - ereport(ERROR, ( 9.1715 - errcode(ERRCODE_DATA_EXCEPTION), 9.1716 - errmsg("can not determine east/west orientation for ecluster"), 9.1717 - errhint("Ensure that each entry has a longitude span of less than 180 degrees.") 9.1718 - )); 9.1719 - } 9.1720 - /* return cluster */ 9.1721 - PG_RETURN_POINTER(cluster); 9.1722 - /* code to throw error */ 9.1723 - pgl_ecluster_in_error: 9.1724 - ereport(ERROR, ( 9.1725 - errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 9.1726 - errmsg("invalid input syntax for type ecluster: \"%s\"", str) 9.1727 - )); 9.1728 -} 9.1729 - 9.1730 -/* convert point ("epoint") to string representation */ 9.1731 -PG_FUNCTION_INFO_V1(pgl_epoint_out); 9.1732 -Datum pgl_epoint_out(PG_FUNCTION_ARGS) { 9.1733 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 9.1734 - char latstr[PGL_NUMBUFLEN]; 9.1735 - char lonstr[PGL_NUMBUFLEN]; 9.1736 - pgl_print_lat(latstr, point->lat); 9.1737 - pgl_print_lon(lonstr, point->lon); 9.1738 - PG_RETURN_CSTRING(psprintf("%s %s", latstr, lonstr)); 9.1739 -} 9.1740 - 9.1741 -/* convert box ("ebox") to string representation */ 9.1742 -PG_FUNCTION_INFO_V1(pgl_ebox_out); 9.1743 -Datum pgl_ebox_out(PG_FUNCTION_ARGS) { 9.1744 - pgl_box *box = (pgl_box *)PG_GETARG_POINTER(0); 9.1745 - double lon_min = box->lon_min; 9.1746 - double lon_max = box->lon_max; 9.1747 - char lat_min_str[PGL_NUMBUFLEN]; 9.1748 - char lat_max_str[PGL_NUMBUFLEN]; 9.1749 - char lon_min_str[PGL_NUMBUFLEN]; 9.1750 - char lon_max_str[PGL_NUMBUFLEN]; 9.1751 - /* return string "empty" if box is set to be empty */ 9.1752 - if (box->lat_min > box->lat_max) PG_RETURN_CSTRING("empty"); 9.1753 - /* use boundaries exceeding W180 or E180 if 180th meridian is enclosed */ 9.1754 - /* (required since pgl_box_in orders the longitude boundaries) */ 9.1755 - if (lon_min > lon_max) { 9.1756 - if (lon_min + lon_max >= 0) lon_min -= 360; 9.1757 - else lon_max += 360; 9.1758 - } 9.1759 - /* format and return result */ 9.1760 - pgl_print_lat(lat_min_str, box->lat_min); 9.1761 - pgl_print_lat(lat_max_str, box->lat_max); 9.1762 - pgl_print_lon(lon_min_str, lon_min); 9.1763 - pgl_print_lon(lon_max_str, lon_max); 9.1764 - PG_RETURN_CSTRING(psprintf( 9.1765 - "%s %s %s %s", 9.1766 - lat_min_str, lon_min_str, lat_max_str, lon_max_str 9.1767 - )); 9.1768 -} 9.1769 - 9.1770 -/* convert circle ("ecircle") to string representation */ 9.1771 -PG_FUNCTION_INFO_V1(pgl_ecircle_out); 9.1772 -Datum pgl_ecircle_out(PG_FUNCTION_ARGS) { 9.1773 - pgl_circle *circle = (pgl_circle *)PG_GETARG_POINTER(0); 9.1774 - char latstr[PGL_NUMBUFLEN]; 9.1775 - char lonstr[PGL_NUMBUFLEN]; 9.1776 - char radstr[PGL_NUMBUFLEN]; 9.1777 - pgl_print_lat(latstr, circle->center.lat); 9.1778 - pgl_print_lon(lonstr, circle->center.lon); 9.1779 - pgl_print_float(radstr, circle->radius); 9.1780 - PG_RETURN_CSTRING(psprintf("%s %s %s", latstr, lonstr, radstr)); 9.1781 -} 9.1782 - 9.1783 -/* convert cluster ("ecluster") to string representation */ 9.1784 -PG_FUNCTION_INFO_V1(pgl_ecluster_out); 9.1785 -Datum pgl_ecluster_out(PG_FUNCTION_ARGS) { 9.1786 - pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); 9.1787 - char latstr[PGL_NUMBUFLEN]; /* string buffer for latitude */ 9.1788 - char lonstr[PGL_NUMBUFLEN]; /* string buffer for longitude */ 9.1789 - char ***strings; /* array of array of strings */ 9.1790 - char *string; /* string of current token */ 9.1791 - char *res, *resptr; /* result and pointer to current write position */ 9.1792 - size_t reslen = 1; /* length of result (init with 1 for terminator) */ 9.1793 - int npoints; /* number of points of current entry */ 9.1794 - int i, j; /* i: entry, j: point in entry */ 9.1795 - /* handle empty clusters */ 9.1796 - if (cluster->nentries == 0) { 9.1797 - /* free detoasted cluster (if copy) */ 9.1798 - PG_FREE_IF_COPY(cluster, 0); 9.1799 - /* return static result */ 9.1800 - PG_RETURN_CSTRING("empty"); 9.1801 - } 9.1802 - /* allocate array of array of strings */ 9.1803 - strings = palloc(cluster->nentries * sizeof(char **)); 9.1804 - /* iterate over all entries in cluster */ 9.1805 - for (i=0; i<cluster->nentries; i++) { 9.1806 - /* get number of points in entry */ 9.1807 - npoints = cluster->entries[i].npoints; 9.1808 - /* allocate array of strings (one string for each point plus two extra) */ 9.1809 - strings[i] = palloc((2 + npoints) * sizeof(char *)); 9.1810 - /* determine opening string */ 9.1811 - switch (cluster->entries[i].entrytype) { 9.1812 - case PGL_ENTRY_POINT: string = (i==0)?"point (" :" point ("; break; 9.1813 - case PGL_ENTRY_PATH: string = (i==0)?"path (" :" path ("; break; 9.1814 - case PGL_ENTRY_OUTLINE: string = (i==0)?"outline (":" outline ("; break; 9.1815 - case PGL_ENTRY_POLYGON: string = (i==0)?"polygon (":" polygon ("; break; 9.1816 - default: string = (i==0)?"unknown" :" unknown"; 9.1817 - } 9.1818 - /* use opening string as first string in array */ 9.1819 - strings[i][0] = string; 9.1820 - /* update result length (for allocating result string later) */ 9.1821 - reslen += strlen(string); 9.1822 - /* iterate over all points */ 9.1823 - for (j=0; j<npoints; j++) { 9.1824 - /* create string representation of point */ 9.1825 - pgl_print_lat(latstr, PGL_ENTRY_POINTS(cluster, i)[j].lat); 9.1826 - pgl_print_lon(lonstr, PGL_ENTRY_POINTS(cluster, i)[j].lon); 9.1827 - string = psprintf((j == 0) ? "%s %s" : " %s %s", latstr, lonstr); 9.1828 - /* copy string pointer to string array */ 9.1829 - strings[i][j+1] = string; 9.1830 - /* update result length (for allocating result string later) */ 9.1831 - reslen += strlen(string); 9.1832 - } 9.1833 - /* use closing parenthesis as last string in array */ 9.1834 - strings[i][npoints+1] = ")"; 9.1835 - /* update result length (for allocating result string later) */ 9.1836 - reslen++; 9.1837 - } 9.1838 - /* allocate result string */ 9.1839 - res = palloc(reslen); 9.1840 - /* set write pointer to begin of result string */ 9.1841 - resptr = res; 9.1842 - /* copy strings into result string */ 9.1843 - for (i=0; i<cluster->nentries; i++) { 9.1844 - npoints = cluster->entries[i].npoints; 9.1845 - for (j=0; j<npoints+2; j++) { 9.1846 - string = strings[i][j]; 9.1847 - strcpy(resptr, string); 9.1848 - resptr += strlen(string); 9.1849 - /* free strings allocated by psprintf */ 9.1850 - if (j != 0 && j != npoints+1) pfree(string); 9.1851 - } 9.1852 - /* free array of strings */ 9.1853 - pfree(strings[i]); 9.1854 - } 9.1855 - /* free array of array of strings */ 9.1856 - pfree(strings); 9.1857 - /* free detoasted cluster (if copy) */ 9.1858 - PG_FREE_IF_COPY(cluster, 0); 9.1859 - /* return result */ 9.1860 - PG_RETURN_CSTRING(res); 9.1861 -} 9.1862 - 9.1863 -/* binary input function for point ("epoint") */ 9.1864 -PG_FUNCTION_INFO_V1(pgl_epoint_recv); 9.1865 -Datum pgl_epoint_recv(PG_FUNCTION_ARGS) { 9.1866 - StringInfo buf = (StringInfo)PG_GETARG_POINTER(0); 9.1867 - pgl_point *point = (pgl_point *)palloc(sizeof(pgl_point)); 9.1868 - point->lat = pq_getmsgfloat8(buf); 9.1869 - point->lon = pq_getmsgfloat8(buf); 9.1870 - PG_RETURN_POINTER(point); 9.1871 -} 9.1872 - 9.1873 -/* binary input function for box ("ebox") */ 9.1874 -PG_FUNCTION_INFO_V1(pgl_ebox_recv); 9.1875 -Datum pgl_ebox_recv(PG_FUNCTION_ARGS) { 9.1876 - StringInfo buf = (StringInfo)PG_GETARG_POINTER(0); 9.1877 - pgl_box *box = (pgl_box *)palloc(sizeof(pgl_box)); 9.1878 - box->lat_min = pq_getmsgfloat8(buf); 9.1879 - box->lat_max = pq_getmsgfloat8(buf); 9.1880 - box->lon_min = pq_getmsgfloat8(buf); 9.1881 - box->lon_max = pq_getmsgfloat8(buf); 9.1882 - PG_RETURN_POINTER(box); 9.1883 -} 9.1884 - 9.1885 -/* binary input function for circle ("ecircle") */ 9.1886 -PG_FUNCTION_INFO_V1(pgl_ecircle_recv); 9.1887 -Datum pgl_ecircle_recv(PG_FUNCTION_ARGS) { 9.1888 - StringInfo buf = (StringInfo)PG_GETARG_POINTER(0); 9.1889 - pgl_circle *circle = (pgl_circle *)palloc(sizeof(pgl_circle)); 9.1890 - circle->center.lat = pq_getmsgfloat8(buf); 9.1891 - circle->center.lon = pq_getmsgfloat8(buf); 9.1892 - circle->radius = pq_getmsgfloat8(buf); 9.1893 - PG_RETURN_POINTER(circle); 9.1894 -} 9.1895 - 9.1896 -/* TODO: binary receive function for cluster */ 9.1897 - 9.1898 -/* binary output function for point ("epoint") */ 9.1899 -PG_FUNCTION_INFO_V1(pgl_epoint_send); 9.1900 -Datum pgl_epoint_send(PG_FUNCTION_ARGS) { 9.1901 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 9.1902 - StringInfoData buf; 9.1903 - pq_begintypsend(&buf); 9.1904 - pq_sendfloat8(&buf, point->lat); 9.1905 - pq_sendfloat8(&buf, point->lon); 9.1906 - PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); 9.1907 -} 9.1908 - 9.1909 -/* binary output function for box ("ebox") */ 9.1910 -PG_FUNCTION_INFO_V1(pgl_ebox_send); 9.1911 -Datum pgl_ebox_send(PG_FUNCTION_ARGS) { 9.1912 - pgl_box *box = (pgl_box *)PG_GETARG_POINTER(0); 9.1913 - StringInfoData buf; 9.1914 - pq_begintypsend(&buf); 9.1915 - pq_sendfloat8(&buf, box->lat_min); 9.1916 - pq_sendfloat8(&buf, box->lat_max); 9.1917 - pq_sendfloat8(&buf, box->lon_min); 9.1918 - pq_sendfloat8(&buf, box->lon_max); 9.1919 - PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); 9.1920 -} 9.1921 - 9.1922 -/* binary output function for circle ("ecircle") */ 9.1923 -PG_FUNCTION_INFO_V1(pgl_ecircle_send); 9.1924 -Datum pgl_ecircle_send(PG_FUNCTION_ARGS) { 9.1925 - pgl_circle *circle = (pgl_circle *)PG_GETARG_POINTER(0); 9.1926 - StringInfoData buf; 9.1927 - pq_begintypsend(&buf); 9.1928 - pq_sendfloat8(&buf, circle->center.lat); 9.1929 - pq_sendfloat8(&buf, circle->center.lon); 9.1930 - pq_sendfloat8(&buf, circle->radius); 9.1931 - PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); 9.1932 -} 9.1933 - 9.1934 -/* TODO: binary send functions for cluster */ 9.1935 - 9.1936 -/* cast point ("epoint") to box ("ebox") */ 9.1937 -PG_FUNCTION_INFO_V1(pgl_epoint_to_ebox); 9.1938 -Datum pgl_epoint_to_ebox(PG_FUNCTION_ARGS) { 9.1939 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 9.1940 - pgl_box *box = palloc(sizeof(pgl_box)); 9.1941 - box->lat_min = point->lat; 9.1942 - box->lat_max = point->lat; 9.1943 - box->lon_min = point->lon; 9.1944 - box->lon_max = point->lon; 9.1945 - PG_RETURN_POINTER(box); 9.1946 -} 9.1947 - 9.1948 -/* cast point ("epoint") to circle ("ecircle") */ 9.1949 -PG_FUNCTION_INFO_V1(pgl_epoint_to_ecircle); 9.1950 -Datum pgl_epoint_to_ecircle(PG_FUNCTION_ARGS) { 9.1951 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 9.1952 - pgl_circle *circle = palloc(sizeof(pgl_box)); 9.1953 - circle->center = *point; 9.1954 - circle->radius = 0; 9.1955 - PG_RETURN_POINTER(circle); 9.1956 -} 9.1957 - 9.1958 -/* cast point ("epoint") to cluster ("ecluster") */ 9.1959 -PG_FUNCTION_INFO_V1(pgl_epoint_to_ecluster); 9.1960 -Datum pgl_epoint_to_ecluster(PG_FUNCTION_ARGS) { 9.1961 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 9.1962 - pgl_newentry entry; 9.1963 - entry.entrytype = PGL_ENTRY_POINT; 9.1964 - entry.npoints = 1; 9.1965 - entry.points = point; 9.1966 - PG_RETURN_POINTER(pgl_new_cluster(1, &entry)); 9.1967 -} 9.1968 - 9.1969 -/* cast box ("ebox") to cluster ("ecluster") */ 9.1970 -#define pgl_ebox_to_ecluster_macro(i, a, b) \ 9.1971 - entries[i].entrytype = PGL_ENTRY_POLYGON; \ 9.1972 - entries[i].npoints = 4; \ 9.1973 - entries[i].points = points[i]; \ 9.1974 - points[i][0].lat = box->lat_min; \ 9.1975 - points[i][0].lon = (a); \ 9.1976 - points[i][1].lat = box->lat_min; \ 9.1977 - points[i][1].lon = (b); \ 9.1978 - points[i][2].lat = box->lat_max; \ 9.1979 - points[i][2].lon = (b); \ 9.1980 - points[i][3].lat = box->lat_max; \ 9.1981 - points[i][3].lon = (a); 9.1982 -PG_FUNCTION_INFO_V1(pgl_ebox_to_ecluster); 9.1983 -Datum pgl_ebox_to_ecluster(PG_FUNCTION_ARGS) { 9.1984 - pgl_box *box = (pgl_box *)PG_GETARG_POINTER(0); 9.1985 - double lon, dlon; 9.1986 - int nentries; 9.1987 - pgl_newentry entries[3]; 9.1988 - pgl_point points[3][4]; 9.1989 - if (box->lat_min > box->lat_max) { 9.1990 - nentries = 0; 9.1991 - } else if (box->lon_min > box->lon_max) { 9.1992 - if (box->lon_min < 0) { 9.1993 - lon = pgl_round((box->lon_min + 180) / 2.0); 9.1994 - nentries = 3; 9.1995 - pgl_ebox_to_ecluster_macro(0, box->lon_min, lon); 9.1996 - pgl_ebox_to_ecluster_macro(1, lon, 180); 9.1997 - pgl_ebox_to_ecluster_macro(2, -180, box->lon_max); 9.1998 - } else if (box->lon_max > 0) { 9.1999 - lon = pgl_round((box->lon_max - 180) / 2.0); 9.2000 - nentries = 3; 9.2001 - pgl_ebox_to_ecluster_macro(0, box->lon_min, 180); 9.2002 - pgl_ebox_to_ecluster_macro(1, -180, lon); 9.2003 - pgl_ebox_to_ecluster_macro(2, lon, box->lon_max); 9.2004 - } else { 9.2005 - nentries = 2; 9.2006 - pgl_ebox_to_ecluster_macro(0, box->lon_min, 180); 9.2007 - pgl_ebox_to_ecluster_macro(1, -180, box->lon_max); 9.2008 - } 9.2009 - } else { 9.2010 - dlon = pgl_round(box->lon_max - box->lon_min); 9.2011 - if (dlon < 180) { 9.2012 - nentries = 1; 9.2013 - pgl_ebox_to_ecluster_macro(0, box->lon_min, box->lon_max); 9.2014 - } else { 9.2015 - lon = pgl_round((box->lon_min + box->lon_max) / 2.0); 9.2016 - if ( 9.2017 - pgl_round(lon - box->lon_min) < 180 && 9.2018 - pgl_round(box->lon_max - lon) < 180 9.2019 - ) { 9.2020 - nentries = 2; 9.2021 - pgl_ebox_to_ecluster_macro(0, box->lon_min, lon); 9.2022 - pgl_ebox_to_ecluster_macro(1, lon, box->lon_max); 9.2023 - } else { 9.2024 - nentries = 3; 9.2025 - pgl_ebox_to_ecluster_macro(0, box->lon_min, -60); 9.2026 - pgl_ebox_to_ecluster_macro(1, -60, 60); 9.2027 - pgl_ebox_to_ecluster_macro(2, 60, box->lon_max); 9.2028 - } 9.2029 - } 9.2030 - } 9.2031 - PG_RETURN_POINTER(pgl_new_cluster(nentries, entries)); 9.2032 -} 9.2033 - 9.2034 -/* extract latitude from point ("epoint") */ 9.2035 -PG_FUNCTION_INFO_V1(pgl_epoint_lat); 9.2036 -Datum pgl_epoint_lat(PG_FUNCTION_ARGS) { 9.2037 - PG_RETURN_FLOAT8(((pgl_point *)PG_GETARG_POINTER(0))->lat); 9.2038 -} 9.2039 - 9.2040 -/* extract longitude from point ("epoint") */ 9.2041 -PG_FUNCTION_INFO_V1(pgl_epoint_lon); 9.2042 -Datum pgl_epoint_lon(PG_FUNCTION_ARGS) { 9.2043 - PG_RETURN_FLOAT8(((pgl_point *)PG_GETARG_POINTER(0))->lon); 9.2044 -} 9.2045 - 9.2046 -/* extract minimum latitude from box ("ebox") */ 9.2047 -PG_FUNCTION_INFO_V1(pgl_ebox_lat_min); 9.2048 -Datum pgl_ebox_lat_min(PG_FUNCTION_ARGS) { 9.2049 - PG_RETURN_FLOAT8(((pgl_box *)PG_GETARG_POINTER(0))->lat_min); 9.2050 -} 9.2051 - 9.2052 -/* extract maximum latitude from box ("ebox") */ 9.2053 -PG_FUNCTION_INFO_V1(pgl_ebox_lat_max); 9.2054 -Datum pgl_ebox_lat_max(PG_FUNCTION_ARGS) { 9.2055 - PG_RETURN_FLOAT8(((pgl_box *)PG_GETARG_POINTER(0))->lat_max); 9.2056 -} 9.2057 - 9.2058 -/* extract minimum longitude from box ("ebox") */ 9.2059 -PG_FUNCTION_INFO_V1(pgl_ebox_lon_min); 9.2060 -Datum pgl_ebox_lon_min(PG_FUNCTION_ARGS) { 9.2061 - PG_RETURN_FLOAT8(((pgl_box *)PG_GETARG_POINTER(0))->lon_min); 9.2062 -} 9.2063 - 9.2064 -/* extract maximum longitude from box ("ebox") */ 9.2065 -PG_FUNCTION_INFO_V1(pgl_ebox_lon_max); 9.2066 -Datum pgl_ebox_lon_max(PG_FUNCTION_ARGS) { 9.2067 - PG_RETURN_FLOAT8(((pgl_box *)PG_GETARG_POINTER(0))->lon_max); 9.2068 -} 9.2069 - 9.2070 -/* extract center point from circle ("ecircle") */ 9.2071 -PG_FUNCTION_INFO_V1(pgl_ecircle_center); 9.2072 -Datum pgl_ecircle_center(PG_FUNCTION_ARGS) { 9.2073 - PG_RETURN_POINTER(&(((pgl_circle *)PG_GETARG_POINTER(0))->center)); 9.2074 -} 9.2075 - 9.2076 -/* extract radius from circle ("ecircle") */ 9.2077 -PG_FUNCTION_INFO_V1(pgl_ecircle_radius); 9.2078 -Datum pgl_ecircle_radius(PG_FUNCTION_ARGS) { 9.2079 - PG_RETURN_FLOAT8(((pgl_circle *)PG_GETARG_POINTER(0))->radius); 9.2080 -} 9.2081 - 9.2082 -/* check if point is inside box (overlap operator "&&") in SQL */ 9.2083 -PG_FUNCTION_INFO_V1(pgl_epoint_ebox_overlap); 9.2084 -Datum pgl_epoint_ebox_overlap(PG_FUNCTION_ARGS) { 9.2085 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 9.2086 - pgl_box *box = (pgl_box *)PG_GETARG_POINTER(1); 9.2087 - PG_RETURN_BOOL(pgl_point_in_box(point, box)); 9.2088 -} 9.2089 - 9.2090 -/* check if point is inside circle (overlap operator "&&") in SQL */ 9.2091 -PG_FUNCTION_INFO_V1(pgl_epoint_ecircle_overlap); 9.2092 -Datum pgl_epoint_ecircle_overlap(PG_FUNCTION_ARGS) { 9.2093 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 9.2094 - pgl_circle *circle = (pgl_circle *)PG_GETARG_POINTER(1); 9.2095 - PG_RETURN_BOOL( 9.2096 - pgl_distance( 9.2097 - point->lat, point->lon, 9.2098 - circle->center.lat, circle->center.lon 9.2099 - ) <= circle->radius 9.2100 - ); 9.2101 -} 9.2102 - 9.2103 -/* check if point is inside cluster (overlap operator "&&") in SQL */ 9.2104 -PG_FUNCTION_INFO_V1(pgl_epoint_ecluster_overlap); 9.2105 -Datum pgl_epoint_ecluster_overlap(PG_FUNCTION_ARGS) { 9.2106 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 9.2107 - pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 9.2108 - bool retval = pgl_point_in_cluster(point, cluster); 9.2109 - PG_FREE_IF_COPY(cluster, 1); 9.2110 - PG_RETURN_BOOL(retval); 9.2111 -} 9.2112 - 9.2113 -/* check if point may be inside cluster (lossy overl. operator "&&+") in SQL */ 9.2114 -PG_FUNCTION_INFO_V1(pgl_epoint_ecluster_may_overlap); 9.2115 -Datum pgl_epoint_ecluster_may_overlap(PG_FUNCTION_ARGS) { 9.2116 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 9.2117 - pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 9.2118 - bool retval = pgl_distance( 9.2119 - point->lat, point->lon, 9.2120 - cluster->bounding.center.lat, cluster->bounding.center.lon 9.2121 - ) <= cluster->bounding.radius; 9.2122 - PG_FREE_IF_COPY(cluster, 1); 9.2123 - PG_RETURN_BOOL(retval); 9.2124 -} 9.2125 - 9.2126 -/* check if two boxes overlap (overlap operator "&&") in SQL */ 9.2127 -PG_FUNCTION_INFO_V1(pgl_ebox_overlap); 9.2128 -Datum pgl_ebox_overlap(PG_FUNCTION_ARGS) { 9.2129 - pgl_box *box1 = (pgl_box *)PG_GETARG_POINTER(0); 9.2130 - pgl_box *box2 = (pgl_box *)PG_GETARG_POINTER(1); 9.2131 - PG_RETURN_BOOL(pgl_boxes_overlap(box1, box2)); 9.2132 -} 9.2133 - 9.2134 -/* check if box and circle may overlap (lossy overl. operator "&&+") in SQL */ 9.2135 -PG_FUNCTION_INFO_V1(pgl_ebox_ecircle_may_overlap); 9.2136 -Datum pgl_ebox_ecircle_may_overlap(PG_FUNCTION_ARGS) { 9.2137 - pgl_box *box = (pgl_box *)PG_GETARG_POINTER(0); 9.2138 - pgl_circle *circle = (pgl_circle *)PG_GETARG_POINTER(1); 9.2139 - PG_RETURN_BOOL( 9.2140 - pgl_estimate_point_box_distance(&circle->center, box) <= circle->radius 9.2141 - ); 9.2142 -} 9.2143 - 9.2144 -/* check if box and cluster may overlap (lossy overl. operator "&&+") in SQL */ 9.2145 -PG_FUNCTION_INFO_V1(pgl_ebox_ecluster_may_overlap); 9.2146 -Datum pgl_ebox_ecluster_may_overlap(PG_FUNCTION_ARGS) { 9.2147 - pgl_box *box = (pgl_box *)PG_GETARG_POINTER(0); 9.2148 - pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 9.2149 - bool retval = pgl_estimate_point_box_distance( 9.2150 - &cluster->bounding.center, 9.2151 - box 9.2152 - ) <= cluster->bounding.radius; 9.2153 - PG_FREE_IF_COPY(cluster, 1); 9.2154 - PG_RETURN_BOOL(retval); 9.2155 -} 9.2156 - 9.2157 -/* check if two circles overlap (overlap operator "&&") in SQL */ 9.2158 -PG_FUNCTION_INFO_V1(pgl_ecircle_overlap); 9.2159 -Datum pgl_ecircle_overlap(PG_FUNCTION_ARGS) { 9.2160 - pgl_circle *circle1 = (pgl_circle *)PG_GETARG_POINTER(0); 9.2161 - pgl_circle *circle2 = (pgl_circle *)PG_GETARG_POINTER(1); 9.2162 - PG_RETURN_BOOL( 9.2163 - pgl_distance( 9.2164 - circle1->center.lat, circle1->center.lon, 9.2165 - circle2->center.lat, circle2->center.lon 9.2166 - ) <= circle1->radius + circle2->radius 9.2167 - ); 9.2168 -} 9.2169 - 9.2170 -/* check if circle and cluster overlap (overlap operator "&&") in SQL */ 9.2171 -PG_FUNCTION_INFO_V1(pgl_ecircle_ecluster_overlap); 9.2172 -Datum pgl_ecircle_ecluster_overlap(PG_FUNCTION_ARGS) { 9.2173 - pgl_circle *circle = (pgl_circle *)PG_GETARG_POINTER(0); 9.2174 - pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 9.2175 - bool retval = ( 9.2176 - pgl_point_cluster_distance(&(circle->center), cluster) <= circle->radius 9.2177 - ); 9.2178 - PG_FREE_IF_COPY(cluster, 1); 9.2179 - PG_RETURN_BOOL(retval); 9.2180 -} 9.2181 - 9.2182 -/* check if circle and cluster may be overlap (l. ov. operator "&&+") in SQL */ 9.2183 -PG_FUNCTION_INFO_V1(pgl_ecircle_ecluster_may_overlap); 9.2184 -Datum pgl_ecircle_ecluster_may_overlap(PG_FUNCTION_ARGS) { 9.2185 - pgl_circle *circle = (pgl_circle *)PG_GETARG_POINTER(0); 9.2186 - pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 9.2187 - bool retval = pgl_distance( 9.2188 - circle->center.lat, circle->center.lon, 9.2189 - cluster->bounding.center.lat, cluster->bounding.center.lon 9.2190 - ) <= circle->radius + cluster->bounding.radius; 9.2191 - PG_FREE_IF_COPY(cluster, 1); 9.2192 - PG_RETURN_BOOL(retval); 9.2193 -} 9.2194 - 9.2195 -/* check if two clusters may overlap (lossy overlap operator "&&+") in SQL */ 9.2196 -PG_FUNCTION_INFO_V1(pgl_ecluster_may_overlap); 9.2197 -Datum pgl_ecluster_may_overlap(PG_FUNCTION_ARGS) { 9.2198 - pgl_cluster *cluster1 = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); 9.2199 - pgl_cluster *cluster2 = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 9.2200 - bool retval = pgl_distance( 9.2201 - cluster1->bounding.center.lat, cluster1->bounding.center.lon, 9.2202 - cluster2->bounding.center.lat, cluster2->bounding.center.lon 9.2203 - ) <= cluster1->bounding.radius + cluster2->bounding.radius; 9.2204 - PG_FREE_IF_COPY(cluster1, 0); 9.2205 - PG_FREE_IF_COPY(cluster2, 1); 9.2206 - PG_RETURN_BOOL(retval); 9.2207 -} 9.2208 - 9.2209 -/* calculate distance between two points ("<->" operator) in SQL */ 9.2210 -PG_FUNCTION_INFO_V1(pgl_epoint_distance); 9.2211 -Datum pgl_epoint_distance(PG_FUNCTION_ARGS) { 9.2212 - pgl_point *point1 = (pgl_point *)PG_GETARG_POINTER(0); 9.2213 - pgl_point *point2 = (pgl_point *)PG_GETARG_POINTER(1); 9.2214 - PG_RETURN_FLOAT8(pgl_distance( 9.2215 - point1->lat, point1->lon, point2->lat, point2->lon 9.2216 - )); 9.2217 -} 9.2218 - 9.2219 -/* calculate point to circle distance ("<->" operator) in SQL */ 9.2220 -PG_FUNCTION_INFO_V1(pgl_epoint_ecircle_distance); 9.2221 -Datum pgl_epoint_ecircle_distance(PG_FUNCTION_ARGS) { 9.2222 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 9.2223 - pgl_circle *circle = (pgl_circle *)PG_GETARG_POINTER(1); 9.2224 - double distance = pgl_distance( 9.2225 - point->lat, point->lon, circle->center.lat, circle->center.lon 9.2226 - ) - circle->radius; 9.2227 - PG_RETURN_FLOAT8((distance <= 0) ? 0 : distance); 9.2228 -} 9.2229 - 9.2230 -/* calculate point to cluster distance ("<->" operator) in SQL */ 9.2231 -PG_FUNCTION_INFO_V1(pgl_epoint_ecluster_distance); 9.2232 -Datum pgl_epoint_ecluster_distance(PG_FUNCTION_ARGS) { 9.2233 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 9.2234 - pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 9.2235 - double distance = pgl_point_cluster_distance(point, cluster); 9.2236 - PG_FREE_IF_COPY(cluster, 1); 9.2237 - PG_RETURN_FLOAT8(distance); 9.2238 -} 9.2239 - 9.2240 -/* calculate distance between two circles ("<->" operator) in SQL */ 9.2241 -PG_FUNCTION_INFO_V1(pgl_ecircle_distance); 9.2242 -Datum pgl_ecircle_distance(PG_FUNCTION_ARGS) { 9.2243 - pgl_circle *circle1 = (pgl_circle *)PG_GETARG_POINTER(0); 9.2244 - pgl_circle *circle2 = (pgl_circle *)PG_GETARG_POINTER(1); 9.2245 - double distance = pgl_distance( 9.2246 - circle1->center.lat, circle1->center.lon, 9.2247 - circle2->center.lat, circle2->center.lon 9.2248 - ) - (circle1->radius + circle2->radius); 9.2249 - PG_RETURN_FLOAT8((distance <= 0) ? 0 : distance); 9.2250 -} 9.2251 - 9.2252 -/* calculate circle to cluster distance ("<->" operator) in SQL */ 9.2253 -PG_FUNCTION_INFO_V1(pgl_ecircle_ecluster_distance); 9.2254 -Datum pgl_ecircle_ecluster_distance(PG_FUNCTION_ARGS) { 9.2255 - pgl_circle *circle = (pgl_circle *)PG_GETARG_POINTER(0); 9.2256 - pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 9.2257 - double distance = ( 9.2258 - pgl_point_cluster_distance(&(circle->center), cluster) - circle->radius 9.2259 - ); 9.2260 - PG_FREE_IF_COPY(cluster, 1); 9.2261 - PG_RETURN_FLOAT8((distance <= 0) ? 0 : distance); 9.2262 -} 9.2263 - 9.2264 - 9.2265 -/*-----------------------------------------------------------* 9.2266 - * B-tree comparison operators and index support functions * 9.2267 - *-----------------------------------------------------------*/ 9.2268 - 9.2269 -/* macro for a B-tree operator (without detoasting) */ 9.2270 -#define PGL_BTREE_OPER(func, type, cmpfunc, oper) \ 9.2271 - PG_FUNCTION_INFO_V1(func); \ 9.2272 - Datum func(PG_FUNCTION_ARGS) { \ 9.2273 - type *a = (type *)PG_GETARG_POINTER(0); \ 9.2274 - type *b = (type *)PG_GETARG_POINTER(1); \ 9.2275 - PG_RETURN_BOOL(cmpfunc(a, b) oper 0); \ 9.2276 - } 9.2277 - 9.2278 -/* macro for a B-tree comparison function (without detoasting) */ 9.2279 -#define PGL_BTREE_CMP(func, type, cmpfunc) \ 9.2280 - PG_FUNCTION_INFO_V1(func); \ 9.2281 - Datum func(PG_FUNCTION_ARGS) { \ 9.2282 - type *a = (type *)PG_GETARG_POINTER(0); \ 9.2283 - type *b = (type *)PG_GETARG_POINTER(1); \ 9.2284 - PG_RETURN_INT32(cmpfunc(a, b)); \ 9.2285 - } 9.2286 - 9.2287 -/* macro for a B-tree operator (with detoasting) */ 9.2288 -#define PGL_BTREE_OPER_DETOAST(func, type, cmpfunc, oper) \ 9.2289 - PG_FUNCTION_INFO_V1(func); \ 9.2290 - Datum func(PG_FUNCTION_ARGS) { \ 9.2291 - bool res; \ 9.2292 - type *a = (type *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); \ 9.2293 - type *b = (type *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); \ 9.2294 - res = cmpfunc(a, b) oper 0; \ 9.2295 - PG_FREE_IF_COPY(a, 0); \ 9.2296 - PG_FREE_IF_COPY(b, 1); \ 9.2297 - PG_RETURN_BOOL(res); \ 9.2298 - } 9.2299 - 9.2300 -/* macro for a B-tree comparison function (with detoasting) */ 9.2301 -#define PGL_BTREE_CMP_DETOAST(func, type, cmpfunc) \ 9.2302 - PG_FUNCTION_INFO_V1(func); \ 9.2303 - Datum func(PG_FUNCTION_ARGS) { \ 9.2304 - int32_t res; \ 9.2305 - type *a = (type *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); \ 9.2306 - type *b = (type *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); \ 9.2307 - res = cmpfunc(a, b); \ 9.2308 - PG_FREE_IF_COPY(a, 0); \ 9.2309 - PG_FREE_IF_COPY(b, 1); \ 9.2310 - PG_RETURN_INT32(res); \ 9.2311 - } 9.2312 - 9.2313 -/* B-tree operators and comparison function for point */ 9.2314 -PGL_BTREE_OPER(pgl_btree_epoint_lt, pgl_point, pgl_point_cmp, <) 9.2315 -PGL_BTREE_OPER(pgl_btree_epoint_le, pgl_point, pgl_point_cmp, <=) 9.2316 -PGL_BTREE_OPER(pgl_btree_epoint_eq, pgl_point, pgl_point_cmp, ==) 9.2317 -PGL_BTREE_OPER(pgl_btree_epoint_ne, pgl_point, pgl_point_cmp, !=) 9.2318 -PGL_BTREE_OPER(pgl_btree_epoint_ge, pgl_point, pgl_point_cmp, >=) 9.2319 -PGL_BTREE_OPER(pgl_btree_epoint_gt, pgl_point, pgl_point_cmp, >) 9.2320 -PGL_BTREE_CMP(pgl_btree_epoint_cmp, pgl_point, pgl_point_cmp) 9.2321 - 9.2322 -/* B-tree operators and comparison function for box */ 9.2323 -PGL_BTREE_OPER(pgl_btree_ebox_lt, pgl_box, pgl_box_cmp, <) 9.2324 -PGL_BTREE_OPER(pgl_btree_ebox_le, pgl_box, pgl_box_cmp, <=) 9.2325 -PGL_BTREE_OPER(pgl_btree_ebox_eq, pgl_box, pgl_box_cmp, ==) 9.2326 -PGL_BTREE_OPER(pgl_btree_ebox_ne, pgl_box, pgl_box_cmp, !=) 9.2327 -PGL_BTREE_OPER(pgl_btree_ebox_ge, pgl_box, pgl_box_cmp, >=) 9.2328 -PGL_BTREE_OPER(pgl_btree_ebox_gt, pgl_box, pgl_box_cmp, >) 9.2329 -PGL_BTREE_CMP(pgl_btree_ebox_cmp, pgl_box, pgl_box_cmp) 9.2330 - 9.2331 -/* B-tree operators and comparison function for circle */ 9.2332 -PGL_BTREE_OPER(pgl_btree_ecircle_lt, pgl_circle, pgl_circle_cmp, <) 9.2333 -PGL_BTREE_OPER(pgl_btree_ecircle_le, pgl_circle, pgl_circle_cmp, <=) 9.2334 -PGL_BTREE_OPER(pgl_btree_ecircle_eq, pgl_circle, pgl_circle_cmp, ==) 9.2335 -PGL_BTREE_OPER(pgl_btree_ecircle_ne, pgl_circle, pgl_circle_cmp, !=) 9.2336 -PGL_BTREE_OPER(pgl_btree_ecircle_ge, pgl_circle, pgl_circle_cmp, >=) 9.2337 -PGL_BTREE_OPER(pgl_btree_ecircle_gt, pgl_circle, pgl_circle_cmp, >) 9.2338 -PGL_BTREE_CMP(pgl_btree_ecircle_cmp, pgl_circle, pgl_circle_cmp) 9.2339 - 9.2340 - 9.2341 -/*--------------------------------* 9.2342 - * GiST index support functions * 9.2343 - *--------------------------------*/ 9.2344 - 9.2345 -/* GiST "consistent" support function */ 9.2346 -PG_FUNCTION_INFO_V1(pgl_gist_consistent); 9.2347 -Datum pgl_gist_consistent(PG_FUNCTION_ARGS) { 9.2348 - GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); 9.2349 - pgl_keyptr key = (pgl_keyptr)DatumGetPointer(entry->key); 9.2350 - StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2); 9.2351 - bool *recheck = (bool *)PG_GETARG_POINTER(4); 9.2352 - /* demand recheck because index and query methods are lossy */ 9.2353 - *recheck = true; 9.2354 - /* strategy number aliases for different operators using the same strategy */ 9.2355 - strategy %= 100; 9.2356 - /* strategy number 11: equality of two points */ 9.2357 - if (strategy == 11) { 9.2358 - /* query datum is another point */ 9.2359 - pgl_point *query = (pgl_point *)PG_GETARG_POINTER(1); 9.2360 - /* convert other point to key */ 9.2361 - pgl_pointkey querykey; 9.2362 - pgl_point_to_key(query, querykey); 9.2363 - /* return true if both keys overlap */ 9.2364 - PG_RETURN_BOOL(pgl_keys_overlap(key, querykey)); 9.2365 - } 9.2366 - /* strategy number 13: equality of two circles */ 9.2367 - if (strategy == 13) { 9.2368 - /* query datum is another circle */ 9.2369 - pgl_circle *query = (pgl_circle *)PG_GETARG_POINTER(1); 9.2370 - /* convert other circle to key */ 9.2371 - pgl_areakey querykey; 9.2372 - pgl_circle_to_key(query, querykey); 9.2373 - /* return true if both keys overlap */ 9.2374 - PG_RETURN_BOOL(pgl_keys_overlap(key, querykey)); 9.2375 - } 9.2376 - /* for all remaining strategies, keys on empty objects produce no match */ 9.2377 - /* (check necessary because query radius may be infinite) */ 9.2378 - if (PGL_KEY_IS_EMPTY(key)) PG_RETURN_BOOL(false); 9.2379 - /* strategy number 21: overlapping with point */ 9.2380 - if (strategy == 21) { 9.2381 - /* query datum is a point */ 9.2382 - pgl_point *query = (pgl_point *)PG_GETARG_POINTER(1); 9.2383 - /* return true if estimated distance (allowed to be smaller than real 9.2384 - distance) between index key and point is zero */ 9.2385 - PG_RETURN_BOOL(pgl_estimate_key_distance(key, query) == 0); 9.2386 - } 9.2387 - /* strategy number 22: (point) overlapping with box */ 9.2388 - if (strategy == 22) { 9.2389 - /* query datum is a box */ 9.2390 - pgl_box *query = (pgl_box *)PG_GETARG_POINTER(1); 9.2391 - /* determine bounding box of indexed key */ 9.2392 - pgl_box keybox; 9.2393 - pgl_key_to_box(key, &keybox); 9.2394 - /* return true if query box overlaps with bounding box of indexed key */ 9.2395 - PG_RETURN_BOOL(pgl_boxes_overlap(query, &keybox)); 9.2396 - } 9.2397 - /* strategy number 23: overlapping with circle */ 9.2398 - if (strategy == 23) { 9.2399 - /* query datum is a circle */ 9.2400 - pgl_circle *query = (pgl_circle *)PG_GETARG_POINTER(1); 9.2401 - /* return true if estimated distance (allowed to be smaller than real 9.2402 - distance) between index key and circle center is smaller than radius */ 9.2403 - PG_RETURN_BOOL( 9.2404 - pgl_estimate_key_distance(key, &(query->center)) <= query->radius 9.2405 - ); 9.2406 - } 9.2407 - /* strategy number 24: overlapping with cluster */ 9.2408 - if (strategy == 24) { 9.2409 - bool retval; /* return value */ 9.2410 - /* query datum is a cluster */ 9.2411 - pgl_cluster *query = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 9.2412 - /* return true if estimated distance (allowed to be smaller than real 9.2413 - distance) between index key and circle center is smaller than radius */ 9.2414 - retval = ( 9.2415 - pgl_estimate_key_distance(key, &(query->bounding.center)) <= 9.2416 - query->bounding.radius 9.2417 - ); 9.2418 - PG_FREE_IF_COPY(query, 1); /* free detoasted cluster (if copy) */ 9.2419 - PG_RETURN_BOOL(retval); 9.2420 - } 9.2421 - /* throw error for any unknown strategy number */ 9.2422 - elog(ERROR, "unrecognized strategy number: %d", strategy); 9.2423 -} 9.2424 - 9.2425 -/* GiST "union" support function */ 9.2426 -PG_FUNCTION_INFO_V1(pgl_gist_union); 9.2427 -Datum pgl_gist_union(PG_FUNCTION_ARGS) { 9.2428 - GistEntryVector *entryvec = (GistEntryVector *)PG_GETARG_POINTER(0); 9.2429 - pgl_keyptr out; /* return value (to be palloc'ed) */ 9.2430 - int i; 9.2431 - /* determine key size */ 9.2432 - size_t keysize = PGL_KEY_IS_AREAKEY( 9.2433 - (pgl_keyptr)DatumGetPointer(entryvec->vector[0].key) 9.2434 - ) ? sizeof (pgl_areakey) : sizeof(pgl_pointkey); 9.2435 - /* begin with first key as result */ 9.2436 - out = palloc(keysize); 9.2437 - memcpy(out, (pgl_keyptr)DatumGetPointer(entryvec->vector[0].key), keysize); 9.2438 - /* unite current result with second, third, etc. key */ 9.2439 - for (i=1; i<entryvec->n; i++) { 9.2440 - pgl_unite_keys(out, (pgl_keyptr)DatumGetPointer(entryvec->vector[i].key)); 9.2441 - } 9.2442 - /* return result */ 9.2443 - PG_RETURN_POINTER(out); 9.2444 -} 9.2445 - 9.2446 -/* GiST "compress" support function for indicis on points */ 9.2447 -PG_FUNCTION_INFO_V1(pgl_gist_compress_epoint); 9.2448 -Datum pgl_gist_compress_epoint(PG_FUNCTION_ARGS) { 9.2449 - GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); 9.2450 - GISTENTRY *retval; /* return value (to be palloc'ed unless set to entry) */ 9.2451 - /* only transform new leaves */ 9.2452 - if (entry->leafkey) { 9.2453 - /* get point to be transformed */ 9.2454 - pgl_point *point = (pgl_point *)DatumGetPointer(entry->key); 9.2455 - /* allocate memory for key */ 9.2456 - pgl_keyptr key = palloc(sizeof(pgl_pointkey)); 9.2457 - /* transform point to key */ 9.2458 - pgl_point_to_key(point, key); 9.2459 - /* create new GISTENTRY structure as return value */ 9.2460 - retval = palloc(sizeof(GISTENTRY)); 9.2461 - gistentryinit( 9.2462 - *retval, PointerGetDatum(key), 9.2463 - entry->rel, entry->page, entry->offset, FALSE 9.2464 - ); 9.2465 - } else { 9.2466 - /* inner nodes have already been transformed */ 9.2467 - retval = entry; 9.2468 - } 9.2469 - /* return pointer to old or new GISTENTRY structure */ 9.2470 - PG_RETURN_POINTER(retval); 9.2471 -} 9.2472 - 9.2473 -/* GiST "compress" support function for indicis on circles */ 9.2474 -PG_FUNCTION_INFO_V1(pgl_gist_compress_ecircle); 9.2475 -Datum pgl_gist_compress_ecircle(PG_FUNCTION_ARGS) { 9.2476 - GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); 9.2477 - GISTENTRY *retval; /* return value (to be palloc'ed unless set to entry) */ 9.2478 - /* only transform new leaves */ 9.2479 - if (entry->leafkey) { 9.2480 - /* get circle to be transformed */ 9.2481 - pgl_circle *circle = (pgl_circle *)DatumGetPointer(entry->key); 9.2482 - /* allocate memory for key */ 9.2483 - pgl_keyptr key = palloc(sizeof(pgl_areakey)); 9.2484 - /* transform circle to key */ 9.2485 - pgl_circle_to_key(circle, key); 9.2486 - /* create new GISTENTRY structure as return value */ 9.2487 - retval = palloc(sizeof(GISTENTRY)); 9.2488 - gistentryinit( 9.2489 - *retval, PointerGetDatum(key), 9.2490 - entry->rel, entry->page, entry->offset, FALSE 9.2491 - ); 9.2492 - } else { 9.2493 - /* inner nodes have already been transformed */ 9.2494 - retval = entry; 9.2495 - } 9.2496 - /* return pointer to old or new GISTENTRY structure */ 9.2497 - PG_RETURN_POINTER(retval); 9.2498 -} 9.2499 - 9.2500 -/* GiST "compress" support function for indices on clusters */ 9.2501 -PG_FUNCTION_INFO_V1(pgl_gist_compress_ecluster); 9.2502 -Datum pgl_gist_compress_ecluster(PG_FUNCTION_ARGS) { 9.2503 - GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); 9.2504 - GISTENTRY *retval; /* return value (to be palloc'ed unless set to entry) */ 9.2505 - /* only transform new leaves */ 9.2506 - if (entry->leafkey) { 9.2507 - /* get cluster to be transformed (detoasting necessary!) */ 9.2508 - pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(entry->key); 9.2509 - /* allocate memory for key */ 9.2510 - pgl_keyptr key = palloc(sizeof(pgl_areakey)); 9.2511 - /* transform cluster to key */ 9.2512 - pgl_circle_to_key(&(cluster->bounding), key); 9.2513 - /* create new GISTENTRY structure as return value */ 9.2514 - retval = palloc(sizeof(GISTENTRY)); 9.2515 - gistentryinit( 9.2516 - *retval, PointerGetDatum(key), 9.2517 - entry->rel, entry->page, entry->offset, FALSE 9.2518 - ); 9.2519 - /* free detoasted datum */ 9.2520 - if ((void *)cluster != (void *)DatumGetPointer(entry->key)) pfree(cluster); 9.2521 - } else { 9.2522 - /* inner nodes have already been transformed */ 9.2523 - retval = entry; 9.2524 - } 9.2525 - /* return pointer to old or new GISTENTRY structure */ 9.2526 - PG_RETURN_POINTER(retval); 9.2527 -} 9.2528 - 9.2529 -/* GiST "decompress" support function for indices */ 9.2530 -PG_FUNCTION_INFO_V1(pgl_gist_decompress); 9.2531 -Datum pgl_gist_decompress(PG_FUNCTION_ARGS) { 9.2532 - /* return passed pointer without transformation */ 9.2533 - PG_RETURN_POINTER(PG_GETARG_POINTER(0)); 9.2534 -} 9.2535 - 9.2536 -/* GiST "penalty" support function */ 9.2537 -PG_FUNCTION_INFO_V1(pgl_gist_penalty); 9.2538 -Datum pgl_gist_penalty(PG_FUNCTION_ARGS) { 9.2539 - GISTENTRY *origentry = (GISTENTRY *)PG_GETARG_POINTER(0); 9.2540 - GISTENTRY *newentry = (GISTENTRY *)PG_GETARG_POINTER(1); 9.2541 - float *penalty = (float *)PG_GETARG_POINTER(2); 9.2542 - /* get original key and key to insert */ 9.2543 - pgl_keyptr orig = (pgl_keyptr)DatumGetPointer(origentry->key); 9.2544 - pgl_keyptr new = (pgl_keyptr)DatumGetPointer(newentry->key); 9.2545 - /* copy original key */ 9.2546 - union { pgl_pointkey pointkey; pgl_areakey areakey; } union_key; 9.2547 - if (PGL_KEY_IS_AREAKEY(orig)) { 9.2548 - memcpy(union_key.areakey, orig, sizeof(union_key.areakey)); 9.2549 - } else { 9.2550 - memcpy(union_key.pointkey, orig, sizeof(union_key.pointkey)); 9.2551 - } 9.2552 - /* calculate union of both keys */ 9.2553 - pgl_unite_keys((pgl_keyptr)&union_key, new); 9.2554 - /* penalty equal to reduction of key length (logarithm of added area) */ 9.2555 - /* (return value by setting referenced value and returning pointer) */ 9.2556 - *penalty = ( 9.2557 - PGL_KEY_NODEDEPTH(orig) - PGL_KEY_NODEDEPTH((pgl_keyptr)&union_key) 9.2558 - ); 9.2559 - PG_RETURN_POINTER(penalty); 9.2560 -} 9.2561 - 9.2562 -/* GiST "picksplit" support function */ 9.2563 -PG_FUNCTION_INFO_V1(pgl_gist_picksplit); 9.2564 -Datum pgl_gist_picksplit(PG_FUNCTION_ARGS) { 9.2565 - GistEntryVector *entryvec = (GistEntryVector *)PG_GETARG_POINTER(0); 9.2566 - GIST_SPLITVEC *v = (GIST_SPLITVEC *)PG_GETARG_POINTER(1); 9.2567 - OffsetNumber i; /* between FirstOffsetNumber and entryvec->n (inclusive) */ 9.2568 - union { 9.2569 - pgl_pointkey pointkey; 9.2570 - pgl_areakey areakey; 9.2571 - } union_all; /* union of all keys (to be calculated from scratch) 9.2572 - (later cut in half) */ 9.2573 - int is_areakey = PGL_KEY_IS_AREAKEY( 9.2574 - (pgl_keyptr)DatumGetPointer(entryvec->vector[FirstOffsetNumber].key) 9.2575 - ); 9.2576 - int keysize = is_areakey ? sizeof(pgl_areakey) : sizeof(pgl_pointkey); 9.2577 - pgl_keyptr unionL = palloc(keysize); /* union of keys that go left */ 9.2578 - pgl_keyptr unionR = palloc(keysize); /* union of keys that go right */ 9.2579 - pgl_keyptr key; /* current key to be processed */ 9.2580 - /* allocate memory for array of left and right keys, set counts to zero */ 9.2581 - v->spl_left = (OffsetNumber *)palloc(entryvec->n * sizeof(OffsetNumber)); 9.2582 - v->spl_nleft = 0; 9.2583 - v->spl_right = (OffsetNumber *)palloc(entryvec->n * sizeof(OffsetNumber)); 9.2584 - v->spl_nright = 0; 9.2585 - /* calculate union of all keys from scratch */ 9.2586 - memcpy( 9.2587 - (pgl_keyptr)&union_all, 9.2588 - (pgl_keyptr)DatumGetPointer(entryvec->vector[FirstOffsetNumber].key), 9.2589 - keysize 9.2590 - ); 9.2591 - for (i=FirstOffsetNumber+1; i<entryvec->n; i=OffsetNumberNext(i)) { 9.2592 - pgl_unite_keys( 9.2593 - (pgl_keyptr)&union_all, 9.2594 - (pgl_keyptr)DatumGetPointer(entryvec->vector[i].key) 9.2595 - ); 9.2596 - } 9.2597 - /* check if trivial split is necessary due to exhausted key length */ 9.2598 - /* (Note: keys for empty objects must have node depth set to maximum) */ 9.2599 - if (PGL_KEY_NODEDEPTH((pgl_keyptr)&union_all) == ( 9.2600 - is_areakey ? PGL_AREAKEY_MAXDEPTH : PGL_POINTKEY_MAXDEPTH 9.2601 - )) { 9.2602 - /* half of all keys go left */ 9.2603 - for ( 9.2604 - i=FirstOffsetNumber; 9.2605 - i<FirstOffsetNumber+(entryvec->n - FirstOffsetNumber)/2; 9.2606 - i=OffsetNumberNext(i) 9.2607 - ) { 9.2608 - /* pointer to current key */ 9.2609 - key = (pgl_keyptr)DatumGetPointer(entryvec->vector[i].key); 9.2610 - /* update unionL */ 9.2611 - /* check if key is first key that goes left */ 9.2612 - if (!v->spl_nleft) { 9.2613 - /* first key that goes left is just copied to unionL */ 9.2614 - memcpy(unionL, key, keysize); 9.2615 - } else { 9.2616 - /* unite current value and next key */ 9.2617 - pgl_unite_keys(unionL, key); 9.2618 - } 9.2619 - /* append offset number to list of keys that go left */ 9.2620 - v->spl_left[v->spl_nleft++] = i; 9.2621 - } 9.2622 - /* other half goes right */ 9.2623 - for ( 9.2624 - i=FirstOffsetNumber+(entryvec->n - FirstOffsetNumber)/2; 9.2625 - i<entryvec->n; 9.2626 - i=OffsetNumberNext(i) 9.2627 - ) { 9.2628 - /* pointer to current key */ 9.2629 - key = (pgl_keyptr)DatumGetPointer(entryvec->vector[i].key); 9.2630 - /* update unionR */ 9.2631 - /* check if key is first key that goes right */ 9.2632 - if (!v->spl_nright) { 9.2633 - /* first key that goes right is just copied to unionR */ 9.2634 - memcpy(unionR, key, keysize); 9.2635 - } else { 9.2636 - /* unite current value and next key */ 9.2637 - pgl_unite_keys(unionR, key); 9.2638 - } 9.2639 - /* append offset number to list of keys that go right */ 9.2640 - v->spl_right[v->spl_nright++] = i; 9.2641 - } 9.2642 - } 9.2643 - /* otherwise, a non-trivial split is possible */ 9.2644 - else { 9.2645 - /* cut covered area in half */ 9.2646 - /* (union_all then refers to area of keys that go left) */ 9.2647 - /* check if union of all keys covers empty and non-empty objects */ 9.2648 - if (PGL_KEY_IS_UNIVERSAL((pgl_keyptr)&union_all)) { 9.2649 - /* if yes, split into empty and non-empty objects */ 9.2650 - pgl_key_set_empty((pgl_keyptr)&union_all); 9.2651 - } else { 9.2652 - /* otherwise split by next bit */ 9.2653 - ((pgl_keyptr)&union_all)[PGL_KEY_NODEDEPTH_OFFSET]++; 9.2654 - /* NOTE: type bit conserved */ 9.2655 - } 9.2656 - /* determine for each key if it goes left or right */ 9.2657 - for (i=FirstOffsetNumber; i<entryvec->n; i=OffsetNumberNext(i)) { 9.2658 - /* pointer to current key */ 9.2659 - key = (pgl_keyptr)DatumGetPointer(entryvec->vector[i].key); 9.2660 - /* keys within one half of the area go left */ 9.2661 - if (pgl_keys_overlap((pgl_keyptr)&union_all, key)) { 9.2662 - /* update unionL */ 9.2663 - /* check if key is first key that goes left */ 9.2664 - if (!v->spl_nleft) { 9.2665 - /* first key that goes left is just copied to unionL */ 9.2666 - memcpy(unionL, key, keysize); 9.2667 - } else { 9.2668 - /* unite current value of unionL and processed key */ 9.2669 - pgl_unite_keys(unionL, key); 9.2670 - } 9.2671 - /* append offset number to list of keys that go left */ 9.2672 - v->spl_left[v->spl_nleft++] = i; 9.2673 - } 9.2674 - /* the other keys go right */ 9.2675 - else { 9.2676 - /* update unionR */ 9.2677 - /* check if key is first key that goes right */ 9.2678 - if (!v->spl_nright) { 9.2679 - /* first key that goes right is just copied to unionR */ 9.2680 - memcpy(unionR, key, keysize); 9.2681 - } else { 9.2682 - /* unite current value of unionR and processed key */ 9.2683 - pgl_unite_keys(unionR, key); 9.2684 - } 9.2685 - /* append offset number to list of keys that go right */ 9.2686 - v->spl_right[v->spl_nright++] = i; 9.2687 - } 9.2688 - } 9.2689 - } 9.2690 - /* store unions in return value */ 9.2691 - v->spl_ldatum = PointerGetDatum(unionL); 9.2692 - v->spl_rdatum = PointerGetDatum(unionR); 9.2693 - /* return all results */ 9.2694 - PG_RETURN_POINTER(v); 9.2695 -} 9.2696 - 9.2697 -/* GiST "same"/"equal" support function */ 9.2698 -PG_FUNCTION_INFO_V1(pgl_gist_same); 9.2699 -Datum pgl_gist_same(PG_FUNCTION_ARGS) { 9.2700 - pgl_keyptr key1 = (pgl_keyptr)PG_GETARG_POINTER(0); 9.2701 - pgl_keyptr key2 = (pgl_keyptr)PG_GETARG_POINTER(1); 9.2702 - bool *boolptr = (bool *)PG_GETARG_POINTER(2); 9.2703 - /* two keys are equal if they are binary equal */ 9.2704 - /* (return result by setting referenced boolean and returning pointer) */ 9.2705 - *boolptr = !memcmp( 9.2706 - key1, 9.2707 - key2, 9.2708 - PGL_KEY_IS_AREAKEY(key1) ? sizeof(pgl_areakey) : sizeof(pgl_pointkey) 9.2709 - ); 9.2710 - PG_RETURN_POINTER(boolptr); 9.2711 -} 9.2712 - 9.2713 -/* GiST "distance" support function */ 9.2714 -PG_FUNCTION_INFO_V1(pgl_gist_distance); 9.2715 -Datum pgl_gist_distance(PG_FUNCTION_ARGS) { 9.2716 - GISTENTRY *entry = (GISTENTRY *)PG_GETARG_POINTER(0); 9.2717 - pgl_keyptr key = (pgl_keyptr)DatumGetPointer(entry->key); 9.2718 - StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2); 9.2719 - bool *recheck = (bool *)PG_GETARG_POINTER(4); 9.2720 - double distance; /* return value */ 9.2721 - /* demand recheck because distance is just an estimation */ 9.2722 - /* (real distance may be bigger) */ 9.2723 - *recheck = true; 9.2724 - /* strategy number aliases for different operators using the same strategy */ 9.2725 - strategy %= 100; 9.2726 - /* strategy number 31: distance to point */ 9.2727 - if (strategy == 31) { 9.2728 - /* query datum is a point */ 9.2729 - pgl_point *query = (pgl_point *)PG_GETARG_POINTER(1); 9.2730 - /* use pgl_estimate_pointkey_distance() function to compute result */ 9.2731 - distance = pgl_estimate_key_distance(key, query); 9.2732 - /* avoid infinity (reserved!) */ 9.2733 - if (!isfinite(distance)) distance = PGL_ULTRA_DISTANCE; 9.2734 - /* return result */ 9.2735 - PG_RETURN_FLOAT8(distance); 9.2736 - } 9.2737 - /* strategy number 33: distance to circle */ 9.2738 - if (strategy == 33) { 9.2739 - /* query datum is a circle */ 9.2740 - pgl_circle *query = (pgl_circle *)PG_GETARG_POINTER(1); 9.2741 - /* estimate distance to circle center and substract circle radius */ 9.2742 - distance = ( 9.2743 - pgl_estimate_key_distance(key, &(query->center)) - query->radius 9.2744 - ); 9.2745 - /* convert non-positive values to zero and avoid infinity (reserved!) */ 9.2746 - if (distance <= 0) distance = 0; 9.2747 - else if (!isfinite(distance)) distance = PGL_ULTRA_DISTANCE; 9.2748 - /* return result */ 9.2749 - PG_RETURN_FLOAT8(distance); 9.2750 - } 9.2751 - /* strategy number 34: distance to cluster */ 9.2752 - if (strategy == 34) { 9.2753 - /* query datum is a cluster */ 9.2754 - pgl_cluster *query = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 9.2755 - /* estimate distance to bounding center and substract bounding radius */ 9.2756 - distance = ( 9.2757 - pgl_estimate_key_distance(key, &(query->bounding.center)) - 9.2758 - query->bounding.radius 9.2759 - ); 9.2760 - /* convert non-positive values to zero and avoid infinity (reserved!) */ 9.2761 - if (distance <= 0) distance = 0; 9.2762 - else if (!isfinite(distance)) distance = PGL_ULTRA_DISTANCE; 9.2763 - /* free detoasted cluster (if copy) */ 9.2764 - PG_FREE_IF_COPY(query, 1); 9.2765 - /* return result */ 9.2766 - PG_RETURN_FLOAT8(distance); 9.2767 - } 9.2768 - /* throw error for any unknown strategy number */ 9.2769 - elog(ERROR, "unrecognized strategy number: %d", strategy); 9.2770 -} 9.2771 -
10.1 --- a/latlon-v0004.c Sat Sep 03 16:00:22 2016 +0200 10.2 +++ b/latlon-v0004.c Fri Sep 09 19:22:30 2016 +0200 10.3 @@ -502,14 +502,6 @@ 10.4 double lat2, lon2; /* latitude and (adjusted) longitude of next vertex */ 10.5 double lon; /* longitude of intersection */ 10.6 int counter = 0; /* counter for intersections east of point */ 10.7 - /* points outside bounding circle are always assumed to be non-overlapping */ 10.8 - /* (necessary for consistent table and index scans) */ 10.9 - if ( 10.10 - pgl_distance( 10.11 - point->lat, point->lon, 10.12 - cluster->bounding.center.lat, cluster->bounding.center.lon 10.13 - ) > cluster->bounding.radius 10.14 - ) return false; 10.15 /* iterate over all entries */ 10.16 for (i=0; i<cluster->nentries; i++) { 10.17 /* get properties of entry */ 10.18 @@ -539,14 +531,22 @@ 10.19 entrytype != PGL_ENTRY_OUTLINE && 10.20 entrytype != PGL_ENTRY_POLYGON 10.21 ) continue; 10.22 - /* get latitude and longitude values of edge */ 10.23 - lat1 = points[j].lat; 10.24 + /* use previously calculated values for lat1 and lon1 if possible */ 10.25 + if (j) { 10.26 + lat1 = lat2; 10.27 + lon1 = lon2; 10.28 + } else { 10.29 + /* otherwise get latitude and longitude values of first vertex */ 10.30 + lat1 = points[0].lat; 10.31 + lon1 = points[0].lon; 10.32 + /* and consider longitude wrap-around for first vertex */ 10.33 + if (lon_dir < 0 && lon1 > lon_break) lon1 = pgl_round(lon1 - 360); 10.34 + else if (lon_dir > 0 && lon1 < lon_break) lon1 = pgl_round(lon1 + 360); 10.35 + } 10.36 + /* get latitude and longitude of next vertex */ 10.37 lat2 = points[k].lat; 10.38 - lon1 = points[j].lon; 10.39 lon2 = points[k].lon; 10.40 - /* consider longitude wrap-around for edge */ 10.41 - if (lon_dir < 0 && lon1 > lon_break) lon1 = pgl_round(lon1 - 360); 10.42 - else if (lon_dir > 0 && lon1 < lon_break) lon1 = pgl_round(lon1 + 360); 10.43 + /* consider longitude wrap-around for next vertex */ 10.44 if (lon_dir < 0 && lon2 > lon_break) lon2 = pgl_round(lon2 - 360); 10.45 else if (lon_dir > 0 && lon2 < lon_break) lon2 = pgl_round(lon2 + 360); 10.46 /* return true if point is on horizontal (west to east) edge of polygon */ 10.47 @@ -569,6 +569,231 @@ 10.48 return counter & 1; 10.49 } 10.50 10.51 +/* check if all points of the second cluster are inside the first cluster */ 10.52 +static inline bool pgl_all_cluster_points_in_cluster( 10.53 + pgl_cluster *outer, pgl_cluster *inner 10.54 +) { 10.55 + int i, j; /* i: entry, j: point in entry */ 10.56 + int npoints; /* number of points in entry */ 10.57 + pgl_point *points; /* array of points in entry */ 10.58 + /* iterate over all entries of "inner" cluster */ 10.59 + for (i=0; i<inner->nentries; i++) { 10.60 + /* get properties of entry */ 10.61 + npoints = inner->entries[i].npoints; 10.62 + points = PGL_ENTRY_POINTS(inner, i); 10.63 + /* iterate over all points in entry of "inner" cluster */ 10.64 + for (j=0; j<npoints; j++) { 10.65 + /* return false if one point of inner cluster is not in outer cluster */ 10.66 + if (!pgl_point_in_cluster(points+j, outer)) return false; 10.67 + } 10.68 + } 10.69 + /* otherwise return true */ 10.70 + return true; 10.71 +} 10.72 + 10.73 +/* check if any point the second cluster is inside the first cluster */ 10.74 +static inline bool pgl_any_cluster_points_in_cluster( 10.75 + pgl_cluster *outer, pgl_cluster *inner 10.76 +) { 10.77 + int i, j; /* i: entry, j: point in entry */ 10.78 + int npoints; /* number of points in entry */ 10.79 + pgl_point *points; /* array of points in entry */ 10.80 + /* iterate over all entries of "inner" cluster */ 10.81 + for (i=0; i<inner->nentries; i++) { 10.82 + /* get properties of entry */ 10.83 + npoints = inner->entries[i].npoints; 10.84 + points = PGL_ENTRY_POINTS(inner, i); 10.85 + /* iterate over all points in entry of "inner" cluster */ 10.86 + for (j=0; j<npoints; j++) { 10.87 + /* return true if one point of inner cluster is in outer cluster */ 10.88 + if (pgl_point_in_cluster(points+j, outer)) return true; 10.89 + } 10.90 + } 10.91 + /* otherwise return false */ 10.92 + return false; 10.93 +} 10.94 + 10.95 +/* check if line segment crosses line */ 10.96 +/* returns -1 if yes, 1 if no, and 0 in corner cases */ 10.97 +/* NOTE: each line (segment) must have a length greater than zero */ 10.98 +static inline double pgl_lseg_crosses_line( 10.99 + double seg_x1, double seg_y1, double seg_x2, double seg_y2, 10.100 + double line_x1, double line_y1, double line_x2, double line_y2, 10.101 + bool strict 10.102 +) { 10.103 + double value = ( 10.104 + (seg_x1-line_x1) * (line_y2-line_y1) - 10.105 + (seg_y1-line_y1) * (line_x2-line_x1) 10.106 + ) * ( 10.107 + (seg_x2-line_x1) * (line_y2-line_y1) - 10.108 + (seg_y2-line_y1) * (line_x2-line_x1) 10.109 + ); 10.110 + if (strict) return value < 0; 10.111 + else return value <= 0; 10.112 +} 10.113 + 10.114 +/* check if paths and outlines of two clusters overlap */ 10.115 +/* (set strict to true to disregard corner cases) */ 10.116 +static bool pgl_outlines_overlap( 10.117 + pgl_cluster *cluster1, pgl_cluster *cluster2, bool strict 10.118 +) { 10.119 + int i1, j1, k1; /* i: entry, j: point in entry, k: next point in entry */ 10.120 + int i2, j2, k2; 10.121 + int entrytype1, entrytype2; /* type of entry */ 10.122 + int npoints1, npoints2; /* number of points in entry */ 10.123 + pgl_point *points1; /* array of points in entry of cluster1 */ 10.124 + pgl_point *points2; /* array of points in entry of cluster2 */ 10.125 + int lon_dir1, lon_dir2; /* first vertex west (-1) or east (+1) */ 10.126 + double lon_break1, lon_break2; /* antipodal longitude of first vertex */ 10.127 + double lat11, lon11; /* latitude and (adjusted) longitude of vertex */ 10.128 + double lat12, lon12; /* latitude and (adjusted) longitude of next vertex */ 10.129 + double lat21, lon21; /* latitude and (adjusted) longitudes for cluster2 */ 10.130 + double lat22, lon22; 10.131 + double wrapvalue; /* temporary helper value to adjust wrap-around */ 10.132 + /* iterate over all entries of cluster1 */ 10.133 + for (i1=0; i1<cluster1->nentries; i1++) { 10.134 + /* get properties of entry in cluster1 and skip points */ 10.135 + npoints1 = cluster1->entries[i1].npoints; 10.136 + if (npoints1 < 2) continue; 10.137 + entrytype1 = cluster1->entries[i1].entrytype; 10.138 + points1 = PGL_ENTRY_POINTS(cluster1, i1); 10.139 + /* determine east/west orientation of first point and calculate antipodal 10.140 + longitude */ 10.141 + lon_break1 = points1[0].lon; 10.142 + if (lon_break1 < 0) { 10.143 + lon_dir1 = -1; 10.144 + lon_break1 = pgl_round(lon_break1 + 180); 10.145 + } else if (lon_break1 > 0) { 10.146 + lon_dir1 = 1; 10.147 + lon_break1 = pgl_round(lon_break1 - 180); 10.148 + } else lon_dir1 = 0; 10.149 + /* iterate over all edges and vertices in cluster1 */ 10.150 + for (j1=0; j1<npoints1; j1++) { 10.151 + /* calculate index of next vertex */ 10.152 + k1 = (j1+1) % npoints1; 10.153 + /* skip last edge unless entry is (closed) outline or polygon */ 10.154 + if ( 10.155 + k1 == 0 && 10.156 + entrytype1 != PGL_ENTRY_OUTLINE && 10.157 + entrytype1 != PGL_ENTRY_POLYGON 10.158 + ) continue; 10.159 + /* use previously calculated values for lat1 and lon1 if possible */ 10.160 + if (j1) { 10.161 + lat11 = lat12; 10.162 + lon11 = lon12; 10.163 + } else { 10.164 + /* otherwise get latitude and longitude values of first vertex */ 10.165 + lat11 = points1[0].lat; 10.166 + lon11 = points1[0].lon; 10.167 + /* and consider longitude wrap-around for first vertex */ 10.168 + if (lon_dir1<0 && lon11>lon_break1) lon11 = pgl_round(lon11-360); 10.169 + else if (lon_dir1>0 && lon11<lon_break1) lon11 = pgl_round(lon11+360); 10.170 + } 10.171 + /* get latitude and longitude of next vertex */ 10.172 + lat12 = points1[k1].lat; 10.173 + lon12 = points1[k1].lon; 10.174 + /* consider longitude wrap-around for next vertex */ 10.175 + if (lon_dir1<0 && lon12>lon_break1) lon12 = pgl_round(lon12-360); 10.176 + else if (lon_dir1>0 && lon12<lon_break1) lon12 = pgl_round(lon12+360); 10.177 + /* skip degenerated edges */ 10.178 + if (lat11 == lat12 && lon11 == lon12) continue; 10.179 + /* iterate over all entries of cluster2 */ 10.180 + for (i2=0; i2<cluster2->nentries; i2++) { 10.181 + /* get points and number of points of entry in cluster2 */ 10.182 + npoints2 = cluster2->entries[i2].npoints; 10.183 + if (npoints2 < 2) continue; 10.184 + entrytype2 = cluster2->entries[i2].entrytype; 10.185 + points2 = PGL_ENTRY_POINTS(cluster2, i2); 10.186 + /* determine east/west orientation of first point and calculate antipodal 10.187 + longitude */ 10.188 + lon_break2 = points2[0].lon; 10.189 + if (lon_break2 < 0) { 10.190 + lon_dir2 = -1; 10.191 + lon_break2 = pgl_round(lon_break2 + 180); 10.192 + } else if (lon_break2 > 0) { 10.193 + lon_dir2 = 1; 10.194 + lon_break2 = pgl_round(lon_break2 - 180); 10.195 + } else lon_dir2 = 0; 10.196 + /* iterate over all edges and vertices in cluster2 */ 10.197 + for (j2=0; j2<npoints2; j2++) { 10.198 + /* calculate index of next vertex */ 10.199 + k2 = (j2+1) % npoints2; 10.200 + /* skip last edge unless entry is (closed) outline or polygon */ 10.201 + if ( 10.202 + k2 == 0 && 10.203 + entrytype2 != PGL_ENTRY_OUTLINE && 10.204 + entrytype2 != PGL_ENTRY_POLYGON 10.205 + ) continue; 10.206 + /* use previously calculated values for lat1 and lon1 if possible */ 10.207 + if (j2) { 10.208 + lat21 = lat22; 10.209 + lon21 = lon22; 10.210 + } else { 10.211 + /* otherwise get latitude and longitude values of first vertex */ 10.212 + lat21 = points2[0].lat; 10.213 + lon21 = points2[0].lon; 10.214 + /* and consider longitude wrap-around for first vertex */ 10.215 + if (lon_dir2<0 && lon21>lon_break2) lon21 = pgl_round(lon21-360); 10.216 + else if (lon_dir2>0 && lon21<lon_break2) lon21 = pgl_round(lon21+360); 10.217 + } 10.218 + /* get latitude and longitude of next vertex */ 10.219 + lat22 = points2[k2].lat; 10.220 + lon22 = points2[k2].lon; 10.221 + /* consider longitude wrap-around for next vertex */ 10.222 + if (lon_dir2<0 && lon22>lon_break2) lon22 = pgl_round(lon22-360); 10.223 + else if (lon_dir2>0 && lon22<lon_break2) lon22 = pgl_round(lon22+360); 10.224 + /* skip degenerated edges */ 10.225 + if (lat21 == lat22 && lon21 == lon22) continue; 10.226 + /* perform another wrap-around where necessary */ 10.227 + /* TODO: improve performance of whole wrap-around mechanism */ 10.228 + wrapvalue = (lon21 + lon22) - (lon11 + lon12); 10.229 + if (wrapvalue > 360) { 10.230 + lon21 = pgl_round(lon21 - 360); 10.231 + lon22 = pgl_round(lon22 - 360); 10.232 + } else if (wrapvalue < -360) { 10.233 + lon21 = pgl_round(lon21 + 360); 10.234 + lon22 = pgl_round(lon22 + 360); 10.235 + } 10.236 + /* return true if segments overlap */ 10.237 + if ( 10.238 + pgl_lseg_crosses_line( 10.239 + lat11, lon11, lat12, lon12, 10.240 + lat21, lon21, lat22, lon22, 10.241 + strict 10.242 + ) && pgl_lseg_crosses_line( 10.243 + lat21, lon21, lat22, lon22, 10.244 + lat11, lon11, lat12, lon12, 10.245 + strict 10.246 + ) 10.247 + ) { 10.248 + return true; 10.249 + } 10.250 + } 10.251 + } 10.252 + } 10.253 + } 10.254 + /* otherwise return false */ 10.255 + return false; 10.256 +} 10.257 + 10.258 +/* check if second cluster is completely contained in first cluster */ 10.259 +static bool pgl_cluster_in_cluster(pgl_cluster *outer, pgl_cluster *inner) { 10.260 + if (!pgl_all_cluster_points_in_cluster(outer, inner)) return false; 10.261 + if (pgl_outlines_overlap(outer, inner, true)) return false; 10.262 + return true; 10.263 +} 10.264 + 10.265 +/* check if two clusters overlap */ 10.266 +static bool pgl_clusters_overlap( 10.267 + pgl_cluster *cluster1, pgl_cluster *cluster2 10.268 +) { 10.269 + if (pgl_any_cluster_points_in_cluster(cluster1, cluster2)) return true; 10.270 + if (pgl_any_cluster_points_in_cluster(cluster2, cluster1)) return true; 10.271 + if (pgl_outlines_overlap(cluster1, cluster2, false)) return true; 10.272 + return false; 10.273 +} 10.274 + 10.275 + 10.276 /* calculate (approximate) distance between point and cluster */ 10.277 static double pgl_point_cluster_distance(pgl_point *point, pgl_cluster *cluster) { 10.278 int i, j, k; /* i: entry, j: point in entry, k: next point in entry */ 10.279 @@ -622,12 +847,18 @@ 10.280 else if (lon_dir > 0 && lon0 < lon_break) lon0 += 360; 10.281 /* iterate over all edges and vertices */ 10.282 for (j=0; j<npoints; j++) { 10.283 - /* get latitude and longitude values of current point */ 10.284 - lat1 = points[j].lat; 10.285 - lon1 = points[j].lon; 10.286 - /* consider longitude wrap-around for current point */ 10.287 - if (lon_dir < 0 && lon1 > lon_break) lon1 -= 360; 10.288 - else if (lon_dir > 0 && lon1 < lon_break) lon1 += 360; 10.289 + /* use previously calculated values for lat1 and lon1 if possible */ 10.290 + if (j) { 10.291 + lat1 = lat2; 10.292 + lon1 = lon2; 10.293 + } else { 10.294 + /* otherwise get latitude and longitude values of first vertex */ 10.295 + lat1 = points[0].lat; 10.296 + lon1 = points[0].lon; 10.297 + /* and consider longitude wrap-around for first vertex */ 10.298 + if (lon_dir < 0 && lon1 > lon_break) lon1 -= 360; 10.299 + else if (lon_dir > 0 && lon1 < lon_break) lon1 += 360; 10.300 + } 10.301 /* calculate distance to vertex */ 10.302 dist = pgl_distance(lat0, lon0, lat1, lon1); 10.303 /* store calculated distance if smallest */ 10.304 @@ -640,10 +871,10 @@ 10.305 entrytype != PGL_ENTRY_OUTLINE && 10.306 entrytype != PGL_ENTRY_POLYGON 10.307 ) continue; 10.308 - /* get latitude and longitude values of next point */ 10.309 + /* get latitude and longitude of next vertex */ 10.310 lat2 = points[k].lat; 10.311 lon2 = points[k].lon; 10.312 - /* consider longitude wrap-around for next point */ 10.313 + /* consider longitude wrap-around for next vertex */ 10.314 if (lon_dir < 0 && lon2 > lon_break) lon2 -= 360; 10.315 else if (lon_dir > 0 && lon2 < lon_break) lon2 += 360; 10.316 /* go to next vertex and edge if edge is degenerated */ 10.317 @@ -669,65 +900,73 @@ 10.318 return min_dist; 10.319 } 10.320 10.321 +/* calculate (approximate) distance between two clusters */ 10.322 +static double pgl_cluster_distance(pgl_cluster *cluster1, pgl_cluster *cluster2) { 10.323 + int i, j; /* i: entry, j: point in entry */ 10.324 + int npoints; /* number of points in entry */ 10.325 + pgl_point *points; /* array of points in entry */ 10.326 + double dist; /* distance calculated in one step */ 10.327 + double min_dist = INFINITY; /* minimum distance */ 10.328 + /* consider distance from each point in one cluster to the whole other */ 10.329 + for (i=0; i<cluster1->nentries; i++) { 10.330 + npoints = cluster1->entries[i].npoints; 10.331 + points = PGL_ENTRY_POINTS(cluster1, i); 10.332 + for (j=0; j<npoints; j++) { 10.333 + dist = pgl_point_cluster_distance(points+j, cluster2); 10.334 + if (dist == 0) return dist; 10.335 + if (dist < min_dist) min_dist = dist; 10.336 + } 10.337 + } 10.338 + /* consider distance from each point in other cluster to the first cluster */ 10.339 + for (i=0; i<cluster2->nentries; i++) { 10.340 + npoints = cluster2->entries[i].npoints; 10.341 + points = PGL_ENTRY_POINTS(cluster2, i); 10.342 + for (j=0; j<npoints; j++) { 10.343 + dist = pgl_point_cluster_distance(points+j, cluster1); 10.344 + if (dist == 0) return dist; 10.345 + if (dist < min_dist) min_dist = dist; 10.346 + } 10.347 + } 10.348 + return min_dist; 10.349 +} 10.350 + 10.351 /* estimator function for distance between box and point */ 10.352 -/* allowed to return smaller values than actually correct */ 10.353 +/* always returns a smaller value than actually correct or zero */ 10.354 static double pgl_estimate_point_box_distance(pgl_point *point, pgl_box *box) { 10.355 - double dlon; /* longitude range of box (delta longitude) */ 10.356 - double h; /* half of distance along meridian */ 10.357 - double d; /* distance between both southern or both northern points */ 10.358 - double cur_dist; /* calculated distance */ 10.359 - double min_dist; /* minimum distance calculated */ 10.360 - /* return infinity if bounding box is empty */ 10.361 + double dlon; /* longitude range of box (delta longitude) */ 10.362 + double distance; /* return value */ 10.363 + /* return infinity if box is empty */ 10.364 if (box->lat_min > box->lat_max) return INFINITY; 10.365 - /* return zero if point is inside bounding box */ 10.366 + /* return zero if point is inside box */ 10.367 if (pgl_point_in_box(point, box)) return 0; 10.368 /* calculate delta longitude */ 10.369 dlon = box->lon_max - box->lon_min; 10.370 if (dlon < 0) dlon += 360; /* 180th meridian crossed */ 10.371 - /* if delta longitude is greater than 180 degrees, perform safe fall-back */ 10.372 - if (dlon > 180) return 0; 10.373 - /* calculate half of distance along meridian */ 10.374 - h = pgl_distance(box->lat_min, 0, box->lat_max, 0) / 2; 10.375 - /* calculate full distance between southern points */ 10.376 - d = pgl_distance(box->lat_min, 0, box->lat_min, dlon); 10.377 - /* calculate maximum of full distance and half distance */ 10.378 - if (h > d) d = h; 10.379 - /* calculate distance from point to first southern vertex and substract 10.380 - maximum error */ 10.381 - min_dist = pgl_distance( 10.382 - point->lat, point->lon, box->lat_min, box->lon_min 10.383 - ) - d; 10.384 - /* return zero if estimated distance is smaller than zero */ 10.385 - if (min_dist <= 0) return 0; 10.386 - /* repeat procedure with second southern vertex */ 10.387 - cur_dist = pgl_distance( 10.388 - point->lat, point->lon, box->lat_min, box->lon_max 10.389 - ) - d; 10.390 - if (cur_dist <= 0) return 0; 10.391 - if (cur_dist < min_dist) min_dist = cur_dist; 10.392 - /* calculate full distance between northern points */ 10.393 - d = pgl_distance(box->lat_max, 0, box->lat_max, dlon); 10.394 - /* calculate maximum of full distance and half distance */ 10.395 - if (h > d) d = h; 10.396 - /* repeat procedure with northern vertices */ 10.397 - cur_dist = pgl_distance( 10.398 - point->lat, point->lon, box->lat_max, box->lon_max 10.399 - ) - d; 10.400 - if (cur_dist <= 0) return 0; 10.401 - if (cur_dist < min_dist) min_dist = cur_dist; 10.402 - cur_dist = pgl_distance( 10.403 - point->lat, point->lon, box->lat_max, box->lon_min 10.404 - ) - d; 10.405 - if (cur_dist <= 0) return 0; 10.406 - if (cur_dist < min_dist) min_dist = cur_dist; 10.407 - /* return smallest value (unless already returned zero) */ 10.408 - return min_dist; 10.409 + /* if delta longitude is greater than 150 degrees, perform safe fall-back */ 10.410 + if (dlon > 150) return 0; 10.411 + /* calculate lower limit for distance (formula below requires dlon <= 150) */ 10.412 + /* TODO: provide better estimation function to improve performance */ 10.413 + distance = ( 10.414 + (1.0-1e-14) * pgl_distance( 10.415 + point->lat, 10.416 + point->lon, 10.417 + (box->lat_min + box->lat_max) / 2, 10.418 + box->lon_min + dlon/2 10.419 + ) - pgl_distance( 10.420 + box->lat_min, box->lon_min, 10.421 + box->lat_max, box->lon_max 10.422 + ) 10.423 + ); 10.424 + /* truncate negative results to zero */ 10.425 + if (distance <= 0) distance = 0; 10.426 + /* return result */ 10.427 + return distance; 10.428 } 10.429 10.430 10.431 -/*----------------------------* 10.432 - * fractal geographic index * 10.433 - *----------------------------*/ 10.434 +/*-------------------------------------------------* 10.435 + * geographic index based on space-filling curve * 10.436 + *-------------------------------------------------*/ 10.437 10.438 /* number of bytes used for geographic (center) position in keys */ 10.439 #define PGL_KEY_LATLON_BYTELEN 7 10.440 @@ -735,9 +974,6 @@ 10.441 /* maximum reference value for logarithmic size of geographic objects */ 10.442 #define PGL_AREAKEY_REFOBJSIZE (PGL_DIAMETER/3.0) /* can be tweaked */ 10.443 10.444 -/* safety margin to avoid floating point errors in distance estimation */ 10.445 -#define PGL_FPE_SAFETY (1.0+1e-14) /* slightly greater than 1.0 */ 10.446 - 10.447 /* pointer to index key (either pgl_pointkey or pgl_areakey) */ 10.448 typedef unsigned char *pgl_keyptr; 10.449 10.450 @@ -1094,7 +1330,7 @@ 10.451 } 10.452 10.453 /* estimator function for distance between point and index key */ 10.454 -/* allowed to return smaller values than actually correct */ 10.455 +/* always returns a smaller value than actually correct or zero */ 10.456 static double pgl_estimate_key_distance(pgl_keyptr key, pgl_point *point) { 10.457 pgl_box box; /* center(!) bounding box of area index key */ 10.458 /* calculate center(!) bounding box and maximum radius of objects covered 10.459 @@ -1103,11 +1339,7 @@ 10.460 /* calculate estimated distance between bounding box of center point of 10.461 indexed object and point passed as second argument, then substract maximum 10.462 radius of objects covered by index key */ 10.463 - /* (use PGL_FPE_SAFETY factor to cope with minor floating point errors) */ 10.464 - distance = ( 10.465 - pgl_estimate_point_box_distance(point, &box) / PGL_FPE_SAFETY - 10.466 - distance * PGL_FPE_SAFETY 10.467 - ); 10.468 + distance = pgl_estimate_point_box_distance(point, &box) - distance; 10.469 /* truncate negative results to zero */ 10.470 if (distance <= 0) distance = 0; 10.471 /* return result */ 10.472 @@ -2102,7 +2334,16 @@ 10.473 Datum pgl_epoint_ecluster_overlap(PG_FUNCTION_ARGS) { 10.474 pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 10.475 pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 10.476 - bool retval = pgl_point_in_cluster(point, cluster); 10.477 + bool retval; 10.478 + /* points outside bounding circle are always assumed to be non-overlapping 10.479 + (necessary for consistent table and index scans) */ 10.480 + if ( 10.481 + pgl_distance( 10.482 + point->lat, point->lon, 10.483 + cluster->bounding.center.lat, cluster->bounding.center.lon 10.484 + ) > cluster->bounding.radius 10.485 + ) retval = false; 10.486 + else retval = pgl_point_in_cluster(point, cluster); 10.487 PG_FREE_IF_COPY(cluster, 1); 10.488 PG_RETURN_BOOL(retval); 10.489 } 10.490 @@ -2189,6 +2430,27 @@ 10.491 PG_RETURN_BOOL(retval); 10.492 } 10.493 10.494 +/* check if two clusters overlap (overlap operator "&&") in SQL */ 10.495 +PG_FUNCTION_INFO_V1(pgl_ecluster_overlap); 10.496 +Datum pgl_ecluster_overlap(PG_FUNCTION_ARGS) { 10.497 + pgl_cluster *cluster1 = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); 10.498 + pgl_cluster *cluster2 = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 10.499 + bool retval; 10.500 + /* clusters with non-touching bounding circles are always assumed to be 10.501 + non-overlapping (improves performance and is necessary for consistent 10.502 + table and index scans) */ 10.503 + if ( 10.504 + pgl_distance( 10.505 + cluster1->bounding.center.lat, cluster1->bounding.center.lon, 10.506 + cluster2->bounding.center.lat, cluster2->bounding.center.lon 10.507 + ) > cluster1->bounding.radius + cluster2->bounding.radius 10.508 + ) retval = false; 10.509 + else retval = pgl_clusters_overlap(cluster1, cluster2); 10.510 + PG_FREE_IF_COPY(cluster1, 0); 10.511 + PG_FREE_IF_COPY(cluster2, 1); 10.512 + PG_RETURN_BOOL(retval); 10.513 +} 10.514 + 10.515 /* check if two clusters may overlap (lossy overlap operator "&&+") in SQL */ 10.516 PG_FUNCTION_INFO_V1(pgl_ecluster_may_overlap); 10.517 Datum pgl_ecluster_may_overlap(PG_FUNCTION_ARGS) { 10.518 @@ -2203,6 +2465,27 @@ 10.519 PG_RETURN_BOOL(retval); 10.520 } 10.521 10.522 +/* check if second cluster is in first cluster (cont. operator "@>) in SQL */ 10.523 +PG_FUNCTION_INFO_V1(pgl_ecluster_contains); 10.524 +Datum pgl_ecluster_contains(PG_FUNCTION_ARGS) { 10.525 + pgl_cluster *outer = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); 10.526 + pgl_cluster *inner = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 10.527 + bool retval; 10.528 + /* clusters with non-touching bounding circles are always assumed to be 10.529 + non-overlapping (improves performance and is necessary for consistent 10.530 + table and index scans) */ 10.531 + if ( 10.532 + pgl_distance( 10.533 + outer->bounding.center.lat, outer->bounding.center.lon, 10.534 + inner->bounding.center.lat, inner->bounding.center.lon 10.535 + ) > outer->bounding.radius + inner->bounding.radius 10.536 + ) retval = false; 10.537 + else retval = pgl_cluster_in_cluster(outer, inner); 10.538 + PG_FREE_IF_COPY(outer, 0); 10.539 + PG_FREE_IF_COPY(inner, 1); 10.540 + PG_RETURN_BOOL(retval); 10.541 +} 10.542 + 10.543 /* calculate distance between two points ("<->" operator) in SQL */ 10.544 PG_FUNCTION_INFO_V1(pgl_epoint_distance); 10.545 Datum pgl_epoint_distance(PG_FUNCTION_ARGS) { 10.546 @@ -2258,6 +2541,17 @@ 10.547 PG_RETURN_FLOAT8((distance <= 0) ? 0 : distance); 10.548 } 10.549 10.550 +/* calculate distance between two clusters ("<->" operator) in SQL */ 10.551 +PG_FUNCTION_INFO_V1(pgl_ecluster_distance); 10.552 +Datum pgl_ecluster_distance(PG_FUNCTION_ARGS) { 10.553 + pgl_cluster *cluster1 = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); 10.554 + pgl_cluster *cluster2 = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 10.555 + double retval = pgl_cluster_distance(cluster1, cluster2); 10.556 + PG_FREE_IF_COPY(cluster1, 0); 10.557 + PG_FREE_IF_COPY(cluster2, 1); 10.558 + PG_RETURN_FLOAT8(retval); 10.559 +} 10.560 + 10.561 10.562 /*-----------------------------------------------------------* 10.563 * B-tree comparison operators and index support functions *
11.1 --- a/latlon.control Sat Sep 03 16:00:22 2016 +0200 11.2 +++ b/latlon.control Fri Sep 09 19:22:30 2016 +0200 11.3 @@ -1,3 +1,3 @@ 11.4 -comment = 'geospatial support' 11.5 -default_version = '0.3' 11.6 +comment = 'Geographic data types and spatial indexing for the WGS-84 spheroid' 11.7 +default_version = '0.4' 11.8 relocatable = true