pgLatLon
changeset 21:54e207df65b7 v0.5
Removed old files for version 0.4
author | jbe |
---|---|
date | Mon Sep 12 18:02:36 2016 +0200 (2016-09-12) |
parents | 8a8d6dc44337 |
children | db2b1c3e39c9 |
files | GNUmakefile latlon--0.3--0.4.sql latlon--0.4.sql latlon-v0004.c |
line diff
1.1 --- a/GNUmakefile Mon Sep 12 18:00:52 2016 +0200 1.2 +++ b/GNUmakefile Mon Sep 12 18:02:36 2016 +0200 1.3 @@ -1,6 +1,6 @@ 1.4 EXTENSION = latlon 1.5 -DATA = latlon--0.3--0.4.sql latlon--0.4.sql latlon--0.4--0.5.sql latlon--0.5.sql 1.6 -MODULES = latlon-v0004 latlon-v0005 1.7 +DATA = latlon--0.4--0.5.sql latlon--0.5.sql 1.8 +MODULES = latlon-v0005 1.9 1.10 PG_CONFIG = pg_config 1.11 PGXS := $(shell $(PG_CONFIG) --pgxs)
2.1 --- a/latlon--0.3--0.4.sql Mon Sep 12 18:00:52 2016 +0200 2.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 2.3 @@ -1,767 +0,0 @@ 2.4 - 2.5 -CREATE OR REPLACE FUNCTION ekey_point_in_dummy(cstring) 2.6 - RETURNS ekey_point 2.7 - LANGUAGE C IMMUTABLE STRICT 2.8 - AS '$libdir/latlon-v0004', 'pgl_notimpl'; 2.9 - 2.10 -CREATE OR REPLACE FUNCTION ekey_point_out_dummy(ekey_point) 2.11 - RETURNS cstring 2.12 - LANGUAGE C IMMUTABLE STRICT 2.13 - AS '$libdir/latlon-v0004', 'pgl_notimpl'; 2.14 - 2.15 -CREATE OR REPLACE FUNCTION ekey_area_in_dummy(cstring) 2.16 - RETURNS ekey_area 2.17 - LANGUAGE C IMMUTABLE STRICT 2.18 - AS '$libdir/latlon-v0004', 'pgl_notimpl'; 2.19 - 2.20 -CREATE OR REPLACE FUNCTION ekey_area_out_dummy(ekey_area) 2.21 - RETURNS cstring 2.22 - LANGUAGE C IMMUTABLE STRICT 2.23 - AS '$libdir/latlon-v0004', 'pgl_notimpl'; 2.24 - 2.25 -CREATE OR REPLACE FUNCTION epoint_in(cstring) 2.26 - RETURNS epoint 2.27 - LANGUAGE C IMMUTABLE STRICT 2.28 - AS '$libdir/latlon-v0004', 'pgl_epoint_in'; 2.29 - 2.30 -CREATE OR REPLACE FUNCTION ebox_in(cstring) 2.31 - RETURNS ebox 2.32 - LANGUAGE C IMMUTABLE STRICT 2.33 - AS '$libdir/latlon-v0004', 'pgl_ebox_in'; 2.34 - 2.35 -CREATE OR REPLACE FUNCTION ecircle_in(cstring) 2.36 - RETURNS ecircle 2.37 - LANGUAGE C IMMUTABLE STRICT 2.38 - AS '$libdir/latlon-v0004', 'pgl_ecircle_in'; 2.39 - 2.40 -CREATE OR REPLACE FUNCTION ecluster_in(cstring) 2.41 - RETURNS ecluster 2.42 - LANGUAGE C IMMUTABLE STRICT 2.43 - AS '$libdir/latlon-v0004', 'pgl_ecluster_in'; 2.44 - 2.45 -CREATE OR REPLACE FUNCTION epoint_out(epoint) 2.46 - RETURNS cstring 2.47 - LANGUAGE C IMMUTABLE STRICT 2.48 - AS '$libdir/latlon-v0004', 'pgl_epoint_out'; 2.49 - 2.50 -CREATE OR REPLACE FUNCTION ebox_out(ebox) 2.51 - RETURNS cstring 2.52 - LANGUAGE C IMMUTABLE STRICT 2.53 - AS '$libdir/latlon-v0004', 'pgl_ebox_out'; 2.54 - 2.55 -CREATE OR REPLACE FUNCTION ecircle_out(ecircle) 2.56 - RETURNS cstring 2.57 - LANGUAGE C IMMUTABLE STRICT 2.58 - AS '$libdir/latlon-v0004', 'pgl_ecircle_out'; 2.59 - 2.60 -CREATE OR REPLACE FUNCTION ecluster_out(ecluster) 2.61 - RETURNS cstring 2.62 - LANGUAGE C IMMUTABLE STRICT 2.63 - AS '$libdir/latlon-v0004', 'pgl_ecluster_out'; 2.64 - 2.65 -CREATE OR REPLACE FUNCTION epoint_recv(internal) 2.66 - RETURNS epoint 2.67 - LANGUAGE C IMMUTABLE STRICT 2.68 - AS '$libdir/latlon-v0004', 'pgl_epoint_recv'; 2.69 - 2.70 -CREATE OR REPLACE FUNCTION ebox_recv(internal) 2.71 - RETURNS ebox 2.72 - LANGUAGE C IMMUTABLE STRICT 2.73 - AS '$libdir/latlon-v0004', 'pgl_ebox_recv'; 2.74 - 2.75 -CREATE OR REPLACE FUNCTION ecircle_recv(internal) 2.76 - RETURNS ecircle 2.77 - LANGUAGE C IMMUTABLE STRICT 2.78 - AS '$libdir/latlon-v0004', 'pgl_ecircle_recv'; 2.79 - 2.80 -CREATE OR REPLACE FUNCTION epoint_send(epoint) 2.81 - RETURNS bytea 2.82 - LANGUAGE C IMMUTABLE STRICT 2.83 - AS '$libdir/latlon-v0004', 'pgl_epoint_send'; 2.84 - 2.85 -CREATE OR REPLACE FUNCTION ebox_send(ebox) 2.86 - RETURNS bytea 2.87 - LANGUAGE C IMMUTABLE STRICT 2.88 - AS '$libdir/latlon-v0004', 'pgl_ebox_send'; 2.89 - 2.90 -CREATE OR REPLACE FUNCTION ecircle_send(ecircle) 2.91 - RETURNS bytea 2.92 - LANGUAGE C IMMUTABLE STRICT 2.93 - AS '$libdir/latlon-v0004', 'pgl_ecircle_send'; 2.94 - 2.95 -CREATE OR REPLACE FUNCTION epoint_btree_lt(epoint, epoint) 2.96 - RETURNS boolean 2.97 - LANGUAGE C IMMUTABLE STRICT 2.98 - AS '$libdir/latlon-v0004', 'pgl_btree_epoint_lt'; 2.99 - 2.100 -CREATE OR REPLACE FUNCTION epoint_btree_le(epoint, epoint) 2.101 - RETURNS boolean 2.102 - LANGUAGE C IMMUTABLE STRICT 2.103 - AS '$libdir/latlon-v0004', 'pgl_btree_epoint_le'; 2.104 - 2.105 -CREATE OR REPLACE FUNCTION epoint_btree_eq(epoint, epoint) 2.106 - RETURNS boolean 2.107 - LANGUAGE C IMMUTABLE STRICT 2.108 - AS '$libdir/latlon-v0004', 'pgl_btree_epoint_eq'; 2.109 - 2.110 -CREATE OR REPLACE FUNCTION epoint_btree_ne(epoint, epoint) 2.111 - RETURNS boolean 2.112 - LANGUAGE C IMMUTABLE STRICT 2.113 - AS '$libdir/latlon-v0004', 'pgl_btree_epoint_ne'; 2.114 - 2.115 -CREATE OR REPLACE FUNCTION epoint_btree_ge(epoint, epoint) 2.116 - RETURNS boolean 2.117 - LANGUAGE C IMMUTABLE STRICT 2.118 - AS '$libdir/latlon-v0004', 'pgl_btree_epoint_ge'; 2.119 - 2.120 -CREATE OR REPLACE FUNCTION epoint_btree_gt(epoint, epoint) 2.121 - RETURNS boolean 2.122 - LANGUAGE C IMMUTABLE STRICT 2.123 - AS '$libdir/latlon-v0004', 'pgl_btree_epoint_gt'; 2.124 - 2.125 -CREATE OR REPLACE FUNCTION epoint_btree_cmp(epoint, epoint) 2.126 - RETURNS int4 2.127 - LANGUAGE C IMMUTABLE STRICT 2.128 - AS '$libdir/latlon-v0004', 'pgl_btree_epoint_cmp'; 2.129 - 2.130 -CREATE OR REPLACE FUNCTION ebox_btree_lt(ebox, ebox) 2.131 - RETURNS boolean 2.132 - LANGUAGE C IMMUTABLE STRICT 2.133 - AS '$libdir/latlon-v0004', 'pgl_btree_ebox_lt'; 2.134 - 2.135 -CREATE OR REPLACE FUNCTION ebox_btree_le(ebox, ebox) 2.136 - RETURNS boolean 2.137 - LANGUAGE C IMMUTABLE STRICT 2.138 - AS '$libdir/latlon-v0004', 'pgl_btree_ebox_le'; 2.139 - 2.140 -CREATE OR REPLACE FUNCTION ebox_btree_eq(ebox, ebox) 2.141 - RETURNS boolean 2.142 - LANGUAGE C IMMUTABLE STRICT 2.143 - AS '$libdir/latlon-v0004', 'pgl_btree_ebox_eq'; 2.144 - 2.145 -CREATE OR REPLACE FUNCTION ebox_btree_ne(ebox, ebox) 2.146 - RETURNS boolean 2.147 - LANGUAGE C IMMUTABLE STRICT 2.148 - AS '$libdir/latlon-v0004', 'pgl_btree_ebox_ne'; 2.149 - 2.150 -CREATE OR REPLACE FUNCTION ebox_btree_ge(ebox, ebox) 2.151 - RETURNS boolean 2.152 - LANGUAGE C IMMUTABLE STRICT 2.153 - AS '$libdir/latlon-v0004', 'pgl_btree_ebox_ge'; 2.154 - 2.155 -CREATE OR REPLACE FUNCTION ebox_btree_gt(ebox, ebox) 2.156 - RETURNS boolean 2.157 - LANGUAGE C IMMUTABLE STRICT 2.158 - AS '$libdir/latlon-v0004', 'pgl_btree_ebox_gt'; 2.159 - 2.160 -CREATE OR REPLACE FUNCTION ebox_btree_cmp(ebox, ebox) 2.161 - RETURNS int4 2.162 - LANGUAGE C IMMUTABLE STRICT 2.163 - AS '$libdir/latlon-v0004', 'pgl_btree_ebox_cmp'; 2.164 - 2.165 -CREATE OR REPLACE FUNCTION ecircle_btree_lt(ecircle, ecircle) 2.166 - RETURNS boolean 2.167 - LANGUAGE C IMMUTABLE STRICT 2.168 - AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_lt'; 2.169 - 2.170 -CREATE OR REPLACE FUNCTION ecircle_btree_le(ecircle, ecircle) 2.171 - RETURNS boolean 2.172 - LANGUAGE C IMMUTABLE STRICT 2.173 - AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_le'; 2.174 - 2.175 -CREATE OR REPLACE FUNCTION ecircle_btree_eq(ecircle, ecircle) 2.176 - RETURNS boolean 2.177 - LANGUAGE C IMMUTABLE STRICT 2.178 - AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_eq'; 2.179 - 2.180 -CREATE OR REPLACE FUNCTION ecircle_btree_ne(ecircle, ecircle) 2.181 - RETURNS boolean 2.182 - LANGUAGE C IMMUTABLE STRICT 2.183 - AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_ne'; 2.184 - 2.185 -CREATE OR REPLACE FUNCTION ecircle_btree_ge(ecircle, ecircle) 2.186 - RETURNS boolean 2.187 - LANGUAGE C IMMUTABLE STRICT 2.188 - AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_ge'; 2.189 - 2.190 -CREATE OR REPLACE FUNCTION ecircle_btree_gt(ecircle, ecircle) 2.191 - RETURNS boolean 2.192 - LANGUAGE C IMMUTABLE STRICT 2.193 - AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_gt'; 2.194 - 2.195 -CREATE OR REPLACE FUNCTION ecircle_btree_cmp(ecircle, ecircle) 2.196 - RETURNS int4 2.197 - LANGUAGE C IMMUTABLE STRICT 2.198 - AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_cmp'; 2.199 - 2.200 -CREATE OR REPLACE FUNCTION cast_epoint_to_ebox(epoint) 2.201 - RETURNS ebox 2.202 - LANGUAGE C IMMUTABLE STRICT 2.203 - AS '$libdir/latlon-v0004', 'pgl_epoint_to_ebox'; 2.204 - 2.205 -CREATE OR REPLACE FUNCTION cast_epoint_to_ecircle(epoint) 2.206 - RETURNS ecircle 2.207 - LANGUAGE C IMMUTABLE STRICT 2.208 - AS '$libdir/latlon-v0004', 'pgl_epoint_to_ecircle'; 2.209 - 2.210 -CREATE OR REPLACE FUNCTION cast_epoint_to_ecluster(epoint) 2.211 - RETURNS ecluster 2.212 - LANGUAGE C IMMUTABLE STRICT 2.213 - AS '$libdir/latlon-v0004', 'pgl_epoint_to_ecluster'; 2.214 - 2.215 -CREATE OR REPLACE FUNCTION cast_ebox_to_ecluster(ebox) 2.216 - RETURNS ecluster 2.217 - LANGUAGE C IMMUTABLE STRICT 2.218 - AS '$libdir/latlon-v0004', 'pgl_ebox_to_ecluster'; 2.219 - 2.220 -CREATE OR REPLACE FUNCTION epoint(float8, float8) 2.221 - RETURNS epoint 2.222 - LANGUAGE C IMMUTABLE STRICT 2.223 - AS '$libdir/latlon-v0004', 'pgl_create_epoint'; 2.224 - 2.225 -CREATE OR REPLACE FUNCTION empty_ebox() 2.226 - RETURNS ebox 2.227 - LANGUAGE C IMMUTABLE STRICT 2.228 - AS '$libdir/latlon-v0004', 'pgl_create_empty_ebox'; 2.229 - 2.230 -CREATE OR REPLACE FUNCTION ebox(float8, float8, float8, float8) 2.231 - RETURNS ebox 2.232 - LANGUAGE C IMMUTABLE STRICT 2.233 - AS '$libdir/latlon-v0004', 'pgl_create_ebox'; 2.234 - 2.235 -CREATE OR REPLACE FUNCTION ebox(epoint, epoint) 2.236 - RETURNS ebox 2.237 - LANGUAGE C IMMUTABLE STRICT 2.238 - AS '$libdir/latlon-v0004', 'pgl_create_ebox_from_epoints'; 2.239 - 2.240 -CREATE OR REPLACE FUNCTION ecircle(float8, float8, float8) 2.241 - RETURNS ecircle 2.242 - LANGUAGE C IMMUTABLE STRICT 2.243 - AS '$libdir/latlon-v0004', 'pgl_create_ecircle'; 2.244 - 2.245 -CREATE OR REPLACE FUNCTION ecircle(epoint, float8) 2.246 - RETURNS ecircle 2.247 - LANGUAGE C IMMUTABLE STRICT 2.248 - AS '$libdir/latlon-v0004', 'pgl_create_ecircle_from_epoint'; 2.249 - 2.250 -CREATE OR REPLACE FUNCTION latitude(epoint) 2.251 - RETURNS float8 2.252 - LANGUAGE C IMMUTABLE STRICT 2.253 - AS '$libdir/latlon-v0004', 'pgl_epoint_lat'; 2.254 - 2.255 -CREATE OR REPLACE FUNCTION longitude(epoint) 2.256 - RETURNS float8 2.257 - LANGUAGE C IMMUTABLE STRICT 2.258 - AS '$libdir/latlon-v0004', 'pgl_epoint_lon'; 2.259 - 2.260 -CREATE OR REPLACE FUNCTION min_latitude(ebox) 2.261 - RETURNS float8 2.262 - LANGUAGE C IMMUTABLE STRICT 2.263 - AS '$libdir/latlon-v0004', 'pgl_ebox_lat_min'; 2.264 - 2.265 -CREATE OR REPLACE FUNCTION max_latitude(ebox) 2.266 - RETURNS float8 2.267 - LANGUAGE C IMMUTABLE STRICT 2.268 - AS '$libdir/latlon-v0004', 'pgl_ebox_lat_max'; 2.269 - 2.270 -CREATE OR REPLACE FUNCTION min_longitude(ebox) 2.271 - RETURNS float8 2.272 - LANGUAGE C IMMUTABLE STRICT 2.273 - AS '$libdir/latlon-v0004', 'pgl_ebox_lon_min'; 2.274 - 2.275 -CREATE OR REPLACE FUNCTION max_longitude(ebox) 2.276 - RETURNS float8 2.277 - LANGUAGE C IMMUTABLE STRICT 2.278 - AS '$libdir/latlon-v0004', 'pgl_ebox_lon_max'; 2.279 - 2.280 -CREATE OR REPLACE FUNCTION center(ecircle) 2.281 - RETURNS epoint 2.282 - LANGUAGE C IMMUTABLE STRICT 2.283 - AS '$libdir/latlon-v0004', 'pgl_ecircle_center'; 2.284 - 2.285 -CREATE OR REPLACE FUNCTION radius(ecircle) 2.286 - RETURNS float8 2.287 - LANGUAGE C IMMUTABLE STRICT 2.288 - AS '$libdir/latlon-v0004', 'pgl_ecircle_radius'; 2.289 - 2.290 -CREATE OR REPLACE FUNCTION epoint_ebox_overlap_proc(epoint, ebox) 2.291 - RETURNS boolean 2.292 - LANGUAGE C IMMUTABLE STRICT 2.293 - AS '$libdir/latlon-v0004', 'pgl_epoint_ebox_overlap'; 2.294 - 2.295 -CREATE OR REPLACE FUNCTION epoint_ecircle_overlap_proc(epoint, ecircle) 2.296 - RETURNS boolean 2.297 - LANGUAGE C IMMUTABLE STRICT 2.298 - AS '$libdir/latlon-v0004', 'pgl_epoint_ecircle_overlap'; 2.299 - 2.300 -CREATE OR REPLACE FUNCTION epoint_ecluster_overlap_proc(epoint, ecluster) 2.301 - RETURNS boolean 2.302 - LANGUAGE C IMMUTABLE STRICT 2.303 - AS '$libdir/latlon-v0004', 'pgl_epoint_ecluster_overlap'; 2.304 - 2.305 -CREATE OR REPLACE FUNCTION epoint_ecluster_may_overlap_proc(epoint, ecluster) 2.306 - RETURNS boolean 2.307 - LANGUAGE C IMMUTABLE STRICT 2.308 - AS '$libdir/latlon-v0004', 'pgl_epoint_ecluster_may_overlap'; 2.309 - 2.310 -CREATE OR REPLACE FUNCTION ebox_overlap_proc(ebox, ebox) 2.311 - RETURNS boolean 2.312 - LANGUAGE C IMMUTABLE STRICT 2.313 - AS '$libdir/latlon-v0004', 'pgl_ebox_overlap'; 2.314 - 2.315 -CREATE OR REPLACE FUNCTION ebox_ecircle_may_overlap_proc(ebox, ecircle) 2.316 - RETURNS boolean 2.317 - LANGUAGE C IMMUTABLE STRICT 2.318 - AS '$libdir/latlon-v0004', 'pgl_ebox_ecircle_may_overlap'; 2.319 - 2.320 -CREATE OR REPLACE FUNCTION ebox_ecluster_may_overlap_proc(ebox, ecluster) 2.321 - RETURNS boolean 2.322 - LANGUAGE C IMMUTABLE STRICT 2.323 - AS '$libdir/latlon-v0004', 'pgl_ebox_ecluster_may_overlap'; 2.324 - 2.325 -CREATE OR REPLACE FUNCTION ecircle_overlap_proc(ecircle, ecircle) 2.326 - RETURNS boolean 2.327 - LANGUAGE C IMMUTABLE STRICT 2.328 - AS '$libdir/latlon-v0004', 'pgl_ecircle_overlap'; 2.329 - 2.330 -CREATE OR REPLACE FUNCTION ecircle_ecluster_overlap_proc(ecircle, ecluster) 2.331 - RETURNS boolean 2.332 - LANGUAGE C IMMUTABLE STRICT 2.333 - AS '$libdir/latlon-v0004', 'pgl_ecircle_ecluster_overlap'; 2.334 - 2.335 -CREATE OR REPLACE FUNCTION ecircle_ecluster_may_overlap_proc(ecircle, ecluster) 2.336 - RETURNS boolean 2.337 - LANGUAGE C IMMUTABLE STRICT 2.338 - AS '$libdir/latlon-v0004', 'pgl_ecircle_ecluster_may_overlap'; 2.339 - 2.340 -CREATE FUNCTION ecluster_overlap_proc(ecluster, ecluster) 2.341 - RETURNS boolean 2.342 - LANGUAGE C IMMUTABLE STRICT 2.343 - AS '$libdir/latlon-v0004', 'pgl_ecluster_overlap'; 2.344 - 2.345 -CREATE OR REPLACE FUNCTION ecluster_may_overlap_proc(ecluster, ecluster) 2.346 - RETURNS boolean 2.347 - LANGUAGE C IMMUTABLE STRICT 2.348 - AS '$libdir/latlon-v0004', 'pgl_ecluster_may_overlap'; 2.349 - 2.350 -CREATE FUNCTION ecluster_contains_proc(ecluster, ecluster) 2.351 - RETURNS boolean 2.352 - LANGUAGE C IMMUTABLE STRICT 2.353 - AS '$libdir/latlon-v0004', 'pgl_ecluster_contains'; 2.354 - 2.355 -CREATE OR REPLACE FUNCTION epoint_distance_proc(epoint, epoint) 2.356 - RETURNS float8 2.357 - LANGUAGE C IMMUTABLE STRICT 2.358 - AS '$libdir/latlon-v0004', 'pgl_epoint_distance'; 2.359 - 2.360 -CREATE OR REPLACE FUNCTION epoint_ecircle_distance_proc(epoint, ecircle) 2.361 - RETURNS float8 2.362 - LANGUAGE C IMMUTABLE STRICT 2.363 - AS '$libdir/latlon-v0004', 'pgl_epoint_ecircle_distance'; 2.364 - 2.365 -CREATE OR REPLACE FUNCTION epoint_ecluster_distance_proc(epoint, ecluster) 2.366 - RETURNS float8 2.367 - LANGUAGE C IMMUTABLE STRICT 2.368 - AS '$libdir/latlon-v0004', 'pgl_epoint_ecluster_distance'; 2.369 - 2.370 -CREATE OR REPLACE FUNCTION ecircle_distance_proc(ecircle, ecircle) 2.371 - RETURNS float8 2.372 - LANGUAGE C IMMUTABLE STRICT 2.373 - AS '$libdir/latlon-v0004', 'pgl_ecircle_distance'; 2.374 - 2.375 -CREATE OR REPLACE FUNCTION ecircle_ecluster_distance_proc(ecircle, ecluster) 2.376 - RETURNS float8 2.377 - LANGUAGE C IMMUTABLE STRICT 2.378 - AS '$libdir/latlon-v0004', 'pgl_ecircle_ecluster_distance'; 2.379 - 2.380 -CREATE FUNCTION ecluster_distance_proc(ecluster, ecluster) 2.381 - RETURNS float8 2.382 - LANGUAGE C IMMUTABLE STRICT 2.383 - AS '$libdir/latlon-v0004', 'pgl_ecluster_distance'; 2.384 - 2.385 -CREATE OPERATOR && ( 2.386 - leftarg = ecluster, 2.387 - rightarg = ecluster, 2.388 - procedure = ecluster_overlap_proc, 2.389 - commutator = &&, 2.390 - restrict = areasel, 2.391 - join = areajoinsel 2.392 -); 2.393 - 2.394 -CREATE FUNCTION ebox_ecircle_overlap_castwrap(ebox, ecircle) 2.395 - RETURNS boolean 2.396 - LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster && $2'; 2.397 - 2.398 -CREATE OPERATOR && ( 2.399 - leftarg = ebox, 2.400 - rightarg = ecircle, 2.401 - procedure = ebox_ecircle_overlap_castwrap, 2.402 - commutator = &&, 2.403 - restrict = areasel, 2.404 - join = areajoinsel 2.405 -); 2.406 - 2.407 -CREATE FUNCTION ebox_ecircle_overlap_castwrap(ecircle, ebox) 2.408 - RETURNS boolean 2.409 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 && $2::ecluster'; 2.410 - 2.411 -CREATE OPERATOR && ( 2.412 - leftarg = ecircle, 2.413 - rightarg = ebox, 2.414 - procedure = ebox_ecircle_overlap_castwrap, 2.415 - commutator = &&, 2.416 - restrict = areasel, 2.417 - join = areajoinsel 2.418 -); 2.419 - 2.420 -CREATE FUNCTION ebox_ecluster_overlap_castwrap(ebox, ecluster) 2.421 - RETURNS boolean 2.422 - LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster && $2'; 2.423 - 2.424 -CREATE OPERATOR && ( 2.425 - leftarg = ebox, 2.426 - rightarg = ecluster, 2.427 - procedure = ebox_ecluster_overlap_castwrap, 2.428 - commutator = &&, 2.429 - restrict = areasel, 2.430 - join = areajoinsel 2.431 -); 2.432 - 2.433 -CREATE FUNCTION ebox_ecluster_overlap_castwrap(ecluster, ebox) 2.434 - RETURNS boolean 2.435 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 && $2::ecluster'; 2.436 - 2.437 -CREATE OPERATOR && ( 2.438 - leftarg = ecluster, 2.439 - rightarg = ebox, 2.440 - procedure = ebox_ecluster_overlap_castwrap, 2.441 - commutator = &&, 2.442 - restrict = areasel, 2.443 - join = areajoinsel 2.444 -); 2.445 - 2.446 - 2.447 -CREATE OPERATOR @> ( 2.448 - leftarg = ebox, 2.449 - rightarg = epoint, 2.450 - procedure = epoint_ebox_overlap_commutator, 2.451 - commutator = <@, 2.452 - restrict = areasel, 2.453 - join = areajoinsel 2.454 -); 2.455 - 2.456 -CREATE OPERATOR <@ ( 2.457 - leftarg = epoint, 2.458 - rightarg = ebox, 2.459 - procedure = epoint_ebox_overlap_proc, 2.460 - commutator = @>, 2.461 - restrict = areasel, 2.462 - join = areajoinsel 2.463 -); 2.464 - 2.465 -CREATE OPERATOR @> ( 2.466 - leftarg = ecluster, 2.467 - rightarg = epoint, 2.468 - procedure = epoint_ecluster_overlap_commutator, 2.469 - commutator = <@, 2.470 - restrict = areasel, 2.471 - join = areajoinsel 2.472 -); 2.473 - 2.474 -CREATE OPERATOR <@ ( 2.475 - leftarg = epoint, 2.476 - rightarg = ecluster, 2.477 - procedure = epoint_ecluster_overlap_proc, 2.478 - commutator = <@, 2.479 - restrict = areasel, 2.480 - join = areajoinsel 2.481 -); 2.482 - 2.483 -CREATE OPERATOR @> ( 2.484 - leftarg = ecluster, 2.485 - rightarg = ecluster, 2.486 - procedure = ecluster_contains_proc, 2.487 - commutator = <@, 2.488 - restrict = areasel, 2.489 - join = areajoinsel 2.490 -); 2.491 - 2.492 -CREATE FUNCTION ecluster_contains_commutator(ecluster, ecluster) 2.493 - RETURNS boolean 2.494 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 @> $1'; 2.495 - 2.496 -CREATE OPERATOR <@ ( 2.497 - leftarg = ecluster, 2.498 - rightarg = ecluster, 2.499 - procedure = ecluster_contains_commutator, 2.500 - commutator = @>, 2.501 - restrict = areasel, 2.502 - join = areajoinsel 2.503 -); 2.504 - 2.505 -CREATE FUNCTION ebox_ecluster_contains_castwrap(ebox, ecluster) 2.506 - RETURNS boolean 2.507 - LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster @> $2'; 2.508 - 2.509 -CREATE OPERATOR @> ( 2.510 - leftarg = ebox, 2.511 - rightarg = ecluster, 2.512 - procedure = ebox_ecluster_contains_castwrap, 2.513 - commutator = <@, 2.514 - restrict = areasel, 2.515 - join = areajoinsel 2.516 -); 2.517 - 2.518 -CREATE FUNCTION ebox_ecluster_contains_castwrap(ecluster, ebox) 2.519 - RETURNS boolean 2.520 - LANGUAGE sql IMMUTABLE AS 'SELECT $2::ecluster @> $1'; 2.521 - 2.522 -CREATE OPERATOR <@ ( 2.523 - leftarg = ecluster, 2.524 - rightarg = ebox, 2.525 - procedure = ebox_ecluster_contains_castwrap, 2.526 - commutator = @>, 2.527 - restrict = areasel, 2.528 - join = areajoinsel 2.529 -); 2.530 - 2.531 -CREATE FUNCTION ecluster_ebox_contains_castwrap(ecluster, ebox) 2.532 - RETURNS boolean 2.533 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 @> $2::ecluster'; 2.534 - 2.535 -CREATE OPERATOR @> ( 2.536 - leftarg = ecluster, 2.537 - rightarg = ebox, 2.538 - procedure = ecluster_ebox_contains_castwrap, 2.539 - commutator = <@, 2.540 - restrict = areasel, 2.541 - join = areajoinsel 2.542 -); 2.543 - 2.544 -CREATE FUNCTION ecluster_ebox_contains_castwrap(ebox, ecluster) 2.545 - RETURNS boolean 2.546 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 @> $1::ecluster'; 2.547 - 2.548 -CREATE OPERATOR <@ ( 2.549 - leftarg = ebox, 2.550 - rightarg = ecluster, 2.551 - procedure = ecluster_ebox_contains_castwrap, 2.552 - commutator = @>, 2.553 - restrict = areasel, 2.554 - join = areajoinsel 2.555 -); 2.556 - 2.557 - 2.558 -CREATE OPERATOR <-> ( 2.559 - leftarg = ecluster, 2.560 - rightarg = ecluster, 2.561 - procedure = ecluster_distance_proc, 2.562 - commutator = <-> 2.563 -); 2.564 - 2.565 -CREATE FUNCTION epoint_ebox_distance_castwrap(epoint, ebox) 2.566 - RETURNS float8 2.567 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 <-> $2::ecluster'; 2.568 - 2.569 -CREATE OPERATOR <-> ( 2.570 - leftarg = epoint, 2.571 - rightarg = ebox, 2.572 - procedure = epoint_ebox_distance_castwrap, 2.573 - commutator = <-> 2.574 -); 2.575 - 2.576 -CREATE FUNCTION epoint_ebox_distance_castwrap(ebox, epoint) 2.577 - RETURNS float8 2.578 - LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster <-> $2'; 2.579 - 2.580 -CREATE OPERATOR <-> ( 2.581 - leftarg = ebox, 2.582 - rightarg = epoint, 2.583 - procedure = epoint_ebox_distance_castwrap, 2.584 - commutator = <-> 2.585 -); 2.586 - 2.587 -CREATE FUNCTION ebox_distance_castwrap(ebox, ebox) 2.588 - RETURNS float8 2.589 - LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster <-> $2::ecluster'; 2.590 - 2.591 -CREATE OPERATOR <-> ( 2.592 - leftarg = ebox, 2.593 - rightarg = ebox, 2.594 - procedure = ebox_distance_castwrap, 2.595 - commutator = <-> 2.596 -); 2.597 - 2.598 -CREATE FUNCTION ebox_ecircle_distance_castwrap(ebox, ecircle) 2.599 - RETURNS float8 2.600 - LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster <-> $2'; 2.601 - 2.602 -CREATE OPERATOR <-> ( 2.603 - leftarg = ebox, 2.604 - rightarg = ecircle, 2.605 - procedure = ebox_ecircle_distance_castwrap, 2.606 - commutator = <-> 2.607 -); 2.608 - 2.609 -CREATE FUNCTION ebox_ecircle_distance_castwrap(ecircle, ebox) 2.610 - RETURNS float8 2.611 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 <-> $2::ecluster'; 2.612 - 2.613 -CREATE OPERATOR <-> ( 2.614 - leftarg = ecircle, 2.615 - rightarg = ebox, 2.616 - procedure = ebox_ecircle_distance_castwrap, 2.617 - commutator = <-> 2.618 -); 2.619 - 2.620 -CREATE FUNCTION ebox_ecluster_distance_castwrap(ebox, ecluster) 2.621 - RETURNS float8 2.622 - LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster <-> $2'; 2.623 - 2.624 -CREATE OPERATOR <-> ( 2.625 - leftarg = ebox, 2.626 - rightarg = ecluster, 2.627 - procedure = ebox_ecluster_distance_castwrap, 2.628 - commutator = <-> 2.629 -); 2.630 - 2.631 -CREATE FUNCTION ebox_ecluster_distance_castwrap(ecluster, ebox) 2.632 - RETURNS float8 2.633 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 <-> $2::ecluster'; 2.634 - 2.635 -CREATE OPERATOR <-> ( 2.636 - leftarg = ecluster, 2.637 - rightarg = ebox, 2.638 - procedure = ebox_ecluster_distance_castwrap, 2.639 - commutator = <-> 2.640 -); 2.641 - 2.642 -DROP OPERATOR CLASS epoint_ops USING gist; 2.643 -DROP OPERATOR CLASS ecircle_ops USING gist; 2.644 -DROP OPERATOR CLASS ecluster_ops USING gist; 2.645 - 2.646 -CREATE OR REPLACE FUNCTION pgl_gist_consistent(internal, internal, smallint, oid, internal) 2.647 - RETURNS boolean 2.648 - LANGUAGE C STRICT 2.649 - AS '$libdir/latlon-v0004', 'pgl_gist_consistent'; 2.650 - 2.651 -CREATE OR REPLACE FUNCTION pgl_gist_union(internal, internal) 2.652 - RETURNS internal 2.653 - LANGUAGE C STRICT 2.654 - AS '$libdir/latlon-v0004', 'pgl_gist_union'; 2.655 - 2.656 -CREATE OR REPLACE FUNCTION pgl_gist_compress_epoint(internal) 2.657 - RETURNS internal 2.658 - LANGUAGE C STRICT 2.659 - AS '$libdir/latlon-v0004', 'pgl_gist_compress_epoint'; 2.660 - 2.661 -CREATE OR REPLACE FUNCTION pgl_gist_compress_ecircle(internal) 2.662 - RETURNS internal 2.663 - LANGUAGE C STRICT 2.664 - AS '$libdir/latlon-v0004', 'pgl_gist_compress_ecircle'; 2.665 - 2.666 -CREATE OR REPLACE FUNCTION pgl_gist_compress_ecluster(internal) 2.667 - RETURNS internal 2.668 - LANGUAGE C STRICT 2.669 - AS '$libdir/latlon-v0004', 'pgl_gist_compress_ecluster'; 2.670 - 2.671 -CREATE OR REPLACE FUNCTION pgl_gist_decompress(internal) 2.672 - RETURNS internal 2.673 - LANGUAGE C STRICT 2.674 - AS '$libdir/latlon-v0004', 'pgl_gist_decompress'; 2.675 - 2.676 -CREATE OR REPLACE FUNCTION pgl_gist_penalty(internal, internal, internal) 2.677 - RETURNS internal 2.678 - LANGUAGE C STRICT 2.679 - AS '$libdir/latlon-v0004', 'pgl_gist_penalty'; 2.680 - 2.681 -CREATE OR REPLACE FUNCTION pgl_gist_picksplit(internal, internal) 2.682 - RETURNS internal 2.683 - LANGUAGE C STRICT 2.684 - AS '$libdir/latlon-v0004', 'pgl_gist_picksplit'; 2.685 - 2.686 -CREATE OR REPLACE FUNCTION pgl_gist_same(internal, internal, internal) 2.687 - RETURNS internal 2.688 - LANGUAGE C STRICT 2.689 - AS '$libdir/latlon-v0004', 'pgl_gist_same'; 2.690 - 2.691 -CREATE OR REPLACE FUNCTION pgl_gist_distance(internal, internal, smallint, oid) 2.692 - RETURNS internal 2.693 - LANGUAGE C STRICT 2.694 - AS '$libdir/latlon-v0004', 'pgl_gist_distance'; 2.695 - 2.696 -CREATE OPERATOR CLASS epoint_ops 2.697 - DEFAULT FOR TYPE epoint USING gist AS 2.698 - OPERATOR 11 = , 2.699 - OPERATOR 22 && (epoint, ebox), 2.700 - OPERATOR 222 <@ (epoint, ebox), 2.701 - OPERATOR 23 && (epoint, ecircle), 2.702 - OPERATOR 24 && (epoint, ecluster), 2.703 - OPERATOR 124 &&+ (epoint, ecluster), 2.704 - OPERATOR 224 <@ (epoint, ecluster), 2.705 - OPERATOR 31 <-> (epoint, epoint) FOR ORDER BY float_ops, 2.706 - OPERATOR 32 <-> (epoint, ebox) FOR ORDER BY float_ops, 2.707 - OPERATOR 33 <-> (epoint, ecircle) FOR ORDER BY float_ops, 2.708 - OPERATOR 34 <-> (epoint, ecluster) FOR ORDER BY float_ops, 2.709 - FUNCTION 1 pgl_gist_consistent(internal, internal, smallint, oid, internal), 2.710 - FUNCTION 2 pgl_gist_union(internal, internal), 2.711 - FUNCTION 3 pgl_gist_compress_epoint(internal), 2.712 - FUNCTION 4 pgl_gist_decompress(internal), 2.713 - FUNCTION 5 pgl_gist_penalty(internal, internal, internal), 2.714 - FUNCTION 6 pgl_gist_picksplit(internal, internal), 2.715 - FUNCTION 7 pgl_gist_same(internal, internal, internal), 2.716 - FUNCTION 8 pgl_gist_distance(internal, internal, smallint, oid), 2.717 - STORAGE ekey_point; 2.718 - 2.719 -CREATE OPERATOR CLASS ecircle_ops 2.720 - DEFAULT FOR TYPE ecircle USING gist AS 2.721 - OPERATOR 13 = , 2.722 - OPERATOR 21 && (ecircle, epoint), 2.723 - OPERATOR 22 && (ecircle, ebox), 2.724 - OPERATOR 122 &&+ (ecircle, ebox), 2.725 - OPERATOR 23 && (ecircle, ecircle), 2.726 - OPERATOR 24 && (ecircle, ecluster), 2.727 - OPERATOR 124 &&+ (ecircle, ecluster), 2.728 - OPERATOR 31 <-> (ecircle, epoint) FOR ORDER BY float_ops, 2.729 - OPERATOR 32 <-> (ecircle, ebox) FOR ORDER BY float_ops, 2.730 - OPERATOR 33 <-> (ecircle, ecircle) FOR ORDER BY float_ops, 2.731 - OPERATOR 34 <-> (ecircle, ecluster) FOR ORDER BY float_ops, 2.732 - FUNCTION 1 pgl_gist_consistent(internal, internal, smallint, oid, internal), 2.733 - FUNCTION 2 pgl_gist_union(internal, internal), 2.734 - FUNCTION 3 pgl_gist_compress_ecircle(internal), 2.735 - FUNCTION 4 pgl_gist_decompress(internal), 2.736 - FUNCTION 5 pgl_gist_penalty(internal, internal, internal), 2.737 - FUNCTION 6 pgl_gist_picksplit(internal, internal), 2.738 - FUNCTION 7 pgl_gist_same(internal, internal, internal), 2.739 - FUNCTION 8 pgl_gist_distance(internal, internal, smallint, oid), 2.740 - STORAGE ekey_area; 2.741 - 2.742 -CREATE OPERATOR CLASS ecluster_ops 2.743 - DEFAULT FOR TYPE ecluster USING gist AS 2.744 - OPERATOR 21 && (ecluster, epoint), 2.745 - OPERATOR 121 &&+ (ecluster, epoint), 2.746 - OPERATOR 221 @> (ecluster, epoint), 2.747 - OPERATOR 22 && (ecluster, ebox), 2.748 - OPERATOR 122 &&+ (ecluster, ebox), 2.749 - OPERATOR 222 @> (ecluster, ebox), 2.750 - OPERATOR 322 <@ (ecluster, ebox), 2.751 - OPERATOR 23 && (ecluster, ecircle), 2.752 - OPERATOR 123 &&+ (ecluster, ecircle), 2.753 - OPERATOR 24 && (ecluster, ecluster), 2.754 - OPERATOR 124 &&+ (ecluster, ecluster), 2.755 - OPERATOR 224 @> (ecluster, ecluster), 2.756 - OPERATOR 324 <@ (ecluster, ecluster), 2.757 - OPERATOR 31 <-> (ecluster, epoint) FOR ORDER BY float_ops, 2.758 - OPERATOR 32 <-> (ecluster, ebox) FOR ORDER BY float_ops, 2.759 - OPERATOR 33 <-> (ecluster, ecircle) FOR ORDER BY float_ops, 2.760 - OPERATOR 34 <-> (ecluster, ecluster) FOR ORDER BY float_ops, 2.761 - FUNCTION 1 pgl_gist_consistent(internal, internal, smallint, oid, internal), 2.762 - FUNCTION 2 pgl_gist_union(internal, internal), 2.763 - FUNCTION 3 pgl_gist_compress_ecluster(internal), 2.764 - FUNCTION 4 pgl_gist_decompress(internal), 2.765 - FUNCTION 5 pgl_gist_penalty(internal, internal, internal), 2.766 - FUNCTION 6 pgl_gist_picksplit(internal, internal), 2.767 - FUNCTION 7 pgl_gist_same(internal, internal, internal), 2.768 - FUNCTION 8 pgl_gist_distance(internal, internal, smallint, oid), 2.769 - STORAGE ekey_area; 2.770 -
3.1 --- a/latlon--0.4.sql Mon Sep 12 18:00:52 2016 +0200 3.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 3.3 @@ -1,1621 +0,0 @@ 3.4 - 3.5 ----------------------------------------- 3.6 --- forward declarations (shell types) -- 3.7 ----------------------------------------- 3.8 - 3.9 -CREATE TYPE epoint; 3.10 -CREATE TYPE ebox; 3.11 -CREATE TYPE ecircle; 3.12 -CREATE TYPE ecluster; 3.13 - 3.14 - 3.15 ------------------------------------------------------------- 3.16 --- dummy input/output functions for dummy index key types -- 3.17 ------------------------------------------------------------- 3.18 - 3.19 -CREATE FUNCTION ekey_point_in_dummy(cstring) 3.20 - RETURNS ekey_point 3.21 - LANGUAGE C IMMUTABLE STRICT 3.22 - AS '$libdir/latlon-v0004', 'pgl_notimpl'; 3.23 - 3.24 -CREATE FUNCTION ekey_point_out_dummy(ekey_point) 3.25 - RETURNS cstring 3.26 - LANGUAGE C IMMUTABLE STRICT 3.27 - AS '$libdir/latlon-v0004', 'pgl_notimpl'; 3.28 - 3.29 -CREATE FUNCTION ekey_area_in_dummy(cstring) 3.30 - RETURNS ekey_area 3.31 - LANGUAGE C IMMUTABLE STRICT 3.32 - AS '$libdir/latlon-v0004', 'pgl_notimpl'; 3.33 - 3.34 -CREATE FUNCTION ekey_area_out_dummy(ekey_area) 3.35 - RETURNS cstring 3.36 - LANGUAGE C IMMUTABLE STRICT 3.37 - AS '$libdir/latlon-v0004', 'pgl_notimpl'; 3.38 - 3.39 - 3.40 --------------------------- 3.41 --- text input functions -- 3.42 --------------------------- 3.43 - 3.44 -CREATE FUNCTION epoint_in(cstring) 3.45 - RETURNS epoint 3.46 - LANGUAGE C IMMUTABLE STRICT 3.47 - AS '$libdir/latlon-v0004', 'pgl_epoint_in'; 3.48 - 3.49 -CREATE FUNCTION ebox_in(cstring) 3.50 - RETURNS ebox 3.51 - LANGUAGE C IMMUTABLE STRICT 3.52 - AS '$libdir/latlon-v0004', 'pgl_ebox_in'; 3.53 - 3.54 -CREATE FUNCTION ecircle_in(cstring) 3.55 - RETURNS ecircle 3.56 - LANGUAGE C IMMUTABLE STRICT 3.57 - AS '$libdir/latlon-v0004', 'pgl_ecircle_in'; 3.58 - 3.59 -CREATE FUNCTION ecluster_in(cstring) 3.60 - RETURNS ecluster 3.61 - LANGUAGE C IMMUTABLE STRICT 3.62 - AS '$libdir/latlon-v0004', 'pgl_ecluster_in'; 3.63 - 3.64 - 3.65 ---------------------------- 3.66 --- text output functions -- 3.67 ---------------------------- 3.68 - 3.69 -CREATE FUNCTION epoint_out(epoint) 3.70 - RETURNS cstring 3.71 - LANGUAGE C IMMUTABLE STRICT 3.72 - AS '$libdir/latlon-v0004', 'pgl_epoint_out'; 3.73 - 3.74 -CREATE FUNCTION ebox_out(ebox) 3.75 - RETURNS cstring 3.76 - LANGUAGE C IMMUTABLE STRICT 3.77 - AS '$libdir/latlon-v0004', 'pgl_ebox_out'; 3.78 - 3.79 -CREATE FUNCTION ecircle_out(ecircle) 3.80 - RETURNS cstring 3.81 - LANGUAGE C IMMUTABLE STRICT 3.82 - AS '$libdir/latlon-v0004', 'pgl_ecircle_out'; 3.83 - 3.84 -CREATE FUNCTION ecluster_out(ecluster) 3.85 - RETURNS cstring 3.86 - LANGUAGE C IMMUTABLE STRICT 3.87 - AS '$libdir/latlon-v0004', 'pgl_ecluster_out'; 3.88 - 3.89 - 3.90 --------------------------- 3.91 --- binary I/O functions -- 3.92 --------------------------- 3.93 - 3.94 -CREATE FUNCTION epoint_recv(internal) 3.95 - RETURNS epoint 3.96 - LANGUAGE C IMMUTABLE STRICT 3.97 - AS '$libdir/latlon-v0004', 'pgl_epoint_recv'; 3.98 - 3.99 -CREATE FUNCTION ebox_recv(internal) 3.100 - RETURNS ebox 3.101 - LANGUAGE C IMMUTABLE STRICT 3.102 - AS '$libdir/latlon-v0004', 'pgl_ebox_recv'; 3.103 - 3.104 -CREATE FUNCTION ecircle_recv(internal) 3.105 - RETURNS ecircle 3.106 - LANGUAGE C IMMUTABLE STRICT 3.107 - AS '$libdir/latlon-v0004', 'pgl_ecircle_recv'; 3.108 - 3.109 -CREATE FUNCTION epoint_send(epoint) 3.110 - RETURNS bytea 3.111 - LANGUAGE C IMMUTABLE STRICT 3.112 - AS '$libdir/latlon-v0004', 'pgl_epoint_send'; 3.113 - 3.114 -CREATE FUNCTION ebox_send(ebox) 3.115 - RETURNS bytea 3.116 - LANGUAGE C IMMUTABLE STRICT 3.117 - AS '$libdir/latlon-v0004', 'pgl_ebox_send'; 3.118 - 3.119 -CREATE FUNCTION ecircle_send(ecircle) 3.120 - RETURNS bytea 3.121 - LANGUAGE C IMMUTABLE STRICT 3.122 - AS '$libdir/latlon-v0004', 'pgl_ecircle_send'; 3.123 - 3.124 - 3.125 ------------------------------------------------ 3.126 --- type definitions of dummy index key types -- 3.127 ------------------------------------------------ 3.128 - 3.129 -CREATE TYPE ekey_point ( 3.130 - internallength = 8, 3.131 - input = ekey_point_in_dummy, 3.132 - output = ekey_point_out_dummy, 3.133 - alignment = char ); 3.134 - 3.135 -CREATE TYPE ekey_area ( 3.136 - internallength = 9, 3.137 - input = ekey_area_in_dummy, 3.138 - output = ekey_area_out_dummy, 3.139 - alignment = char ); 3.140 - 3.141 - 3.142 ------------------------------------------- 3.143 --- definitions of geographic data types -- 3.144 ------------------------------------------- 3.145 - 3.146 -CREATE TYPE epoint ( 3.147 - internallength = 16, 3.148 - input = epoint_in, 3.149 - output = epoint_out, 3.150 - receive = epoint_recv, 3.151 - send = epoint_send, 3.152 - alignment = double ); 3.153 - 3.154 -CREATE TYPE ebox ( 3.155 - internallength = 32, 3.156 - input = ebox_in, 3.157 - output = ebox_out, 3.158 - receive = ebox_recv, 3.159 - send = ebox_send, 3.160 - alignment = double ); 3.161 - 3.162 -CREATE TYPE ecircle ( 3.163 - internallength = 24, 3.164 - input = ecircle_in, 3.165 - output = ecircle_out, 3.166 - receive = ecircle_recv, 3.167 - send = ecircle_send, 3.168 - alignment = double ); 3.169 - 3.170 -CREATE TYPE ecluster ( 3.171 - internallength = VARIABLE, 3.172 - input = ecluster_in, 3.173 - output = ecluster_out, 3.174 - alignment = double, 3.175 - storage = external ); 3.176 - 3.177 - 3.178 --------------------- 3.179 --- B-tree support -- 3.180 --------------------- 3.181 - 3.182 --- begin of B-tree support for epoint 3.183 - 3.184 -CREATE FUNCTION epoint_btree_lt(epoint, epoint) 3.185 - RETURNS boolean 3.186 - LANGUAGE C IMMUTABLE STRICT 3.187 - AS '$libdir/latlon-v0004', 'pgl_btree_epoint_lt'; 3.188 - 3.189 -CREATE FUNCTION epoint_btree_le(epoint, epoint) 3.190 - RETURNS boolean 3.191 - LANGUAGE C IMMUTABLE STRICT 3.192 - AS '$libdir/latlon-v0004', 'pgl_btree_epoint_le'; 3.193 - 3.194 -CREATE FUNCTION epoint_btree_eq(epoint, epoint) 3.195 - RETURNS boolean 3.196 - LANGUAGE C IMMUTABLE STRICT 3.197 - AS '$libdir/latlon-v0004', 'pgl_btree_epoint_eq'; 3.198 - 3.199 -CREATE FUNCTION epoint_btree_ne(epoint, epoint) 3.200 - RETURNS boolean 3.201 - LANGUAGE C IMMUTABLE STRICT 3.202 - AS '$libdir/latlon-v0004', 'pgl_btree_epoint_ne'; 3.203 - 3.204 -CREATE FUNCTION epoint_btree_ge(epoint, epoint) 3.205 - RETURNS boolean 3.206 - LANGUAGE C IMMUTABLE STRICT 3.207 - AS '$libdir/latlon-v0004', 'pgl_btree_epoint_ge'; 3.208 - 3.209 -CREATE FUNCTION epoint_btree_gt(epoint, epoint) 3.210 - RETURNS boolean 3.211 - LANGUAGE C IMMUTABLE STRICT 3.212 - AS '$libdir/latlon-v0004', 'pgl_btree_epoint_gt'; 3.213 - 3.214 -CREATE OPERATOR <<< ( 3.215 - leftarg = epoint, 3.216 - rightarg = epoint, 3.217 - procedure = epoint_btree_lt, 3.218 - commutator = >>>, 3.219 - negator = >>>=, 3.220 - restrict = scalarltsel, 3.221 - join = scalarltjoinsel 3.222 -); 3.223 - 3.224 -CREATE OPERATOR <<<= ( 3.225 - leftarg = epoint, 3.226 - rightarg = epoint, 3.227 - procedure = epoint_btree_le, 3.228 - commutator = >>>=, 3.229 - negator = >>>, 3.230 - restrict = scalarltsel, 3.231 - join = scalarltjoinsel 3.232 -); 3.233 - 3.234 -CREATE OPERATOR = ( 3.235 - leftarg = epoint, 3.236 - rightarg = epoint, 3.237 - procedure = epoint_btree_eq, 3.238 - commutator = =, 3.239 - negator = <>, 3.240 - restrict = eqsel, 3.241 - join = eqjoinsel, 3.242 - merges 3.243 -); 3.244 - 3.245 -CREATE OPERATOR <> ( 3.246 - leftarg = epoint, 3.247 - rightarg = epoint, 3.248 - procedure = epoint_btree_eq, 3.249 - commutator = <>, 3.250 - negator = =, 3.251 - restrict = neqsel, 3.252 - join = neqjoinsel 3.253 -); 3.254 - 3.255 -CREATE OPERATOR >>>= ( 3.256 - leftarg = epoint, 3.257 - rightarg = epoint, 3.258 - procedure = epoint_btree_ge, 3.259 - commutator = <<<=, 3.260 - negator = <<<, 3.261 - restrict = scalargtsel, 3.262 - join = scalargtjoinsel 3.263 -); 3.264 - 3.265 -CREATE OPERATOR >>> ( 3.266 - leftarg = epoint, 3.267 - rightarg = epoint, 3.268 - procedure = epoint_btree_gt, 3.269 - commutator = <<<, 3.270 - negator = <<<=, 3.271 - restrict = scalargtsel, 3.272 - join = scalargtjoinsel 3.273 -); 3.274 - 3.275 -CREATE FUNCTION epoint_btree_cmp(epoint, epoint) 3.276 - RETURNS int4 3.277 - LANGUAGE C IMMUTABLE STRICT 3.278 - AS '$libdir/latlon-v0004', 'pgl_btree_epoint_cmp'; 3.279 - 3.280 -CREATE OPERATOR CLASS epoint_btree_ops 3.281 - DEFAULT FOR TYPE epoint USING btree AS 3.282 - OPERATOR 1 <<< , 3.283 - OPERATOR 2 <<<= , 3.284 - OPERATOR 3 = , 3.285 - OPERATOR 4 >>>= , 3.286 - OPERATOR 5 >>> , 3.287 - FUNCTION 1 epoint_btree_cmp(epoint, epoint); 3.288 - 3.289 --- end of B-tree support for epoint 3.290 - 3.291 --- begin of B-tree support for ebox 3.292 - 3.293 -CREATE FUNCTION ebox_btree_lt(ebox, ebox) 3.294 - RETURNS boolean 3.295 - LANGUAGE C IMMUTABLE STRICT 3.296 - AS '$libdir/latlon-v0004', 'pgl_btree_ebox_lt'; 3.297 - 3.298 -CREATE FUNCTION ebox_btree_le(ebox, ebox) 3.299 - RETURNS boolean 3.300 - LANGUAGE C IMMUTABLE STRICT 3.301 - AS '$libdir/latlon-v0004', 'pgl_btree_ebox_le'; 3.302 - 3.303 -CREATE FUNCTION ebox_btree_eq(ebox, ebox) 3.304 - RETURNS boolean 3.305 - LANGUAGE C IMMUTABLE STRICT 3.306 - AS '$libdir/latlon-v0004', 'pgl_btree_ebox_eq'; 3.307 - 3.308 -CREATE FUNCTION ebox_btree_ne(ebox, ebox) 3.309 - RETURNS boolean 3.310 - LANGUAGE C IMMUTABLE STRICT 3.311 - AS '$libdir/latlon-v0004', 'pgl_btree_ebox_ne'; 3.312 - 3.313 -CREATE FUNCTION ebox_btree_ge(ebox, ebox) 3.314 - RETURNS boolean 3.315 - LANGUAGE C IMMUTABLE STRICT 3.316 - AS '$libdir/latlon-v0004', 'pgl_btree_ebox_ge'; 3.317 - 3.318 -CREATE FUNCTION ebox_btree_gt(ebox, ebox) 3.319 - RETURNS boolean 3.320 - LANGUAGE C IMMUTABLE STRICT 3.321 - AS '$libdir/latlon-v0004', 'pgl_btree_ebox_gt'; 3.322 - 3.323 -CREATE OPERATOR <<< ( 3.324 - leftarg = ebox, 3.325 - rightarg = ebox, 3.326 - procedure = ebox_btree_lt, 3.327 - commutator = >>>, 3.328 - negator = >>>=, 3.329 - restrict = scalarltsel, 3.330 - join = scalarltjoinsel 3.331 -); 3.332 - 3.333 -CREATE OPERATOR <<<= ( 3.334 - leftarg = ebox, 3.335 - rightarg = ebox, 3.336 - procedure = ebox_btree_le, 3.337 - commutator = >>>=, 3.338 - negator = >>>, 3.339 - restrict = scalarltsel, 3.340 - join = scalarltjoinsel 3.341 -); 3.342 - 3.343 -CREATE OPERATOR = ( 3.344 - leftarg = ebox, 3.345 - rightarg = ebox, 3.346 - procedure = ebox_btree_eq, 3.347 - commutator = =, 3.348 - negator = <>, 3.349 - restrict = eqsel, 3.350 - join = eqjoinsel, 3.351 - merges 3.352 -); 3.353 - 3.354 -CREATE OPERATOR <> ( 3.355 - leftarg = ebox, 3.356 - rightarg = ebox, 3.357 - procedure = ebox_btree_eq, 3.358 - commutator = <>, 3.359 - negator = =, 3.360 - restrict = neqsel, 3.361 - join = neqjoinsel 3.362 -); 3.363 - 3.364 -CREATE OPERATOR >>>= ( 3.365 - leftarg = ebox, 3.366 - rightarg = ebox, 3.367 - procedure = ebox_btree_ge, 3.368 - commutator = <<<=, 3.369 - negator = <<<, 3.370 - restrict = scalargtsel, 3.371 - join = scalargtjoinsel 3.372 -); 3.373 - 3.374 -CREATE OPERATOR >>> ( 3.375 - leftarg = ebox, 3.376 - rightarg = ebox, 3.377 - procedure = ebox_btree_gt, 3.378 - commutator = <<<, 3.379 - negator = <<<=, 3.380 - restrict = scalargtsel, 3.381 - join = scalargtjoinsel 3.382 -); 3.383 - 3.384 -CREATE FUNCTION ebox_btree_cmp(ebox, ebox) 3.385 - RETURNS int4 3.386 - LANGUAGE C IMMUTABLE STRICT 3.387 - AS '$libdir/latlon-v0004', 'pgl_btree_ebox_cmp'; 3.388 - 3.389 -CREATE OPERATOR CLASS ebox_btree_ops 3.390 - DEFAULT FOR TYPE ebox USING btree AS 3.391 - OPERATOR 1 <<< , 3.392 - OPERATOR 2 <<<= , 3.393 - OPERATOR 3 = , 3.394 - OPERATOR 4 >>>= , 3.395 - OPERATOR 5 >>> , 3.396 - FUNCTION 1 ebox_btree_cmp(ebox, ebox); 3.397 - 3.398 --- end of B-tree support for ebox 3.399 - 3.400 --- begin of B-tree support for ecircle 3.401 - 3.402 -CREATE FUNCTION ecircle_btree_lt(ecircle, ecircle) 3.403 - RETURNS boolean 3.404 - LANGUAGE C IMMUTABLE STRICT 3.405 - AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_lt'; 3.406 - 3.407 -CREATE FUNCTION ecircle_btree_le(ecircle, ecircle) 3.408 - RETURNS boolean 3.409 - LANGUAGE C IMMUTABLE STRICT 3.410 - AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_le'; 3.411 - 3.412 -CREATE FUNCTION ecircle_btree_eq(ecircle, ecircle) 3.413 - RETURNS boolean 3.414 - LANGUAGE C IMMUTABLE STRICT 3.415 - AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_eq'; 3.416 - 3.417 -CREATE FUNCTION ecircle_btree_ne(ecircle, ecircle) 3.418 - RETURNS boolean 3.419 - LANGUAGE C IMMUTABLE STRICT 3.420 - AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_ne'; 3.421 - 3.422 -CREATE FUNCTION ecircle_btree_ge(ecircle, ecircle) 3.423 - RETURNS boolean 3.424 - LANGUAGE C IMMUTABLE STRICT 3.425 - AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_ge'; 3.426 - 3.427 -CREATE FUNCTION ecircle_btree_gt(ecircle, ecircle) 3.428 - RETURNS boolean 3.429 - LANGUAGE C IMMUTABLE STRICT 3.430 - AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_gt'; 3.431 - 3.432 -CREATE OPERATOR <<< ( 3.433 - leftarg = ecircle, 3.434 - rightarg = ecircle, 3.435 - procedure = ecircle_btree_lt, 3.436 - commutator = >>>, 3.437 - negator = >>>=, 3.438 - restrict = scalarltsel, 3.439 - join = scalarltjoinsel 3.440 -); 3.441 - 3.442 -CREATE OPERATOR <<<= ( 3.443 - leftarg = ecircle, 3.444 - rightarg = ecircle, 3.445 - procedure = ecircle_btree_le, 3.446 - commutator = >>>=, 3.447 - negator = >>>, 3.448 - restrict = scalarltsel, 3.449 - join = scalarltjoinsel 3.450 -); 3.451 - 3.452 -CREATE OPERATOR = ( 3.453 - leftarg = ecircle, 3.454 - rightarg = ecircle, 3.455 - procedure = ecircle_btree_eq, 3.456 - commutator = =, 3.457 - negator = <>, 3.458 - restrict = eqsel, 3.459 - join = eqjoinsel, 3.460 - merges 3.461 -); 3.462 - 3.463 -CREATE OPERATOR <> ( 3.464 - leftarg = ecircle, 3.465 - rightarg = ecircle, 3.466 - procedure = ecircle_btree_eq, 3.467 - commutator = <>, 3.468 - negator = =, 3.469 - restrict = neqsel, 3.470 - join = neqjoinsel 3.471 -); 3.472 - 3.473 -CREATE OPERATOR >>>= ( 3.474 - leftarg = ecircle, 3.475 - rightarg = ecircle, 3.476 - procedure = ecircle_btree_ge, 3.477 - commutator = <<<=, 3.478 - negator = <<<, 3.479 - restrict = scalargtsel, 3.480 - join = scalargtjoinsel 3.481 -); 3.482 - 3.483 -CREATE OPERATOR >>> ( 3.484 - leftarg = ecircle, 3.485 - rightarg = ecircle, 3.486 - procedure = ecircle_btree_gt, 3.487 - commutator = <<<, 3.488 - negator = <<<=, 3.489 - restrict = scalargtsel, 3.490 - join = scalargtjoinsel 3.491 -); 3.492 - 3.493 -CREATE FUNCTION ecircle_btree_cmp(ecircle, ecircle) 3.494 - RETURNS int4 3.495 - LANGUAGE C IMMUTABLE STRICT 3.496 - AS '$libdir/latlon-v0004', 'pgl_btree_ecircle_cmp'; 3.497 - 3.498 -CREATE OPERATOR CLASS ecircle_btree_ops 3.499 - DEFAULT FOR TYPE ecircle USING btree AS 3.500 - OPERATOR 1 <<< , 3.501 - OPERATOR 2 <<<= , 3.502 - OPERATOR 3 = , 3.503 - OPERATOR 4 >>>= , 3.504 - OPERATOR 5 >>> , 3.505 - FUNCTION 1 ecircle_btree_cmp(ecircle, ecircle); 3.506 - 3.507 --- end of B-tree support for ecircle 3.508 - 3.509 - 3.510 ----------------- 3.511 --- type casts -- 3.512 ----------------- 3.513 - 3.514 -CREATE FUNCTION cast_epoint_to_ebox(epoint) 3.515 - RETURNS ebox 3.516 - LANGUAGE C IMMUTABLE STRICT 3.517 - AS '$libdir/latlon-v0004', 'pgl_epoint_to_ebox'; 3.518 - 3.519 -CREATE CAST (epoint AS ebox) WITH FUNCTION cast_epoint_to_ebox(epoint); 3.520 - 3.521 -CREATE FUNCTION cast_epoint_to_ecircle(epoint) 3.522 - RETURNS ecircle 3.523 - LANGUAGE C IMMUTABLE STRICT 3.524 - AS '$libdir/latlon-v0004', 'pgl_epoint_to_ecircle'; 3.525 - 3.526 -CREATE CAST (epoint AS ecircle) WITH FUNCTION cast_epoint_to_ecircle(epoint); 3.527 - 3.528 -CREATE FUNCTION cast_epoint_to_ecluster(epoint) 3.529 - RETURNS ecluster 3.530 - LANGUAGE C IMMUTABLE STRICT 3.531 - AS '$libdir/latlon-v0004', 'pgl_epoint_to_ecluster'; 3.532 - 3.533 -CREATE CAST (epoint AS ecluster) WITH FUNCTION cast_epoint_to_ecluster(epoint); 3.534 - 3.535 -CREATE FUNCTION cast_ebox_to_ecluster(ebox) 3.536 - RETURNS ecluster 3.537 - LANGUAGE C IMMUTABLE STRICT 3.538 - AS '$libdir/latlon-v0004', 'pgl_ebox_to_ecluster'; 3.539 - 3.540 -CREATE CAST (ebox AS ecluster) WITH FUNCTION cast_ebox_to_ecluster(ebox); 3.541 - 3.542 - 3.543 ---------------------------- 3.544 --- constructor functions -- 3.545 ---------------------------- 3.546 - 3.547 -CREATE FUNCTION epoint(float8, float8) 3.548 - RETURNS epoint 3.549 - LANGUAGE C IMMUTABLE STRICT 3.550 - AS '$libdir/latlon-v0004', 'pgl_create_epoint'; 3.551 - 3.552 -CREATE FUNCTION epoint_latlon(float8, float8) 3.553 - RETURNS epoint 3.554 - LANGUAGE SQL IMMUTABLE STRICT AS $$ 3.555 - SELECT epoint($1, $2) 3.556 - $$; 3.557 - 3.558 -CREATE FUNCTION epoint_lonlat(float8, float8) 3.559 - RETURNS epoint 3.560 - LANGUAGE SQL IMMUTABLE STRICT AS $$ 3.561 - SELECT epoint($2, $1) 3.562 - $$; 3.563 - 3.564 -CREATE FUNCTION empty_ebox() 3.565 - RETURNS ebox 3.566 - LANGUAGE C IMMUTABLE STRICT 3.567 - AS '$libdir/latlon-v0004', 'pgl_create_empty_ebox'; 3.568 - 3.569 -CREATE FUNCTION ebox(float8, float8, float8, float8) 3.570 - RETURNS ebox 3.571 - LANGUAGE C IMMUTABLE STRICT 3.572 - AS '$libdir/latlon-v0004', 'pgl_create_ebox'; 3.573 - 3.574 -CREATE FUNCTION ebox(epoint, epoint) 3.575 - RETURNS ebox 3.576 - LANGUAGE C IMMUTABLE STRICT 3.577 - AS '$libdir/latlon-v0004', 'pgl_create_ebox_from_epoints'; 3.578 - 3.579 -CREATE FUNCTION ecircle(float8, float8, float8) 3.580 - RETURNS ecircle 3.581 - LANGUAGE C IMMUTABLE STRICT 3.582 - AS '$libdir/latlon-v0004', 'pgl_create_ecircle'; 3.583 - 3.584 -CREATE FUNCTION ecircle(epoint, float8) 3.585 - RETURNS ecircle 3.586 - LANGUAGE C IMMUTABLE STRICT 3.587 - AS '$libdir/latlon-v0004', 'pgl_create_ecircle_from_epoint'; 3.588 - 3.589 -CREATE FUNCTION ecluster_concat(ecluster[]) 3.590 - RETURNS ecluster 3.591 - LANGUAGE sql IMMUTABLE STRICT AS $$ 3.592 - SELECT array_to_string($1, ' ')::ecluster 3.593 - $$; 3.594 - 3.595 -CREATE FUNCTION ecluster_concat(ecluster, ecluster) 3.596 - RETURNS ecluster 3.597 - LANGUAGE sql IMMUTABLE STRICT AS $$ 3.598 - SELECT ($1::text || ' ' || $2::text)::ecluster 3.599 - $$; 3.600 - 3.601 -CREATE FUNCTION ecluster_create_multipoint(epoint[]) 3.602 - RETURNS ecluster 3.603 - LANGUAGE sql IMMUTABLE STRICT AS $$ 3.604 - SELECT 3.605 - array_to_string(array_agg('point (' || unnest || ')'), ' ')::ecluster 3.606 - FROM unnest($1) 3.607 - $$; 3.608 - 3.609 -CREATE FUNCTION ecluster_create_path(epoint[]) 3.610 - RETURNS ecluster 3.611 - LANGUAGE sql IMMUTABLE STRICT AS $$ 3.612 - SELECT CASE WHEN "str" = '' THEN 'empty'::ecluster ELSE 3.613 - ('path (' || array_to_string($1, ' ') || ')')::ecluster 3.614 - END 3.615 - FROM array_to_string($1, ' ') AS "str" 3.616 - $$; 3.617 - 3.618 -CREATE FUNCTION ecluster_create_outline(epoint[]) 3.619 - RETURNS ecluster 3.620 - LANGUAGE sql IMMUTABLE STRICT AS $$ 3.621 - SELECT CASE WHEN "str" = '' THEN 'empty'::ecluster ELSE 3.622 - ('outline (' || array_to_string($1, ' ') || ')')::ecluster 3.623 - END 3.624 - FROM array_to_string($1, ' ') AS "str" 3.625 - $$; 3.626 - 3.627 -CREATE FUNCTION ecluster_create_polygon(epoint[]) 3.628 - RETURNS ecluster 3.629 - LANGUAGE sql IMMUTABLE STRICT AS $$ 3.630 - SELECT CASE WHEN "str" = '' THEN 'empty'::ecluster ELSE 3.631 - ('polygon (' || array_to_string($1, ' ') || ')')::ecluster 3.632 - END 3.633 - FROM array_to_string($1, ' ') AS "str" 3.634 - $$; 3.635 - 3.636 - 3.637 ----------------------- 3.638 --- getter functions -- 3.639 ----------------------- 3.640 - 3.641 -CREATE FUNCTION latitude(epoint) 3.642 - RETURNS float8 3.643 - LANGUAGE C IMMUTABLE STRICT 3.644 - AS '$libdir/latlon-v0004', 'pgl_epoint_lat'; 3.645 - 3.646 -CREATE FUNCTION longitude(epoint) 3.647 - RETURNS float8 3.648 - LANGUAGE C IMMUTABLE STRICT 3.649 - AS '$libdir/latlon-v0004', 'pgl_epoint_lon'; 3.650 - 3.651 -CREATE FUNCTION min_latitude(ebox) 3.652 - RETURNS float8 3.653 - LANGUAGE C IMMUTABLE STRICT 3.654 - AS '$libdir/latlon-v0004', 'pgl_ebox_lat_min'; 3.655 - 3.656 -CREATE FUNCTION max_latitude(ebox) 3.657 - RETURNS float8 3.658 - LANGUAGE C IMMUTABLE STRICT 3.659 - AS '$libdir/latlon-v0004', 'pgl_ebox_lat_max'; 3.660 - 3.661 -CREATE FUNCTION min_longitude(ebox) 3.662 - RETURNS float8 3.663 - LANGUAGE C IMMUTABLE STRICT 3.664 - AS '$libdir/latlon-v0004', 'pgl_ebox_lon_min'; 3.665 - 3.666 -CREATE FUNCTION max_longitude(ebox) 3.667 - RETURNS float8 3.668 - LANGUAGE C IMMUTABLE STRICT 3.669 - AS '$libdir/latlon-v0004', 'pgl_ebox_lon_max'; 3.670 - 3.671 -CREATE FUNCTION center(ecircle) 3.672 - RETURNS epoint 3.673 - LANGUAGE C IMMUTABLE STRICT 3.674 - AS '$libdir/latlon-v0004', 'pgl_ecircle_center'; 3.675 - 3.676 -CREATE FUNCTION radius(ecircle) 3.677 - RETURNS float8 3.678 - LANGUAGE C IMMUTABLE STRICT 3.679 - AS '$libdir/latlon-v0004', 'pgl_ecircle_radius'; 3.680 - 3.681 -CREATE FUNCTION ecluster_extract_points(ecluster) 3.682 - RETURNS SETOF epoint 3.683 - LANGUAGE sql IMMUTABLE STRICT AS $$ 3.684 - SELECT "match"[2]::epoint 3.685 - FROM regexp_matches($1::text, e'(^| )point \\(([^)]+)\\)', 'g') AS "match" 3.686 - $$; 3.687 - 3.688 -CREATE FUNCTION ecluster_extract_paths(ecluster) 3.689 - RETURNS SETOF epoint[] 3.690 - LANGUAGE sql IMMUTABLE STRICT AS $$ 3.691 - SELECT ( 3.692 - SELECT array_agg("m2"[1]::epoint) 3.693 - FROM regexp_matches("m1"[2], e'[^ ]+ [^ ]+', 'g') AS "m2" 3.694 - ) 3.695 - FROM regexp_matches($1::text, e'(^| )path \\(([^)]+)\\)', 'g') AS "m1" 3.696 - $$; 3.697 - 3.698 -CREATE FUNCTION ecluster_extract_outlines(ecluster) 3.699 - RETURNS SETOF epoint[] 3.700 - LANGUAGE sql IMMUTABLE STRICT AS $$ 3.701 - SELECT ( 3.702 - SELECT array_agg("m2"[1]::epoint) 3.703 - FROM regexp_matches("m1"[2], e'[^ ]+ [^ ]+', 'g') AS "m2" 3.704 - ) 3.705 - FROM regexp_matches($1::text, e'(^| )outline \\(([^)]+)\\)', 'g') AS "m1" 3.706 - $$; 3.707 - 3.708 -CREATE FUNCTION ecluster_extract_polygons(ecluster) 3.709 - RETURNS SETOF epoint[] 3.710 - LANGUAGE sql IMMUTABLE STRICT AS $$ 3.711 - SELECT ( 3.712 - SELECT array_agg("m2"[1]::epoint) 3.713 - FROM regexp_matches("m1"[2], e'[^ ]+ [^ ]+', 'g') AS "m2" 3.714 - ) 3.715 - FROM regexp_matches($1::text, e'(^| )polygon \\(([^)]+)\\)', 'g') AS "m1" 3.716 - $$; 3.717 - 3.718 - 3.719 ---------------- 3.720 --- operators -- 3.721 ---------------- 3.722 - 3.723 -CREATE FUNCTION epoint_ebox_overlap_proc(epoint, ebox) 3.724 - RETURNS boolean 3.725 - LANGUAGE C IMMUTABLE STRICT 3.726 - AS '$libdir/latlon-v0004', 'pgl_epoint_ebox_overlap'; 3.727 - 3.728 -CREATE FUNCTION epoint_ecircle_overlap_proc(epoint, ecircle) 3.729 - RETURNS boolean 3.730 - LANGUAGE C IMMUTABLE STRICT 3.731 - AS '$libdir/latlon-v0004', 'pgl_epoint_ecircle_overlap'; 3.732 - 3.733 -CREATE FUNCTION epoint_ecluster_overlap_proc(epoint, ecluster) 3.734 - RETURNS boolean 3.735 - LANGUAGE C IMMUTABLE STRICT 3.736 - AS '$libdir/latlon-v0004', 'pgl_epoint_ecluster_overlap'; 3.737 - 3.738 -CREATE FUNCTION epoint_ecluster_may_overlap_proc(epoint, ecluster) 3.739 - RETURNS boolean 3.740 - LANGUAGE C IMMUTABLE STRICT 3.741 - AS '$libdir/latlon-v0004', 'pgl_epoint_ecluster_may_overlap'; 3.742 - 3.743 -CREATE FUNCTION ebox_overlap_proc(ebox, ebox) 3.744 - RETURNS boolean 3.745 - LANGUAGE C IMMUTABLE STRICT 3.746 - AS '$libdir/latlon-v0004', 'pgl_ebox_overlap'; 3.747 - 3.748 -CREATE FUNCTION ebox_ecircle_may_overlap_proc(ebox, ecircle) 3.749 - RETURNS boolean 3.750 - LANGUAGE C IMMUTABLE STRICT 3.751 - AS '$libdir/latlon-v0004', 'pgl_ebox_ecircle_may_overlap'; 3.752 - 3.753 -CREATE FUNCTION ebox_ecluster_may_overlap_proc(ebox, ecluster) 3.754 - RETURNS boolean 3.755 - LANGUAGE C IMMUTABLE STRICT 3.756 - AS '$libdir/latlon-v0004', 'pgl_ebox_ecluster_may_overlap'; 3.757 - 3.758 -CREATE FUNCTION ecircle_overlap_proc(ecircle, ecircle) 3.759 - RETURNS boolean 3.760 - LANGUAGE C IMMUTABLE STRICT 3.761 - AS '$libdir/latlon-v0004', 'pgl_ecircle_overlap'; 3.762 - 3.763 -CREATE FUNCTION ecircle_ecluster_overlap_proc(ecircle, ecluster) 3.764 - RETURNS boolean 3.765 - LANGUAGE C IMMUTABLE STRICT 3.766 - AS '$libdir/latlon-v0004', 'pgl_ecircle_ecluster_overlap'; 3.767 - 3.768 -CREATE FUNCTION ecircle_ecluster_may_overlap_proc(ecircle, ecluster) 3.769 - RETURNS boolean 3.770 - LANGUAGE C IMMUTABLE STRICT 3.771 - AS '$libdir/latlon-v0004', 'pgl_ecircle_ecluster_may_overlap'; 3.772 - 3.773 -CREATE FUNCTION ecluster_overlap_proc(ecluster, ecluster) 3.774 - RETURNS boolean 3.775 - LANGUAGE C IMMUTABLE STRICT 3.776 - AS '$libdir/latlon-v0004', 'pgl_ecluster_overlap'; 3.777 - 3.778 -CREATE FUNCTION ecluster_may_overlap_proc(ecluster, ecluster) 3.779 - RETURNS boolean 3.780 - LANGUAGE C IMMUTABLE STRICT 3.781 - AS '$libdir/latlon-v0004', 'pgl_ecluster_may_overlap'; 3.782 - 3.783 -CREATE FUNCTION ecluster_contains_proc(ecluster, ecluster) 3.784 - RETURNS boolean 3.785 - LANGUAGE C IMMUTABLE STRICT 3.786 - AS '$libdir/latlon-v0004', 'pgl_ecluster_contains'; 3.787 - 3.788 -CREATE FUNCTION epoint_distance_proc(epoint, epoint) 3.789 - RETURNS float8 3.790 - LANGUAGE C IMMUTABLE STRICT 3.791 - AS '$libdir/latlon-v0004', 'pgl_epoint_distance'; 3.792 - 3.793 -CREATE FUNCTION epoint_ecircle_distance_proc(epoint, ecircle) 3.794 - RETURNS float8 3.795 - LANGUAGE C IMMUTABLE STRICT 3.796 - AS '$libdir/latlon-v0004', 'pgl_epoint_ecircle_distance'; 3.797 - 3.798 -CREATE FUNCTION epoint_ecluster_distance_proc(epoint, ecluster) 3.799 - RETURNS float8 3.800 - LANGUAGE C IMMUTABLE STRICT 3.801 - AS '$libdir/latlon-v0004', 'pgl_epoint_ecluster_distance'; 3.802 - 3.803 -CREATE FUNCTION ecircle_distance_proc(ecircle, ecircle) 3.804 - RETURNS float8 3.805 - LANGUAGE C IMMUTABLE STRICT 3.806 - AS '$libdir/latlon-v0004', 'pgl_ecircle_distance'; 3.807 - 3.808 -CREATE FUNCTION ecircle_ecluster_distance_proc(ecircle, ecluster) 3.809 - RETURNS float8 3.810 - LANGUAGE C IMMUTABLE STRICT 3.811 - AS '$libdir/latlon-v0004', 'pgl_ecircle_ecluster_distance'; 3.812 - 3.813 -CREATE FUNCTION ecluster_distance_proc(ecluster, ecluster) 3.814 - RETURNS float8 3.815 - LANGUAGE C IMMUTABLE STRICT 3.816 - AS '$libdir/latlon-v0004', 'pgl_ecluster_distance'; 3.817 - 3.818 -CREATE OPERATOR && ( 3.819 - leftarg = epoint, 3.820 - rightarg = ebox, 3.821 - procedure = epoint_ebox_overlap_proc, 3.822 - commutator = &&, 3.823 - restrict = areasel, 3.824 - join = areajoinsel 3.825 -); 3.826 - 3.827 -CREATE FUNCTION epoint_ebox_overlap_commutator(ebox, epoint) 3.828 - RETURNS boolean 3.829 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 && $1'; 3.830 - 3.831 -CREATE OPERATOR && ( 3.832 - leftarg = ebox, 3.833 - rightarg = epoint, 3.834 - procedure = epoint_ebox_overlap_commutator, 3.835 - commutator = &&, 3.836 - restrict = areasel, 3.837 - join = areajoinsel 3.838 -); 3.839 - 3.840 -CREATE OPERATOR && ( 3.841 - leftarg = epoint, 3.842 - rightarg = ecircle, 3.843 - procedure = epoint_ecircle_overlap_proc, 3.844 - commutator = &&, 3.845 - restrict = areasel, 3.846 - join = areajoinsel 3.847 -); 3.848 - 3.849 -CREATE FUNCTION epoint_ecircle_overlap_commutator(ecircle, epoint) 3.850 - RETURNS boolean 3.851 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 && $1'; 3.852 - 3.853 -CREATE OPERATOR && ( 3.854 - leftarg = ecircle, 3.855 - rightarg = epoint, 3.856 - procedure = epoint_ecircle_overlap_commutator, 3.857 - commutator = &&, 3.858 - restrict = areasel, 3.859 - join = areajoinsel 3.860 -); 3.861 - 3.862 -CREATE OPERATOR && ( 3.863 - leftarg = epoint, 3.864 - rightarg = ecluster, 3.865 - procedure = epoint_ecluster_overlap_proc, 3.866 - commutator = &&, 3.867 - restrict = areasel, 3.868 - join = areajoinsel 3.869 -); 3.870 - 3.871 -CREATE FUNCTION epoint_ecluster_overlap_commutator(ecluster, epoint) 3.872 - RETURNS boolean 3.873 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 && $1'; 3.874 - 3.875 -CREATE OPERATOR && ( 3.876 - leftarg = ecluster, 3.877 - rightarg = epoint, 3.878 - procedure = epoint_ecluster_overlap_commutator, 3.879 - commutator = &&, 3.880 - restrict = areasel, 3.881 - join = areajoinsel 3.882 -); 3.883 - 3.884 -CREATE OPERATOR && ( 3.885 - leftarg = ebox, 3.886 - rightarg = ebox, 3.887 - procedure = ebox_overlap_proc, 3.888 - commutator = &&, 3.889 - restrict = areasel, 3.890 - join = areajoinsel 3.891 -); 3.892 - 3.893 -CREATE OPERATOR && ( 3.894 - leftarg = ecircle, 3.895 - rightarg = ecircle, 3.896 - procedure = ecircle_overlap_proc, 3.897 - commutator = &&, 3.898 - restrict = areasel, 3.899 - join = areajoinsel 3.900 -); 3.901 - 3.902 -CREATE OPERATOR && ( 3.903 - leftarg = ecircle, 3.904 - rightarg = ecluster, 3.905 - procedure = ecircle_ecluster_overlap_proc, 3.906 - commutator = &&, 3.907 - restrict = areasel, 3.908 - join = areajoinsel 3.909 -); 3.910 - 3.911 -CREATE FUNCTION ecircle_ecluster_overlap_commutator(ecluster, ecircle) 3.912 - RETURNS boolean 3.913 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 && $1'; 3.914 - 3.915 -CREATE OPERATOR && ( 3.916 - leftarg = ecluster, 3.917 - rightarg = ecircle, 3.918 - procedure = ecircle_ecluster_overlap_commutator, 3.919 - commutator = &&, 3.920 - restrict = areasel, 3.921 - join = areajoinsel 3.922 -); 3.923 - 3.924 -CREATE OPERATOR && ( 3.925 - leftarg = ecluster, 3.926 - rightarg = ecluster, 3.927 - procedure = ecluster_overlap_proc, 3.928 - commutator = &&, 3.929 - restrict = areasel, 3.930 - join = areajoinsel 3.931 -); 3.932 - 3.933 -CREATE FUNCTION ebox_ecircle_overlap_castwrap(ebox, ecircle) 3.934 - RETURNS boolean 3.935 - LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster && $2'; 3.936 - 3.937 -CREATE OPERATOR && ( 3.938 - leftarg = ebox, 3.939 - rightarg = ecircle, 3.940 - procedure = ebox_ecircle_overlap_castwrap, 3.941 - commutator = &&, 3.942 - restrict = areasel, 3.943 - join = areajoinsel 3.944 -); 3.945 - 3.946 -CREATE FUNCTION ebox_ecircle_overlap_castwrap(ecircle, ebox) 3.947 - RETURNS boolean 3.948 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 && $2::ecluster'; 3.949 - 3.950 -CREATE OPERATOR && ( 3.951 - leftarg = ecircle, 3.952 - rightarg = ebox, 3.953 - procedure = ebox_ecircle_overlap_castwrap, 3.954 - commutator = &&, 3.955 - restrict = areasel, 3.956 - join = areajoinsel 3.957 -); 3.958 - 3.959 -CREATE FUNCTION ebox_ecluster_overlap_castwrap(ebox, ecluster) 3.960 - RETURNS boolean 3.961 - LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster && $2'; 3.962 - 3.963 -CREATE OPERATOR && ( 3.964 - leftarg = ebox, 3.965 - rightarg = ecluster, 3.966 - procedure = ebox_ecluster_overlap_castwrap, 3.967 - commutator = &&, 3.968 - restrict = areasel, 3.969 - join = areajoinsel 3.970 -); 3.971 - 3.972 -CREATE FUNCTION ebox_ecluster_overlap_castwrap(ecluster, ebox) 3.973 - RETURNS boolean 3.974 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 && $2::ecluster'; 3.975 - 3.976 -CREATE OPERATOR && ( 3.977 - leftarg = ecluster, 3.978 - rightarg = ebox, 3.979 - procedure = ebox_ecluster_overlap_castwrap, 3.980 - commutator = &&, 3.981 - restrict = areasel, 3.982 - join = areajoinsel 3.983 -); 3.984 - 3.985 -CREATE OPERATOR &&+ ( 3.986 - leftarg = epoint, 3.987 - rightarg = ecluster, 3.988 - procedure = epoint_ecluster_may_overlap_proc, 3.989 - commutator = &&+, 3.990 - restrict = areasel, 3.991 - join = areajoinsel 3.992 -); 3.993 - 3.994 -CREATE FUNCTION epoint_ecluster_may_overlap_commutator(ecluster, epoint) 3.995 - RETURNS boolean 3.996 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 &&+ $1'; 3.997 - 3.998 -CREATE OPERATOR &&+ ( 3.999 - leftarg = ecluster, 3.1000 - rightarg = epoint, 3.1001 - procedure = epoint_ecluster_may_overlap_commutator, 3.1002 - commutator = &&+, 3.1003 - restrict = areasel, 3.1004 - join = areajoinsel 3.1005 -); 3.1006 - 3.1007 -CREATE OPERATOR &&+ ( 3.1008 - leftarg = ebox, 3.1009 - rightarg = ecircle, 3.1010 - procedure = ebox_ecircle_may_overlap_proc, 3.1011 - commutator = &&+, 3.1012 - restrict = areasel, 3.1013 - join = areajoinsel 3.1014 -); 3.1015 - 3.1016 -CREATE FUNCTION ebox_ecircle_may_overlap_commutator(ecircle, ebox) 3.1017 - RETURNS boolean 3.1018 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 &&+ $1'; 3.1019 - 3.1020 -CREATE OPERATOR &&+ ( 3.1021 - leftarg = ecircle, 3.1022 - rightarg = ebox, 3.1023 - procedure = ebox_ecircle_may_overlap_commutator, 3.1024 - commutator = &&+, 3.1025 - restrict = areasel, 3.1026 - join = areajoinsel 3.1027 -); 3.1028 - 3.1029 -CREATE OPERATOR &&+ ( 3.1030 - leftarg = ebox, 3.1031 - rightarg = ecluster, 3.1032 - procedure = ebox_ecluster_may_overlap_proc, 3.1033 - commutator = &&+, 3.1034 - restrict = areasel, 3.1035 - join = areajoinsel 3.1036 -); 3.1037 - 3.1038 -CREATE FUNCTION ebox_ecluster_may_overlap_commutator(ecluster, ebox) 3.1039 - RETURNS boolean 3.1040 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 &&+ $1'; 3.1041 - 3.1042 -CREATE OPERATOR &&+ ( 3.1043 - leftarg = ecluster, 3.1044 - rightarg = ebox, 3.1045 - procedure = ebox_ecluster_may_overlap_commutator, 3.1046 - commutator = &&+, 3.1047 - restrict = areasel, 3.1048 - join = areajoinsel 3.1049 -); 3.1050 - 3.1051 -CREATE OPERATOR &&+ ( 3.1052 - leftarg = ecircle, 3.1053 - rightarg = ecluster, 3.1054 - procedure = ecircle_ecluster_may_overlap_proc, 3.1055 - commutator = &&+, 3.1056 - restrict = areasel, 3.1057 - join = areajoinsel 3.1058 -); 3.1059 - 3.1060 -CREATE FUNCTION ecircle_ecluster_may_overlap_commutator(ecluster, ecircle) 3.1061 - RETURNS boolean 3.1062 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 &&+ $1'; 3.1063 - 3.1064 -CREATE OPERATOR &&+ ( 3.1065 - leftarg = ecluster, 3.1066 - rightarg = ecircle, 3.1067 - procedure = ecircle_ecluster_may_overlap_commutator, 3.1068 - commutator = &&+, 3.1069 - restrict = areasel, 3.1070 - join = areajoinsel 3.1071 -); 3.1072 - 3.1073 -CREATE OPERATOR &&+ ( 3.1074 - leftarg = ecluster, 3.1075 - rightarg = ecluster, 3.1076 - procedure = ecluster_may_overlap_proc, 3.1077 - commutator = &&+, 3.1078 - restrict = areasel, 3.1079 - join = areajoinsel 3.1080 -); 3.1081 - 3.1082 -CREATE OPERATOR @> ( 3.1083 - leftarg = ebox, 3.1084 - rightarg = epoint, 3.1085 - procedure = epoint_ebox_overlap_commutator, 3.1086 - commutator = <@, 3.1087 - restrict = areasel, 3.1088 - join = areajoinsel 3.1089 -); 3.1090 - 3.1091 -CREATE OPERATOR <@ ( 3.1092 - leftarg = epoint, 3.1093 - rightarg = ebox, 3.1094 - procedure = epoint_ebox_overlap_proc, 3.1095 - commutator = @>, 3.1096 - restrict = areasel, 3.1097 - join = areajoinsel 3.1098 -); 3.1099 - 3.1100 -CREATE OPERATOR @> ( 3.1101 - leftarg = ecluster, 3.1102 - rightarg = epoint, 3.1103 - procedure = epoint_ecluster_overlap_commutator, 3.1104 - commutator = <@, 3.1105 - restrict = areasel, 3.1106 - join = areajoinsel 3.1107 -); 3.1108 - 3.1109 -CREATE OPERATOR <@ ( 3.1110 - leftarg = epoint, 3.1111 - rightarg = ecluster, 3.1112 - procedure = epoint_ecluster_overlap_proc, 3.1113 - commutator = <@, 3.1114 - restrict = areasel, 3.1115 - join = areajoinsel 3.1116 -); 3.1117 - 3.1118 -CREATE OPERATOR @> ( 3.1119 - leftarg = ecluster, 3.1120 - rightarg = ecluster, 3.1121 - procedure = ecluster_contains_proc, 3.1122 - commutator = <@, 3.1123 - restrict = areasel, 3.1124 - join = areajoinsel 3.1125 -); 3.1126 - 3.1127 -CREATE FUNCTION ecluster_contains_commutator(ecluster, ecluster) 3.1128 - RETURNS boolean 3.1129 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 @> $1'; 3.1130 - 3.1131 -CREATE OPERATOR <@ ( 3.1132 - leftarg = ecluster, 3.1133 - rightarg = ecluster, 3.1134 - procedure = ecluster_contains_commutator, 3.1135 - commutator = @>, 3.1136 - restrict = areasel, 3.1137 - join = areajoinsel 3.1138 -); 3.1139 - 3.1140 -CREATE FUNCTION ebox_ecluster_contains_castwrap(ebox, ecluster) 3.1141 - RETURNS boolean 3.1142 - LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster @> $2'; 3.1143 - 3.1144 -CREATE OPERATOR @> ( 3.1145 - leftarg = ebox, 3.1146 - rightarg = ecluster, 3.1147 - procedure = ebox_ecluster_contains_castwrap, 3.1148 - commutator = <@, 3.1149 - restrict = areasel, 3.1150 - join = areajoinsel 3.1151 -); 3.1152 - 3.1153 -CREATE FUNCTION ebox_ecluster_contains_castwrap(ecluster, ebox) 3.1154 - RETURNS boolean 3.1155 - LANGUAGE sql IMMUTABLE AS 'SELECT $2::ecluster @> $1'; 3.1156 - 3.1157 -CREATE OPERATOR <@ ( 3.1158 - leftarg = ecluster, 3.1159 - rightarg = ebox, 3.1160 - procedure = ebox_ecluster_contains_castwrap, 3.1161 - commutator = @>, 3.1162 - restrict = areasel, 3.1163 - join = areajoinsel 3.1164 -); 3.1165 - 3.1166 -CREATE FUNCTION ecluster_ebox_contains_castwrap(ecluster, ebox) 3.1167 - RETURNS boolean 3.1168 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 @> $2::ecluster'; 3.1169 - 3.1170 -CREATE OPERATOR @> ( 3.1171 - leftarg = ecluster, 3.1172 - rightarg = ebox, 3.1173 - procedure = ecluster_ebox_contains_castwrap, 3.1174 - commutator = <@, 3.1175 - restrict = areasel, 3.1176 - join = areajoinsel 3.1177 -); 3.1178 - 3.1179 -CREATE FUNCTION ecluster_ebox_contains_castwrap(ebox, ecluster) 3.1180 - RETURNS boolean 3.1181 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 @> $1::ecluster'; 3.1182 - 3.1183 -CREATE OPERATOR <@ ( 3.1184 - leftarg = ebox, 3.1185 - rightarg = ecluster, 3.1186 - procedure = ecluster_ebox_contains_castwrap, 3.1187 - commutator = @>, 3.1188 - restrict = areasel, 3.1189 - join = areajoinsel 3.1190 -); 3.1191 - 3.1192 -CREATE OPERATOR <-> ( 3.1193 - leftarg = epoint, 3.1194 - rightarg = epoint, 3.1195 - procedure = epoint_distance_proc, 3.1196 - commutator = <-> 3.1197 -); 3.1198 - 3.1199 -CREATE OPERATOR <-> ( 3.1200 - leftarg = epoint, 3.1201 - rightarg = ecircle, 3.1202 - procedure = epoint_ecircle_distance_proc, 3.1203 - commutator = <-> 3.1204 -); 3.1205 - 3.1206 -CREATE FUNCTION epoint_ecircle_distance_commutator(ecircle, epoint) 3.1207 - RETURNS float8 3.1208 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 <-> $1'; 3.1209 - 3.1210 -CREATE OPERATOR <-> ( 3.1211 - leftarg = ecircle, 3.1212 - rightarg = epoint, 3.1213 - procedure = epoint_ecircle_distance_commutator, 3.1214 - commutator = <-> 3.1215 -); 3.1216 - 3.1217 -CREATE OPERATOR <-> ( 3.1218 - leftarg = epoint, 3.1219 - rightarg = ecluster, 3.1220 - procedure = epoint_ecluster_distance_proc, 3.1221 - commutator = <-> 3.1222 -); 3.1223 - 3.1224 -CREATE FUNCTION epoint_ecluster_distance_commutator(ecluster, epoint) 3.1225 - RETURNS float8 3.1226 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 <-> $1'; 3.1227 - 3.1228 -CREATE OPERATOR <-> ( 3.1229 - leftarg = ecluster, 3.1230 - rightarg = epoint, 3.1231 - procedure = epoint_ecluster_distance_commutator, 3.1232 - commutator = <-> 3.1233 -); 3.1234 - 3.1235 -CREATE OPERATOR <-> ( 3.1236 - leftarg = ecircle, 3.1237 - rightarg = ecircle, 3.1238 - procedure = ecircle_distance_proc, 3.1239 - commutator = <-> 3.1240 -); 3.1241 - 3.1242 -CREATE OPERATOR <-> ( 3.1243 - leftarg = ecircle, 3.1244 - rightarg = ecluster, 3.1245 - procedure = ecircle_ecluster_distance_proc, 3.1246 - commutator = <-> 3.1247 -); 3.1248 - 3.1249 -CREATE FUNCTION ecircle_ecluster_distance_commutator(ecluster, ecircle) 3.1250 - RETURNS float8 3.1251 - LANGUAGE sql IMMUTABLE AS 'SELECT $2 <-> $1'; 3.1252 - 3.1253 -CREATE OPERATOR <-> ( 3.1254 - leftarg = ecluster, 3.1255 - rightarg = ecircle, 3.1256 - procedure = ecircle_ecluster_distance_commutator, 3.1257 - commutator = <-> 3.1258 -); 3.1259 - 3.1260 -CREATE OPERATOR <-> ( 3.1261 - leftarg = ecluster, 3.1262 - rightarg = ecluster, 3.1263 - procedure = ecluster_distance_proc, 3.1264 - commutator = <-> 3.1265 -); 3.1266 - 3.1267 -CREATE FUNCTION epoint_ebox_distance_castwrap(epoint, ebox) 3.1268 - RETURNS float8 3.1269 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 <-> $2::ecluster'; 3.1270 - 3.1271 -CREATE OPERATOR <-> ( 3.1272 - leftarg = epoint, 3.1273 - rightarg = ebox, 3.1274 - procedure = epoint_ebox_distance_castwrap, 3.1275 - commutator = <-> 3.1276 -); 3.1277 - 3.1278 -CREATE FUNCTION epoint_ebox_distance_castwrap(ebox, epoint) 3.1279 - RETURNS float8 3.1280 - LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster <-> $2'; 3.1281 - 3.1282 -CREATE OPERATOR <-> ( 3.1283 - leftarg = ebox, 3.1284 - rightarg = epoint, 3.1285 - procedure = epoint_ebox_distance_castwrap, 3.1286 - commutator = <-> 3.1287 -); 3.1288 - 3.1289 -CREATE FUNCTION ebox_distance_castwrap(ebox, ebox) 3.1290 - RETURNS float8 3.1291 - LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster <-> $2::ecluster'; 3.1292 - 3.1293 -CREATE OPERATOR <-> ( 3.1294 - leftarg = ebox, 3.1295 - rightarg = ebox, 3.1296 - procedure = ebox_distance_castwrap, 3.1297 - commutator = <-> 3.1298 -); 3.1299 - 3.1300 -CREATE FUNCTION ebox_ecircle_distance_castwrap(ebox, ecircle) 3.1301 - RETURNS float8 3.1302 - LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster <-> $2'; 3.1303 - 3.1304 -CREATE OPERATOR <-> ( 3.1305 - leftarg = ebox, 3.1306 - rightarg = ecircle, 3.1307 - procedure = ebox_ecircle_distance_castwrap, 3.1308 - commutator = <-> 3.1309 -); 3.1310 - 3.1311 -CREATE FUNCTION ebox_ecircle_distance_castwrap(ecircle, ebox) 3.1312 - RETURNS float8 3.1313 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 <-> $2::ecluster'; 3.1314 - 3.1315 -CREATE OPERATOR <-> ( 3.1316 - leftarg = ecircle, 3.1317 - rightarg = ebox, 3.1318 - procedure = ebox_ecircle_distance_castwrap, 3.1319 - commutator = <-> 3.1320 -); 3.1321 - 3.1322 -CREATE FUNCTION ebox_ecluster_distance_castwrap(ebox, ecluster) 3.1323 - RETURNS float8 3.1324 - LANGUAGE sql IMMUTABLE AS 'SELECT $1::ecluster <-> $2'; 3.1325 - 3.1326 -CREATE OPERATOR <-> ( 3.1327 - leftarg = ebox, 3.1328 - rightarg = ecluster, 3.1329 - procedure = ebox_ecluster_distance_castwrap, 3.1330 - commutator = <-> 3.1331 -); 3.1332 - 3.1333 -CREATE FUNCTION ebox_ecluster_distance_castwrap(ecluster, ebox) 3.1334 - RETURNS float8 3.1335 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 <-> $2::ecluster'; 3.1336 - 3.1337 -CREATE OPERATOR <-> ( 3.1338 - leftarg = ecluster, 3.1339 - rightarg = ebox, 3.1340 - procedure = ebox_ecluster_distance_castwrap, 3.1341 - commutator = <-> 3.1342 -); 3.1343 - 3.1344 - 3.1345 ----------------- 3.1346 --- GiST index -- 3.1347 ----------------- 3.1348 - 3.1349 -CREATE FUNCTION pgl_gist_consistent(internal, internal, smallint, oid, internal) 3.1350 - RETURNS boolean 3.1351 - LANGUAGE C STRICT 3.1352 - AS '$libdir/latlon-v0004', 'pgl_gist_consistent'; 3.1353 - 3.1354 -CREATE FUNCTION pgl_gist_union(internal, internal) 3.1355 - RETURNS internal 3.1356 - LANGUAGE C STRICT 3.1357 - AS '$libdir/latlon-v0004', 'pgl_gist_union'; 3.1358 - 3.1359 -CREATE FUNCTION pgl_gist_compress_epoint(internal) 3.1360 - RETURNS internal 3.1361 - LANGUAGE C STRICT 3.1362 - AS '$libdir/latlon-v0004', 'pgl_gist_compress_epoint'; 3.1363 - 3.1364 -CREATE FUNCTION pgl_gist_compress_ecircle(internal) 3.1365 - RETURNS internal 3.1366 - LANGUAGE C STRICT 3.1367 - AS '$libdir/latlon-v0004', 'pgl_gist_compress_ecircle'; 3.1368 - 3.1369 -CREATE FUNCTION pgl_gist_compress_ecluster(internal) 3.1370 - RETURNS internal 3.1371 - LANGUAGE C STRICT 3.1372 - AS '$libdir/latlon-v0004', 'pgl_gist_compress_ecluster'; 3.1373 - 3.1374 -CREATE FUNCTION pgl_gist_decompress(internal) 3.1375 - RETURNS internal 3.1376 - LANGUAGE C STRICT 3.1377 - AS '$libdir/latlon-v0004', 'pgl_gist_decompress'; 3.1378 - 3.1379 -CREATE FUNCTION pgl_gist_penalty(internal, internal, internal) 3.1380 - RETURNS internal 3.1381 - LANGUAGE C STRICT 3.1382 - AS '$libdir/latlon-v0004', 'pgl_gist_penalty'; 3.1383 - 3.1384 -CREATE FUNCTION pgl_gist_picksplit(internal, internal) 3.1385 - RETURNS internal 3.1386 - LANGUAGE C STRICT 3.1387 - AS '$libdir/latlon-v0004', 'pgl_gist_picksplit'; 3.1388 - 3.1389 -CREATE FUNCTION pgl_gist_same(internal, internal, internal) 3.1390 - RETURNS internal 3.1391 - LANGUAGE C STRICT 3.1392 - AS '$libdir/latlon-v0004', 'pgl_gist_same'; 3.1393 - 3.1394 -CREATE FUNCTION pgl_gist_distance(internal, internal, smallint, oid) 3.1395 - RETURNS internal 3.1396 - LANGUAGE C STRICT 3.1397 - AS '$libdir/latlon-v0004', 'pgl_gist_distance'; 3.1398 - 3.1399 -CREATE OPERATOR CLASS epoint_ops 3.1400 - DEFAULT FOR TYPE epoint USING gist AS 3.1401 - OPERATOR 11 = , 3.1402 - OPERATOR 22 && (epoint, ebox), 3.1403 - OPERATOR 222 <@ (epoint, ebox), 3.1404 - OPERATOR 23 && (epoint, ecircle), 3.1405 - OPERATOR 24 && (epoint, ecluster), 3.1406 - OPERATOR 124 &&+ (epoint, ecluster), 3.1407 - OPERATOR 224 <@ (epoint, ecluster), 3.1408 - OPERATOR 31 <-> (epoint, epoint) FOR ORDER BY float_ops, 3.1409 - OPERATOR 32 <-> (epoint, ebox) FOR ORDER BY float_ops, 3.1410 - OPERATOR 33 <-> (epoint, ecircle) FOR ORDER BY float_ops, 3.1411 - OPERATOR 34 <-> (epoint, ecluster) FOR ORDER BY float_ops, 3.1412 - FUNCTION 1 pgl_gist_consistent(internal, internal, smallint, oid, internal), 3.1413 - FUNCTION 2 pgl_gist_union(internal, internal), 3.1414 - FUNCTION 3 pgl_gist_compress_epoint(internal), 3.1415 - FUNCTION 4 pgl_gist_decompress(internal), 3.1416 - FUNCTION 5 pgl_gist_penalty(internal, internal, internal), 3.1417 - FUNCTION 6 pgl_gist_picksplit(internal, internal), 3.1418 - FUNCTION 7 pgl_gist_same(internal, internal, internal), 3.1419 - FUNCTION 8 pgl_gist_distance(internal, internal, smallint, oid), 3.1420 - STORAGE ekey_point; 3.1421 - 3.1422 -CREATE OPERATOR CLASS ecircle_ops 3.1423 - DEFAULT FOR TYPE ecircle USING gist AS 3.1424 - OPERATOR 13 = , 3.1425 - OPERATOR 21 && (ecircle, epoint), 3.1426 - OPERATOR 22 && (ecircle, ebox), 3.1427 - OPERATOR 122 &&+ (ecircle, ebox), 3.1428 - OPERATOR 23 && (ecircle, ecircle), 3.1429 - OPERATOR 24 && (ecircle, ecluster), 3.1430 - OPERATOR 124 &&+ (ecircle, ecluster), 3.1431 - OPERATOR 31 <-> (ecircle, epoint) FOR ORDER BY float_ops, 3.1432 - OPERATOR 32 <-> (ecircle, ebox) FOR ORDER BY float_ops, 3.1433 - OPERATOR 33 <-> (ecircle, ecircle) FOR ORDER BY float_ops, 3.1434 - OPERATOR 34 <-> (ecircle, ecluster) FOR ORDER BY float_ops, 3.1435 - FUNCTION 1 pgl_gist_consistent(internal, internal, smallint, oid, internal), 3.1436 - FUNCTION 2 pgl_gist_union(internal, internal), 3.1437 - FUNCTION 3 pgl_gist_compress_ecircle(internal), 3.1438 - FUNCTION 4 pgl_gist_decompress(internal), 3.1439 - FUNCTION 5 pgl_gist_penalty(internal, internal, internal), 3.1440 - FUNCTION 6 pgl_gist_picksplit(internal, internal), 3.1441 - FUNCTION 7 pgl_gist_same(internal, internal, internal), 3.1442 - FUNCTION 8 pgl_gist_distance(internal, internal, smallint, oid), 3.1443 - STORAGE ekey_area; 3.1444 - 3.1445 -CREATE OPERATOR CLASS ecluster_ops 3.1446 - DEFAULT FOR TYPE ecluster USING gist AS 3.1447 - OPERATOR 21 && (ecluster, epoint), 3.1448 - OPERATOR 121 &&+ (ecluster, epoint), 3.1449 - OPERATOR 221 @> (ecluster, epoint), 3.1450 - OPERATOR 22 && (ecluster, ebox), 3.1451 - OPERATOR 122 &&+ (ecluster, ebox), 3.1452 - OPERATOR 222 @> (ecluster, ebox), 3.1453 - OPERATOR 322 <@ (ecluster, ebox), 3.1454 - OPERATOR 23 && (ecluster, ecircle), 3.1455 - OPERATOR 123 &&+ (ecluster, ecircle), 3.1456 - OPERATOR 24 && (ecluster, ecluster), 3.1457 - OPERATOR 124 &&+ (ecluster, ecluster), 3.1458 - OPERATOR 224 @> (ecluster, ecluster), 3.1459 - OPERATOR 324 <@ (ecluster, ecluster), 3.1460 - OPERATOR 31 <-> (ecluster, epoint) FOR ORDER BY float_ops, 3.1461 - OPERATOR 32 <-> (ecluster, ebox) FOR ORDER BY float_ops, 3.1462 - OPERATOR 33 <-> (ecluster, ecircle) FOR ORDER BY float_ops, 3.1463 - OPERATOR 34 <-> (ecluster, ecluster) FOR ORDER BY float_ops, 3.1464 - FUNCTION 1 pgl_gist_consistent(internal, internal, smallint, oid, internal), 3.1465 - FUNCTION 2 pgl_gist_union(internal, internal), 3.1466 - FUNCTION 3 pgl_gist_compress_ecluster(internal), 3.1467 - FUNCTION 4 pgl_gist_decompress(internal), 3.1468 - FUNCTION 5 pgl_gist_penalty(internal, internal, internal), 3.1469 - FUNCTION 6 pgl_gist_picksplit(internal, internal), 3.1470 - FUNCTION 7 pgl_gist_same(internal, internal, internal), 3.1471 - FUNCTION 8 pgl_gist_distance(internal, internal, smallint, oid), 3.1472 - STORAGE ekey_area; 3.1473 - 3.1474 - 3.1475 ---------------------- 3.1476 --- alias functions -- 3.1477 ---------------------- 3.1478 - 3.1479 -CREATE FUNCTION distance(epoint, epoint) 3.1480 - RETURNS float8 3.1481 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 <-> $2'; 3.1482 - 3.1483 -CREATE FUNCTION distance(ecluster, epoint) 3.1484 - RETURNS float8 3.1485 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 <-> $2'; 3.1486 - 3.1487 -CREATE FUNCTION distance_within(epoint, epoint, float8) 3.1488 - RETURNS boolean 3.1489 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 && ecircle($2, $3)'; 3.1490 - 3.1491 -CREATE FUNCTION distance_within(ecluster, epoint, float8) 3.1492 - RETURNS boolean 3.1493 - LANGUAGE sql IMMUTABLE AS 'SELECT $1 && ecircle($2, $3)'; 3.1494 - 3.1495 - 3.1496 --------------------------------- 3.1497 --- other data storage formats -- 3.1498 --------------------------------- 3.1499 - 3.1500 -CREATE FUNCTION coords_to_epoint(float8, float8, text = 'epoint_lonlat') 3.1501 - RETURNS epoint 3.1502 - LANGUAGE plpgsql IMMUTABLE STRICT AS $$ 3.1503 - DECLARE 3.1504 - "result" epoint; 3.1505 - BEGIN 3.1506 - IF $3 = 'epoint_lonlat' THEN 3.1507 - -- avoid dynamic command execution for better performance 3.1508 - RETURN epoint($2, $1); 3.1509 - END IF; 3.1510 - IF $3 = 'epoint' OR $3 = 'epoint_latlon' THEN 3.1511 - -- avoid dynamic command execution for better performance 3.1512 - RETURN epoint($1, $2); 3.1513 - END IF; 3.1514 - EXECUTE 'SELECT ' || $3 || '($1, $2)' INTO STRICT "result" USING $1, $2; 3.1515 - RETURN "result"; 3.1516 - END; 3.1517 - $$; 3.1518 - 3.1519 -CREATE FUNCTION GeoJSON_to_epoint(jsonb, text = 'epoint_lonlat') 3.1520 - RETURNS epoint 3.1521 - LANGUAGE sql IMMUTABLE STRICT AS $$ 3.1522 - SELECT CASE 3.1523 - WHEN $1->>'type' = 'Point' THEN 3.1524 - coords_to_epoint( 3.1525 - ($1->'coordinates'->>1)::float8, 3.1526 - ($1->'coordinates'->>0)::float8, 3.1527 - $2 3.1528 - ) 3.1529 - WHEN $1->>'type' = 'Feature' THEN 3.1530 - GeoJSON_to_epoint($1->'geometry', $2) 3.1531 - ELSE 3.1532 - NULL 3.1533 - END 3.1534 - $$; 3.1535 - 3.1536 -CREATE FUNCTION GeoJSON_to_ecluster(jsonb, text = 'epoint_lonlat') 3.1537 - RETURNS ecluster 3.1538 - LANGUAGE sql IMMUTABLE STRICT AS $$ 3.1539 - SELECT CASE $1->>'type' 3.1540 - WHEN 'Point' THEN 3.1541 - coords_to_epoint( 3.1542 - ($1->'coordinates'->>1)::float8, 3.1543 - ($1->'coordinates'->>0)::float8, 3.1544 - $2 3.1545 - )::ecluster 3.1546 - WHEN 'MultiPoint' THEN 3.1547 - ( SELECT ecluster_create_multipoint(array_agg( 3.1548 - coords_to_epoint( 3.1549 - ("coord"->>1)::float8, 3.1550 - ("coord"->>0)::float8, 3.1551 - $2 3.1552 - ) 3.1553 - )) 3.1554 - FROM jsonb_array_elements($1->'coordinates') AS "coord" 3.1555 - ) 3.1556 - WHEN 'LineString' THEN 3.1557 - ( SELECT ecluster_create_path(array_agg( 3.1558 - coords_to_epoint( 3.1559 - ("coord"->>1)::float8, 3.1560 - ("coord"->>0)::float8, 3.1561 - $2 3.1562 - ) 3.1563 - )) 3.1564 - FROM jsonb_array_elements($1->'coordinates') AS "coord" 3.1565 - ) 3.1566 - WHEN 'MultiLineString' THEN 3.1567 - ( SELECT ecluster_concat(array_agg( 3.1568 - ( SELECT ecluster_create_path(array_agg( 3.1569 - coords_to_epoint( 3.1570 - ("coord"->>1)::float8, 3.1571 - ("coord"->>0)::float8, 3.1572 - $2 3.1573 - ) 3.1574 - )) 3.1575 - FROM jsonb_array_elements("coord_array") AS "coord" 3.1576 - ) 3.1577 - )) 3.1578 - FROM jsonb_array_elements($1->'coordinates') AS "coord_array" 3.1579 - ) 3.1580 - WHEN 'Polygon' THEN 3.1581 - ( SELECT ecluster_concat(array_agg( 3.1582 - ( SELECT ecluster_create_polygon(array_agg( 3.1583 - coords_to_epoint( 3.1584 - ("coord"->>1)::float8, 3.1585 - ("coord"->>0)::float8, 3.1586 - $2 3.1587 - ) 3.1588 - )) 3.1589 - FROM jsonb_array_elements("coord_array") AS "coord" 3.1590 - ) 3.1591 - )) 3.1592 - FROM jsonb_array_elements($1->'coordinates') AS "coord_array" 3.1593 - ) 3.1594 - WHEN 'MultiPolygon' THEN 3.1595 - ( SELECT ecluster_concat(array_agg( 3.1596 - ( SELECT ecluster_concat(array_agg( 3.1597 - ( SELECT ecluster_create_polygon(array_agg( 3.1598 - coords_to_epoint( 3.1599 - ("coord"->>1)::float8, 3.1600 - ("coord"->>0)::float8, 3.1601 - $2 3.1602 - ) 3.1603 - )) 3.1604 - FROM jsonb_array_elements("coord_array") AS "coord" 3.1605 - ) 3.1606 - )) 3.1607 - FROM jsonb_array_elements("coord_array_array") AS "coord_array" 3.1608 - ) 3.1609 - )) 3.1610 - FROM jsonb_array_elements($1->'coordinates') AS "coord_array_array" 3.1611 - ) 3.1612 - WHEN 'Feature' THEN 3.1613 - GeoJSON_to_ecluster($1->'geometry', $2) 3.1614 - WHEN 'FeatureCollection' THEN 3.1615 - ( SELECT ecluster_concat(array_agg( 3.1616 - GeoJSON_to_ecluster("feature", $2) 3.1617 - )) 3.1618 - FROM jsonb_array_elements($1->'features') AS "feature" 3.1619 - ) 3.1620 - ELSE 3.1621 - NULL 3.1622 - END 3.1623 - $$; 3.1624 -
4.1 --- a/latlon-v0004.c Mon Sep 12 18:00:52 2016 +0200 4.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 4.3 @@ -1,3062 +0,0 @@ 4.4 - 4.5 -/*-------------* 4.6 - * C prelude * 4.7 - *-------------*/ 4.8 - 4.9 -#include "postgres.h" 4.10 -#include "fmgr.h" 4.11 -#include "libpq/pqformat.h" 4.12 -#include "access/gist.h" 4.13 -#include "access/stratnum.h" 4.14 -#include "utils/array.h" 4.15 -#include <math.h> 4.16 - 4.17 -#ifdef PG_MODULE_MAGIC 4.18 -PG_MODULE_MAGIC; 4.19 -#endif 4.20 - 4.21 -#if INT_MAX < 2147483647 4.22 -#error Expected int type to be at least 32 bit wide 4.23 -#endif 4.24 - 4.25 - 4.26 -/*---------------------------------* 4.27 - * distance calculation on earth * 4.28 - * (using WGS-84 spheroid) * 4.29 - *---------------------------------*/ 4.30 - 4.31 -/* WGS-84 spheroid with following parameters: 4.32 - semi-major axis a = 6378137 4.33 - semi-minor axis b = a * (1 - 1/298.257223563) 4.34 - estimated diameter = 2 * (2*a+b)/3 4.35 -*/ 4.36 -#define PGL_SPHEROID_A 6378137.0 /* semi major axis */ 4.37 -#define PGL_SPHEROID_F (1.0/298.257223563) /* flattening */ 4.38 -#define PGL_SPHEROID_B (PGL_SPHEROID_A * (1.0-PGL_SPHEROID_F)) 4.39 -#define PGL_EPS2 ( ( PGL_SPHEROID_A * PGL_SPHEROID_A - \ 4.40 - PGL_SPHEROID_B * PGL_SPHEROID_B ) / \ 4.41 - ( PGL_SPHEROID_A * PGL_SPHEROID_A ) ) 4.42 -#define PGL_SUBEPS2 (1.0-PGL_EPS2) 4.43 -#define PGL_DIAMETER ((4.0*PGL_SPHEROID_A + 2.0*PGL_SPHEROID_B) / 3.0) 4.44 -#define PGL_SCALE (PGL_SPHEROID_A / PGL_DIAMETER) /* semi-major ref. */ 4.45 -#define PGL_FADELIMIT (PGL_DIAMETER * M_PI / 6.0) /* 1/6 circumference */ 4.46 -#define PGL_MAXDIST (PGL_DIAMETER * M_PI / 2.0) /* maximum distance */ 4.47 - 4.48 -/* calculate distance between two points on earth (given in degrees) */ 4.49 -static inline double pgl_distance( 4.50 - double lat1, double lon1, double lat2, double lon2 4.51 -) { 4.52 - float8 lat1cos, lat1sin, lat2cos, lat2sin, lon2cos, lon2sin; 4.53 - float8 nphi1, nphi2, x1, z1, x2, y2, z2, g, s, t; 4.54 - /* normalize delta longitude (lon2 > 0 && lon1 = 0) */ 4.55 - /* lon1 = 0 (not used anymore) */ 4.56 - lon2 = fabs(lon2-lon1); 4.57 - /* convert to radians (first divide, then multiply) */ 4.58 - lat1 = (lat1 / 180.0) * M_PI; 4.59 - lat2 = (lat2 / 180.0) * M_PI; 4.60 - lon2 = (lon2 / 180.0) * M_PI; 4.61 - /* make lat2 >= lat1 to ensure reversal-symmetry despite floating point 4.62 - operations (lon2 >= lon1 is already ensured in a previous step) */ 4.63 - if (lat2 < lat1) { float8 swap = lat1; lat1 = lat2; lat2 = swap; } 4.64 - /* calculate 3d coordinates on scaled ellipsoid which has an average diameter 4.65 - of 1.0 */ 4.66 - lat1cos = cos(lat1); lat1sin = sin(lat1); 4.67 - lat2cos = cos(lat2); lat2sin = sin(lat2); 4.68 - lon2cos = cos(lon2); lon2sin = sin(lon2); 4.69 - nphi1 = PGL_SCALE / sqrt(1 - PGL_EPS2 * lat1sin * lat1sin); 4.70 - nphi2 = PGL_SCALE / sqrt(1 - PGL_EPS2 * lat2sin * lat2sin); 4.71 - x1 = nphi1 * lat1cos; 4.72 - z1 = nphi1 * PGL_SUBEPS2 * lat1sin; 4.73 - x2 = nphi2 * lat2cos * lon2cos; 4.74 - y2 = nphi2 * lat2cos * lon2sin; 4.75 - z2 = nphi2 * PGL_SUBEPS2 * lat2sin; 4.76 - /* calculate tunnel distance through scaled (diameter 1.0) ellipsoid */ 4.77 - g = sqrt((x2-x1)*(x2-x1) + y2*y2 + (z2-z1)*(z2-z1)); 4.78 - /* convert tunnel distance through scaled ellipsoid to approximated surface 4.79 - distance on original ellipsoid */ 4.80 - if (g > 1.0) g = 1.0; 4.81 - s = PGL_DIAMETER * asin(g); 4.82 - /* return result only if small enough to be precise (less than 1/3 of 4.83 - maximum possible distance) */ 4.84 - if (s <= PGL_FADELIMIT) return s; 4.85 - /* calculate tunnel distance to antipodal point through scaled ellipsoid */ 4.86 - g = sqrt((x2+x1)*(x2+x1) + y2*y2 + (z2+z1)*(z2+z1)); 4.87 - /* convert tunnel distance to antipodal point through scaled ellipsoid to 4.88 - approximated surface distance to antipodal point on original ellipsoid */ 4.89 - if (g > 1.0) g = 1.0; 4.90 - t = PGL_DIAMETER * asin(g); 4.91 - /* surface distance between original points can now be approximated by 4.92 - substracting antipodal distance from maximum possible distance; 4.93 - return result only if small enough (less than 1/3 of maximum possible 4.94 - distance) */ 4.95 - if (t <= PGL_FADELIMIT) return PGL_MAXDIST-t; 4.96 - /* otherwise crossfade direct and antipodal result to ensure monotonicity */ 4.97 - return ( 4.98 - (s * (t-PGL_FADELIMIT) + (PGL_MAXDIST-t) * (s-PGL_FADELIMIT)) / 4.99 - (s + t - 2*PGL_FADELIMIT) 4.100 - ); 4.101 -} 4.102 - 4.103 -/* finite distance that can not be reached on earth */ 4.104 -#define PGL_ULTRA_DISTANCE (3 * PGL_MAXDIST) 4.105 - 4.106 - 4.107 -/*--------------------------------* 4.108 - * simple geographic data types * 4.109 - *--------------------------------*/ 4.110 - 4.111 -/* point on earth given by latitude and longitude in degrees */ 4.112 -/* (type "epoint" in SQL) */ 4.113 -typedef struct { 4.114 - double lat; /* between -90 and 90 (both inclusive) */ 4.115 - double lon; /* between -180 and 180 (both inclusive) */ 4.116 -} pgl_point; 4.117 - 4.118 -/* box delimited by two parallels and two meridians (all in degrees) */ 4.119 -/* (type "ebox" in SQL) */ 4.120 -typedef struct { 4.121 - double lat_min; /* between -90 and 90 (both inclusive) */ 4.122 - double lat_max; /* between -90 and 90 (both inclusive) */ 4.123 - double lon_min; /* between -180 and 180 (both inclusive) */ 4.124 - double lon_max; /* between -180 and 180 (both inclusive) */ 4.125 - /* if lat_min > lat_max, then box is empty */ 4.126 - /* if lon_min > lon_max, then 180th meridian is crossed */ 4.127 -} pgl_box; 4.128 - 4.129 -/* circle on earth surface (for radial searches with fixed radius) */ 4.130 -/* (type "ecircle" in SQL) */ 4.131 -typedef struct { 4.132 - pgl_point center; 4.133 - double radius; /* positive (including +0 but excluding -0), or -INFINITY */ 4.134 - /* A negative radius (i.e. -INFINITY) denotes nothing (i.e. no point), 4.135 - zero radius (0) denotes a single point, 4.136 - a finite radius (0 < radius < INFINITY) denotes a filled circle, and 4.137 - a radius of INFINITY is valid and means complete coverage of earth. */ 4.138 -} pgl_circle; 4.139 - 4.140 - 4.141 -/*----------------------------------* 4.142 - * geographic "cluster" data type * 4.143 - *----------------------------------*/ 4.144 - 4.145 -/* A cluster is a collection of points, paths, outlines, and polygons. If two 4.146 - polygons in a cluster overlap, the area covered by both polygons does not 4.147 - belong to the cluster. This way, a cluster can be used to describe complex 4.148 - shapes like polygons with holes. Outlines are non-filled polygons. Paths are 4.149 - open by default (i.e. the last point in the list is not connected with the 4.150 - first point in the list). Note that each outline or polygon in a cluster 4.151 - must cover a longitude range of less than 180 degrees to avoid ambiguities. 4.152 - Areas which are larger may be split into multiple polygons. */ 4.153 - 4.154 -/* maximum number of points in a cluster */ 4.155 -/* (limited to avoid integer overflows, e.g. when allocating memory) */ 4.156 -#define PGL_CLUSTER_MAXPOINTS 16777216 4.157 - 4.158 -/* types of cluster entries */ 4.159 -#define PGL_ENTRY_POINT 1 /* a point */ 4.160 -#define PGL_ENTRY_PATH 2 /* a path from first point to last point */ 4.161 -#define PGL_ENTRY_OUTLINE 3 /* a non-filled polygon with given vertices */ 4.162 -#define PGL_ENTRY_POLYGON 4 /* a filled polygon with given vertices */ 4.163 - 4.164 -/* Entries of a cluster are described by two different structs: pgl_newentry 4.165 - and pgl_entry. The first is used only during construction of a cluster, the 4.166 - second is used in all other cases (e.g. when reading clusters from the 4.167 - database, performing operations, etc). */ 4.168 - 4.169 -/* entry for new geographic cluster during construction of that cluster */ 4.170 -typedef struct { 4.171 - int32_t entrytype; 4.172 - int32_t npoints; 4.173 - pgl_point *points; /* pointer to an array of points (pgl_point) */ 4.174 -} pgl_newentry; 4.175 - 4.176 -/* entry of geographic cluster */ 4.177 -typedef struct { 4.178 - int32_t entrytype; /* type of entry: point, path, outline, polygon */ 4.179 - int32_t npoints; /* number of stored points (set to 1 for point entry) */ 4.180 - int32_t offset; /* offset of pgl_point array from cluster base address */ 4.181 - /* use macro PGL_ENTRY_POINTS to obtain a pointer to the array of points */ 4.182 -} pgl_entry; 4.183 - 4.184 -/* geographic cluster which is a collection of points, (open) paths, polygons, 4.185 - and outlines (non-filled polygons) */ 4.186 -typedef struct { 4.187 - char header[VARHDRSZ]; /* PostgreSQL header for variable size data types */ 4.188 - int32_t nentries; /* number of stored points */ 4.189 - pgl_circle bounding; /* bounding circle */ 4.190 - /* Note: bounding circle ensures alignment of pgl_cluster for points */ 4.191 - pgl_entry entries[FLEXIBLE_ARRAY_MEMBER]; /* var-length data */ 4.192 -} pgl_cluster; 4.193 - 4.194 -/* macro to determine memory alignment of points */ 4.195 -/* (needed to store pgl_point array after entries in pgl_cluster) */ 4.196 -typedef struct { char dummy; pgl_point aligned; } pgl_point_alignment; 4.197 -#define PGL_POINT_ALIGNMENT offsetof(pgl_point_alignment, aligned) 4.198 - 4.199 -/* macro to extract a pointer to the array of points of a cluster entry */ 4.200 -#define PGL_ENTRY_POINTS(cluster, idx) \ 4.201 - ((pgl_point *)(((intptr_t)cluster)+(cluster)->entries[idx].offset)) 4.202 - 4.203 -/* convert pgl_newentry array to pgl_cluster */ 4.204 -static pgl_cluster *pgl_new_cluster(int nentries, pgl_newentry *entries) { 4.205 - int i; /* index of current entry */ 4.206 - int npoints = 0; /* number of points in whole cluster */ 4.207 - int entry_npoints; /* number of points in current entry */ 4.208 - int points_offset = PGL_POINT_ALIGNMENT * ( 4.209 - ( offsetof(pgl_cluster, entries) + 4.210 - nentries * sizeof(pgl_entry) + 4.211 - PGL_POINT_ALIGNMENT - 1 4.212 - ) / PGL_POINT_ALIGNMENT 4.213 - ); /* offset of pgl_point array from base address (considering alignment) */ 4.214 - pgl_cluster *cluster; /* new cluster to be returned */ 4.215 - /* determine total number of points */ 4.216 - for (i=0; i<nentries; i++) npoints += entries[i].npoints; 4.217 - /* allocate memory for cluster (including entries and points) */ 4.218 - cluster = palloc(points_offset + npoints * sizeof(pgl_point)); 4.219 - /* re-count total number of points to determine offset for each entry */ 4.220 - npoints = 0; 4.221 - /* copy entries and points */ 4.222 - for (i=0; i<nentries; i++) { 4.223 - /* determine number of points in entry */ 4.224 - entry_npoints = entries[i].npoints; 4.225 - /* copy entry */ 4.226 - cluster->entries[i].entrytype = entries[i].entrytype; 4.227 - cluster->entries[i].npoints = entry_npoints; 4.228 - /* calculate offset (in bytes) of pgl_point array */ 4.229 - cluster->entries[i].offset = points_offset + npoints * sizeof(pgl_point); 4.230 - /* copy points */ 4.231 - memcpy( 4.232 - PGL_ENTRY_POINTS(cluster, i), 4.233 - entries[i].points, 4.234 - entry_npoints * sizeof(pgl_point) 4.235 - ); 4.236 - /* update total number of points processed */ 4.237 - npoints += entry_npoints; 4.238 - } 4.239 - /* set number of entries in cluster */ 4.240 - cluster->nentries = nentries; 4.241 - /* set PostgreSQL header for variable sized data */ 4.242 - SET_VARSIZE(cluster, points_offset + npoints * sizeof(pgl_point)); 4.243 - /* return newly created cluster */ 4.244 - return cluster; 4.245 -} 4.246 - 4.247 - 4.248 -/*----------------------------------------* 4.249 - * C functions on geographic data types * 4.250 - *----------------------------------------*/ 4.251 - 4.252 -/* round latitude or longitude to 12 digits after decimal point */ 4.253 -static inline double pgl_round(double val) { 4.254 - return round(val * 1e12) / 1e12; 4.255 -} 4.256 - 4.257 -/* compare two points */ 4.258 -/* (equality when same point on earth is described, otherwise an arbitrary 4.259 - linear order) */ 4.260 -static int pgl_point_cmp(pgl_point *point1, pgl_point *point2) { 4.261 - double lon1, lon2; /* modified longitudes for special cases */ 4.262 - /* use latitude as first ordering criterion */ 4.263 - if (point1->lat < point2->lat) return -1; 4.264 - if (point1->lat > point2->lat) return 1; 4.265 - /* determine modified longitudes (considering special case of poles and 4.266 - 180th meridian which can be described as W180 or E180) */ 4.267 - if (point1->lat == -90 || point1->lat == 90) lon1 = 0; 4.268 - else if (point1->lon == 180) lon1 = -180; 4.269 - else lon1 = point1->lon; 4.270 - if (point2->lat == -90 || point2->lat == 90) lon2 = 0; 4.271 - else if (point2->lon == 180) lon2 = -180; 4.272 - else lon2 = point2->lon; 4.273 - /* use (modified) longitude as secondary ordering criterion */ 4.274 - if (lon1 < lon2) return -1; 4.275 - if (lon1 > lon2) return 1; 4.276 - /* no difference found, points are equal */ 4.277 - return 0; 4.278 -} 4.279 - 4.280 -/* compare two boxes */ 4.281 -/* (equality when same box on earth is described, otherwise an arbitrary linear 4.282 - order) */ 4.283 -static int pgl_box_cmp(pgl_box *box1, pgl_box *box2) { 4.284 - /* two empty boxes are equal, and an empty box is always considered "less 4.285 - than" a non-empty box */ 4.286 - if (box1->lat_min> box1->lat_max && box2->lat_min<=box2->lat_max) return -1; 4.287 - if (box1->lat_min> box1->lat_max && box2->lat_min> box2->lat_max) return 0; 4.288 - if (box1->lat_min<=box1->lat_max && box2->lat_min> box2->lat_max) return 1; 4.289 - /* use southern border as first ordering criterion */ 4.290 - if (box1->lat_min < box2->lat_min) return -1; 4.291 - if (box1->lat_min > box2->lat_min) return 1; 4.292 - /* use northern border as second ordering criterion */ 4.293 - if (box1->lat_max < box2->lat_max) return -1; 4.294 - if (box1->lat_max > box2->lat_max) return 1; 4.295 - /* use western border as third ordering criterion */ 4.296 - if (box1->lon_min < box2->lon_min) return -1; 4.297 - if (box1->lon_min > box2->lon_min) return 1; 4.298 - /* use eastern border as fourth ordering criterion */ 4.299 - if (box1->lon_max < box2->lon_max) return -1; 4.300 - if (box1->lon_max > box2->lon_max) return 1; 4.301 - /* no difference found, boxes are equal */ 4.302 - return 0; 4.303 -} 4.304 - 4.305 -/* compare two circles */ 4.306 -/* (equality when same circle on earth is described, otherwise an arbitrary 4.307 - linear order) */ 4.308 -static int pgl_circle_cmp(pgl_circle *circle1, pgl_circle *circle2) { 4.309 - /* two circles with same infinite radius (positive or negative infinity) are 4.310 - considered equal independently of center point */ 4.311 - if ( 4.312 - !isfinite(circle1->radius) && !isfinite(circle2->radius) && 4.313 - circle1->radius == circle2->radius 4.314 - ) return 0; 4.315 - /* use radius as first ordering criterion */ 4.316 - if (circle1->radius < circle2->radius) return -1; 4.317 - if (circle1->radius > circle2->radius) return 1; 4.318 - /* use center point as secondary ordering criterion */ 4.319 - return pgl_point_cmp(&(circle1->center), &(circle2->center)); 4.320 -} 4.321 - 4.322 -/* set box to empty box*/ 4.323 -static void pgl_box_set_empty(pgl_box *box) { 4.324 - box->lat_min = INFINITY; 4.325 - box->lat_max = -INFINITY; 4.326 - box->lon_min = 0; 4.327 - box->lon_max = 0; 4.328 -} 4.329 - 4.330 -/* check if point is inside a box */ 4.331 -static bool pgl_point_in_box(pgl_point *point, pgl_box *box) { 4.332 - return ( 4.333 - point->lat >= box->lat_min && point->lat <= box->lat_max && ( 4.334 - (box->lon_min > box->lon_max) ? ( 4.335 - /* box crosses 180th meridian */ 4.336 - point->lon >= box->lon_min || point->lon <= box->lon_max 4.337 - ) : ( 4.338 - /* box does not cross the 180th meridian */ 4.339 - point->lon >= box->lon_min && point->lon <= box->lon_max 4.340 - ) 4.341 - ) 4.342 - ); 4.343 -} 4.344 - 4.345 -/* check if two boxes overlap */ 4.346 -static bool pgl_boxes_overlap(pgl_box *box1, pgl_box *box2) { 4.347 - return ( 4.348 - box2->lat_max >= box2->lat_min && /* ensure box2 is not empty */ 4.349 - ( box2->lat_min >= box1->lat_min || box2->lat_max >= box1->lat_min ) && 4.350 - ( box2->lat_min <= box1->lat_max || box2->lat_max <= box1->lat_max ) && ( 4.351 - ( 4.352 - /* check if one and only one box crosses the 180th meridian */ 4.353 - ((box1->lon_min > box1->lon_max) ? 1 : 0) ^ 4.354 - ((box2->lon_min > box2->lon_max) ? 1 : 0) 4.355 - ) ? ( 4.356 - /* exactly one box crosses the 180th meridian */ 4.357 - box2->lon_min >= box1->lon_min || box2->lon_max >= box1->lon_min || 4.358 - box2->lon_min <= box1->lon_max || box2->lon_max <= box1->lon_max 4.359 - ) : ( 4.360 - /* no box or both boxes cross the 180th meridian */ 4.361 - ( 4.362 - (box2->lon_min >= box1->lon_min || box2->lon_max >= box1->lon_min) && 4.363 - (box2->lon_min <= box1->lon_max || box2->lon_max <= box1->lon_max) 4.364 - ) || 4.365 - /* handle W180 == E180 */ 4.366 - ( box1->lon_min == -180 && box2->lon_max == 180 ) || 4.367 - ( box2->lon_min == -180 && box1->lon_max == 180 ) 4.368 - ) 4.369 - ) 4.370 - ); 4.371 -} 4.372 - 4.373 -/* check unambiguousness of east/west orientation of cluster entries and set 4.374 - bounding circle of cluster */ 4.375 -static bool pgl_finalize_cluster(pgl_cluster *cluster) { 4.376 - int i, j; /* i: index of entry, j: index of point in entry */ 4.377 - int npoints; /* number of points in entry */ 4.378 - int total_npoints = 0; /* total number of points in cluster */ 4.379 - pgl_point *points; /* points in entry */ 4.380 - int lon_dir; /* first point of entry west (-1) or east (+1) */ 4.381 - double lon_break = 0; /* antipodal longitude of first point in entry */ 4.382 - double lon_min, lon_max; /* covered longitude range of entry */ 4.383 - double value; /* temporary variable */ 4.384 - /* reset bounding circle center to empty circle at 0/0 coordinates */ 4.385 - cluster->bounding.center.lat = 0; 4.386 - cluster->bounding.center.lon = 0; 4.387 - cluster->bounding.radius = -INFINITY; 4.388 - /* if cluster is not empty */ 4.389 - if (cluster->nentries != 0) { 4.390 - /* iterate over all cluster entries and ensure they each cover a longitude 4.391 - range less than 180 degrees */ 4.392 - for (i=0; i<cluster->nentries; i++) { 4.393 - /* get properties of entry */ 4.394 - npoints = cluster->entries[i].npoints; 4.395 - points = PGL_ENTRY_POINTS(cluster, i); 4.396 - /* get longitude of first point of entry */ 4.397 - value = points[0].lon; 4.398 - /* initialize lon_min and lon_max with longitude of first point */ 4.399 - lon_min = value; 4.400 - lon_max = value; 4.401 - /* determine east/west orientation of first point and calculate antipodal 4.402 - longitude (Note: rounding required here) */ 4.403 - if (value < 0) { lon_dir = -1; lon_break = pgl_round(value + 180); } 4.404 - else if (value > 0) { lon_dir = 1; lon_break = pgl_round(value - 180); } 4.405 - else lon_dir = 0; 4.406 - /* iterate over all other points in entry */ 4.407 - for (j=1; j<npoints; j++) { 4.408 - /* consider longitude wrap-around */ 4.409 - value = points[j].lon; 4.410 - if (lon_dir<0 && value>lon_break) value = pgl_round(value - 360); 4.411 - else if (lon_dir>0 && value<lon_break) value = pgl_round(value + 360); 4.412 - /* update lon_min and lon_max */ 4.413 - if (value < lon_min) lon_min = value; 4.414 - else if (value > lon_max) lon_max = value; 4.415 - /* return false if 180 degrees or more are covered */ 4.416 - if (lon_max - lon_min >= 180) return false; 4.417 - } 4.418 - } 4.419 - /* iterate over all points of all entries and calculate arbitrary center 4.420 - point for bounding circle (best if center point minimizes the radius, 4.421 - but some error is allowed here) */ 4.422 - for (i=0; i<cluster->nentries; i++) { 4.423 - /* get properties of entry */ 4.424 - npoints = cluster->entries[i].npoints; 4.425 - points = PGL_ENTRY_POINTS(cluster, i); 4.426 - /* check if first entry */ 4.427 - if (i==0) { 4.428 - /* get longitude of first point of first entry in whole cluster */ 4.429 - value = points[0].lon; 4.430 - /* initialize lon_min and lon_max with longitude of first point of 4.431 - first entry in whole cluster (used to determine if whole cluster 4.432 - covers a longitude range of 180 degrees or more) */ 4.433 - lon_min = value; 4.434 - lon_max = value; 4.435 - /* determine east/west orientation of first point and calculate 4.436 - antipodal longitude (Note: rounding not necessary here) */ 4.437 - if (value < 0) { lon_dir = -1; lon_break = value + 180; } 4.438 - else if (value > 0) { lon_dir = 1; lon_break = value - 180; } 4.439 - else lon_dir = 0; 4.440 - } 4.441 - /* iterate over all points in entry */ 4.442 - for (j=0; j<npoints; j++) { 4.443 - /* longitude wrap-around (Note: rounding not necessary here) */ 4.444 - value = points[j].lon; 4.445 - if (lon_dir < 0 && value > lon_break) value -= 360; 4.446 - else if (lon_dir > 0 && value < lon_break) value += 360; 4.447 - if (value < lon_min) lon_min = value; 4.448 - else if (value > lon_max) lon_max = value; 4.449 - /* set bounding circle to cover whole earth if more than 180 degrees 4.450 - are covered */ 4.451 - if (lon_max - lon_min >= 180) { 4.452 - cluster->bounding.center.lat = 0; 4.453 - cluster->bounding.center.lon = 0; 4.454 - cluster->bounding.radius = INFINITY; 4.455 - return true; 4.456 - } 4.457 - /* add point to bounding circle center (for average calculation) */ 4.458 - cluster->bounding.center.lat += points[j].lat; 4.459 - cluster->bounding.center.lon += value; 4.460 - } 4.461 - /* count total number of points */ 4.462 - total_npoints += npoints; 4.463 - } 4.464 - /* determine average latitude and longitude of cluster */ 4.465 - cluster->bounding.center.lat /= total_npoints; 4.466 - cluster->bounding.center.lon /= total_npoints; 4.467 - /* normalize longitude of center of cluster bounding circle */ 4.468 - if (cluster->bounding.center.lon < -180) { 4.469 - cluster->bounding.center.lon += 360; 4.470 - } 4.471 - else if (cluster->bounding.center.lon > 180) { 4.472 - cluster->bounding.center.lon -= 360; 4.473 - } 4.474 - /* round bounding circle center (useful if it is used by other functions) */ 4.475 - cluster->bounding.center.lat = pgl_round(cluster->bounding.center.lat); 4.476 - cluster->bounding.center.lon = pgl_round(cluster->bounding.center.lon); 4.477 - /* calculate radius of bounding circle */ 4.478 - for (i=0; i<cluster->nentries; i++) { 4.479 - npoints = cluster->entries[i].npoints; 4.480 - points = PGL_ENTRY_POINTS(cluster, i); 4.481 - for (j=0; j<npoints; j++) { 4.482 - value = pgl_distance( 4.483 - cluster->bounding.center.lat, cluster->bounding.center.lon, 4.484 - points[j].lat, points[j].lon 4.485 - ); 4.486 - if (value > cluster->bounding.radius) cluster->bounding.radius = value; 4.487 - } 4.488 - } 4.489 - } 4.490 - /* return true (east/west orientation is unambiguous) */ 4.491 - return true; 4.492 -} 4.493 - 4.494 -/* check if point is inside cluster */ 4.495 -static bool pgl_point_in_cluster(pgl_point *point, pgl_cluster *cluster) { 4.496 - int i, j, k; /* i: entry, j: point in entry, k: next point in entry */ 4.497 - int entrytype; /* type of entry */ 4.498 - int npoints; /* number of points in entry */ 4.499 - pgl_point *points; /* array of points in entry */ 4.500 - int lon_dir = 0; /* first vertex west (-1) or east (+1) */ 4.501 - double lon_break = 0; /* antipodal longitude of first vertex */ 4.502 - double lat0 = point->lat; /* latitude of point */ 4.503 - double lon0; /* (adjusted) longitude of point */ 4.504 - double lat1, lon1; /* latitude and (adjusted) longitude of vertex */ 4.505 - double lat2, lon2; /* latitude and (adjusted) longitude of next vertex */ 4.506 - double lon; /* longitude of intersection */ 4.507 - int counter = 0; /* counter for intersections east of point */ 4.508 - /* iterate over all entries */ 4.509 - for (i=0; i<cluster->nentries; i++) { 4.510 - /* get properties of entry */ 4.511 - entrytype = cluster->entries[i].entrytype; 4.512 - npoints = cluster->entries[i].npoints; 4.513 - points = PGL_ENTRY_POINTS(cluster, i); 4.514 - /* determine east/west orientation of first point of entry and calculate 4.515 - antipodal longitude */ 4.516 - lon_break = points[0].lon; 4.517 - if (lon_break < 0) { lon_dir = -1; lon_break += 180; } 4.518 - else if (lon_break > 0) { lon_dir = 1; lon_break -= 180; } 4.519 - else lon_dir = 0; 4.520 - /* get longitude of point */ 4.521 - lon0 = point->lon; 4.522 - /* consider longitude wrap-around for point */ 4.523 - if (lon_dir < 0 && lon0 > lon_break) lon0 = pgl_round(lon0 - 360); 4.524 - else if (lon_dir > 0 && lon0 < lon_break) lon0 = pgl_round(lon0 + 360); 4.525 - /* iterate over all edges and vertices */ 4.526 - for (j=0; j<npoints; j++) { 4.527 - /* return true if point is on vertex of polygon */ 4.528 - if (pgl_point_cmp(point, &(points[j])) == 0) return true; 4.529 - /* calculate index of next vertex */ 4.530 - k = (j+1) % npoints; 4.531 - /* skip last edge unless entry is (closed) outline or polygon */ 4.532 - if ( 4.533 - k == 0 && 4.534 - entrytype != PGL_ENTRY_OUTLINE && 4.535 - entrytype != PGL_ENTRY_POLYGON 4.536 - ) continue; 4.537 - /* use previously calculated values for lat1 and lon1 if possible */ 4.538 - if (j) { 4.539 - lat1 = lat2; 4.540 - lon1 = lon2; 4.541 - } else { 4.542 - /* otherwise get latitude and longitude values of first vertex */ 4.543 - lat1 = points[0].lat; 4.544 - lon1 = points[0].lon; 4.545 - /* and consider longitude wrap-around for first vertex */ 4.546 - if (lon_dir < 0 && lon1 > lon_break) lon1 = pgl_round(lon1 - 360); 4.547 - else if (lon_dir > 0 && lon1 < lon_break) lon1 = pgl_round(lon1 + 360); 4.548 - } 4.549 - /* get latitude and longitude of next vertex */ 4.550 - lat2 = points[k].lat; 4.551 - lon2 = points[k].lon; 4.552 - /* consider longitude wrap-around for next vertex */ 4.553 - if (lon_dir < 0 && lon2 > lon_break) lon2 = pgl_round(lon2 - 360); 4.554 - else if (lon_dir > 0 && lon2 < lon_break) lon2 = pgl_round(lon2 + 360); 4.555 - /* return true if point is on horizontal (west to east) edge of polygon */ 4.556 - if ( 4.557 - lat0 == lat1 && lat0 == lat2 && 4.558 - ( (lon0 >= lon1 && lon0 <= lon2) || (lon0 >= lon2 && lon0 <= lon1) ) 4.559 - ) return true; 4.560 - /* check if edge crosses east/west line of point */ 4.561 - if ((lat1 < lat0 && lat2 >= lat0) || (lat2 < lat0 && lat1 >= lat0)) { 4.562 - /* calculate longitude of intersection */ 4.563 - lon = (lon1 * (lat2-lat0) + lon2 * (lat0-lat1)) / (lat2-lat1); 4.564 - /* return true if intersection goes (approximately) through point */ 4.565 - if (pgl_round(lon) == lon0) return true; 4.566 - /* count intersection if east of point and entry is polygon*/ 4.567 - if (entrytype == PGL_ENTRY_POLYGON && lon > lon0) counter++; 4.568 - } 4.569 - } 4.570 - } 4.571 - /* return true if number of intersections is odd */ 4.572 - return counter & 1; 4.573 -} 4.574 - 4.575 -/* check if all points of the second cluster are inside the first cluster */ 4.576 -static inline bool pgl_all_cluster_points_in_cluster( 4.577 - pgl_cluster *outer, pgl_cluster *inner 4.578 -) { 4.579 - int i, j; /* i: entry, j: point in entry */ 4.580 - int npoints; /* number of points in entry */ 4.581 - pgl_point *points; /* array of points in entry */ 4.582 - /* iterate over all entries of "inner" cluster */ 4.583 - for (i=0; i<inner->nentries; i++) { 4.584 - /* get properties of entry */ 4.585 - npoints = inner->entries[i].npoints; 4.586 - points = PGL_ENTRY_POINTS(inner, i); 4.587 - /* iterate over all points in entry of "inner" cluster */ 4.588 - for (j=0; j<npoints; j++) { 4.589 - /* return false if one point of inner cluster is not in outer cluster */ 4.590 - if (!pgl_point_in_cluster(points+j, outer)) return false; 4.591 - } 4.592 - } 4.593 - /* otherwise return true */ 4.594 - return true; 4.595 -} 4.596 - 4.597 -/* check if any point the second cluster is inside the first cluster */ 4.598 -static inline bool pgl_any_cluster_points_in_cluster( 4.599 - pgl_cluster *outer, pgl_cluster *inner 4.600 -) { 4.601 - int i, j; /* i: entry, j: point in entry */ 4.602 - int npoints; /* number of points in entry */ 4.603 - pgl_point *points; /* array of points in entry */ 4.604 - /* iterate over all entries of "inner" cluster */ 4.605 - for (i=0; i<inner->nentries; i++) { 4.606 - /* get properties of entry */ 4.607 - npoints = inner->entries[i].npoints; 4.608 - points = PGL_ENTRY_POINTS(inner, i); 4.609 - /* iterate over all points in entry of "inner" cluster */ 4.610 - for (j=0; j<npoints; j++) { 4.611 - /* return true if one point of inner cluster is in outer cluster */ 4.612 - if (pgl_point_in_cluster(points+j, outer)) return true; 4.613 - } 4.614 - } 4.615 - /* otherwise return false */ 4.616 - return false; 4.617 -} 4.618 - 4.619 -/* check if line segment crosses line */ 4.620 -/* returns -1 if yes, 1 if no, and 0 in corner cases */ 4.621 -/* NOTE: each line (segment) must have a length greater than zero */ 4.622 -static inline double pgl_lseg_crosses_line( 4.623 - double seg_x1, double seg_y1, double seg_x2, double seg_y2, 4.624 - double line_x1, double line_y1, double line_x2, double line_y2, 4.625 - bool strict 4.626 -) { 4.627 - double value = ( 4.628 - (seg_x1-line_x1) * (line_y2-line_y1) - 4.629 - (seg_y1-line_y1) * (line_x2-line_x1) 4.630 - ) * ( 4.631 - (seg_x2-line_x1) * (line_y2-line_y1) - 4.632 - (seg_y2-line_y1) * (line_x2-line_x1) 4.633 - ); 4.634 - if (strict) return value < 0; 4.635 - else return value <= 0; 4.636 -} 4.637 - 4.638 -/* check if paths and outlines of two clusters overlap */ 4.639 -/* (set strict to true to disregard corner cases) */ 4.640 -static bool pgl_outlines_overlap( 4.641 - pgl_cluster *cluster1, pgl_cluster *cluster2, bool strict 4.642 -) { 4.643 - int i1, j1, k1; /* i: entry, j: point in entry, k: next point in entry */ 4.644 - int i2, j2, k2; 4.645 - int entrytype1, entrytype2; /* type of entry */ 4.646 - int npoints1, npoints2; /* number of points in entry */ 4.647 - pgl_point *points1; /* array of points in entry of cluster1 */ 4.648 - pgl_point *points2; /* array of points in entry of cluster2 */ 4.649 - int lon_dir1, lon_dir2; /* first vertex west (-1) or east (+1) */ 4.650 - double lon_break1, lon_break2; /* antipodal longitude of first vertex */ 4.651 - double lat11, lon11; /* latitude and (adjusted) longitude of vertex */ 4.652 - double lat12, lon12; /* latitude and (adjusted) longitude of next vertex */ 4.653 - double lat21, lon21; /* latitude and (adjusted) longitudes for cluster2 */ 4.654 - double lat22, lon22; 4.655 - double wrapvalue; /* temporary helper value to adjust wrap-around */ 4.656 - /* iterate over all entries of cluster1 */ 4.657 - for (i1=0; i1<cluster1->nentries; i1++) { 4.658 - /* get properties of entry in cluster1 and skip points */ 4.659 - npoints1 = cluster1->entries[i1].npoints; 4.660 - if (npoints1 < 2) continue; 4.661 - entrytype1 = cluster1->entries[i1].entrytype; 4.662 - points1 = PGL_ENTRY_POINTS(cluster1, i1); 4.663 - /* determine east/west orientation of first point and calculate antipodal 4.664 - longitude */ 4.665 - lon_break1 = points1[0].lon; 4.666 - if (lon_break1 < 0) { 4.667 - lon_dir1 = -1; 4.668 - lon_break1 = pgl_round(lon_break1 + 180); 4.669 - } else if (lon_break1 > 0) { 4.670 - lon_dir1 = 1; 4.671 - lon_break1 = pgl_round(lon_break1 - 180); 4.672 - } else lon_dir1 = 0; 4.673 - /* iterate over all edges and vertices in cluster1 */ 4.674 - for (j1=0; j1<npoints1; j1++) { 4.675 - /* calculate index of next vertex */ 4.676 - k1 = (j1+1) % npoints1; 4.677 - /* skip last edge unless entry is (closed) outline or polygon */ 4.678 - if ( 4.679 - k1 == 0 && 4.680 - entrytype1 != PGL_ENTRY_OUTLINE && 4.681 - entrytype1 != PGL_ENTRY_POLYGON 4.682 - ) continue; 4.683 - /* use previously calculated values for lat1 and lon1 if possible */ 4.684 - if (j1) { 4.685 - lat11 = lat12; 4.686 - lon11 = lon12; 4.687 - } else { 4.688 - /* otherwise get latitude and longitude values of first vertex */ 4.689 - lat11 = points1[0].lat; 4.690 - lon11 = points1[0].lon; 4.691 - /* and consider longitude wrap-around for first vertex */ 4.692 - if (lon_dir1<0 && lon11>lon_break1) lon11 = pgl_round(lon11-360); 4.693 - else if (lon_dir1>0 && lon11<lon_break1) lon11 = pgl_round(lon11+360); 4.694 - } 4.695 - /* get latitude and longitude of next vertex */ 4.696 - lat12 = points1[k1].lat; 4.697 - lon12 = points1[k1].lon; 4.698 - /* consider longitude wrap-around for next vertex */ 4.699 - if (lon_dir1<0 && lon12>lon_break1) lon12 = pgl_round(lon12-360); 4.700 - else if (lon_dir1>0 && lon12<lon_break1) lon12 = pgl_round(lon12+360); 4.701 - /* skip degenerated edges */ 4.702 - if (lat11 == lat12 && lon11 == lon12) continue; 4.703 - /* iterate over all entries of cluster2 */ 4.704 - for (i2=0; i2<cluster2->nentries; i2++) { 4.705 - /* get points and number of points of entry in cluster2 */ 4.706 - npoints2 = cluster2->entries[i2].npoints; 4.707 - if (npoints2 < 2) continue; 4.708 - entrytype2 = cluster2->entries[i2].entrytype; 4.709 - points2 = PGL_ENTRY_POINTS(cluster2, i2); 4.710 - /* determine east/west orientation of first point and calculate antipodal 4.711 - longitude */ 4.712 - lon_break2 = points2[0].lon; 4.713 - if (lon_break2 < 0) { 4.714 - lon_dir2 = -1; 4.715 - lon_break2 = pgl_round(lon_break2 + 180); 4.716 - } else if (lon_break2 > 0) { 4.717 - lon_dir2 = 1; 4.718 - lon_break2 = pgl_round(lon_break2 - 180); 4.719 - } else lon_dir2 = 0; 4.720 - /* iterate over all edges and vertices in cluster2 */ 4.721 - for (j2=0; j2<npoints2; j2++) { 4.722 - /* calculate index of next vertex */ 4.723 - k2 = (j2+1) % npoints2; 4.724 - /* skip last edge unless entry is (closed) outline or polygon */ 4.725 - if ( 4.726 - k2 == 0 && 4.727 - entrytype2 != PGL_ENTRY_OUTLINE && 4.728 - entrytype2 != PGL_ENTRY_POLYGON 4.729 - ) continue; 4.730 - /* use previously calculated values for lat1 and lon1 if possible */ 4.731 - if (j2) { 4.732 - lat21 = lat22; 4.733 - lon21 = lon22; 4.734 - } else { 4.735 - /* otherwise get latitude and longitude values of first vertex */ 4.736 - lat21 = points2[0].lat; 4.737 - lon21 = points2[0].lon; 4.738 - /* and consider longitude wrap-around for first vertex */ 4.739 - if (lon_dir2<0 && lon21>lon_break2) lon21 = pgl_round(lon21-360); 4.740 - else if (lon_dir2>0 && lon21<lon_break2) lon21 = pgl_round(lon21+360); 4.741 - } 4.742 - /* get latitude and longitude of next vertex */ 4.743 - lat22 = points2[k2].lat; 4.744 - lon22 = points2[k2].lon; 4.745 - /* consider longitude wrap-around for next vertex */ 4.746 - if (lon_dir2<0 && lon22>lon_break2) lon22 = pgl_round(lon22-360); 4.747 - else if (lon_dir2>0 && lon22<lon_break2) lon22 = pgl_round(lon22+360); 4.748 - /* skip degenerated edges */ 4.749 - if (lat21 == lat22 && lon21 == lon22) continue; 4.750 - /* perform another wrap-around where necessary */ 4.751 - /* TODO: improve performance of whole wrap-around mechanism */ 4.752 - wrapvalue = (lon21 + lon22) - (lon11 + lon12); 4.753 - if (wrapvalue > 360) { 4.754 - lon21 = pgl_round(lon21 - 360); 4.755 - lon22 = pgl_round(lon22 - 360); 4.756 - } else if (wrapvalue < -360) { 4.757 - lon21 = pgl_round(lon21 + 360); 4.758 - lon22 = pgl_round(lon22 + 360); 4.759 - } 4.760 - /* return true if segments overlap */ 4.761 - if ( 4.762 - pgl_lseg_crosses_line( 4.763 - lat11, lon11, lat12, lon12, 4.764 - lat21, lon21, lat22, lon22, 4.765 - strict 4.766 - ) && pgl_lseg_crosses_line( 4.767 - lat21, lon21, lat22, lon22, 4.768 - lat11, lon11, lat12, lon12, 4.769 - strict 4.770 - ) 4.771 - ) { 4.772 - return true; 4.773 - } 4.774 - } 4.775 - } 4.776 - } 4.777 - } 4.778 - /* otherwise return false */ 4.779 - return false; 4.780 -} 4.781 - 4.782 -/* check if second cluster is completely contained in first cluster */ 4.783 -static bool pgl_cluster_in_cluster(pgl_cluster *outer, pgl_cluster *inner) { 4.784 - if (!pgl_all_cluster_points_in_cluster(outer, inner)) return false; 4.785 - if (pgl_outlines_overlap(outer, inner, true)) return false; 4.786 - return true; 4.787 -} 4.788 - 4.789 -/* check if two clusters overlap */ 4.790 -static bool pgl_clusters_overlap( 4.791 - pgl_cluster *cluster1, pgl_cluster *cluster2 4.792 -) { 4.793 - if (pgl_any_cluster_points_in_cluster(cluster1, cluster2)) return true; 4.794 - if (pgl_any_cluster_points_in_cluster(cluster2, cluster1)) return true; 4.795 - if (pgl_outlines_overlap(cluster1, cluster2, false)) return true; 4.796 - return false; 4.797 -} 4.798 - 4.799 - 4.800 -/* calculate (approximate) distance between point and cluster */ 4.801 -static double pgl_point_cluster_distance(pgl_point *point, pgl_cluster *cluster) { 4.802 - int i, j, k; /* i: entry, j: point in entry, k: next point in entry */ 4.803 - int entrytype; /* type of entry */ 4.804 - int npoints; /* number of points in entry */ 4.805 - pgl_point *points; /* array of points in entry */ 4.806 - int lon_dir = 0; /* first vertex west (-1) or east (+1) */ 4.807 - double lon_break = 0; /* antipodal longitude of first vertex */ 4.808 - double lon_min = 0; /* minimum (adjusted) longitude of entry vertices */ 4.809 - double lon_max = 0; /* maximum (adjusted) longitude of entry vertices */ 4.810 - double lat0 = point->lat; /* latitude of point */ 4.811 - double lon0; /* (adjusted) longitude of point */ 4.812 - double lat1, lon1; /* latitude and (adjusted) longitude of vertex */ 4.813 - double lat2, lon2; /* latitude and (adjusted) longitude of next vertex */ 4.814 - double s; /* scalar for vector calculations */ 4.815 - double dist; /* distance calculated in one step */ 4.816 - double min_dist = INFINITY; /* minimum distance */ 4.817 - /* distance is zero if point is contained in cluster */ 4.818 - if (pgl_point_in_cluster(point, cluster)) return 0; 4.819 - /* iterate over all entries */ 4.820 - for (i=0; i<cluster->nentries; i++) { 4.821 - /* get properties of entry */ 4.822 - entrytype = cluster->entries[i].entrytype; 4.823 - npoints = cluster->entries[i].npoints; 4.824 - points = PGL_ENTRY_POINTS(cluster, i); 4.825 - /* determine east/west orientation of first point of entry and calculate 4.826 - antipodal longitude */ 4.827 - lon_break = points[0].lon; 4.828 - if (lon_break < 0) { lon_dir = -1; lon_break += 180; } 4.829 - else if (lon_break > 0) { lon_dir = 1; lon_break -= 180; } 4.830 - else lon_dir = 0; 4.831 - /* determine covered longitude range */ 4.832 - for (j=0; j<npoints; j++) { 4.833 - /* get longitude of vertex */ 4.834 - lon1 = points[j].lon; 4.835 - /* adjust longitude to fix potential wrap-around */ 4.836 - if (lon_dir < 0 && lon1 > lon_break) lon1 -= 360; 4.837 - else if (lon_dir > 0 && lon1 < lon_break) lon1 += 360; 4.838 - /* update minimum and maximum longitude of polygon */ 4.839 - if (j == 0 || lon1 < lon_min) lon_min = lon1; 4.840 - if (j == 0 || lon1 > lon_max) lon_max = lon1; 4.841 - } 4.842 - /* adjust longitude wrap-around according to full longitude range */ 4.843 - lon_break = (lon_max + lon_min) / 2; 4.844 - if (lon_break < 0) { lon_dir = -1; lon_break += 180; } 4.845 - else if (lon_break > 0) { lon_dir = 1; lon_break -= 180; } 4.846 - /* get longitude of point */ 4.847 - lon0 = point->lon; 4.848 - /* consider longitude wrap-around for point */ 4.849 - if (lon_dir < 0 && lon0 > lon_break) lon0 -= 360; 4.850 - else if (lon_dir > 0 && lon0 < lon_break) lon0 += 360; 4.851 - /* iterate over all edges and vertices */ 4.852 - for (j=0; j<npoints; j++) { 4.853 - /* use previously calculated values for lat1 and lon1 if possible */ 4.854 - if (j) { 4.855 - lat1 = lat2; 4.856 - lon1 = lon2; 4.857 - } else { 4.858 - /* otherwise get latitude and longitude values of first vertex */ 4.859 - lat1 = points[0].lat; 4.860 - lon1 = points[0].lon; 4.861 - /* and consider longitude wrap-around for first vertex */ 4.862 - if (lon_dir < 0 && lon1 > lon_break) lon1 -= 360; 4.863 - else if (lon_dir > 0 && lon1 < lon_break) lon1 += 360; 4.864 - } 4.865 - /* calculate distance to vertex */ 4.866 - dist = pgl_distance(lat0, lon0, lat1, lon1); 4.867 - /* store calculated distance if smallest */ 4.868 - if (dist < min_dist) min_dist = dist; 4.869 - /* calculate index of next vertex */ 4.870 - k = (j+1) % npoints; 4.871 - /* skip last edge unless entry is (closed) outline or polygon */ 4.872 - if ( 4.873 - k == 0 && 4.874 - entrytype != PGL_ENTRY_OUTLINE && 4.875 - entrytype != PGL_ENTRY_POLYGON 4.876 - ) continue; 4.877 - /* get latitude and longitude of next vertex */ 4.878 - lat2 = points[k].lat; 4.879 - lon2 = points[k].lon; 4.880 - /* consider longitude wrap-around for next vertex */ 4.881 - if (lon_dir < 0 && lon2 > lon_break) lon2 -= 360; 4.882 - else if (lon_dir > 0 && lon2 < lon_break) lon2 += 360; 4.883 - /* go to next vertex and edge if edge is degenerated */ 4.884 - if (lat1 == lat2 && lon1 == lon2) continue; 4.885 - /* otherwise test if point can be projected onto edge of polygon */ 4.886 - s = ( 4.887 - ((lat0-lat1) * (lat2-lat1) + (lon0-lon1) * (lon2-lon1)) / 4.888 - ((lat2-lat1) * (lat2-lat1) + (lon2-lon1) * (lon2-lon1)) 4.889 - ); 4.890 - /* go to next vertex and edge if point cannot be projected */ 4.891 - if (!(s > 0 && s < 1)) continue; 4.892 - /* calculate distance from original point to projected point */ 4.893 - dist = pgl_distance( 4.894 - lat0, lon0, 4.895 - lat1 + s * (lat2-lat1), 4.896 - lon1 + s * (lon2-lon1) 4.897 - ); 4.898 - /* store calculated distance if smallest */ 4.899 - if (dist < min_dist) min_dist = dist; 4.900 - } 4.901 - } 4.902 - /* return minimum distance */ 4.903 - return min_dist; 4.904 -} 4.905 - 4.906 -/* calculate (approximate) distance between two clusters */ 4.907 -static double pgl_cluster_distance(pgl_cluster *cluster1, pgl_cluster *cluster2) { 4.908 - int i, j; /* i: entry, j: point in entry */ 4.909 - int npoints; /* number of points in entry */ 4.910 - pgl_point *points; /* array of points in entry */ 4.911 - double dist; /* distance calculated in one step */ 4.912 - double min_dist = INFINITY; /* minimum distance */ 4.913 - /* consider distance from each point in one cluster to the whole other */ 4.914 - for (i=0; i<cluster1->nentries; i++) { 4.915 - npoints = cluster1->entries[i].npoints; 4.916 - points = PGL_ENTRY_POINTS(cluster1, i); 4.917 - for (j=0; j<npoints; j++) { 4.918 - dist = pgl_point_cluster_distance(points+j, cluster2); 4.919 - if (dist == 0) return dist; 4.920 - if (dist < min_dist) min_dist = dist; 4.921 - } 4.922 - } 4.923 - /* consider distance from each point in other cluster to the first cluster */ 4.924 - for (i=0; i<cluster2->nentries; i++) { 4.925 - npoints = cluster2->entries[i].npoints; 4.926 - points = PGL_ENTRY_POINTS(cluster2, i); 4.927 - for (j=0; j<npoints; j++) { 4.928 - dist = pgl_point_cluster_distance(points+j, cluster1); 4.929 - if (dist == 0) return dist; 4.930 - if (dist < min_dist) min_dist = dist; 4.931 - } 4.932 - } 4.933 - return min_dist; 4.934 -} 4.935 - 4.936 -/* estimator function for distance between box and point */ 4.937 -/* always returns a smaller value than actually correct or zero */ 4.938 -static double pgl_estimate_point_box_distance(pgl_point *point, pgl_box *box) { 4.939 - double dlon; /* longitude range of box (delta longitude) */ 4.940 - double distance; /* return value */ 4.941 - /* return infinity if box is empty */ 4.942 - if (box->lat_min > box->lat_max) return INFINITY; 4.943 - /* return zero if point is inside box */ 4.944 - if (pgl_point_in_box(point, box)) return 0; 4.945 - /* calculate delta longitude */ 4.946 - dlon = box->lon_max - box->lon_min; 4.947 - if (dlon < 0) dlon += 360; /* 180th meridian crossed */ 4.948 - /* if delta longitude is greater than 150 degrees, perform safe fall-back */ 4.949 - if (dlon > 150) return 0; 4.950 - /* calculate lower limit for distance (formula below requires dlon <= 150) */ 4.951 - /* TODO: provide better estimation function to improve performance */ 4.952 - distance = ( 4.953 - (1.0-1e-14) * pgl_distance( 4.954 - point->lat, 4.955 - point->lon, 4.956 - (box->lat_min + box->lat_max) / 2, 4.957 - box->lon_min + dlon/2 4.958 - ) - pgl_distance( 4.959 - box->lat_min, box->lon_min, 4.960 - box->lat_max, box->lon_max 4.961 - ) 4.962 - ); 4.963 - /* truncate negative results to zero */ 4.964 - if (distance <= 0) distance = 0; 4.965 - /* return result */ 4.966 - return distance; 4.967 -} 4.968 - 4.969 - 4.970 -/*-------------------------------------------------* 4.971 - * geographic index based on space-filling curve * 4.972 - *-------------------------------------------------*/ 4.973 - 4.974 -/* number of bytes used for geographic (center) position in keys */ 4.975 -#define PGL_KEY_LATLON_BYTELEN 7 4.976 - 4.977 -/* maximum reference value for logarithmic size of geographic objects */ 4.978 -#define PGL_AREAKEY_REFOBJSIZE (PGL_DIAMETER/3.0) /* can be tweaked */ 4.979 - 4.980 -/* pointer to index key (either pgl_pointkey or pgl_areakey) */ 4.981 -typedef unsigned char *pgl_keyptr; 4.982 - 4.983 -/* index key for points (objects with zero area) on the spheroid */ 4.984 -/* bit 0..55: interspersed bits of latitude and longitude, 4.985 - bit 56..57: always zero, 4.986 - bit 58..63: node depth in hypothetic (full) tree from 0 to 56 (incl.) */ 4.987 -typedef unsigned char pgl_pointkey[PGL_KEY_LATLON_BYTELEN+1]; 4.988 - 4.989 -/* index key for geographic objects on spheroid with area greater than zero */ 4.990 -/* bit 0..55: interspersed bits of latitude and longitude of center point, 4.991 - bit 56: always set to 1, 4.992 - bit 57..63: node depth in hypothetic (full) tree from 0 to (2*56)+1 (incl.), 4.993 - bit 64..71: logarithmic object size from 0 to 56+1 = 57 (incl.), but set to 4.994 - PGL_KEY_OBJSIZE_EMPTY (with interspersed bits = 0 and node depth 4.995 - = 113) for empty objects, and set to PGL_KEY_OBJSIZE_UNIVERSAL 4.996 - (with interspersed bits = 0 and node depth = 0) for keys which 4.997 - cover both empty and non-empty objects */ 4.998 - 4.999 -typedef unsigned char pgl_areakey[PGL_KEY_LATLON_BYTELEN+2]; 4.1000 - 4.1001 -/* helper macros for reading/writing index keys */ 4.1002 -#define PGL_KEY_NODEDEPTH_OFFSET PGL_KEY_LATLON_BYTELEN 4.1003 -#define PGL_KEY_OBJSIZE_OFFSET (PGL_KEY_NODEDEPTH_OFFSET+1) 4.1004 -#define PGL_POINTKEY_MAXDEPTH (PGL_KEY_LATLON_BYTELEN*8) 4.1005 -#define PGL_AREAKEY_MAXDEPTH (2*PGL_POINTKEY_MAXDEPTH+1) 4.1006 -#define PGL_AREAKEY_MAXOBJSIZE (PGL_POINTKEY_MAXDEPTH+1) 4.1007 -#define PGL_AREAKEY_TYPEMASK 0x80 4.1008 -#define PGL_KEY_LATLONBIT(key, n) ((key)[(n)/8] & (0x80 >> ((n)%8))) 4.1009 -#define PGL_KEY_LATLONBIT_DIFF(key1, key2, n) \ 4.1010 - ( PGL_KEY_LATLONBIT(key1, n) ^ \ 4.1011 - PGL_KEY_LATLONBIT(key2, n) ) 4.1012 -#define PGL_KEY_IS_AREAKEY(key) ((key)[PGL_KEY_NODEDEPTH_OFFSET] & \ 4.1013 - PGL_AREAKEY_TYPEMASK) 4.1014 -#define PGL_KEY_NODEDEPTH(key) ((key)[PGL_KEY_NODEDEPTH_OFFSET] & \ 4.1015 - (PGL_AREAKEY_TYPEMASK-1)) 4.1016 -#define PGL_KEY_OBJSIZE(key) ((key)[PGL_KEY_OBJSIZE_OFFSET]) 4.1017 -#define PGL_KEY_OBJSIZE_EMPTY 126 4.1018 -#define PGL_KEY_OBJSIZE_UNIVERSAL 127 4.1019 -#define PGL_KEY_IS_EMPTY(key) ( PGL_KEY_IS_AREAKEY(key) && \ 4.1020 - (key)[PGL_KEY_OBJSIZE_OFFSET] == \ 4.1021 - PGL_KEY_OBJSIZE_EMPTY ) 4.1022 -#define PGL_KEY_IS_UNIVERSAL(key) ( PGL_KEY_IS_AREAKEY(key) && \ 4.1023 - (key)[PGL_KEY_OBJSIZE_OFFSET] == \ 4.1024 - PGL_KEY_OBJSIZE_UNIVERSAL ) 4.1025 - 4.1026 -/* set area key to match empty objects only */ 4.1027 -static void pgl_key_set_empty(pgl_keyptr key) { 4.1028 - memset(key, 0, sizeof(pgl_areakey)); 4.1029 - /* Note: setting node depth to maximum is required for picksplit function */ 4.1030 - key[PGL_KEY_NODEDEPTH_OFFSET] = PGL_AREAKEY_TYPEMASK | PGL_AREAKEY_MAXDEPTH; 4.1031 - key[PGL_KEY_OBJSIZE_OFFSET] = PGL_KEY_OBJSIZE_EMPTY; 4.1032 -} 4.1033 - 4.1034 -/* set area key to match any object (including empty objects) */ 4.1035 -static void pgl_key_set_universal(pgl_keyptr key) { 4.1036 - memset(key, 0, sizeof(pgl_areakey)); 4.1037 - key[PGL_KEY_NODEDEPTH_OFFSET] = PGL_AREAKEY_TYPEMASK; 4.1038 - key[PGL_KEY_OBJSIZE_OFFSET] = PGL_KEY_OBJSIZE_UNIVERSAL; 4.1039 -} 4.1040 - 4.1041 -/* convert a point on earth into a max-depth key to be used in index */ 4.1042 -static void pgl_point_to_key(pgl_point *point, pgl_keyptr key) { 4.1043 - double lat = point->lat; 4.1044 - double lon = point->lon; 4.1045 - int i; 4.1046 - /* clear latitude and longitude bits */ 4.1047 - memset(key, 0, PGL_KEY_LATLON_BYTELEN); 4.1048 - /* set node depth to maximum and type bit to zero */ 4.1049 - key[PGL_KEY_NODEDEPTH_OFFSET] = PGL_POINTKEY_MAXDEPTH; 4.1050 - /* iterate over all latitude/longitude bit pairs */ 4.1051 - for (i=0; i<PGL_POINTKEY_MAXDEPTH/2; i++) { 4.1052 - /* determine latitude bit */ 4.1053 - if (lat >= 0) { 4.1054 - key[i/4] |= 0x80 >> (2*(i%4)); 4.1055 - lat *= 2; lat -= 90; 4.1056 - } else { 4.1057 - lat *= 2; lat += 90; 4.1058 - } 4.1059 - /* determine longitude bit */ 4.1060 - if (lon >= 0) { 4.1061 - key[i/4] |= 0x80 >> (2*(i%4)+1); 4.1062 - lon *= 2; lon -= 180; 4.1063 - } else { 4.1064 - lon *= 2; lon += 180; 4.1065 - } 4.1066 - } 4.1067 -} 4.1068 - 4.1069 -/* convert a circle on earth into a max-depth key to be used in an index */ 4.1070 -static void pgl_circle_to_key(pgl_circle *circle, pgl_keyptr key) { 4.1071 - /* handle special case of empty circle */ 4.1072 - if (circle->radius < 0) { 4.1073 - pgl_key_set_empty(key); 4.1074 - return; 4.1075 - } 4.1076 - /* perform same action as for point keys */ 4.1077 - pgl_point_to_key(&(circle->center), key); 4.1078 - /* but overwrite type and node depth to fit area index key */ 4.1079 - key[PGL_KEY_NODEDEPTH_OFFSET] = PGL_AREAKEY_TYPEMASK | PGL_AREAKEY_MAXDEPTH; 4.1080 - /* check if radius is greater than (or equal to) reference size */ 4.1081 - /* (treat equal values as greater values for numerical safety) */ 4.1082 - if (circle->radius >= PGL_AREAKEY_REFOBJSIZE) { 4.1083 - /* if yes, set logarithmic size to zero */ 4.1084 - key[PGL_KEY_OBJSIZE_OFFSET] = 0; 4.1085 - } else { 4.1086 - /* otherwise, determine logarithmic size iteratively */ 4.1087 - /* (one step is equivalent to a factor of sqrt(2)) */ 4.1088 - double reference = PGL_AREAKEY_REFOBJSIZE / M_SQRT2; 4.1089 - int objsize = 1; 4.1090 - while (objsize < PGL_AREAKEY_MAXOBJSIZE) { 4.1091 - /* stop when radius is greater than (or equal to) adjusted reference */ 4.1092 - /* (treat equal values as greater values for numerical safety) */ 4.1093 - if (circle->radius >= reference) break; 4.1094 - reference /= M_SQRT2; 4.1095 - objsize++; 4.1096 - } 4.1097 - /* set logarithmic size to determined value */ 4.1098 - key[PGL_KEY_OBJSIZE_OFFSET] = objsize; 4.1099 - } 4.1100 -} 4.1101 - 4.1102 -/* check if one key is subkey of another key or vice versa */ 4.1103 -static bool pgl_keys_overlap(pgl_keyptr key1, pgl_keyptr key2) { 4.1104 - int i; /* key bit offset (includes both lat/lon and log. obj. size bits) */ 4.1105 - /* determine smallest depth */ 4.1106 - int depth1 = PGL_KEY_NODEDEPTH(key1); 4.1107 - int depth2 = PGL_KEY_NODEDEPTH(key2); 4.1108 - int depth = (depth1 < depth2) ? depth1 : depth2; 4.1109 - /* check if keys are area keys (assuming that both keys have same type) */ 4.1110 - if (PGL_KEY_IS_AREAKEY(key1)) { 4.1111 - int j = 0; /* bit offset for logarithmic object size bits */ 4.1112 - int k = 0; /* bit offset for latitude and longitude */ 4.1113 - /* fetch logarithmic object size information */ 4.1114 - int objsize1 = PGL_KEY_OBJSIZE(key1); 4.1115 - int objsize2 = PGL_KEY_OBJSIZE(key2); 4.1116 - /* handle special cases for empty objects (universal and empty keys) */ 4.1117 - if ( 4.1118 - objsize1 == PGL_KEY_OBJSIZE_UNIVERSAL || 4.1119 - objsize2 == PGL_KEY_OBJSIZE_UNIVERSAL 4.1120 - ) return true; 4.1121 - if ( 4.1122 - objsize1 == PGL_KEY_OBJSIZE_EMPTY || 4.1123 - objsize2 == PGL_KEY_OBJSIZE_EMPTY 4.1124 - ) return objsize1 == objsize2; 4.1125 - /* iterate through key bits */ 4.1126 - for (i=0; i<depth; i++) { 4.1127 - /* every second bit is a bit describing the object size */ 4.1128 - if (i%2 == 0) { 4.1129 - /* check if object size bit is different in both keys (objsize1 and 4.1130 - objsize2 describe the minimum index when object size bit is set) */ 4.1131 - if ( 4.1132 - (objsize1 <= j && objsize2 > j) || 4.1133 - (objsize2 <= j && objsize1 > j) 4.1134 - ) { 4.1135 - /* bit differs, therefore keys are in separate branches */ 4.1136 - return false; 4.1137 - } 4.1138 - /* increase bit counter for object size bits */ 4.1139 - j++; 4.1140 - } 4.1141 - /* all other bits describe latitude and longitude */ 4.1142 - else { 4.1143 - /* check if bit differs in both keys */ 4.1144 - if (PGL_KEY_LATLONBIT_DIFF(key1, key2, k)) { 4.1145 - /* bit differs, therefore keys are in separate branches */ 4.1146 - return false; 4.1147 - } 4.1148 - /* increase bit counter for latitude/longitude bits */ 4.1149 - k++; 4.1150 - } 4.1151 - } 4.1152 - } 4.1153 - /* if not, keys are point keys */ 4.1154 - else { 4.1155 - /* iterate through key bits */ 4.1156 - for (i=0; i<depth; i++) { 4.1157 - /* check if bit differs in both keys */ 4.1158 - if (PGL_KEY_LATLONBIT_DIFF(key1, key2, i)) { 4.1159 - /* bit differs, therefore keys are in separate branches */ 4.1160 - return false; 4.1161 - } 4.1162 - } 4.1163 - } 4.1164 - /* return true because keys are in the same branch */ 4.1165 - return true; 4.1166 -} 4.1167 - 4.1168 -/* combine two keys into new key which covers both original keys */ 4.1169 -/* (result stored in first argument) */ 4.1170 -static void pgl_unite_keys(pgl_keyptr dst, pgl_keyptr src) { 4.1171 - int i; /* key bit offset (includes both lat/lon and log. obj. size bits) */ 4.1172 - /* determine smallest depth */ 4.1173 - int depth1 = PGL_KEY_NODEDEPTH(dst); 4.1174 - int depth2 = PGL_KEY_NODEDEPTH(src); 4.1175 - int depth = (depth1 < depth2) ? depth1 : depth2; 4.1176 - /* check if keys are area keys (assuming that both keys have same type) */ 4.1177 - if (PGL_KEY_IS_AREAKEY(dst)) { 4.1178 - pgl_areakey dstbuf = { 0, }; /* destination buffer (cleared) */ 4.1179 - int j = 0; /* bit offset for logarithmic object size bits */ 4.1180 - int k = 0; /* bit offset for latitude and longitude */ 4.1181 - /* fetch logarithmic object size information */ 4.1182 - int objsize1 = PGL_KEY_OBJSIZE(dst); 4.1183 - int objsize2 = PGL_KEY_OBJSIZE(src); 4.1184 - /* handle special cases for empty objects (universal and empty keys) */ 4.1185 - if ( 4.1186 - objsize1 > PGL_AREAKEY_MAXOBJSIZE || 4.1187 - objsize2 > PGL_AREAKEY_MAXOBJSIZE 4.1188 - ) { 4.1189 - if ( 4.1190 - objsize1 == PGL_KEY_OBJSIZE_EMPTY && 4.1191 - objsize2 == PGL_KEY_OBJSIZE_EMPTY 4.1192 - ) pgl_key_set_empty(dst); 4.1193 - else pgl_key_set_universal(dst); 4.1194 - return; 4.1195 - } 4.1196 - /* iterate through key bits */ 4.1197 - for (i=0; i<depth; i++) { 4.1198 - /* every second bit is a bit describing the object size */ 4.1199 - if (i%2 == 0) { 4.1200 - /* increase bit counter for object size bits first */ 4.1201 - /* (handy when setting objsize variable) */ 4.1202 - j++; 4.1203 - /* check if object size bit is set in neither key */ 4.1204 - if (objsize1 >= j && objsize2 >= j) { 4.1205 - /* set objsize in destination buffer to indicate that size bit is 4.1206 - unset in destination buffer at the current bit position */ 4.1207 - dstbuf[PGL_KEY_OBJSIZE_OFFSET] = j; 4.1208 - } 4.1209 - /* break if object size bit is set in one key only */ 4.1210 - else if (objsize1 >= j || objsize2 >= j) break; 4.1211 - } 4.1212 - /* all other bits describe latitude and longitude */ 4.1213 - else { 4.1214 - /* break if bit differs in both keys */ 4.1215 - if (PGL_KEY_LATLONBIT(dst, k)) { 4.1216 - if (!PGL_KEY_LATLONBIT(src, k)) break; 4.1217 - /* but set bit in destination buffer if bit is set in both keys */ 4.1218 - dstbuf[k/8] |= 0x80 >> (k%8); 4.1219 - } else if (PGL_KEY_LATLONBIT(src, k)) break; 4.1220 - /* increase bit counter for latitude/longitude bits */ 4.1221 - k++; 4.1222 - } 4.1223 - } 4.1224 - /* set common node depth and type bit (type bit = 1) */ 4.1225 - dstbuf[PGL_KEY_NODEDEPTH_OFFSET] = PGL_AREAKEY_TYPEMASK | i; 4.1226 - /* copy contents of destination buffer to first key */ 4.1227 - memcpy(dst, dstbuf, sizeof(pgl_areakey)); 4.1228 - } 4.1229 - /* if not, keys are point keys */ 4.1230 - else { 4.1231 - pgl_pointkey dstbuf = { 0, }; /* destination buffer (cleared) */ 4.1232 - /* iterate through key bits */ 4.1233 - for (i=0; i<depth; i++) { 4.1234 - /* break if bit differs in both keys */ 4.1235 - if (PGL_KEY_LATLONBIT(dst, i)) { 4.1236 - if (!PGL_KEY_LATLONBIT(src, i)) break; 4.1237 - /* but set bit in destination buffer if bit is set in both keys */ 4.1238 - dstbuf[i/8] |= 0x80 >> (i%8); 4.1239 - } else if (PGL_KEY_LATLONBIT(src, i)) break; 4.1240 - } 4.1241 - /* set common node depth (type bit = 0) */ 4.1242 - dstbuf[PGL_KEY_NODEDEPTH_OFFSET] = i; 4.1243 - /* copy contents of destination buffer to first key */ 4.1244 - memcpy(dst, dstbuf, sizeof(pgl_pointkey)); 4.1245 - } 4.1246 -} 4.1247 - 4.1248 -/* determine center(!) boundaries and radius estimation of index key */ 4.1249 -static double pgl_key_to_box(pgl_keyptr key, pgl_box *box) { 4.1250 - int i; 4.1251 - /* determine node depth */ 4.1252 - int depth = PGL_KEY_NODEDEPTH(key); 4.1253 - /* center point of possible result */ 4.1254 - double lat = 0; 4.1255 - double lon = 0; 4.1256 - /* maximum distance of real center point from key center */ 4.1257 - double dlat = 90; 4.1258 - double dlon = 180; 4.1259 - /* maximum radius of contained objects */ 4.1260 - double radius = 0; /* always return zero for point index keys */ 4.1261 - /* check if key is area key */ 4.1262 - if (PGL_KEY_IS_AREAKEY(key)) { 4.1263 - /* get logarithmic object size */ 4.1264 - int objsize = PGL_KEY_OBJSIZE(key); 4.1265 - /* handle special cases for empty objects (universal and empty keys) */ 4.1266 - if (objsize == PGL_KEY_OBJSIZE_EMPTY) { 4.1267 - pgl_box_set_empty(box); 4.1268 - return 0; 4.1269 - } else if (objsize == PGL_KEY_OBJSIZE_UNIVERSAL) { 4.1270 - box->lat_min = -90; 4.1271 - box->lat_max = 90; 4.1272 - box->lon_min = -180; 4.1273 - box->lon_max = 180; 4.1274 - return 0; /* any value >= 0 would do */ 4.1275 - } 4.1276 - /* calculate maximum possible radius of objects covered by the given key */ 4.1277 - if (objsize == 0) radius = INFINITY; 4.1278 - else { 4.1279 - radius = PGL_AREAKEY_REFOBJSIZE; 4.1280 - while (--objsize) radius /= M_SQRT2; 4.1281 - } 4.1282 - /* iterate over latitude and longitude bits in key */ 4.1283 - /* (every second bit is a latitude or longitude bit) */ 4.1284 - for (i=0; i<depth/2; i++) { 4.1285 - /* check if latitude bit */ 4.1286 - if (i%2 == 0) { 4.1287 - /* cut latitude dimension in half */ 4.1288 - dlat /= 2; 4.1289 - /* increase center latitude if bit is 1, otherwise decrease */ 4.1290 - if (PGL_KEY_LATLONBIT(key, i)) lat += dlat; 4.1291 - else lat -= dlat; 4.1292 - } 4.1293 - /* otherwise longitude bit */ 4.1294 - else { 4.1295 - /* cut longitude dimension in half */ 4.1296 - dlon /= 2; 4.1297 - /* increase center longitude if bit is 1, otherwise decrease */ 4.1298 - if (PGL_KEY_LATLONBIT(key, i)) lon += dlon; 4.1299 - else lon -= dlon; 4.1300 - } 4.1301 - } 4.1302 - } 4.1303 - /* if not, keys are point keys */ 4.1304 - else { 4.1305 - /* iterate over all bits in key */ 4.1306 - for (i=0; i<depth; i++) { 4.1307 - /* check if latitude bit */ 4.1308 - if (i%2 == 0) { 4.1309 - /* cut latitude dimension in half */ 4.1310 - dlat /= 2; 4.1311 - /* increase center latitude if bit is 1, otherwise decrease */ 4.1312 - if (PGL_KEY_LATLONBIT(key, i)) lat += dlat; 4.1313 - else lat -= dlat; 4.1314 - } 4.1315 - /* otherwise longitude bit */ 4.1316 - else { 4.1317 - /* cut longitude dimension in half */ 4.1318 - dlon /= 2; 4.1319 - /* increase center longitude if bit is 1, otherwise decrease */ 4.1320 - if (PGL_KEY_LATLONBIT(key, i)) lon += dlon; 4.1321 - else lon -= dlon; 4.1322 - } 4.1323 - } 4.1324 - } 4.1325 - /* calculate boundaries from center point and remaining dlat and dlon */ 4.1326 - /* (return values through pointer to box) */ 4.1327 - box->lat_min = lat - dlat; 4.1328 - box->lat_max = lat + dlat; 4.1329 - box->lon_min = lon - dlon; 4.1330 - box->lon_max = lon + dlon; 4.1331 - /* return radius (as a function return value) */ 4.1332 - return radius; 4.1333 -} 4.1334 - 4.1335 -/* estimator function for distance between point and index key */ 4.1336 -/* always returns a smaller value than actually correct or zero */ 4.1337 -static double pgl_estimate_key_distance(pgl_keyptr key, pgl_point *point) { 4.1338 - pgl_box box; /* center(!) bounding box of area index key */ 4.1339 - /* calculate center(!) bounding box and maximum radius of objects covered 4.1340 - by area index key (radius is zero for point index keys) */ 4.1341 - double distance = pgl_key_to_box(key, &box); 4.1342 - /* calculate estimated distance between bounding box of center point of 4.1343 - indexed object and point passed as second argument, then substract maximum 4.1344 - radius of objects covered by index key */ 4.1345 - distance = pgl_estimate_point_box_distance(point, &box) - distance; 4.1346 - /* truncate negative results to zero */ 4.1347 - if (distance <= 0) distance = 0; 4.1348 - /* return result */ 4.1349 - return distance; 4.1350 -} 4.1351 - 4.1352 - 4.1353 -/*---------------------------------* 4.1354 - * helper functions for text I/O * 4.1355 - *---------------------------------*/ 4.1356 - 4.1357 -#define PGL_NUMBUFLEN 64 /* buffer size for number to string conversion */ 4.1358 - 4.1359 -/* convert floating point number to string (round-trip safe) */ 4.1360 -static void pgl_print_float(char *buf, double flt) { 4.1361 - /* check if number is integral */ 4.1362 - if (trunc(flt) == flt) { 4.1363 - /* for integral floats use maximum precision */ 4.1364 - snprintf(buf, PGL_NUMBUFLEN, "%.17g", flt); 4.1365 - } else { 4.1366 - /* otherwise check if 15, 16, or 17 digits needed (round-trip safety) */ 4.1367 - snprintf(buf, PGL_NUMBUFLEN, "%.15g", flt); 4.1368 - if (strtod(buf, NULL) != flt) snprintf(buf, PGL_NUMBUFLEN, "%.16g", flt); 4.1369 - if (strtod(buf, NULL) != flt) snprintf(buf, PGL_NUMBUFLEN, "%.17g", flt); 4.1370 - } 4.1371 -} 4.1372 - 4.1373 -/* convert latitude floating point number (in degrees) to string */ 4.1374 -static void pgl_print_lat(char *buf, double lat) { 4.1375 - if (signbit(lat)) { 4.1376 - /* treat negative latitudes (including -0) as south */ 4.1377 - snprintf(buf, PGL_NUMBUFLEN, "S%015.12f", -lat); 4.1378 - } else { 4.1379 - /* treat positive latitudes (including +0) as north */ 4.1380 - snprintf(buf, PGL_NUMBUFLEN, "N%015.12f", lat); 4.1381 - } 4.1382 -} 4.1383 - 4.1384 -/* convert longitude floating point number (in degrees) to string */ 4.1385 -static void pgl_print_lon(char *buf, double lon) { 4.1386 - if (signbit(lon)) { 4.1387 - /* treat negative longitudes (including -0) as west */ 4.1388 - snprintf(buf, PGL_NUMBUFLEN, "W%016.12f", -lon); 4.1389 - } else { 4.1390 - /* treat positive longitudes (including +0) as east */ 4.1391 - snprintf(buf, PGL_NUMBUFLEN, "E%016.12f", lon); 4.1392 - } 4.1393 -} 4.1394 - 4.1395 -/* bit masks used as return value of pgl_scan() function */ 4.1396 -#define PGL_SCAN_NONE 0 /* no value has been parsed */ 4.1397 -#define PGL_SCAN_LAT (1<<0) /* latitude has been parsed */ 4.1398 -#define PGL_SCAN_LON (1<<1) /* longitude has been parsed */ 4.1399 -#define PGL_SCAN_LATLON (PGL_SCAN_LAT | PGL_SCAN_LON) /* bitwise OR of both */ 4.1400 - 4.1401 -/* parse a coordinate (can be latitude or longitude) */ 4.1402 -static int pgl_scan(char **str, double *lat, double *lon) { 4.1403 - double val; 4.1404 - int len; 4.1405 - if ( 4.1406 - sscanf(*str, " N %lf %n", &val, &len) || 4.1407 - sscanf(*str, " n %lf %n", &val, &len) 4.1408 - ) { 4.1409 - *str += len; *lat = val; return PGL_SCAN_LAT; 4.1410 - } 4.1411 - if ( 4.1412 - sscanf(*str, " S %lf %n", &val, &len) || 4.1413 - sscanf(*str, " s %lf %n", &val, &len) 4.1414 - ) { 4.1415 - *str += len; *lat = -val; return PGL_SCAN_LAT; 4.1416 - } 4.1417 - if ( 4.1418 - sscanf(*str, " E %lf %n", &val, &len) || 4.1419 - sscanf(*str, " e %lf %n", &val, &len) 4.1420 - ) { 4.1421 - *str += len; *lon = val; return PGL_SCAN_LON; 4.1422 - } 4.1423 - if ( 4.1424 - sscanf(*str, " W %lf %n", &val, &len) || 4.1425 - sscanf(*str, " w %lf %n", &val, &len) 4.1426 - ) { 4.1427 - *str += len; *lon = -val; return PGL_SCAN_LON; 4.1428 - } 4.1429 - return PGL_SCAN_NONE; 4.1430 -} 4.1431 - 4.1432 - 4.1433 -/*-----------------* 4.1434 - * SQL functions * 4.1435 - *-----------------*/ 4.1436 - 4.1437 -/* Note: These function names use "epoint", "ebox", etc. notation here instead 4.1438 - of "point", "box", etc. in order to distinguish them from any previously 4.1439 - defined functions. */ 4.1440 - 4.1441 -/* function needed for dummy types and/or not implemented features */ 4.1442 -PG_FUNCTION_INFO_V1(pgl_notimpl); 4.1443 -Datum pgl_notimpl(PG_FUNCTION_ARGS) { 4.1444 - ereport(ERROR, (errmsg("not implemented by pgLatLon"))); 4.1445 -} 4.1446 - 4.1447 -/* set point to latitude and longitude (including checks) */ 4.1448 -static void pgl_epoint_set_latlon(pgl_point *point, double lat, double lon) { 4.1449 - /* reject infinite or NaN values */ 4.1450 - if (!isfinite(lat) || !isfinite(lon)) { 4.1451 - ereport(ERROR, ( 4.1452 - errcode(ERRCODE_DATA_EXCEPTION), 4.1453 - errmsg("epoint requires finite coordinates") 4.1454 - )); 4.1455 - } 4.1456 - /* check latitude bounds */ 4.1457 - if (lat < -90) { 4.1458 - ereport(WARNING, (errmsg("latitude exceeds south pole"))); 4.1459 - lat = -90; 4.1460 - } else if (lat > 90) { 4.1461 - ereport(WARNING, (errmsg("latitude exceeds north pole"))); 4.1462 - lat = 90; 4.1463 - } 4.1464 - /* check longitude bounds */ 4.1465 - if (lon < -180) { 4.1466 - ereport(NOTICE, (errmsg("longitude west of 180th meridian normalized"))); 4.1467 - lon += 360 - trunc(lon / 360) * 360; 4.1468 - } else if (lon > 180) { 4.1469 - ereport(NOTICE, (errmsg("longitude east of 180th meridian normalized"))); 4.1470 - lon -= 360 + trunc(lon / 360) * 360; 4.1471 - } 4.1472 - /* store rounded latitude/longitude values for round-trip safety */ 4.1473 - point->lat = pgl_round(lat); 4.1474 - point->lon = pgl_round(lon); 4.1475 -} 4.1476 - 4.1477 -/* create point ("epoint" in SQL) from latitude and longitude */ 4.1478 -PG_FUNCTION_INFO_V1(pgl_create_epoint); 4.1479 -Datum pgl_create_epoint(PG_FUNCTION_ARGS) { 4.1480 - pgl_point *point = (pgl_point *)palloc(sizeof(pgl_point)); 4.1481 - pgl_epoint_set_latlon(point, PG_GETARG_FLOAT8(0), PG_GETARG_FLOAT8(1)); 4.1482 - PG_RETURN_POINTER(point); 4.1483 -} 4.1484 - 4.1485 -/* parse point ("epoint" in SQL) */ 4.1486 -/* format: '[NS]<float> [EW]<float>' */ 4.1487 -PG_FUNCTION_INFO_V1(pgl_epoint_in); 4.1488 -Datum pgl_epoint_in(PG_FUNCTION_ARGS) { 4.1489 - char *str = PG_GETARG_CSTRING(0); /* input string */ 4.1490 - char *strptr = str; /* current position within string */ 4.1491 - int done = 0; /* bit mask storing if latitude or longitude was read */ 4.1492 - double lat, lon; /* parsed values as double precision floats */ 4.1493 - pgl_point *point; /* return value (to be palloc'ed) */ 4.1494 - /* parse two floats (each latitude or longitude) separated by white-space */ 4.1495 - done |= pgl_scan(&strptr, &lat, &lon); 4.1496 - if (strptr != str && isspace(strptr[-1])) { 4.1497 - done |= pgl_scan(&strptr, &lat, &lon); 4.1498 - } 4.1499 - /* require end of string, and latitude and longitude parsed successfully */ 4.1500 - if (strptr[0] || done != PGL_SCAN_LATLON) { 4.1501 - ereport(ERROR, ( 4.1502 - errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 4.1503 - errmsg("invalid input syntax for type epoint: \"%s\"", str) 4.1504 - )); 4.1505 - } 4.1506 - /* allocate memory for result */ 4.1507 - point = (pgl_point *)palloc(sizeof(pgl_point)); 4.1508 - /* set latitude and longitude (and perform checks) */ 4.1509 - pgl_epoint_set_latlon(point, lat, lon); 4.1510 - /* return result */ 4.1511 - PG_RETURN_POINTER(point); 4.1512 -} 4.1513 - 4.1514 -/* create box ("ebox" in SQL) that is empty */ 4.1515 -PG_FUNCTION_INFO_V1(pgl_create_empty_ebox); 4.1516 -Datum pgl_create_empty_ebox(PG_FUNCTION_ARGS) { 4.1517 - pgl_box *box = (pgl_box *)palloc(sizeof(pgl_box)); 4.1518 - pgl_box_set_empty(box); 4.1519 - PG_RETURN_POINTER(box); 4.1520 -} 4.1521 - 4.1522 -/* set box to given boundaries (including checks) */ 4.1523 -static void pgl_ebox_set_boundaries( 4.1524 - pgl_box *box, 4.1525 - double lat_min, double lat_max, double lon_min, double lon_max 4.1526 -) { 4.1527 - /* if minimum latitude is greater than maximum latitude, return empty box */ 4.1528 - if (lat_min > lat_max) { 4.1529 - pgl_box_set_empty(box); 4.1530 - return; 4.1531 - } 4.1532 - /* otherwise reject infinite or NaN values */ 4.1533 - if ( 4.1534 - !isfinite(lat_min) || !isfinite(lat_max) || 4.1535 - !isfinite(lon_min) || !isfinite(lon_max) 4.1536 - ) { 4.1537 - ereport(ERROR, ( 4.1538 - errcode(ERRCODE_DATA_EXCEPTION), 4.1539 - errmsg("ebox requires finite coordinates") 4.1540 - )); 4.1541 - } 4.1542 - /* check latitude bounds */ 4.1543 - if (lat_max < -90) { 4.1544 - ereport(WARNING, (errmsg("northern latitude exceeds south pole"))); 4.1545 - lat_max = -90; 4.1546 - } else if (lat_max > 90) { 4.1547 - ereport(WARNING, (errmsg("northern latitude exceeds north pole"))); 4.1548 - lat_max = 90; 4.1549 - } 4.1550 - if (lat_min < -90) { 4.1551 - ereport(WARNING, (errmsg("southern latitude exceeds south pole"))); 4.1552 - lat_min = -90; 4.1553 - } else if (lat_min > 90) { 4.1554 - ereport(WARNING, (errmsg("southern latitude exceeds north pole"))); 4.1555 - lat_min = 90; 4.1556 - } 4.1557 - /* check if all longitudes are included */ 4.1558 - if (lon_max - lon_min >= 360) { 4.1559 - if (lon_max - lon_min > 360) ereport(WARNING, ( 4.1560 - errmsg("longitude coverage greater than 360 degrees") 4.1561 - )); 4.1562 - lon_min = -180; 4.1563 - lon_max = 180; 4.1564 - } else { 4.1565 - /* normalize longitude bounds */ 4.1566 - if (lon_min < -180) lon_min += 360 - trunc(lon_min / 360) * 360; 4.1567 - else if (lon_min > 180) lon_min -= 360 + trunc(lon_min / 360) * 360; 4.1568 - if (lon_max < -180) lon_max += 360 - trunc(lon_max / 360) * 360; 4.1569 - else if (lon_max > 180) lon_max -= 360 + trunc(lon_max / 360) * 360; 4.1570 - } 4.1571 - /* store rounded latitude/longitude values for round-trip safety */ 4.1572 - box->lat_min = pgl_round(lat_min); 4.1573 - box->lat_max = pgl_round(lat_max); 4.1574 - box->lon_min = pgl_round(lon_min); 4.1575 - box->lon_max = pgl_round(lon_max); 4.1576 - /* ensure that rounding does not change orientation */ 4.1577 - if (lon_min > lon_max && box->lon_min == box->lon_max) { 4.1578 - box->lon_min = -180; 4.1579 - box->lon_max = 180; 4.1580 - } 4.1581 -} 4.1582 - 4.1583 -/* create box ("ebox" in SQL) from min/max latitude and min/max longitude */ 4.1584 -PG_FUNCTION_INFO_V1(pgl_create_ebox); 4.1585 -Datum pgl_create_ebox(PG_FUNCTION_ARGS) { 4.1586 - pgl_box *box = (pgl_box *)palloc(sizeof(pgl_box)); 4.1587 - pgl_ebox_set_boundaries( 4.1588 - box, 4.1589 - PG_GETARG_FLOAT8(0), PG_GETARG_FLOAT8(1), 4.1590 - PG_GETARG_FLOAT8(2), PG_GETARG_FLOAT8(3) 4.1591 - ); 4.1592 - PG_RETURN_POINTER(box); 4.1593 -} 4.1594 - 4.1595 -/* create box ("ebox" in SQL) from two points ("epoint"s) */ 4.1596 -/* (can not be used to cover a longitude range of more than 120 degrees) */ 4.1597 -PG_FUNCTION_INFO_V1(pgl_create_ebox_from_epoints); 4.1598 -Datum pgl_create_ebox_from_epoints(PG_FUNCTION_ARGS) { 4.1599 - pgl_point *point1 = (pgl_point *)PG_GETARG_POINTER(0); 4.1600 - pgl_point *point2 = (pgl_point *)PG_GETARG_POINTER(1); 4.1601 - pgl_box *box = (pgl_box *)palloc(sizeof(pgl_box)); 4.1602 - double lat_min, lat_max, lon_min, lon_max; 4.1603 - double dlon; /* longitude range (delta longitude) */ 4.1604 - /* order latitude and longitude boundaries */ 4.1605 - if (point2->lat < point1->lat) { 4.1606 - lat_min = point2->lat; 4.1607 - lat_max = point1->lat; 4.1608 - } else { 4.1609 - lat_min = point1->lat; 4.1610 - lat_max = point2->lat; 4.1611 - } 4.1612 - if (point2->lon < point1->lon) { 4.1613 - lon_min = point2->lon; 4.1614 - lon_max = point1->lon; 4.1615 - } else { 4.1616 - lon_min = point1->lon; 4.1617 - lon_max = point2->lon; 4.1618 - } 4.1619 - /* calculate longitude range (round to avoid floating point errors) */ 4.1620 - dlon = pgl_round(lon_max - lon_min); 4.1621 - /* determine east-west direction */ 4.1622 - if (dlon >= 240) { 4.1623 - /* assume that 180th meridian is crossed and swap min/max longitude */ 4.1624 - double swap = lon_min; lon_min = lon_max; lon_max = swap; 4.1625 - } else if (dlon > 120) { 4.1626 - /* unclear orientation since delta longitude > 120 */ 4.1627 - ereport(ERROR, ( 4.1628 - errcode(ERRCODE_DATA_EXCEPTION), 4.1629 - errmsg("can not determine east/west orientation for ebox") 4.1630 - )); 4.1631 - } 4.1632 - /* use boundaries to setup box (and perform checks) */ 4.1633 - pgl_ebox_set_boundaries(box, lat_min, lat_max, lon_min, lon_max); 4.1634 - /* return result */ 4.1635 - PG_RETURN_POINTER(box); 4.1636 -} 4.1637 - 4.1638 -/* parse box ("ebox" in SQL) */ 4.1639 -/* format: '[NS]<float> [EW]<float> [NS]<float> [EW]<float>' 4.1640 - or: '[NS]<float> [NS]<float> [EW]<float> [EW]<float>' */ 4.1641 -PG_FUNCTION_INFO_V1(pgl_ebox_in); 4.1642 -Datum pgl_ebox_in(PG_FUNCTION_ARGS) { 4.1643 - char *str = PG_GETARG_CSTRING(0); /* input string */ 4.1644 - char *str_lower; /* lower case version of input string */ 4.1645 - char *strptr; /* current position within string */ 4.1646 - int valid; /* number of valid chars */ 4.1647 - int done; /* specifies if latitude or longitude was read */ 4.1648 - double val; /* temporary variable */ 4.1649 - int lat_count = 0; /* count of latitude values parsed */ 4.1650 - int lon_count = 0; /* count of longitufde values parsed */ 4.1651 - double lat_min, lat_max, lon_min, lon_max; /* see pgl_box struct */ 4.1652 - pgl_box *box; /* return value (to be palloc'ed) */ 4.1653 - /* lowercase input */ 4.1654 - str_lower = psprintf("%s", str); 4.1655 - for (strptr=str_lower; *strptr; strptr++) { 4.1656 - if (*strptr >= 'A' && *strptr <= 'Z') *strptr += 'a' - 'A'; 4.1657 - } 4.1658 - /* reset reading position to start of (lowercase) string */ 4.1659 - strptr = str_lower; 4.1660 - /* check if empty box */ 4.1661 - valid = 0; 4.1662 - sscanf(strptr, " empty %n", &valid); 4.1663 - if (valid && strptr[valid] == 0) { 4.1664 - /* allocate and return empty box */ 4.1665 - box = (pgl_box *)palloc(sizeof(pgl_box)); 4.1666 - pgl_box_set_empty(box); 4.1667 - PG_RETURN_POINTER(box); 4.1668 - } 4.1669 - /* demand four blocks separated by whitespace */ 4.1670 - valid = 0; 4.1671 - sscanf(strptr, " %*s %*s %*s %*s %n", &valid); 4.1672 - /* if four blocks separated by whitespace exist, parse those blocks */ 4.1673 - if (strptr[valid] == 0) while (strptr[0]) { 4.1674 - /* parse either latitude or longitude (whichever found in input string) */ 4.1675 - done = pgl_scan(&strptr, &val, &val); 4.1676 - /* store latitude or longitude in lat_min, lat_max, lon_min, or lon_max */ 4.1677 - if (done == PGL_SCAN_LAT) { 4.1678 - if (!lat_count) lat_min = val; else lat_max = val; 4.1679 - lat_count++; 4.1680 - } else if (done == PGL_SCAN_LON) { 4.1681 - if (!lon_count) lon_min = val; else lon_max = val; 4.1682 - lon_count++; 4.1683 - } else { 4.1684 - break; 4.1685 - } 4.1686 - } 4.1687 - /* require end of string, and two latitude and two longitude values */ 4.1688 - if (strptr[0] || lat_count != 2 || lon_count != 2) { 4.1689 - ereport(ERROR, ( 4.1690 - errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 4.1691 - errmsg("invalid input syntax for type ebox: \"%s\"", str) 4.1692 - )); 4.1693 - } 4.1694 - /* free lower case string */ 4.1695 - pfree(str_lower); 4.1696 - /* order boundaries (maximum greater than minimum) */ 4.1697 - if (lat_min > lat_max) { val = lat_min; lat_min = lat_max; lat_max = val; } 4.1698 - if (lon_min > lon_max) { val = lon_min; lon_min = lon_max; lon_max = val; } 4.1699 - /* allocate memory for result */ 4.1700 - box = (pgl_box *)palloc(sizeof(pgl_box)); 4.1701 - /* set boundaries (and perform checks) */ 4.1702 - pgl_ebox_set_boundaries(box, lat_min, lat_max, lon_min, lon_max); 4.1703 - /* return result */ 4.1704 - PG_RETURN_POINTER(box); 4.1705 -} 4.1706 - 4.1707 -/* set circle to given latitude, longitude, and radius (including checks) */ 4.1708 -static void pgl_ecircle_set_latlon_radius( 4.1709 - pgl_circle *circle, double lat, double lon, double radius 4.1710 -) { 4.1711 - /* set center point (including checks) */ 4.1712 - pgl_epoint_set_latlon(&(circle->center), lat, lon); 4.1713 - /* handle non-positive radius */ 4.1714 - if (isnan(radius)) { 4.1715 - ereport(ERROR, ( 4.1716 - errcode(ERRCODE_DATA_EXCEPTION), 4.1717 - errmsg("invalid radius for ecircle") 4.1718 - )); 4.1719 - } 4.1720 - if (radius == 0) radius = 0; /* avoids -0 */ 4.1721 - else if (radius < 0) { 4.1722 - if (isfinite(radius)) { 4.1723 - ereport(NOTICE, (errmsg("negative radius converted to minus infinity"))); 4.1724 - } 4.1725 - radius = -INFINITY; 4.1726 - } 4.1727 - /* store radius (round-trip safety is ensured by pgl_print_float) */ 4.1728 - circle->radius = radius; 4.1729 -} 4.1730 - 4.1731 -/* create circle ("ecircle" in SQL) from latitude, longitude, and radius */ 4.1732 -PG_FUNCTION_INFO_V1(pgl_create_ecircle); 4.1733 -Datum pgl_create_ecircle(PG_FUNCTION_ARGS) { 4.1734 - pgl_circle *circle = (pgl_circle *)palloc(sizeof(pgl_circle)); 4.1735 - pgl_ecircle_set_latlon_radius( 4.1736 - circle, PG_GETARG_FLOAT8(0), PG_GETARG_FLOAT8(1), PG_GETARG_FLOAT8(2) 4.1737 - ); 4.1738 - PG_RETURN_POINTER(circle); 4.1739 -} 4.1740 - 4.1741 -/* create circle ("ecircle" in SQL) from point ("epoint"), and radius */ 4.1742 -PG_FUNCTION_INFO_V1(pgl_create_ecircle_from_epoint); 4.1743 -Datum pgl_create_ecircle_from_epoint(PG_FUNCTION_ARGS) { 4.1744 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 4.1745 - double radius = PG_GETARG_FLOAT8(1); 4.1746 - pgl_circle *circle = (pgl_circle *)palloc(sizeof(pgl_circle)); 4.1747 - /* set latitude, longitude, radius (and perform checks) */ 4.1748 - pgl_ecircle_set_latlon_radius(circle, point->lat, point->lon, radius); 4.1749 - /* return result */ 4.1750 - PG_RETURN_POINTER(circle); 4.1751 -} 4.1752 - 4.1753 -/* parse circle ("ecircle" in SQL) */ 4.1754 -/* format: '[NS]<float> [EW]<float> <float>' */ 4.1755 -PG_FUNCTION_INFO_V1(pgl_ecircle_in); 4.1756 -Datum pgl_ecircle_in(PG_FUNCTION_ARGS) { 4.1757 - char *str = PG_GETARG_CSTRING(0); /* input string */ 4.1758 - char *strptr = str; /* current position within string */ 4.1759 - double lat, lon, radius; /* parsed values as double precision flaots */ 4.1760 - int valid = 0; /* number of valid chars */ 4.1761 - int done = 0; /* stores if latitude and/or longitude was read */ 4.1762 - pgl_circle *circle; /* return value (to be palloc'ed) */ 4.1763 - /* demand three blocks separated by whitespace */ 4.1764 - sscanf(strptr, " %*s %*s %*s %n", &valid); 4.1765 - /* if three blocks separated by whitespace exist, parse those blocks */ 4.1766 - if (strptr[valid] == 0) { 4.1767 - /* parse latitude and longitude */ 4.1768 - done |= pgl_scan(&strptr, &lat, &lon); 4.1769 - done |= pgl_scan(&strptr, &lat, &lon); 4.1770 - /* parse radius (while incrementing strptr by number of bytes parsed) */ 4.1771 - valid = 0; 4.1772 - if (sscanf(strptr, " %lf %n", &radius, &valid) == 1) strptr += valid; 4.1773 - } 4.1774 - /* require end of string and both latitude and longitude being parsed */ 4.1775 - if (strptr[0] || done != PGL_SCAN_LATLON) { 4.1776 - ereport(ERROR, ( 4.1777 - errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 4.1778 - errmsg("invalid input syntax for type ecircle: \"%s\"", str) 4.1779 - )); 4.1780 - } 4.1781 - /* allocate memory for result */ 4.1782 - circle = (pgl_circle *)palloc(sizeof(pgl_circle)); 4.1783 - /* set latitude, longitude, radius (and perform checks) */ 4.1784 - pgl_ecircle_set_latlon_radius(circle, lat, lon, radius); 4.1785 - /* return result */ 4.1786 - PG_RETURN_POINTER(circle); 4.1787 -} 4.1788 - 4.1789 -/* parse cluster ("ecluster" in SQL) */ 4.1790 -PG_FUNCTION_INFO_V1(pgl_ecluster_in); 4.1791 -Datum pgl_ecluster_in(PG_FUNCTION_ARGS) { 4.1792 - int i; 4.1793 - char *str = PG_GETARG_CSTRING(0); /* input string */ 4.1794 - char *str_lower; /* lower case version of input string */ 4.1795 - char *strptr; /* pointer to current reading position of input */ 4.1796 - int npoints_total = 0; /* total number of points in cluster */ 4.1797 - int nentries = 0; /* total number of entries */ 4.1798 - pgl_newentry *entries; /* array of pgl_newentry to create pgl_cluster */ 4.1799 - int entries_buflen = 4; /* maximum number of elements in entries array */ 4.1800 - int valid; /* number of valid chars processed */ 4.1801 - double lat, lon; /* latitude and longitude of parsed point */ 4.1802 - int entrytype; /* current entry type */ 4.1803 - int npoints; /* number of points in current entry */ 4.1804 - pgl_point *points; /* array of pgl_point for pgl_newentry */ 4.1805 - int points_buflen; /* maximum number of elements in points array */ 4.1806 - int done; /* return value of pgl_scan function */ 4.1807 - pgl_cluster *cluster; /* created cluster */ 4.1808 - /* lowercase input */ 4.1809 - str_lower = psprintf("%s", str); 4.1810 - for (strptr=str_lower; *strptr; strptr++) { 4.1811 - if (*strptr >= 'A' && *strptr <= 'Z') *strptr += 'a' - 'A'; 4.1812 - } 4.1813 - /* reset reading position to start of (lowercase) string */ 4.1814 - strptr = str_lower; 4.1815 - /* allocate initial buffer for entries */ 4.1816 - entries = palloc(entries_buflen * sizeof(pgl_newentry)); 4.1817 - /* parse until end of string */ 4.1818 - while (strptr[0]) { 4.1819 - /* require previous white-space or closing parenthesis before next token */ 4.1820 - if (strptr != str_lower && !isspace(strptr[-1]) && strptr[-1] != ')') { 4.1821 - goto pgl_ecluster_in_error; 4.1822 - } 4.1823 - /* ignore token "empty" */ 4.1824 - valid = 0; sscanf(strptr, " empty %n", &valid); 4.1825 - if (valid) { strptr += valid; continue; } 4.1826 - /* test for "point" token */ 4.1827 - valid = 0; sscanf(strptr, " point ( %n", &valid); 4.1828 - if (valid) { 4.1829 - strptr += valid; 4.1830 - entrytype = PGL_ENTRY_POINT; 4.1831 - goto pgl_ecluster_in_type_ok; 4.1832 - } 4.1833 - /* test for "path" token */ 4.1834 - valid = 0; sscanf(strptr, " path ( %n", &valid); 4.1835 - if (valid) { 4.1836 - strptr += valid; 4.1837 - entrytype = PGL_ENTRY_PATH; 4.1838 - goto pgl_ecluster_in_type_ok; 4.1839 - } 4.1840 - /* test for "outline" token */ 4.1841 - valid = 0; sscanf(strptr, " outline ( %n", &valid); 4.1842 - if (valid) { 4.1843 - strptr += valid; 4.1844 - entrytype = PGL_ENTRY_OUTLINE; 4.1845 - goto pgl_ecluster_in_type_ok; 4.1846 - } 4.1847 - /* test for "polygon" token */ 4.1848 - valid = 0; sscanf(strptr, " polygon ( %n", &valid); 4.1849 - if (valid) { 4.1850 - strptr += valid; 4.1851 - entrytype = PGL_ENTRY_POLYGON; 4.1852 - goto pgl_ecluster_in_type_ok; 4.1853 - } 4.1854 - /* error if no valid token found */ 4.1855 - goto pgl_ecluster_in_error; 4.1856 - pgl_ecluster_in_type_ok: 4.1857 - /* check if pgl_newentry array needs to grow */ 4.1858 - if (nentries == entries_buflen) { 4.1859 - pgl_newentry *newbuf; 4.1860 - entries_buflen *= 2; 4.1861 - newbuf = palloc(entries_buflen * sizeof(pgl_newentry)); 4.1862 - memcpy(newbuf, entries, nentries * sizeof(pgl_newentry)); 4.1863 - pfree(entries); 4.1864 - entries = newbuf; 4.1865 - } 4.1866 - /* reset number of points for current entry */ 4.1867 - npoints = 0; 4.1868 - /* allocate array for points */ 4.1869 - points_buflen = 4; 4.1870 - points = palloc(points_buflen * sizeof(pgl_point)); 4.1871 - /* parse until closing parenthesis */ 4.1872 - while (strptr[0] != ')') { 4.1873 - /* error on unexpected end of string */ 4.1874 - if (strptr[0] == 0) goto pgl_ecluster_in_error; 4.1875 - /* mark neither latitude nor longitude as read */ 4.1876 - done = PGL_SCAN_NONE; 4.1877 - /* require white-space before second, third, etc. point */ 4.1878 - if (npoints != 0 && !isspace(strptr[-1])) goto pgl_ecluster_in_error; 4.1879 - /* scan latitude (or longitude) */ 4.1880 - done |= pgl_scan(&strptr, &lat, &lon); 4.1881 - /* require white-space before second coordinate */ 4.1882 - if (strptr != str && !isspace(strptr[-1])) goto pgl_ecluster_in_error; 4.1883 - /* scan longitude (or latitude) */ 4.1884 - done |= pgl_scan(&strptr, &lat, &lon); 4.1885 - /* error unless both latitude and longitude were parsed */ 4.1886 - if (done != PGL_SCAN_LATLON) goto pgl_ecluster_in_error; 4.1887 - /* throw error if number of points is too high */ 4.1888 - if (npoints_total == PGL_CLUSTER_MAXPOINTS) { 4.1889 - ereport(ERROR, ( 4.1890 - errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 4.1891 - errmsg( 4.1892 - "too many points for ecluster entry (maximum %i)", 4.1893 - PGL_CLUSTER_MAXPOINTS 4.1894 - ) 4.1895 - )); 4.1896 - } 4.1897 - /* check if pgl_point array needs to grow */ 4.1898 - if (npoints == points_buflen) { 4.1899 - pgl_point *newbuf; 4.1900 - points_buflen *= 2; 4.1901 - newbuf = palloc(points_buflen * sizeof(pgl_point)); 4.1902 - memcpy(newbuf, points, npoints * sizeof(pgl_point)); 4.1903 - pfree(points); 4.1904 - points = newbuf; 4.1905 - } 4.1906 - /* append point to pgl_point array (includes checks) */ 4.1907 - pgl_epoint_set_latlon(&(points[npoints++]), lat, lon); 4.1908 - /* increase total number of points */ 4.1909 - npoints_total++; 4.1910 - } 4.1911 - /* error if entry has no points */ 4.1912 - if (!npoints) goto pgl_ecluster_in_error; 4.1913 - /* entries with one point are automatically of type "point" */ 4.1914 - if (npoints == 1) entrytype = PGL_ENTRY_POINT; 4.1915 - /* if entries have more than one point */ 4.1916 - else { 4.1917 - /* throw error if entry type is "point" */ 4.1918 - if (entrytype == PGL_ENTRY_POINT) { 4.1919 - ereport(ERROR, ( 4.1920 - errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 4.1921 - errmsg("invalid input syntax for type ecluster (point entry with more than one point)") 4.1922 - )); 4.1923 - } 4.1924 - /* coerce outlines and polygons with more than 2 points to be a path */ 4.1925 - if (npoints == 2) entrytype = PGL_ENTRY_PATH; 4.1926 - } 4.1927 - /* append entry to pgl_newentry array */ 4.1928 - entries[nentries].entrytype = entrytype; 4.1929 - entries[nentries].npoints = npoints; 4.1930 - entries[nentries].points = points; 4.1931 - nentries++; 4.1932 - /* consume closing parenthesis */ 4.1933 - strptr++; 4.1934 - /* consume white-space */ 4.1935 - while (isspace(strptr[0])) strptr++; 4.1936 - } 4.1937 - /* free lower case string */ 4.1938 - pfree(str_lower); 4.1939 - /* create cluster from pgl_newentry array */ 4.1940 - cluster = pgl_new_cluster(nentries, entries); 4.1941 - /* free pgl_newentry array */ 4.1942 - for (i=0; i<nentries; i++) pfree(entries[i].points); 4.1943 - pfree(entries); 4.1944 - /* set bounding circle of cluster and check east/west orientation */ 4.1945 - if (!pgl_finalize_cluster(cluster)) { 4.1946 - ereport(ERROR, ( 4.1947 - errcode(ERRCODE_DATA_EXCEPTION), 4.1948 - errmsg("can not determine east/west orientation for ecluster"), 4.1949 - errhint("Ensure that each entry has a longitude span of less than 180 degrees.") 4.1950 - )); 4.1951 - } 4.1952 - /* return cluster */ 4.1953 - PG_RETURN_POINTER(cluster); 4.1954 - /* code to throw error */ 4.1955 - pgl_ecluster_in_error: 4.1956 - ereport(ERROR, ( 4.1957 - errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 4.1958 - errmsg("invalid input syntax for type ecluster: \"%s\"", str) 4.1959 - )); 4.1960 -} 4.1961 - 4.1962 -/* convert point ("epoint") to string representation */ 4.1963 -PG_FUNCTION_INFO_V1(pgl_epoint_out); 4.1964 -Datum pgl_epoint_out(PG_FUNCTION_ARGS) { 4.1965 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 4.1966 - char latstr[PGL_NUMBUFLEN]; 4.1967 - char lonstr[PGL_NUMBUFLEN]; 4.1968 - pgl_print_lat(latstr, point->lat); 4.1969 - pgl_print_lon(lonstr, point->lon); 4.1970 - PG_RETURN_CSTRING(psprintf("%s %s", latstr, lonstr)); 4.1971 -} 4.1972 - 4.1973 -/* convert box ("ebox") to string representation */ 4.1974 -PG_FUNCTION_INFO_V1(pgl_ebox_out); 4.1975 -Datum pgl_ebox_out(PG_FUNCTION_ARGS) { 4.1976 - pgl_box *box = (pgl_box *)PG_GETARG_POINTER(0); 4.1977 - double lon_min = box->lon_min; 4.1978 - double lon_max = box->lon_max; 4.1979 - char lat_min_str[PGL_NUMBUFLEN]; 4.1980 - char lat_max_str[PGL_NUMBUFLEN]; 4.1981 - char lon_min_str[PGL_NUMBUFLEN]; 4.1982 - char lon_max_str[PGL_NUMBUFLEN]; 4.1983 - /* return string "empty" if box is set to be empty */ 4.1984 - if (box->lat_min > box->lat_max) PG_RETURN_CSTRING("empty"); 4.1985 - /* use boundaries exceeding W180 or E180 if 180th meridian is enclosed */ 4.1986 - /* (required since pgl_box_in orders the longitude boundaries) */ 4.1987 - if (lon_min > lon_max) { 4.1988 - if (lon_min + lon_max >= 0) lon_min -= 360; 4.1989 - else lon_max += 360; 4.1990 - } 4.1991 - /* format and return result */ 4.1992 - pgl_print_lat(lat_min_str, box->lat_min); 4.1993 - pgl_print_lat(lat_max_str, box->lat_max); 4.1994 - pgl_print_lon(lon_min_str, lon_min); 4.1995 - pgl_print_lon(lon_max_str, lon_max); 4.1996 - PG_RETURN_CSTRING(psprintf( 4.1997 - "%s %s %s %s", 4.1998 - lat_min_str, lon_min_str, lat_max_str, lon_max_str 4.1999 - )); 4.2000 -} 4.2001 - 4.2002 -/* convert circle ("ecircle") to string representation */ 4.2003 -PG_FUNCTION_INFO_V1(pgl_ecircle_out); 4.2004 -Datum pgl_ecircle_out(PG_FUNCTION_ARGS) { 4.2005 - pgl_circle *circle = (pgl_circle *)PG_GETARG_POINTER(0); 4.2006 - char latstr[PGL_NUMBUFLEN]; 4.2007 - char lonstr[PGL_NUMBUFLEN]; 4.2008 - char radstr[PGL_NUMBUFLEN]; 4.2009 - pgl_print_lat(latstr, circle->center.lat); 4.2010 - pgl_print_lon(lonstr, circle->center.lon); 4.2011 - pgl_print_float(radstr, circle->radius); 4.2012 - PG_RETURN_CSTRING(psprintf("%s %s %s", latstr, lonstr, radstr)); 4.2013 -} 4.2014 - 4.2015 -/* convert cluster ("ecluster") to string representation */ 4.2016 -PG_FUNCTION_INFO_V1(pgl_ecluster_out); 4.2017 -Datum pgl_ecluster_out(PG_FUNCTION_ARGS) { 4.2018 - pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); 4.2019 - char latstr[PGL_NUMBUFLEN]; /* string buffer for latitude */ 4.2020 - char lonstr[PGL_NUMBUFLEN]; /* string buffer for longitude */ 4.2021 - char ***strings; /* array of array of strings */ 4.2022 - char *string; /* string of current token */ 4.2023 - char *res, *resptr; /* result and pointer to current write position */ 4.2024 - size_t reslen = 1; /* length of result (init with 1 for terminator) */ 4.2025 - int npoints; /* number of points of current entry */ 4.2026 - int i, j; /* i: entry, j: point in entry */ 4.2027 - /* handle empty clusters */ 4.2028 - if (cluster->nentries == 0) { 4.2029 - /* free detoasted cluster (if copy) */ 4.2030 - PG_FREE_IF_COPY(cluster, 0); 4.2031 - /* return static result */ 4.2032 - PG_RETURN_CSTRING("empty"); 4.2033 - } 4.2034 - /* allocate array of array of strings */ 4.2035 - strings = palloc(cluster->nentries * sizeof(char **)); 4.2036 - /* iterate over all entries in cluster */ 4.2037 - for (i=0; i<cluster->nentries; i++) { 4.2038 - /* get number of points in entry */ 4.2039 - npoints = cluster->entries[i].npoints; 4.2040 - /* allocate array of strings (one string for each point plus two extra) */ 4.2041 - strings[i] = palloc((2 + npoints) * sizeof(char *)); 4.2042 - /* determine opening string */ 4.2043 - switch (cluster->entries[i].entrytype) { 4.2044 - case PGL_ENTRY_POINT: string = (i==0)?"point (" :" point ("; break; 4.2045 - case PGL_ENTRY_PATH: string = (i==0)?"path (" :" path ("; break; 4.2046 - case PGL_ENTRY_OUTLINE: string = (i==0)?"outline (":" outline ("; break; 4.2047 - case PGL_ENTRY_POLYGON: string = (i==0)?"polygon (":" polygon ("; break; 4.2048 - default: string = (i==0)?"unknown" :" unknown"; 4.2049 - } 4.2050 - /* use opening string as first string in array */ 4.2051 - strings[i][0] = string; 4.2052 - /* update result length (for allocating result string later) */ 4.2053 - reslen += strlen(string); 4.2054 - /* iterate over all points */ 4.2055 - for (j=0; j<npoints; j++) { 4.2056 - /* create string representation of point */ 4.2057 - pgl_print_lat(latstr, PGL_ENTRY_POINTS(cluster, i)[j].lat); 4.2058 - pgl_print_lon(lonstr, PGL_ENTRY_POINTS(cluster, i)[j].lon); 4.2059 - string = psprintf((j == 0) ? "%s %s" : " %s %s", latstr, lonstr); 4.2060 - /* copy string pointer to string array */ 4.2061 - strings[i][j+1] = string; 4.2062 - /* update result length (for allocating result string later) */ 4.2063 - reslen += strlen(string); 4.2064 - } 4.2065 - /* use closing parenthesis as last string in array */ 4.2066 - strings[i][npoints+1] = ")"; 4.2067 - /* update result length (for allocating result string later) */ 4.2068 - reslen++; 4.2069 - } 4.2070 - /* allocate result string */ 4.2071 - res = palloc(reslen); 4.2072 - /* set write pointer to begin of result string */ 4.2073 - resptr = res; 4.2074 - /* copy strings into result string */ 4.2075 - for (i=0; i<cluster->nentries; i++) { 4.2076 - npoints = cluster->entries[i].npoints; 4.2077 - for (j=0; j<npoints+2; j++) { 4.2078 - string = strings[i][j]; 4.2079 - strcpy(resptr, string); 4.2080 - resptr += strlen(string); 4.2081 - /* free strings allocated by psprintf */ 4.2082 - if (j != 0 && j != npoints+1) pfree(string); 4.2083 - } 4.2084 - /* free array of strings */ 4.2085 - pfree(strings[i]); 4.2086 - } 4.2087 - /* free array of array of strings */ 4.2088 - pfree(strings); 4.2089 - /* free detoasted cluster (if copy) */ 4.2090 - PG_FREE_IF_COPY(cluster, 0); 4.2091 - /* return result */ 4.2092 - PG_RETURN_CSTRING(res); 4.2093 -} 4.2094 - 4.2095 -/* binary input function for point ("epoint") */ 4.2096 -PG_FUNCTION_INFO_V1(pgl_epoint_recv); 4.2097 -Datum pgl_epoint_recv(PG_FUNCTION_ARGS) { 4.2098 - StringInfo buf = (StringInfo)PG_GETARG_POINTER(0); 4.2099 - pgl_point *point = (pgl_point *)palloc(sizeof(pgl_point)); 4.2100 - point->lat = pq_getmsgfloat8(buf); 4.2101 - point->lon = pq_getmsgfloat8(buf); 4.2102 - PG_RETURN_POINTER(point); 4.2103 -} 4.2104 - 4.2105 -/* binary input function for box ("ebox") */ 4.2106 -PG_FUNCTION_INFO_V1(pgl_ebox_recv); 4.2107 -Datum pgl_ebox_recv(PG_FUNCTION_ARGS) { 4.2108 - StringInfo buf = (StringInfo)PG_GETARG_POINTER(0); 4.2109 - pgl_box *box = (pgl_box *)palloc(sizeof(pgl_box)); 4.2110 - box->lat_min = pq_getmsgfloat8(buf); 4.2111 - box->lat_max = pq_getmsgfloat8(buf); 4.2112 - box->lon_min = pq_getmsgfloat8(buf); 4.2113 - box->lon_max = pq_getmsgfloat8(buf); 4.2114 - PG_RETURN_POINTER(box); 4.2115 -} 4.2116 - 4.2117 -/* binary input function for circle ("ecircle") */ 4.2118 -PG_FUNCTION_INFO_V1(pgl_ecircle_recv); 4.2119 -Datum pgl_ecircle_recv(PG_FUNCTION_ARGS) { 4.2120 - StringInfo buf = (StringInfo)PG_GETARG_POINTER(0); 4.2121 - pgl_circle *circle = (pgl_circle *)palloc(sizeof(pgl_circle)); 4.2122 - circle->center.lat = pq_getmsgfloat8(buf); 4.2123 - circle->center.lon = pq_getmsgfloat8(buf); 4.2124 - circle->radius = pq_getmsgfloat8(buf); 4.2125 - PG_RETURN_POINTER(circle); 4.2126 -} 4.2127 - 4.2128 -/* TODO: binary receive function for cluster */ 4.2129 - 4.2130 -/* binary output function for point ("epoint") */ 4.2131 -PG_FUNCTION_INFO_V1(pgl_epoint_send); 4.2132 -Datum pgl_epoint_send(PG_FUNCTION_ARGS) { 4.2133 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 4.2134 - StringInfoData buf; 4.2135 - pq_begintypsend(&buf); 4.2136 - pq_sendfloat8(&buf, point->lat); 4.2137 - pq_sendfloat8(&buf, point->lon); 4.2138 - PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); 4.2139 -} 4.2140 - 4.2141 -/* binary output function for box ("ebox") */ 4.2142 -PG_FUNCTION_INFO_V1(pgl_ebox_send); 4.2143 -Datum pgl_ebox_send(PG_FUNCTION_ARGS) { 4.2144 - pgl_box *box = (pgl_box *)PG_GETARG_POINTER(0); 4.2145 - StringInfoData buf; 4.2146 - pq_begintypsend(&buf); 4.2147 - pq_sendfloat8(&buf, box->lat_min); 4.2148 - pq_sendfloat8(&buf, box->lat_max); 4.2149 - pq_sendfloat8(&buf, box->lon_min); 4.2150 - pq_sendfloat8(&buf, box->lon_max); 4.2151 - PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); 4.2152 -} 4.2153 - 4.2154 -/* binary output function for circle ("ecircle") */ 4.2155 -PG_FUNCTION_INFO_V1(pgl_ecircle_send); 4.2156 -Datum pgl_ecircle_send(PG_FUNCTION_ARGS) { 4.2157 - pgl_circle *circle = (pgl_circle *)PG_GETARG_POINTER(0); 4.2158 - StringInfoData buf; 4.2159 - pq_begintypsend(&buf); 4.2160 - pq_sendfloat8(&buf, circle->center.lat); 4.2161 - pq_sendfloat8(&buf, circle->center.lon); 4.2162 - pq_sendfloat8(&buf, circle->radius); 4.2163 - PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); 4.2164 -} 4.2165 - 4.2166 -/* TODO: binary send functions for cluster */ 4.2167 - 4.2168 -/* cast point ("epoint") to box ("ebox") */ 4.2169 -PG_FUNCTION_INFO_V1(pgl_epoint_to_ebox); 4.2170 -Datum pgl_epoint_to_ebox(PG_FUNCTION_ARGS) { 4.2171 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 4.2172 - pgl_box *box = palloc(sizeof(pgl_box)); 4.2173 - box->lat_min = point->lat; 4.2174 - box->lat_max = point->lat; 4.2175 - box->lon_min = point->lon; 4.2176 - box->lon_max = point->lon; 4.2177 - PG_RETURN_POINTER(box); 4.2178 -} 4.2179 - 4.2180 -/* cast point ("epoint") to circle ("ecircle") */ 4.2181 -PG_FUNCTION_INFO_V1(pgl_epoint_to_ecircle); 4.2182 -Datum pgl_epoint_to_ecircle(PG_FUNCTION_ARGS) { 4.2183 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 4.2184 - pgl_circle *circle = palloc(sizeof(pgl_box)); 4.2185 - circle->center = *point; 4.2186 - circle->radius = 0; 4.2187 - PG_RETURN_POINTER(circle); 4.2188 -} 4.2189 - 4.2190 -/* cast point ("epoint") to cluster ("ecluster") */ 4.2191 -PG_FUNCTION_INFO_V1(pgl_epoint_to_ecluster); 4.2192 -Datum pgl_epoint_to_ecluster(PG_FUNCTION_ARGS) { 4.2193 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 4.2194 - pgl_newentry entry; 4.2195 - entry.entrytype = PGL_ENTRY_POINT; 4.2196 - entry.npoints = 1; 4.2197 - entry.points = point; 4.2198 - PG_RETURN_POINTER(pgl_new_cluster(1, &entry)); 4.2199 -} 4.2200 - 4.2201 -/* cast box ("ebox") to cluster ("ecluster") */ 4.2202 -#define pgl_ebox_to_ecluster_macro(i, a, b) \ 4.2203 - entries[i].entrytype = PGL_ENTRY_POLYGON; \ 4.2204 - entries[i].npoints = 4; \ 4.2205 - entries[i].points = points[i]; \ 4.2206 - points[i][0].lat = box->lat_min; \ 4.2207 - points[i][0].lon = (a); \ 4.2208 - points[i][1].lat = box->lat_min; \ 4.2209 - points[i][1].lon = (b); \ 4.2210 - points[i][2].lat = box->lat_max; \ 4.2211 - points[i][2].lon = (b); \ 4.2212 - points[i][3].lat = box->lat_max; \ 4.2213 - points[i][3].lon = (a); 4.2214 -PG_FUNCTION_INFO_V1(pgl_ebox_to_ecluster); 4.2215 -Datum pgl_ebox_to_ecluster(PG_FUNCTION_ARGS) { 4.2216 - pgl_box *box = (pgl_box *)PG_GETARG_POINTER(0); 4.2217 - double lon, dlon; 4.2218 - int nentries; 4.2219 - pgl_newentry entries[3]; 4.2220 - pgl_point points[3][4]; 4.2221 - if (box->lat_min > box->lat_max) { 4.2222 - nentries = 0; 4.2223 - } else if (box->lon_min > box->lon_max) { 4.2224 - if (box->lon_min < 0) { 4.2225 - lon = pgl_round((box->lon_min + 180) / 2.0); 4.2226 - nentries = 3; 4.2227 - pgl_ebox_to_ecluster_macro(0, box->lon_min, lon); 4.2228 - pgl_ebox_to_ecluster_macro(1, lon, 180); 4.2229 - pgl_ebox_to_ecluster_macro(2, -180, box->lon_max); 4.2230 - } else if (box->lon_max > 0) { 4.2231 - lon = pgl_round((box->lon_max - 180) / 2.0); 4.2232 - nentries = 3; 4.2233 - pgl_ebox_to_ecluster_macro(0, box->lon_min, 180); 4.2234 - pgl_ebox_to_ecluster_macro(1, -180, lon); 4.2235 - pgl_ebox_to_ecluster_macro(2, lon, box->lon_max); 4.2236 - } else { 4.2237 - nentries = 2; 4.2238 - pgl_ebox_to_ecluster_macro(0, box->lon_min, 180); 4.2239 - pgl_ebox_to_ecluster_macro(1, -180, box->lon_max); 4.2240 - } 4.2241 - } else { 4.2242 - dlon = pgl_round(box->lon_max - box->lon_min); 4.2243 - if (dlon < 180) { 4.2244 - nentries = 1; 4.2245 - pgl_ebox_to_ecluster_macro(0, box->lon_min, box->lon_max); 4.2246 - } else { 4.2247 - lon = pgl_round((box->lon_min + box->lon_max) / 2.0); 4.2248 - if ( 4.2249 - pgl_round(lon - box->lon_min) < 180 && 4.2250 - pgl_round(box->lon_max - lon) < 180 4.2251 - ) { 4.2252 - nentries = 2; 4.2253 - pgl_ebox_to_ecluster_macro(0, box->lon_min, lon); 4.2254 - pgl_ebox_to_ecluster_macro(1, lon, box->lon_max); 4.2255 - } else { 4.2256 - nentries = 3; 4.2257 - pgl_ebox_to_ecluster_macro(0, box->lon_min, -60); 4.2258 - pgl_ebox_to_ecluster_macro(1, -60, 60); 4.2259 - pgl_ebox_to_ecluster_macro(2, 60, box->lon_max); 4.2260 - } 4.2261 - } 4.2262 - } 4.2263 - PG_RETURN_POINTER(pgl_new_cluster(nentries, entries)); 4.2264 -} 4.2265 - 4.2266 -/* extract latitude from point ("epoint") */ 4.2267 -PG_FUNCTION_INFO_V1(pgl_epoint_lat); 4.2268 -Datum pgl_epoint_lat(PG_FUNCTION_ARGS) { 4.2269 - PG_RETURN_FLOAT8(((pgl_point *)PG_GETARG_POINTER(0))->lat); 4.2270 -} 4.2271 - 4.2272 -/* extract longitude from point ("epoint") */ 4.2273 -PG_FUNCTION_INFO_V1(pgl_epoint_lon); 4.2274 -Datum pgl_epoint_lon(PG_FUNCTION_ARGS) { 4.2275 - PG_RETURN_FLOAT8(((pgl_point *)PG_GETARG_POINTER(0))->lon); 4.2276 -} 4.2277 - 4.2278 -/* extract minimum latitude from box ("ebox") */ 4.2279 -PG_FUNCTION_INFO_V1(pgl_ebox_lat_min); 4.2280 -Datum pgl_ebox_lat_min(PG_FUNCTION_ARGS) { 4.2281 - PG_RETURN_FLOAT8(((pgl_box *)PG_GETARG_POINTER(0))->lat_min); 4.2282 -} 4.2283 - 4.2284 -/* extract maximum latitude from box ("ebox") */ 4.2285 -PG_FUNCTION_INFO_V1(pgl_ebox_lat_max); 4.2286 -Datum pgl_ebox_lat_max(PG_FUNCTION_ARGS) { 4.2287 - PG_RETURN_FLOAT8(((pgl_box *)PG_GETARG_POINTER(0))->lat_max); 4.2288 -} 4.2289 - 4.2290 -/* extract minimum longitude from box ("ebox") */ 4.2291 -PG_FUNCTION_INFO_V1(pgl_ebox_lon_min); 4.2292 -Datum pgl_ebox_lon_min(PG_FUNCTION_ARGS) { 4.2293 - PG_RETURN_FLOAT8(((pgl_box *)PG_GETARG_POINTER(0))->lon_min); 4.2294 -} 4.2295 - 4.2296 -/* extract maximum longitude from box ("ebox") */ 4.2297 -PG_FUNCTION_INFO_V1(pgl_ebox_lon_max); 4.2298 -Datum pgl_ebox_lon_max(PG_FUNCTION_ARGS) { 4.2299 - PG_RETURN_FLOAT8(((pgl_box *)PG_GETARG_POINTER(0))->lon_max); 4.2300 -} 4.2301 - 4.2302 -/* extract center point from circle ("ecircle") */ 4.2303 -PG_FUNCTION_INFO_V1(pgl_ecircle_center); 4.2304 -Datum pgl_ecircle_center(PG_FUNCTION_ARGS) { 4.2305 - PG_RETURN_POINTER(&(((pgl_circle *)PG_GETARG_POINTER(0))->center)); 4.2306 -} 4.2307 - 4.2308 -/* extract radius from circle ("ecircle") */ 4.2309 -PG_FUNCTION_INFO_V1(pgl_ecircle_radius); 4.2310 -Datum pgl_ecircle_radius(PG_FUNCTION_ARGS) { 4.2311 - PG_RETURN_FLOAT8(((pgl_circle *)PG_GETARG_POINTER(0))->radius); 4.2312 -} 4.2313 - 4.2314 -/* check if point is inside box (overlap operator "&&") in SQL */ 4.2315 -PG_FUNCTION_INFO_V1(pgl_epoint_ebox_overlap); 4.2316 -Datum pgl_epoint_ebox_overlap(PG_FUNCTION_ARGS) { 4.2317 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 4.2318 - pgl_box *box = (pgl_box *)PG_GETARG_POINTER(1); 4.2319 - PG_RETURN_BOOL(pgl_point_in_box(point, box)); 4.2320 -} 4.2321 - 4.2322 -/* check if point is inside circle (overlap operator "&&") in SQL */ 4.2323 -PG_FUNCTION_INFO_V1(pgl_epoint_ecircle_overlap); 4.2324 -Datum pgl_epoint_ecircle_overlap(PG_FUNCTION_ARGS) { 4.2325 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 4.2326 - pgl_circle *circle = (pgl_circle *)PG_GETARG_POINTER(1); 4.2327 - PG_RETURN_BOOL( 4.2328 - pgl_distance( 4.2329 - point->lat, point->lon, 4.2330 - circle->center.lat, circle->center.lon 4.2331 - ) <= circle->radius 4.2332 - ); 4.2333 -} 4.2334 - 4.2335 -/* check if point is inside cluster (overlap operator "&&") in SQL */ 4.2336 -PG_FUNCTION_INFO_V1(pgl_epoint_ecluster_overlap); 4.2337 -Datum pgl_epoint_ecluster_overlap(PG_FUNCTION_ARGS) { 4.2338 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 4.2339 - pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 4.2340 - bool retval; 4.2341 - /* points outside bounding circle are always assumed to be non-overlapping 4.2342 - (necessary for consistent table and index scans) */ 4.2343 - if ( 4.2344 - pgl_distance( 4.2345 - point->lat, point->lon, 4.2346 - cluster->bounding.center.lat, cluster->bounding.center.lon 4.2347 - ) > cluster->bounding.radius 4.2348 - ) retval = false; 4.2349 - else retval = pgl_point_in_cluster(point, cluster); 4.2350 - PG_FREE_IF_COPY(cluster, 1); 4.2351 - PG_RETURN_BOOL(retval); 4.2352 -} 4.2353 - 4.2354 -/* check if point may be inside cluster (lossy overl. operator "&&+") in SQL */ 4.2355 -PG_FUNCTION_INFO_V1(pgl_epoint_ecluster_may_overlap); 4.2356 -Datum pgl_epoint_ecluster_may_overlap(PG_FUNCTION_ARGS) { 4.2357 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 4.2358 - pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 4.2359 - bool retval = pgl_distance( 4.2360 - point->lat, point->lon, 4.2361 - cluster->bounding.center.lat, cluster->bounding.center.lon 4.2362 - ) <= cluster->bounding.radius; 4.2363 - PG_FREE_IF_COPY(cluster, 1); 4.2364 - PG_RETURN_BOOL(retval); 4.2365 -} 4.2366 - 4.2367 -/* check if two boxes overlap (overlap operator "&&") in SQL */ 4.2368 -PG_FUNCTION_INFO_V1(pgl_ebox_overlap); 4.2369 -Datum pgl_ebox_overlap(PG_FUNCTION_ARGS) { 4.2370 - pgl_box *box1 = (pgl_box *)PG_GETARG_POINTER(0); 4.2371 - pgl_box *box2 = (pgl_box *)PG_GETARG_POINTER(1); 4.2372 - PG_RETURN_BOOL(pgl_boxes_overlap(box1, box2)); 4.2373 -} 4.2374 - 4.2375 -/* check if box and circle may overlap (lossy overl. operator "&&+") in SQL */ 4.2376 -PG_FUNCTION_INFO_V1(pgl_ebox_ecircle_may_overlap); 4.2377 -Datum pgl_ebox_ecircle_may_overlap(PG_FUNCTION_ARGS) { 4.2378 - pgl_box *box = (pgl_box *)PG_GETARG_POINTER(0); 4.2379 - pgl_circle *circle = (pgl_circle *)PG_GETARG_POINTER(1); 4.2380 - PG_RETURN_BOOL( 4.2381 - pgl_estimate_point_box_distance(&circle->center, box) <= circle->radius 4.2382 - ); 4.2383 -} 4.2384 - 4.2385 -/* check if box and cluster may overlap (lossy overl. operator "&&+") in SQL */ 4.2386 -PG_FUNCTION_INFO_V1(pgl_ebox_ecluster_may_overlap); 4.2387 -Datum pgl_ebox_ecluster_may_overlap(PG_FUNCTION_ARGS) { 4.2388 - pgl_box *box = (pgl_box *)PG_GETARG_POINTER(0); 4.2389 - pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 4.2390 - bool retval = pgl_estimate_point_box_distance( 4.2391 - &cluster->bounding.center, 4.2392 - box 4.2393 - ) <= cluster->bounding.radius; 4.2394 - PG_FREE_IF_COPY(cluster, 1); 4.2395 - PG_RETURN_BOOL(retval); 4.2396 -} 4.2397 - 4.2398 -/* check if two circles overlap (overlap operator "&&") in SQL */ 4.2399 -PG_FUNCTION_INFO_V1(pgl_ecircle_overlap); 4.2400 -Datum pgl_ecircle_overlap(PG_FUNCTION_ARGS) { 4.2401 - pgl_circle *circle1 = (pgl_circle *)PG_GETARG_POINTER(0); 4.2402 - pgl_circle *circle2 = (pgl_circle *)PG_GETARG_POINTER(1); 4.2403 - PG_RETURN_BOOL( 4.2404 - pgl_distance( 4.2405 - circle1->center.lat, circle1->center.lon, 4.2406 - circle2->center.lat, circle2->center.lon 4.2407 - ) <= circle1->radius + circle2->radius 4.2408 - ); 4.2409 -} 4.2410 - 4.2411 -/* check if circle and cluster overlap (overlap operator "&&") in SQL */ 4.2412 -PG_FUNCTION_INFO_V1(pgl_ecircle_ecluster_overlap); 4.2413 -Datum pgl_ecircle_ecluster_overlap(PG_FUNCTION_ARGS) { 4.2414 - pgl_circle *circle = (pgl_circle *)PG_GETARG_POINTER(0); 4.2415 - pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 4.2416 - bool retval = ( 4.2417 - pgl_point_cluster_distance(&(circle->center), cluster) <= circle->radius 4.2418 - ); 4.2419 - PG_FREE_IF_COPY(cluster, 1); 4.2420 - PG_RETURN_BOOL(retval); 4.2421 -} 4.2422 - 4.2423 -/* check if circle and cluster may overlap (l. ov. operator "&&+") in SQL */ 4.2424 -PG_FUNCTION_INFO_V1(pgl_ecircle_ecluster_may_overlap); 4.2425 -Datum pgl_ecircle_ecluster_may_overlap(PG_FUNCTION_ARGS) { 4.2426 - pgl_circle *circle = (pgl_circle *)PG_GETARG_POINTER(0); 4.2427 - pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 4.2428 - bool retval = pgl_distance( 4.2429 - circle->center.lat, circle->center.lon, 4.2430 - cluster->bounding.center.lat, cluster->bounding.center.lon 4.2431 - ) <= circle->radius + cluster->bounding.radius; 4.2432 - PG_FREE_IF_COPY(cluster, 1); 4.2433 - PG_RETURN_BOOL(retval); 4.2434 -} 4.2435 - 4.2436 -/* check if two clusters overlap (overlap operator "&&") in SQL */ 4.2437 -PG_FUNCTION_INFO_V1(pgl_ecluster_overlap); 4.2438 -Datum pgl_ecluster_overlap(PG_FUNCTION_ARGS) { 4.2439 - pgl_cluster *cluster1 = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); 4.2440 - pgl_cluster *cluster2 = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 4.2441 - bool retval; 4.2442 - /* clusters with non-touching bounding circles are always assumed to be 4.2443 - non-overlapping (improves performance and is necessary for consistent 4.2444 - table and index scans) */ 4.2445 - if ( 4.2446 - pgl_distance( 4.2447 - cluster1->bounding.center.lat, cluster1->bounding.center.lon, 4.2448 - cluster2->bounding.center.lat, cluster2->bounding.center.lon 4.2449 - ) > cluster1->bounding.radius + cluster2->bounding.radius 4.2450 - ) retval = false; 4.2451 - else retval = pgl_clusters_overlap(cluster1, cluster2); 4.2452 - PG_FREE_IF_COPY(cluster1, 0); 4.2453 - PG_FREE_IF_COPY(cluster2, 1); 4.2454 - PG_RETURN_BOOL(retval); 4.2455 -} 4.2456 - 4.2457 -/* check if two clusters may overlap (lossy overlap operator "&&+") in SQL */ 4.2458 -PG_FUNCTION_INFO_V1(pgl_ecluster_may_overlap); 4.2459 -Datum pgl_ecluster_may_overlap(PG_FUNCTION_ARGS) { 4.2460 - pgl_cluster *cluster1 = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); 4.2461 - pgl_cluster *cluster2 = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 4.2462 - bool retval = pgl_distance( 4.2463 - cluster1->bounding.center.lat, cluster1->bounding.center.lon, 4.2464 - cluster2->bounding.center.lat, cluster2->bounding.center.lon 4.2465 - ) <= cluster1->bounding.radius + cluster2->bounding.radius; 4.2466 - PG_FREE_IF_COPY(cluster1, 0); 4.2467 - PG_FREE_IF_COPY(cluster2, 1); 4.2468 - PG_RETURN_BOOL(retval); 4.2469 -} 4.2470 - 4.2471 -/* check if second cluster is in first cluster (cont. operator "@>) in SQL */ 4.2472 -PG_FUNCTION_INFO_V1(pgl_ecluster_contains); 4.2473 -Datum pgl_ecluster_contains(PG_FUNCTION_ARGS) { 4.2474 - pgl_cluster *outer = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); 4.2475 - pgl_cluster *inner = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 4.2476 - bool retval; 4.2477 - /* clusters with non-touching bounding circles are always assumed to be 4.2478 - non-overlapping (improves performance and is necessary for consistent 4.2479 - table and index scans) */ 4.2480 - if ( 4.2481 - pgl_distance( 4.2482 - outer->bounding.center.lat, outer->bounding.center.lon, 4.2483 - inner->bounding.center.lat, inner->bounding.center.lon 4.2484 - ) > outer->bounding.radius + inner->bounding.radius 4.2485 - ) retval = false; 4.2486 - else retval = pgl_cluster_in_cluster(outer, inner); 4.2487 - PG_FREE_IF_COPY(outer, 0); 4.2488 - PG_FREE_IF_COPY(inner, 1); 4.2489 - PG_RETURN_BOOL(retval); 4.2490 -} 4.2491 - 4.2492 -/* calculate distance between two points ("<->" operator) in SQL */ 4.2493 -PG_FUNCTION_INFO_V1(pgl_epoint_distance); 4.2494 -Datum pgl_epoint_distance(PG_FUNCTION_ARGS) { 4.2495 - pgl_point *point1 = (pgl_point *)PG_GETARG_POINTER(0); 4.2496 - pgl_point *point2 = (pgl_point *)PG_GETARG_POINTER(1); 4.2497 - PG_RETURN_FLOAT8(pgl_distance( 4.2498 - point1->lat, point1->lon, point2->lat, point2->lon 4.2499 - )); 4.2500 -} 4.2501 - 4.2502 -/* calculate point to circle distance ("<->" operator) in SQL */ 4.2503 -PG_FUNCTION_INFO_V1(pgl_epoint_ecircle_distance); 4.2504 -Datum pgl_epoint_ecircle_distance(PG_FUNCTION_ARGS) { 4.2505 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 4.2506 - pgl_circle *circle = (pgl_circle *)PG_GETARG_POINTER(1); 4.2507 - double distance = pgl_distance( 4.2508 - point->lat, point->lon, circle->center.lat, circle->center.lon 4.2509 - ) - circle->radius; 4.2510 - PG_RETURN_FLOAT8((distance <= 0) ? 0 : distance); 4.2511 -} 4.2512 - 4.2513 -/* calculate point to cluster distance ("<->" operator) in SQL */ 4.2514 -PG_FUNCTION_INFO_V1(pgl_epoint_ecluster_distance); 4.2515 -Datum pgl_epoint_ecluster_distance(PG_FUNCTION_ARGS) { 4.2516 - pgl_point *point = (pgl_point *)PG_GETARG_POINTER(0); 4.2517 - pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 4.2518 - double distance = pgl_point_cluster_distance(point, cluster); 4.2519 - PG_FREE_IF_COPY(cluster, 1); 4.2520 - PG_RETURN_FLOAT8(distance); 4.2521 -} 4.2522 - 4.2523 -/* calculate distance between two circles ("<->" operator) in SQL */ 4.2524 -PG_FUNCTION_INFO_V1(pgl_ecircle_distance); 4.2525 -Datum pgl_ecircle_distance(PG_FUNCTION_ARGS) { 4.2526 - pgl_circle *circle1 = (pgl_circle *)PG_GETARG_POINTER(0); 4.2527 - pgl_circle *circle2 = (pgl_circle *)PG_GETARG_POINTER(1); 4.2528 - double distance = pgl_distance( 4.2529 - circle1->center.lat, circle1->center.lon, 4.2530 - circle2->center.lat, circle2->center.lon 4.2531 - ) - (circle1->radius + circle2->radius); 4.2532 - PG_RETURN_FLOAT8((distance <= 0) ? 0 : distance); 4.2533 -} 4.2534 - 4.2535 -/* calculate circle to cluster distance ("<->" operator) in SQL */ 4.2536 -PG_FUNCTION_INFO_V1(pgl_ecircle_ecluster_distance); 4.2537 -Datum pgl_ecircle_ecluster_distance(PG_FUNCTION_ARGS) { 4.2538 - pgl_circle *circle = (pgl_circle *)PG_GETARG_POINTER(0); 4.2539 - pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 4.2540 - double distance = ( 4.2541 - pgl_point_cluster_distance(&(circle->center), cluster) - circle->radius 4.2542 - ); 4.2543 - PG_FREE_IF_COPY(cluster, 1); 4.2544 - PG_RETURN_FLOAT8((distance <= 0) ? 0 : distance); 4.2545 -} 4.2546 - 4.2547 -/* calculate distance between two clusters ("<->" operator) in SQL */ 4.2548 -PG_FUNCTION_INFO_V1(pgl_ecluster_distance); 4.2549 -Datum pgl_ecluster_distance(PG_FUNCTION_ARGS) { 4.2550 - pgl_cluster *cluster1 = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); 4.2551 - pgl_cluster *cluster2 = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 4.2552 - double retval = pgl_cluster_distance(cluster1, cluster2); 4.2553 - PG_FREE_IF_COPY(cluster1, 0); 4.2554 - PG_FREE_IF_COPY(cluster2, 1); 4.2555 - PG_RETURN_FLOAT8(retval); 4.2556 -} 4.2557 - 4.2558 - 4.2559 -/*-----------------------------------------------------------* 4.2560 - * B-tree comparison operators and index support functions * 4.2561 - *-----------------------------------------------------------*/ 4.2562 - 4.2563 -/* macro for a B-tree operator (without detoasting) */ 4.2564 -#define PGL_BTREE_OPER(func, type, cmpfunc, oper) \ 4.2565 - PG_FUNCTION_INFO_V1(func); \ 4.2566 - Datum func(PG_FUNCTION_ARGS) { \ 4.2567 - type *a = (type *)PG_GETARG_POINTER(0); \ 4.2568 - type *b = (type *)PG_GETARG_POINTER(1); \ 4.2569 - PG_RETURN_BOOL(cmpfunc(a, b) oper 0); \ 4.2570 - } 4.2571 - 4.2572 -/* macro for a B-tree comparison function (without detoasting) */ 4.2573 -#define PGL_BTREE_CMP(func, type, cmpfunc) \ 4.2574 - PG_FUNCTION_INFO_V1(func); \ 4.2575 - Datum func(PG_FUNCTION_ARGS) { \ 4.2576 - type *a = (type *)PG_GETARG_POINTER(0); \ 4.2577 - type *b = (type *)PG_GETARG_POINTER(1); \ 4.2578 - PG_RETURN_INT32(cmpfunc(a, b)); \ 4.2579 - } 4.2580 - 4.2581 -/* macro for a B-tree operator (with detoasting) */ 4.2582 -#define PGL_BTREE_OPER_DETOAST(func, type, cmpfunc, oper) \ 4.2583 - PG_FUNCTION_INFO_V1(func); \ 4.2584 - Datum func(PG_FUNCTION_ARGS) { \ 4.2585 - bool res; \ 4.2586 - type *a = (type *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); \ 4.2587 - type *b = (type *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); \ 4.2588 - res = cmpfunc(a, b) oper 0; \ 4.2589 - PG_FREE_IF_COPY(a, 0); \ 4.2590 - PG_FREE_IF_COPY(b, 1); \ 4.2591 - PG_RETURN_BOOL(res); \ 4.2592 - } 4.2593 - 4.2594 -/* macro for a B-tree comparison function (with detoasting) */ 4.2595 -#define PGL_BTREE_CMP_DETOAST(func, type, cmpfunc) \ 4.2596 - PG_FUNCTION_INFO_V1(func); \ 4.2597 - Datum func(PG_FUNCTION_ARGS) { \ 4.2598 - int32_t res; \ 4.2599 - type *a = (type *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); \ 4.2600 - type *b = (type *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); \ 4.2601 - res = cmpfunc(a, b); \ 4.2602 - PG_FREE_IF_COPY(a, 0); \ 4.2603 - PG_FREE_IF_COPY(b, 1); \ 4.2604 - PG_RETURN_INT32(res); \ 4.2605 - } 4.2606 - 4.2607 -/* B-tree operators and comparison function for point */ 4.2608 -PGL_BTREE_OPER(pgl_btree_epoint_lt, pgl_point, pgl_point_cmp, <) 4.2609 -PGL_BTREE_OPER(pgl_btree_epoint_le, pgl_point, pgl_point_cmp, <=) 4.2610 -PGL_BTREE_OPER(pgl_btree_epoint_eq, pgl_point, pgl_point_cmp, ==) 4.2611 -PGL_BTREE_OPER(pgl_btree_epoint_ne, pgl_point, pgl_point_cmp, !=) 4.2612 -PGL_BTREE_OPER(pgl_btree_epoint_ge, pgl_point, pgl_point_cmp, >=) 4.2613 -PGL_BTREE_OPER(pgl_btree_epoint_gt, pgl_point, pgl_point_cmp, >) 4.2614 -PGL_BTREE_CMP(pgl_btree_epoint_cmp, pgl_point, pgl_point_cmp) 4.2615 - 4.2616 -/* B-tree operators and comparison function for box */ 4.2617 -PGL_BTREE_OPER(pgl_btree_ebox_lt, pgl_box, pgl_box_cmp, <) 4.2618 -PGL_BTREE_OPER(pgl_btree_ebox_le, pgl_box, pgl_box_cmp, <=) 4.2619 -PGL_BTREE_OPER(pgl_btree_ebox_eq, pgl_box, pgl_box_cmp, ==) 4.2620 -PGL_BTREE_OPER(pgl_btree_ebox_ne, pgl_box, pgl_box_cmp, !=) 4.2621 -PGL_BTREE_OPER(pgl_btree_ebox_ge, pgl_box, pgl_box_cmp, >=) 4.2622 -PGL_BTREE_OPER(pgl_btree_ebox_gt, pgl_box, pgl_box_cmp, >) 4.2623 -PGL_BTREE_CMP(pgl_btree_ebox_cmp, pgl_box, pgl_box_cmp) 4.2624 - 4.2625 -/* B-tree operators and comparison function for circle */ 4.2626 -PGL_BTREE_OPER(pgl_btree_ecircle_lt, pgl_circle, pgl_circle_cmp, <) 4.2627 -PGL_BTREE_OPER(pgl_btree_ecircle_le, pgl_circle, pgl_circle_cmp, <=) 4.2628 -PGL_BTREE_OPER(pgl_btree_ecircle_eq, pgl_circle, pgl_circle_cmp, ==) 4.2629 -PGL_BTREE_OPER(pgl_btree_ecircle_ne, pgl_circle, pgl_circle_cmp, !=) 4.2630 -PGL_BTREE_OPER(pgl_btree_ecircle_ge, pgl_circle, pgl_circle_cmp, >=) 4.2631 -PGL_BTREE_OPER(pgl_btree_ecircle_gt, pgl_circle, pgl_circle_cmp, >) 4.2632 -PGL_BTREE_CMP(pgl_btree_ecircle_cmp, pgl_circle, pgl_circle_cmp) 4.2633 - 4.2634 - 4.2635 -/*--------------------------------* 4.2636 - * GiST index support functions * 4.2637 - *--------------------------------*/ 4.2638 - 4.2639 -/* GiST "consistent" support function */ 4.2640 -PG_FUNCTION_INFO_V1(pgl_gist_consistent); 4.2641 -Datum pgl_gist_consistent(PG_FUNCTION_ARGS) { 4.2642 - GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); 4.2643 - pgl_keyptr key = (pgl_keyptr)DatumGetPointer(entry->key); 4.2644 - StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2); 4.2645 - bool *recheck = (bool *)PG_GETARG_POINTER(4); 4.2646 - /* demand recheck because index and query methods are lossy */ 4.2647 - *recheck = true; 4.2648 - /* strategy number aliases for different operators using the same strategy */ 4.2649 - strategy %= 100; 4.2650 - /* strategy number 11: equality of two points */ 4.2651 - if (strategy == 11) { 4.2652 - /* query datum is another point */ 4.2653 - pgl_point *query = (pgl_point *)PG_GETARG_POINTER(1); 4.2654 - /* convert other point to key */ 4.2655 - pgl_pointkey querykey; 4.2656 - pgl_point_to_key(query, querykey); 4.2657 - /* return true if both keys overlap */ 4.2658 - PG_RETURN_BOOL(pgl_keys_overlap(key, querykey)); 4.2659 - } 4.2660 - /* strategy number 13: equality of two circles */ 4.2661 - if (strategy == 13) { 4.2662 - /* query datum is another circle */ 4.2663 - pgl_circle *query = (pgl_circle *)PG_GETARG_POINTER(1); 4.2664 - /* convert other circle to key */ 4.2665 - pgl_areakey querykey; 4.2666 - pgl_circle_to_key(query, querykey); 4.2667 - /* return true if both keys overlap */ 4.2668 - PG_RETURN_BOOL(pgl_keys_overlap(key, querykey)); 4.2669 - } 4.2670 - /* for all remaining strategies, keys on empty objects produce no match */ 4.2671 - /* (check necessary because query radius may be infinite) */ 4.2672 - if (PGL_KEY_IS_EMPTY(key)) PG_RETURN_BOOL(false); 4.2673 - /* strategy number 21: overlapping with point */ 4.2674 - if (strategy == 21) { 4.2675 - /* query datum is a point */ 4.2676 - pgl_point *query = (pgl_point *)PG_GETARG_POINTER(1); 4.2677 - /* return true if estimated distance (allowed to be smaller than real 4.2678 - distance) between index key and point is zero */ 4.2679 - PG_RETURN_BOOL(pgl_estimate_key_distance(key, query) == 0); 4.2680 - } 4.2681 - /* strategy number 22: (point) overlapping with box */ 4.2682 - if (strategy == 22) { 4.2683 - /* query datum is a box */ 4.2684 - pgl_box *query = (pgl_box *)PG_GETARG_POINTER(1); 4.2685 - /* determine bounding box of indexed key */ 4.2686 - pgl_box keybox; 4.2687 - pgl_key_to_box(key, &keybox); 4.2688 - /* return true if query box overlaps with bounding box of indexed key */ 4.2689 - PG_RETURN_BOOL(pgl_boxes_overlap(query, &keybox)); 4.2690 - } 4.2691 - /* strategy number 23: overlapping with circle */ 4.2692 - if (strategy == 23) { 4.2693 - /* query datum is a circle */ 4.2694 - pgl_circle *query = (pgl_circle *)PG_GETARG_POINTER(1); 4.2695 - /* return true if estimated distance (allowed to be smaller than real 4.2696 - distance) between index key and circle center is smaller than radius */ 4.2697 - PG_RETURN_BOOL( 4.2698 - pgl_estimate_key_distance(key, &(query->center)) <= query->radius 4.2699 - ); 4.2700 - } 4.2701 - /* strategy number 24: overlapping with cluster */ 4.2702 - if (strategy == 24) { 4.2703 - bool retval; /* return value */ 4.2704 - /* query datum is a cluster */ 4.2705 - pgl_cluster *query = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 4.2706 - /* return true if estimated distance (allowed to be smaller than real 4.2707 - distance) between index key and circle center is smaller than radius */ 4.2708 - retval = ( 4.2709 - pgl_estimate_key_distance(key, &(query->bounding.center)) <= 4.2710 - query->bounding.radius 4.2711 - ); 4.2712 - PG_FREE_IF_COPY(query, 1); /* free detoasted cluster (if copy) */ 4.2713 - PG_RETURN_BOOL(retval); 4.2714 - } 4.2715 - /* throw error for any unknown strategy number */ 4.2716 - elog(ERROR, "unrecognized strategy number: %d", strategy); 4.2717 -} 4.2718 - 4.2719 -/* GiST "union" support function */ 4.2720 -PG_FUNCTION_INFO_V1(pgl_gist_union); 4.2721 -Datum pgl_gist_union(PG_FUNCTION_ARGS) { 4.2722 - GistEntryVector *entryvec = (GistEntryVector *)PG_GETARG_POINTER(0); 4.2723 - pgl_keyptr out; /* return value (to be palloc'ed) */ 4.2724 - int i; 4.2725 - /* determine key size */ 4.2726 - size_t keysize = PGL_KEY_IS_AREAKEY( 4.2727 - (pgl_keyptr)DatumGetPointer(entryvec->vector[0].key) 4.2728 - ) ? sizeof (pgl_areakey) : sizeof(pgl_pointkey); 4.2729 - /* begin with first key as result */ 4.2730 - out = palloc(keysize); 4.2731 - memcpy(out, (pgl_keyptr)DatumGetPointer(entryvec->vector[0].key), keysize); 4.2732 - /* unite current result with second, third, etc. key */ 4.2733 - for (i=1; i<entryvec->n; i++) { 4.2734 - pgl_unite_keys(out, (pgl_keyptr)DatumGetPointer(entryvec->vector[i].key)); 4.2735 - } 4.2736 - /* return result */ 4.2737 - PG_RETURN_POINTER(out); 4.2738 -} 4.2739 - 4.2740 -/* GiST "compress" support function for indicis on points */ 4.2741 -PG_FUNCTION_INFO_V1(pgl_gist_compress_epoint); 4.2742 -Datum pgl_gist_compress_epoint(PG_FUNCTION_ARGS) { 4.2743 - GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); 4.2744 - GISTENTRY *retval; /* return value (to be palloc'ed unless set to entry) */ 4.2745 - /* only transform new leaves */ 4.2746 - if (entry->leafkey) { 4.2747 - /* get point to be transformed */ 4.2748 - pgl_point *point = (pgl_point *)DatumGetPointer(entry->key); 4.2749 - /* allocate memory for key */ 4.2750 - pgl_keyptr key = palloc(sizeof(pgl_pointkey)); 4.2751 - /* transform point to key */ 4.2752 - pgl_point_to_key(point, key); 4.2753 - /* create new GISTENTRY structure as return value */ 4.2754 - retval = palloc(sizeof(GISTENTRY)); 4.2755 - gistentryinit( 4.2756 - *retval, PointerGetDatum(key), 4.2757 - entry->rel, entry->page, entry->offset, FALSE 4.2758 - ); 4.2759 - } else { 4.2760 - /* inner nodes have already been transformed */ 4.2761 - retval = entry; 4.2762 - } 4.2763 - /* return pointer to old or new GISTENTRY structure */ 4.2764 - PG_RETURN_POINTER(retval); 4.2765 -} 4.2766 - 4.2767 -/* GiST "compress" support function for indicis on circles */ 4.2768 -PG_FUNCTION_INFO_V1(pgl_gist_compress_ecircle); 4.2769 -Datum pgl_gist_compress_ecircle(PG_FUNCTION_ARGS) { 4.2770 - GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); 4.2771 - GISTENTRY *retval; /* return value (to be palloc'ed unless set to entry) */ 4.2772 - /* only transform new leaves */ 4.2773 - if (entry->leafkey) { 4.2774 - /* get circle to be transformed */ 4.2775 - pgl_circle *circle = (pgl_circle *)DatumGetPointer(entry->key); 4.2776 - /* allocate memory for key */ 4.2777 - pgl_keyptr key = palloc(sizeof(pgl_areakey)); 4.2778 - /* transform circle to key */ 4.2779 - pgl_circle_to_key(circle, key); 4.2780 - /* create new GISTENTRY structure as return value */ 4.2781 - retval = palloc(sizeof(GISTENTRY)); 4.2782 - gistentryinit( 4.2783 - *retval, PointerGetDatum(key), 4.2784 - entry->rel, entry->page, entry->offset, FALSE 4.2785 - ); 4.2786 - } else { 4.2787 - /* inner nodes have already been transformed */ 4.2788 - retval = entry; 4.2789 - } 4.2790 - /* return pointer to old or new GISTENTRY structure */ 4.2791 - PG_RETURN_POINTER(retval); 4.2792 -} 4.2793 - 4.2794 -/* GiST "compress" support function for indices on clusters */ 4.2795 -PG_FUNCTION_INFO_V1(pgl_gist_compress_ecluster); 4.2796 -Datum pgl_gist_compress_ecluster(PG_FUNCTION_ARGS) { 4.2797 - GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); 4.2798 - GISTENTRY *retval; /* return value (to be palloc'ed unless set to entry) */ 4.2799 - /* only transform new leaves */ 4.2800 - if (entry->leafkey) { 4.2801 - /* get cluster to be transformed (detoasting necessary!) */ 4.2802 - pgl_cluster *cluster = (pgl_cluster *)PG_DETOAST_DATUM(entry->key); 4.2803 - /* allocate memory for key */ 4.2804 - pgl_keyptr key = palloc(sizeof(pgl_areakey)); 4.2805 - /* transform cluster to key */ 4.2806 - pgl_circle_to_key(&(cluster->bounding), key); 4.2807 - /* create new GISTENTRY structure as return value */ 4.2808 - retval = palloc(sizeof(GISTENTRY)); 4.2809 - gistentryinit( 4.2810 - *retval, PointerGetDatum(key), 4.2811 - entry->rel, entry->page, entry->offset, FALSE 4.2812 - ); 4.2813 - /* free detoasted datum */ 4.2814 - if ((void *)cluster != (void *)DatumGetPointer(entry->key)) pfree(cluster); 4.2815 - } else { 4.2816 - /* inner nodes have already been transformed */ 4.2817 - retval = entry; 4.2818 - } 4.2819 - /* return pointer to old or new GISTENTRY structure */ 4.2820 - PG_RETURN_POINTER(retval); 4.2821 -} 4.2822 - 4.2823 -/* GiST "decompress" support function for indices */ 4.2824 -PG_FUNCTION_INFO_V1(pgl_gist_decompress); 4.2825 -Datum pgl_gist_decompress(PG_FUNCTION_ARGS) { 4.2826 - /* return passed pointer without transformation */ 4.2827 - PG_RETURN_POINTER(PG_GETARG_POINTER(0)); 4.2828 -} 4.2829 - 4.2830 -/* GiST "penalty" support function */ 4.2831 -PG_FUNCTION_INFO_V1(pgl_gist_penalty); 4.2832 -Datum pgl_gist_penalty(PG_FUNCTION_ARGS) { 4.2833 - GISTENTRY *origentry = (GISTENTRY *)PG_GETARG_POINTER(0); 4.2834 - GISTENTRY *newentry = (GISTENTRY *)PG_GETARG_POINTER(1); 4.2835 - float *penalty = (float *)PG_GETARG_POINTER(2); 4.2836 - /* get original key and key to insert */ 4.2837 - pgl_keyptr orig = (pgl_keyptr)DatumGetPointer(origentry->key); 4.2838 - pgl_keyptr new = (pgl_keyptr)DatumGetPointer(newentry->key); 4.2839 - /* copy original key */ 4.2840 - union { pgl_pointkey pointkey; pgl_areakey areakey; } union_key; 4.2841 - if (PGL_KEY_IS_AREAKEY(orig)) { 4.2842 - memcpy(union_key.areakey, orig, sizeof(union_key.areakey)); 4.2843 - } else { 4.2844 - memcpy(union_key.pointkey, orig, sizeof(union_key.pointkey)); 4.2845 - } 4.2846 - /* calculate union of both keys */ 4.2847 - pgl_unite_keys((pgl_keyptr)&union_key, new); 4.2848 - /* penalty equal to reduction of key length (logarithm of added area) */ 4.2849 - /* (return value by setting referenced value and returning pointer) */ 4.2850 - *penalty = ( 4.2851 - PGL_KEY_NODEDEPTH(orig) - PGL_KEY_NODEDEPTH((pgl_keyptr)&union_key) 4.2852 - ); 4.2853 - PG_RETURN_POINTER(penalty); 4.2854 -} 4.2855 - 4.2856 -/* GiST "picksplit" support function */ 4.2857 -PG_FUNCTION_INFO_V1(pgl_gist_picksplit); 4.2858 -Datum pgl_gist_picksplit(PG_FUNCTION_ARGS) { 4.2859 - GistEntryVector *entryvec = (GistEntryVector *)PG_GETARG_POINTER(0); 4.2860 - GIST_SPLITVEC *v = (GIST_SPLITVEC *)PG_GETARG_POINTER(1); 4.2861 - OffsetNumber i; /* between FirstOffsetNumber and entryvec->n (inclusive) */ 4.2862 - union { 4.2863 - pgl_pointkey pointkey; 4.2864 - pgl_areakey areakey; 4.2865 - } union_all; /* union of all keys (to be calculated from scratch) 4.2866 - (later cut in half) */ 4.2867 - int is_areakey = PGL_KEY_IS_AREAKEY( 4.2868 - (pgl_keyptr)DatumGetPointer(entryvec->vector[FirstOffsetNumber].key) 4.2869 - ); 4.2870 - int keysize = is_areakey ? sizeof(pgl_areakey) : sizeof(pgl_pointkey); 4.2871 - pgl_keyptr unionL = palloc(keysize); /* union of keys that go left */ 4.2872 - pgl_keyptr unionR = palloc(keysize); /* union of keys that go right */ 4.2873 - pgl_keyptr key; /* current key to be processed */ 4.2874 - /* allocate memory for array of left and right keys, set counts to zero */ 4.2875 - v->spl_left = (OffsetNumber *)palloc(entryvec->n * sizeof(OffsetNumber)); 4.2876 - v->spl_nleft = 0; 4.2877 - v->spl_right = (OffsetNumber *)palloc(entryvec->n * sizeof(OffsetNumber)); 4.2878 - v->spl_nright = 0; 4.2879 - /* calculate union of all keys from scratch */ 4.2880 - memcpy( 4.2881 - (pgl_keyptr)&union_all, 4.2882 - (pgl_keyptr)DatumGetPointer(entryvec->vector[FirstOffsetNumber].key), 4.2883 - keysize 4.2884 - ); 4.2885 - for (i=FirstOffsetNumber+1; i<entryvec->n; i=OffsetNumberNext(i)) { 4.2886 - pgl_unite_keys( 4.2887 - (pgl_keyptr)&union_all, 4.2888 - (pgl_keyptr)DatumGetPointer(entryvec->vector[i].key) 4.2889 - ); 4.2890 - } 4.2891 - /* check if trivial split is necessary due to exhausted key length */ 4.2892 - /* (Note: keys for empty objects must have node depth set to maximum) */ 4.2893 - if (PGL_KEY_NODEDEPTH((pgl_keyptr)&union_all) == ( 4.2894 - is_areakey ? PGL_AREAKEY_MAXDEPTH : PGL_POINTKEY_MAXDEPTH 4.2895 - )) { 4.2896 - /* half of all keys go left */ 4.2897 - for ( 4.2898 - i=FirstOffsetNumber; 4.2899 - i<FirstOffsetNumber+(entryvec->n - FirstOffsetNumber)/2; 4.2900 - i=OffsetNumberNext(i) 4.2901 - ) { 4.2902 - /* pointer to current key */ 4.2903 - key = (pgl_keyptr)DatumGetPointer(entryvec->vector[i].key); 4.2904 - /* update unionL */ 4.2905 - /* check if key is first key that goes left */ 4.2906 - if (!v->spl_nleft) { 4.2907 - /* first key that goes left is just copied to unionL */ 4.2908 - memcpy(unionL, key, keysize); 4.2909 - } else { 4.2910 - /* unite current value and next key */ 4.2911 - pgl_unite_keys(unionL, key); 4.2912 - } 4.2913 - /* append offset number to list of keys that go left */ 4.2914 - v->spl_left[v->spl_nleft++] = i; 4.2915 - } 4.2916 - /* other half goes right */ 4.2917 - for ( 4.2918 - i=FirstOffsetNumber+(entryvec->n - FirstOffsetNumber)/2; 4.2919 - i<entryvec->n; 4.2920 - i=OffsetNumberNext(i) 4.2921 - ) { 4.2922 - /* pointer to current key */ 4.2923 - key = (pgl_keyptr)DatumGetPointer(entryvec->vector[i].key); 4.2924 - /* update unionR */ 4.2925 - /* check if key is first key that goes right */ 4.2926 - if (!v->spl_nright) { 4.2927 - /* first key that goes right is just copied to unionR */ 4.2928 - memcpy(unionR, key, keysize); 4.2929 - } else { 4.2930 - /* unite current value and next key */ 4.2931 - pgl_unite_keys(unionR, key); 4.2932 - } 4.2933 - /* append offset number to list of keys that go right */ 4.2934 - v->spl_right[v->spl_nright++] = i; 4.2935 - } 4.2936 - } 4.2937 - /* otherwise, a non-trivial split is possible */ 4.2938 - else { 4.2939 - /* cut covered area in half */ 4.2940 - /* (union_all then refers to area of keys that go left) */ 4.2941 - /* check if union of all keys covers empty and non-empty objects */ 4.2942 - if (PGL_KEY_IS_UNIVERSAL((pgl_keyptr)&union_all)) { 4.2943 - /* if yes, split into empty and non-empty objects */ 4.2944 - pgl_key_set_empty((pgl_keyptr)&union_all); 4.2945 - } else { 4.2946 - /* otherwise split by next bit */ 4.2947 - ((pgl_keyptr)&union_all)[PGL_KEY_NODEDEPTH_OFFSET]++; 4.2948 - /* NOTE: type bit conserved */ 4.2949 - } 4.2950 - /* determine for each key if it goes left or right */ 4.2951 - for (i=FirstOffsetNumber; i<entryvec->n; i=OffsetNumberNext(i)) { 4.2952 - /* pointer to current key */ 4.2953 - key = (pgl_keyptr)DatumGetPointer(entryvec->vector[i].key); 4.2954 - /* keys within one half of the area go left */ 4.2955 - if (pgl_keys_overlap((pgl_keyptr)&union_all, key)) { 4.2956 - /* update unionL */ 4.2957 - /* check if key is first key that goes left */ 4.2958 - if (!v->spl_nleft) { 4.2959 - /* first key that goes left is just copied to unionL */ 4.2960 - memcpy(unionL, key, keysize); 4.2961 - } else { 4.2962 - /* unite current value of unionL and processed key */ 4.2963 - pgl_unite_keys(unionL, key); 4.2964 - } 4.2965 - /* append offset number to list of keys that go left */ 4.2966 - v->spl_left[v->spl_nleft++] = i; 4.2967 - } 4.2968 - /* the other keys go right */ 4.2969 - else { 4.2970 - /* update unionR */ 4.2971 - /* check if key is first key that goes right */ 4.2972 - if (!v->spl_nright) { 4.2973 - /* first key that goes right is just copied to unionR */ 4.2974 - memcpy(unionR, key, keysize); 4.2975 - } else { 4.2976 - /* unite current value of unionR and processed key */ 4.2977 - pgl_unite_keys(unionR, key); 4.2978 - } 4.2979 - /* append offset number to list of keys that go right */ 4.2980 - v->spl_right[v->spl_nright++] = i; 4.2981 - } 4.2982 - } 4.2983 - } 4.2984 - /* store unions in return value */ 4.2985 - v->spl_ldatum = PointerGetDatum(unionL); 4.2986 - v->spl_rdatum = PointerGetDatum(unionR); 4.2987 - /* return all results */ 4.2988 - PG_RETURN_POINTER(v); 4.2989 -} 4.2990 - 4.2991 -/* GiST "same"/"equal" support function */ 4.2992 -PG_FUNCTION_INFO_V1(pgl_gist_same); 4.2993 -Datum pgl_gist_same(PG_FUNCTION_ARGS) { 4.2994 - pgl_keyptr key1 = (pgl_keyptr)PG_GETARG_POINTER(0); 4.2995 - pgl_keyptr key2 = (pgl_keyptr)PG_GETARG_POINTER(1); 4.2996 - bool *boolptr = (bool *)PG_GETARG_POINTER(2); 4.2997 - /* two keys are equal if they are binary equal */ 4.2998 - /* (return result by setting referenced boolean and returning pointer) */ 4.2999 - *boolptr = !memcmp( 4.3000 - key1, 4.3001 - key2, 4.3002 - PGL_KEY_IS_AREAKEY(key1) ? sizeof(pgl_areakey) : sizeof(pgl_pointkey) 4.3003 - ); 4.3004 - PG_RETURN_POINTER(boolptr); 4.3005 -} 4.3006 - 4.3007 -/* GiST "distance" support function */ 4.3008 -PG_FUNCTION_INFO_V1(pgl_gist_distance); 4.3009 -Datum pgl_gist_distance(PG_FUNCTION_ARGS) { 4.3010 - GISTENTRY *entry = (GISTENTRY *)PG_GETARG_POINTER(0); 4.3011 - pgl_keyptr key = (pgl_keyptr)DatumGetPointer(entry->key); 4.3012 - StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2); 4.3013 - bool *recheck = (bool *)PG_GETARG_POINTER(4); 4.3014 - double distance; /* return value */ 4.3015 - /* demand recheck because distance is just an estimation */ 4.3016 - /* (real distance may be bigger) */ 4.3017 - *recheck = true; 4.3018 - /* strategy number aliases for different operators using the same strategy */ 4.3019 - strategy %= 100; 4.3020 - /* strategy number 31: distance to point */ 4.3021 - if (strategy == 31) { 4.3022 - /* query datum is a point */ 4.3023 - pgl_point *query = (pgl_point *)PG_GETARG_POINTER(1); 4.3024 - /* use pgl_estimate_pointkey_distance() function to compute result */ 4.3025 - distance = pgl_estimate_key_distance(key, query); 4.3026 - /* avoid infinity (reserved!) */ 4.3027 - if (!isfinite(distance)) distance = PGL_ULTRA_DISTANCE; 4.3028 - /* return result */ 4.3029 - PG_RETURN_FLOAT8(distance); 4.3030 - } 4.3031 - /* strategy number 33: distance to circle */ 4.3032 - if (strategy == 33) { 4.3033 - /* query datum is a circle */ 4.3034 - pgl_circle *query = (pgl_circle *)PG_GETARG_POINTER(1); 4.3035 - /* estimate distance to circle center and substract circle radius */ 4.3036 - distance = ( 4.3037 - pgl_estimate_key_distance(key, &(query->center)) - query->radius 4.3038 - ); 4.3039 - /* convert non-positive values to zero and avoid infinity (reserved!) */ 4.3040 - if (distance <= 0) distance = 0; 4.3041 - else if (!isfinite(distance)) distance = PGL_ULTRA_DISTANCE; 4.3042 - /* return result */ 4.3043 - PG_RETURN_FLOAT8(distance); 4.3044 - } 4.3045 - /* strategy number 34: distance to cluster */ 4.3046 - if (strategy == 34) { 4.3047 - /* query datum is a cluster */ 4.3048 - pgl_cluster *query = (pgl_cluster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 4.3049 - /* estimate distance to bounding center and substract bounding radius */ 4.3050 - distance = ( 4.3051 - pgl_estimate_key_distance(key, &(query->bounding.center)) - 4.3052 - query->bounding.radius 4.3053 - ); 4.3054 - /* convert non-positive values to zero and avoid infinity (reserved!) */ 4.3055 - if (distance <= 0) distance = 0; 4.3056 - else if (!isfinite(distance)) distance = PGL_ULTRA_DISTANCE; 4.3057 - /* free detoasted cluster (if copy) */ 4.3058 - PG_FREE_IF_COPY(query, 1); 4.3059 - /* return result */ 4.3060 - PG_RETURN_FLOAT8(distance); 4.3061 - } 4.3062 - /* throw error for any unknown strategy number */ 4.3063 - elog(ERROR, "unrecognized strategy number: %d", strategy); 4.3064 -} 4.3065 -