pgLatLon
changeset 81:b0e17a5a0258
Renamed README.mkd to README.md
| author | jbe |
|---|---|
| date | Thu Oct 23 15:15:56 2025 +0200 (2 days ago) |
| parents | b9cdc74a90db |
| children | 8a08dc69de98 |
| files | README.md README.mkd make-doc.sh |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/README.md Thu Oct 23 15:15:56 2025 +0200 1.3 @@ -0,0 +1,570 @@ 1.4 +pgLatLon v0.15 documentation 1.5 +============================ 1.6 + 1.7 +pgLatLon is a spatial database extension for the PostgreSQL object-relational 1.8 +database management system providing geographic data types and spatial indexing 1.9 +for the WGS-84 spheroid. 1.10 + 1.11 +While many other spatial databases still use imprecise bounding boxes for 1.12 +many operations, pgLatLon aims to support more precise calculations for all 1.13 +implemented geographic operators. Efficient indexing of geographic objects 1.14 +is provided using space-filling fractal curves. Optimizations on bit level 1.15 +(including logarithmic compression) allow for a highly memory-efficient 1.16 +non-overlapping index suitable for huge datasets. 1.17 + 1.18 +pgLatLon is a lightweight solution as it only depends on PostgreSQL itself (and 1.19 +a C compiler for building). 1.20 + 1.21 +Unlike competing spatial extensions for PostgreSQL, pgLatLon is available under 1.22 +the permissive MIT/X11 license to avoid problems with viral licenses like the 1.23 +GPLv2/v3. 1.24 + 1.25 + 1.26 +Installation 1.27 +------------ 1.28 + 1.29 +### Automatic installation 1.30 + 1.31 +Prerequisites: 1.32 + 1.33 +* Ensure that the `pg_config` binary is in your path (shipped with PostgreSQL). 1.34 +* Ensure that GNU Make is available (either as `make` or `gmake`). 1.35 + 1.36 +Then simply type: 1.37 + 1.38 + make install 1.39 + 1.40 +### Manual installation 1.41 + 1.42 +It is also possible to compile and install the extension without GNU Make as 1.43 +follows: 1.44 + 1.45 + cc -Wall -O2 -fPIC -shared -I `pg_config --includedir-server` -o latlon-v0010.so latlon-v0010.c 1.46 + cp latlon-v0010.so `pg_config --pkglibdir` 1.47 + cp latlon.control `pg_config --sharedir`/extension/ 1.48 + cp latlon--*.sql `pg_config --sharedir`/extension/ 1.49 + 1.50 +### Loading the extension 1.51 + 1.52 +After installation, you can create a database and load the extension as 1.53 +follows: 1.54 + 1.55 + % createdb test_database 1.56 + % psql test_database 1.57 + psql (9.5.4) 1.58 + Type "help" for help. 1.59 + 1.60 + test_database=# CREATE EXTENSION latlon; 1.61 + 1.62 +### Updating 1.63 + 1.64 +Before updating your database cluster to a new version of pgLatLon, you may 1.65 +want to uninstall the old by calling "`make uninstall`" in the unpacked source 1.66 +code directory of your old pgLatLon version. You may also manually delete the 1.67 +`latlon-v????.so` files from your PostgreSQL library directory and the 1.68 +`latlon.control` and `latlon--*.sql` files from your PostgreSQL extension 1.69 +directory. 1.70 + 1.71 +The new version can be installed as described above. For altering an existing 1.72 +database to use the installed new version (mandatory if you removed the old 1.73 +version), execute the following SQL command in the respective databases: 1.74 + 1.75 + ALTER EXTENSION latlon UPDATE; 1.76 + 1.77 +If the update contains modifications to operator classes, it may be necessary 1.78 +to drop all indices on geographic data types first (you will get an error 1.79 +message in this case). These indices can be re-created after the update. 1.80 + 1.81 +Note that taking several update steps at once (e.g. updating from version 0.2 1.82 +directly to version 0.4) requires the intermediate versions to be installed 1.83 +(i.e. in this example version 0.3 would need to be installed). Whenever you 1.84 +install or uninstall an intermediate or old version, make sure to afterwards 1.85 +re-install the latest pgLatLon version to ensure that the `latlon.control` file 1.86 +is available and points to the latest version. 1.87 + 1.88 +If the update contains modifications to the internal data representation 1.89 +format, an update path might not be available. In this case, create a dump of 1.90 +your database, delete your database, and restore it from your dump. 1.91 + 1.92 +Be sure to always keep backups of all your data before attempting to update. 1.93 + 1.94 + 1.95 +Reference 1.96 +--------- 1.97 + 1.98 +### 1. Types 1.99 + 1.100 +pgLatLon provides four geographic types: `epoint`, `ebox`, `ecircle`, and 1.101 +`ecluster`. 1.102 + 1.103 +#### `epoint` 1.104 + 1.105 +A point on the Earth spheroid (WGS-84). 1.106 + 1.107 +The text input format is `'[N|S]<float> [E|W]<float>'`, where each float is in 1.108 +degrees. Note the required white space between the latitude and longitude 1.109 +components. Each floating point number may have a sign, in which case `N`/`S` 1.110 +or `E`/`W` are switched respectively (e.g. `E-5` is the same as `W5`). 1.111 + 1.112 +An `epoint` may also be created from two floating point numbers by calling 1.113 +`epoint(latitude, longitude)`, where positive latitudes are used for the 1.114 +northern hemisphere, negative latitudes are used for the southern hemisphere, 1.115 +positive longitudes indicate positions east of the prime meridian, and negative 1.116 +longitudes indicate positions west of the prime meridian. 1.117 + 1.118 +Latitudes exceeding -90 or +90 degrees are truncated to -90 or +90 1.119 +respectively, in which case a warning will be issued. Longitudes exceeding -180 1.120 +or +180 degrees will be converted to values between -180 and +180 (both 1.121 +inclusive) by adding or substracting a multiple of 360 degrees, in which case a 1.122 +notice will be issued. 1.123 + 1.124 +If the latitude is -90 or +90 (south pole or north pole), a longitude value is 1.125 +still stored in the datum, and if a point is on the prime meridian or the 1.126 +180th meridian, the east/west bit is also stored in the datum. In case of the 1.127 +prime meridian, this is done by storing a floating point value of -0 for 1.128 +0 degrees west and a value of +0 for 0 degrees east. In case of the 1.129 +180th meridian, this is done by storing -180 or +180 respectively. The equality 1.130 +operator, however, returns true when the same points on Earth are described, 1.131 +i.e. the longitude is ignored for the poles, and 180 degrees west is considered 1.132 +to be equal to 180 degrees east. 1.133 + 1.134 +#### `ebox` 1.135 + 1.136 +An area on Earth demarcated by a southern and northern latitude, and a western 1.137 +and eastern longitude (all given in WGS-84). 1.138 + 1.139 +The text input format is 1.140 +`'{N|S}<float> {E|W}<float> {N|S}<float> {E|W}<float>'`, where each float is in 1.141 +degrees. The ordering of the four white-space separated blocks is not 1.142 +significant. To include the 180th meridian, one longitude boundary must be 1.143 +equal to or exceed `W180` or `E180`, e.g. `'N10 N20 E170 E190'`. 1.144 + 1.145 +A special value is the empty area, denoted by the text represenation `'empty'`. 1.146 +Such an `ebox` does not contain any point. 1.147 + 1.148 +An `ebox` may also be created from four floating point numbers by calling 1.149 +`ebox(min_latitude, max_latitude, min_longitude, max_longitude)`, where 1.150 +positive values are used for north and east, and negative values are used for 1.151 +south and west. If `min_latitude` is strictly greater than `max_latitude`, an 1.152 +empty `ebox` is created. If `min_longitude` is greater than `max_longitude` and 1.153 +if both longitudes are between -180 and +180 degrees, then the area oriented in 1.154 +such way that the 180th meridian is included. 1.155 + 1.156 +If the longitude span is less than 120 degrees, an `ebox` may be alternatively 1.157 +created from two `epoints` in the following way: `ebox(epoint(lat1, lon1), 1.158 +epoint(lat2, lon2))`. In this case `lat1` and `lat2` as well as `lon1` and 1.159 +`lon2` can be swapped without any impact. 1.160 + 1.161 +#### `ecircle` 1.162 + 1.163 +An area containing all points not farther away from a given center point 1.164 +(WGS-84) than a given radius. 1.165 + 1.166 +The text input format is `'{N|S}<float> {E|W}<float> <float>'`, where the first 1.167 +two floats denote the center point in degrees and the third float denotes the 1.168 +radius in meters. A radius equal to minus infinity denotes an empty circle 1.169 +which contains no point at all (despite having a center), while a radius equal 1.170 +to zero denotes a circle that includes a single point. 1.171 + 1.172 +An `ecircle` may also be created by calling `ecircle(epoint(...), radius)` or 1.173 +from three floating point numbers by calling `ecircle(latitude, longitude, 1.174 +radius)`. 1.175 + 1.176 +#### `ecluster` 1.177 + 1.178 +A collection of points, paths, polygons, and outlines on the WGS-84 spheroid. 1.179 +Each path, polygon, or outline must cover a longitude range of less than 1.180 +180 degrees to avoid ambiguities. 1.181 + 1.182 +The text input format is a white-space separated list of the following items: 1.183 + 1.184 +* `point ({N|S}<float> {E|W}<float>)` 1.185 +* `path ({N|S}<float> {E|W}<float> {N|S}<float> {E|W}<float> ...)` 1.186 +* `outline ({N|S}<float> {E|W}<float> {N|S}<float> {E|W}<float> {N|S}<float> {E|W}<float> ...)` 1.187 +* `polygon ({N|S}<float> {E|W}<float> {N|S}<float> {E|W}<float> {N|S}<float> {E|W}<float> ...)` 1.188 + 1.189 +Paths are open by default (i.e. there is no connection from the last point in 1.190 +the list to the first point in the list). Outlines and polygons, in contrast, 1.191 +are automatically closed (i.e. there is a line segment from the last point in 1.192 +the list to the first point in the list) which means the first point should not 1.193 +be repeated as last point in the list. Polygons are filled, outlines are not. 1.194 + 1.195 +### 2. Indices 1.196 + 1.197 +Two kinds of indices are supported: B-tree and GiST indices. 1.198 + 1.199 +#### B-tree indices 1.200 + 1.201 +A B-tree index can be used for simple equality searches and is supported by the 1.202 +`epoint`, `ebox`, and `ecircle` data types. B-tree indices can not be used for 1.203 +geographic searches. 1.204 + 1.205 +#### GiST indices 1.206 + 1.207 +For geographic searches, GiST indices must be used. The `epoint`, `ecircle`, 1.208 +and `ecluster` data types support GiST indexing. A GiST index for geographic 1.209 +searches can be created as follows: 1.210 + 1.211 + CREATE TABLE tbl ( 1.212 + id serial4 PRIMARY KEY, 1.213 + loc epoint NOT NULL ); 1.214 + 1.215 + CREATE INDEX name_of_index ON tbl USING gist (loc); 1.216 + 1.217 +GiST indices also support nearest neighbor searches when using the distance 1.218 +operator (`<->`) in the ORDER BY clause. 1.219 + 1.220 +#### Indices on other data types (e.g. GeoJSON) 1.221 + 1.222 +Note that further types can be indexed by using an index on an expression with 1.223 +a conversion function. One conversion function provided by pgLatLon is the 1.224 +`GeoJSON_to_ecluster(jsonb, text)` function: 1.225 + 1.226 + CREATE TABLE tbl ( 1.227 + id serial4 PRIMARY KEY, 1.228 + loc jsonb NOT NULL ); 1.229 + 1.230 + CREATE INDEX name_of_index ON tbl USING gist ((GeoJSON_to_ecluster("loc"))); 1.231 + 1.232 +When using the conversion function in an expression, the index will be used 1.233 +automatically: 1.234 + 1.235 + SELECT * FROM tbl WHERE GeoJSON_to_ecluster("loc") && 'N50 E10 10000'::ecircle; 1.236 + 1.237 +### 3. Operators 1.238 + 1.239 +#### Equality operator `=` 1.240 + 1.241 +Tests if two geographic objects are equal. 1.242 + 1.243 +The longitude is ignored for the poles, and 180 degrees west is considered to 1.244 +be equal to 180 degrees east. 1.245 + 1.246 +For boxes and circles, two empty objects are considered equal. (Note that a 1.247 +circle is not empty if the radius is zero but only if it is negative infinity, 1.248 +i.e. smaller than zero.) Two circles with a positive infinite radius are also 1.249 +considered equal. 1.250 + 1.251 +Implemented for: 1.252 + 1.253 +* `epoint = epoint` 1.254 +* `ebox = ebox` 1.255 +* `ecircle = ecircle` 1.256 + 1.257 +The negation is the inequality operator (`<>` or `!=`). 1.258 + 1.259 +#### Linear ordering operators `<<<`, `<<<=`, `>>>=`, `>>>` 1.260 + 1.261 +These operators create an arbitrary (but well-defined) linear ordering of 1.262 +geographic objects, which is used internally for B-tree indexing and merge 1.263 +joins. These operators will usually not be used by an application programmer. 1.264 + 1.265 +#### Overlap operator `&&` 1.266 + 1.267 +Tests if two geographic objects have at least one point in common. Currently 1.268 +implemented for: 1.269 + 1.270 +* `epoint && ebox` 1.271 +* `epoint && ecircle` 1.272 +* `epoint && ecluster` 1.273 +* `ebox && ebox` 1.274 +* `ebox && ecircle` 1.275 +* `ebox && ecluster` 1.276 +* `ecircle && ecircle` 1.277 +* `ecircle && ecluster` 1.278 +* `ecluster && ecluster` 1.279 + 1.280 +The `&&` operator is commutative, i.e. "`a && b`" is the same as "`b && a`". 1.281 +Each commutation is supported as well. 1.282 + 1.283 +#### Lossy overlap operator `&&+` 1.284 + 1.285 +Tests if two geographic objects may have at least one point in common. Opposed 1.286 +to the `&&` operator, the `&&+` operator may return false positives and is 1.287 +currently implemented for: 1.288 + 1.289 +* `epoint &&+ ecluster` 1.290 +* `ebox &&+ ecircle` 1.291 +* `ebox &&+ ecluster` 1.292 +* `ecircle &&+ ecluster` 1.293 +* `ecluster &&+ ecluster` 1.294 + 1.295 +The `&&+` operator is commutative, i.e. "`a &&+ b`" is the same as "`b &&+ a`". 1.296 +Each commutation is supported as well. 1.297 + 1.298 +Where two data types support both the `&&` and the `&&+` operator, the `&&+` 1.299 +operator computes faster. 1.300 + 1.301 +#### Contains operator `@>` 1.302 + 1.303 +Tests if the object right of the operator is contained in the object left of 1.304 +the operator. Currently implemented for: 1.305 + 1.306 +* `ebox @> epoint` (alias for `&&`) 1.307 +* `ebox @> ebox` 1.308 +* `ebox @> ecluster` 1.309 +* `ecluster @> epoint` (alias for `&&`) 1.310 +* `ecluster @> ebox` 1.311 +* `ecluster @> ecluster` 1.312 + 1.313 +The commutator of `@>` ("contains") is `<@` ("is contained in"), i.e. 1.314 +"`a @> b`" is the same as "`b <@ a`". 1.315 + 1.316 +Whether the perimeter of an object is taken into account is undefined and may 1.317 +differ between the left and the right hand side of the operator. The current 1.318 +implementation (where not an alias for `&&`) returns true only if an object is 1.319 +contained completely within the other object, not touching its perimeter, 1.320 +paths, outlines, or any singular points. 1.321 + 1.322 +#### Distance operator `<->` 1.323 + 1.324 +Calculates the shortest distance between two geographic objects in meters (zero 1.325 +if the objects are overlapping). Currently implemented for: 1.326 + 1.327 +* `epoint <-> epoint` 1.328 +* `epoint <-> ebox` 1.329 +* `epoint <-> ecircle` 1.330 +* `epoint <-> ecluster` 1.331 +* `ebox <-> ebox` 1.332 +* `ebox <-> ecircle` 1.333 +* `ebox <-> ecluster` 1.334 +* `ecircle <-> ecircle` 1.335 +* `ecircle <-> ecluster` 1.336 +* `ecluster <-> ecluster` 1.337 + 1.338 +The `<->` operator is commutative, i.e. "`a <-> b`" is the same as "`b <-> a`". 1.339 +Each commutation is supported as well. 1.340 + 1.341 +For short distances, the result is very accurate (i.e. respects the dimensions 1.342 +of the WGS-84 spheroid). For longer distances in the order of magnitude of 1.343 +Earth's radius or greater, the value is only approximate (but the error is 1.344 +still less than 0.2% as long as no polygons with very long edges are involved). 1.345 + 1.346 +The functions `distance(epoint, epoint)` and `distance(ecluster, epoint)` can 1.347 +be used as an alias for this operator. 1.348 + 1.349 +Note: In case of radial searches with a fixed radius, this operator should 1.350 +not be used. Instead, an `ecircle` should be created and used in combination 1.351 +with the overlap operator (`&&`). Alternatively, the functions 1.352 +`distance_within(epoint, epoint, float8)` or `distance_within(ecluster, epoint, 1.353 +float8)` can be used for fixed-radius searches. 1.354 + 1.355 +### 4. Functions 1.356 + 1.357 +#### `center(circle)` 1.358 + 1.359 +Returns the center of an `ecircle` as an `epoint`. 1.360 + 1.361 +#### `distance(epoint, epoint)` 1.362 + 1.363 +Calculates the distance between two `epoint` datums in meters. This function is 1.364 +an alias for the distance operator `<->`. 1.365 + 1.366 +Note: In case of radial searches with a fixed radius, this function should not be 1.367 +used. Use `distance_within(epoint, epoint, float8)` instead. 1.368 + 1.369 +#### `distance(ecluster, epoint)` 1.370 + 1.371 +Calculates the distance from an `ecluster` to an `epoint` in meters. This 1.372 +function is an alias for the distance operator `<->`. 1.373 + 1.374 +Note: In case of radial searches with a fixed radius, this function should not be 1.375 +used. Use `distance_within(epoint, epoint, float8)` instead. 1.376 + 1.377 +#### `distance_within(`variable `epoint,` fixed `epoint,` radius `float8)` 1.378 + 1.379 +Checks if the distance between two `epoint` datums is not greater than a given 1.380 +value (search radius). 1.381 + 1.382 +Note: In case of radial searches with a fixed radius, the first argument must 1.383 +be used for the table column, while the second argument must be used for the 1.384 +search center. Otherwise an existing index cannot be used. 1.385 + 1.386 +#### `distance_within(`variable `ecluster,` fixed `epoint,` radius `float8)` 1.387 + 1.388 +Checks if the distance from an `ecluster` to an `epoint` is not greater than a 1.389 +given value (search radius). 1.390 + 1.391 +#### `ebox(`latmin `float8,` latmax `float8,` lonmin `float8,` lonmax `float8)` 1.392 + 1.393 +Creates a new `ebox` with the given boundaries. 1.394 +See "1. Types", subsection `ebox` for details. 1.395 + 1.396 +#### `ebox(epoint, epoint)` 1.397 + 1.398 +Creates a new `ebox`. This function may only be used if the longitude 1.399 +difference is less than or equal to 120 degrees. 1.400 +See "1. Types", subsection `ebox` for details. 1.401 + 1.402 +#### `ecircle(epoint, float8)` 1.403 + 1.404 +Creates an `ecircle` with the given center point and radius. 1.405 + 1.406 +#### `ecircle(`latitude `float8,` longitude `float8,` radius `float8)` 1.407 + 1.408 +Creates an `ecircle` with the given center point and radius. 1.409 + 1.410 +#### `ecluster_concat(ecluster, ecluster)` 1.411 + 1.412 +Combines two clusters to form a new `ecluster` by uniting all entries of both 1.413 +clusters. Note that two overlapping areas of polygons annihilate each other 1.414 +(which may be used to create polygons with holes). 1.415 + 1.416 +#### `ecluster_concat(ecluster[])` 1.417 + 1.418 +Creates a new `ecluster` that unites all entries of all clusters in the passed 1.419 +array. Note that two overlapping areas of polygons annihilate each other (which 1.420 +may be used to create polygons with holes). 1.421 + 1.422 +#### `ecluster_create_multipoint(epoint[])` 1.423 + 1.424 +Creates a new `ecluster` which contains multiple points. 1.425 + 1.426 +#### `ecluster_create_outline(epoint[])` 1.427 + 1.428 +Creates a new `ecluster` that is an outline given by the passed points. 1.429 + 1.430 +#### `ecluster_create_path(epoint[])` 1.431 + 1.432 +Creates a new `ecluster` that is a path given by the passed points. 1.433 + 1.434 +#### `ecluster_create_polygon(epoint[])` 1.435 + 1.436 +Creates a new `ecluster` that is a polygon given by the passed points. 1.437 + 1.438 +#### `ecluster_extract_outlines(ecluster)` 1.439 + 1.440 +Set-returning function that returns the outlines of an `ecluster` as `epoint[]` 1.441 +rows. 1.442 + 1.443 +#### `ecluster_extract_paths(ecluster)` 1.444 + 1.445 +Set-returning function that returns the paths of an `ecluster` as `epoint[]` 1.446 +rows. 1.447 + 1.448 +#### `ecluster_extract_points(ecluster)` 1.449 + 1.450 +Set-returning function that returns the points of an `ecluster` as `epoint` 1.451 +rows. 1.452 + 1.453 +#### `ecluster_extract_polygons(ecluster)` 1.454 + 1.455 +Set-returning function that returns the polygons of an `ecluster` as `epoint[]` 1.456 +rows. 1.457 + 1.458 +#### `empty_ebox`() 1.459 + 1.460 +Returns the empty `ebox`. 1.461 +See "1. Types", subsection `ebox` for details. 1.462 + 1.463 +#### `epoint(`latitude `float8,` longitude `float8)` 1.464 + 1.465 +Returns an `epoint` with the given latitude and longitude. 1.466 + 1.467 +#### `epoint_latlon(`latitude `float8,` longitude `float8)` 1.468 + 1.469 +Alias for `epoint(float8, float8)`. 1.470 + 1.471 +#### `epoint_lonlat(`longitude `float8,` latitude `float8)` 1.472 + 1.473 +Same as `epoint(float8, float8)` but with arguments reversed. 1.474 + 1.475 +#### `fair_distance(ecluster, epoint,` samples `int4 = 10000)` 1.476 + 1.477 +When working with user-generated content, users may be tempted to create 1.478 +intentionally oversized objects in order to optimize search results in an 1.479 +unfair manner. The `fair_distance` function aims to handle this by returning an 1.480 +adjusted distance (i.e. distance increased by a penalty) if a geographic object 1.481 +(the `ecluster`) consists of more than one point. 1.482 + 1.483 +The first argument to this function is an `ecluster`, the second argument is a 1.484 +search point (`epoint`), and the third argument is an interger related to the 1.485 +precision (higher precision will require more computation time). 1.486 + 1.487 +The penalty by which the returned distance is increased fulfills (at least) the 1.488 +following properties: 1.489 + 1.490 +* The penalty function is continuous (except noise created by numerical 1.491 + integration, see paragraph after this list) as long as no objects are added 1.492 + to or removed from the `ecluster`. That particularly means: small changes in 1.493 + the search point (second argument) cause only small changes in the result. 1.494 +* For search points far away from the `ecluster` (i.e. large distances compared 1.495 + to the dimensions of the `ecluster`), the penalty approaches zero, i.e. the 1.496 + behavior of the `fair_distance` function approaches the behavior of the 1.497 + `distance` function. 1.498 +* If the `ecluster` consists of a set of points, the penalty for a search point 1.499 + close to one of those points (closer than half of the minimum distance 1.500 + between each pair of points in the `ecluster`) is chosen in such a way that 1.501 + the adjusted distance is equal to the distance from the search point to the 1.502 + closest point in the `ecluster` multiplied by the square root of the count of 1.503 + points in the `ecluster`. 1.504 +* If the `ecluster` does not cover any area (i.e. only consists of points, 1.505 + paths, and/or outlines), and if the search point (second argument) overlaps 1.506 + with the `ecluster`, then the penalty (and thus the result) is zero. 1.507 +* The integral (or average) of the square of the fair distance value (result of 1.508 + this function) over all possible search points is independent of the 1.509 + `ecluster` as long as the `ecluster` does not cover more than a half of 1.510 + earth's surface. 1.511 + 1.512 +The function uses numerical integration to compute the result. The third 1.513 +parameter (which defaults to 10000) can be used to adjust the number of samples 1.514 +taken. A higher sample count increases precision as well as execution time of 1.515 +the function. Because this function internally uses a spherical model of earth 1.516 +for certain steps of the calculation, the precision cannot be increased 1.517 +unboundedly. 1.518 + 1.519 +Despite the limitations explained above, it is ensured that the penalty is 1.520 +always positive, i.e. results returned by the `fair_distance` function are 1.521 +always equal to or greater than the results returned by the `distance` 1.522 +function regardless of stochastic effects. Furthermore, all results are 1.523 +deterministic and reproducible with the same version of pgLatLon. 1.524 + 1.525 +#### `GeoJSON_to_epoint(jsonb, text)` 1.526 + 1.527 +Maps a GeoJSON object of type "Point" or "Feature" (which contains a 1.528 +"Point") to an `epoint` datum. For any other JSON objects, NULL is returned. 1.529 + 1.530 +The second parameter (which defaults to `epoint_lonlat`) may be set to a name 1.531 +of a conversion function that transforms two coordinates (two `float8` 1.532 +parameters) to an `epoint`. 1.533 + 1.534 +#### `GeoJSON_to_ecluster(jsonb, text)` 1.535 + 1.536 +Maps a (valid) GeoJSON object to an `ecluster`. Note that this function 1.537 +does not check whether the JSONB object is a valid GeoJSON object. 1.538 + 1.539 +The second parameter (which defaults to `epoint_lonlat`) may be set to a name 1.540 +of a conversion function that transforms two coordinates (two `float8` 1.541 +parameters) to an `epoint`. 1.542 + 1.543 +#### `max_latitude(ebox)` 1.544 + 1.545 +Returns the northern boundary of a given `ebox` in degrees between -90 and +90. 1.546 + 1.547 +#### `max_longitude(ebox)` 1.548 + 1.549 +Returns the eastern boundary of a given `ebox` in degrees between -180 and +180 1.550 +(both inclusive). 1.551 + 1.552 +#### `min_latitude(ebox)` 1.553 + 1.554 +Returns the southern boundary of a given `ebox` in degrees between -90 and +90. 1.555 + 1.556 +#### `min_longitude(ebox)` 1.557 + 1.558 +Returns the western boundary of a given `ebox` in degrees between -180 and +180 1.559 +(both inclusive). 1.560 + 1.561 +#### `latitude(epoint)` 1.562 + 1.563 +Returns the latitude value of an `epoint` in degrees between -90 and +90. 1.564 + 1.565 +#### `longitude(epoint)` 1.566 + 1.567 +Returns the longitude value of an `epoint` in degrees between -180 and +180 1.568 +(both inclusive). 1.569 + 1.570 +#### `radius(ecircle)` 1.571 + 1.572 +Returns the radius of an `ecircle` in meters. 1.573 +
2.1 --- a/README.mkd Thu Oct 23 10:39:05 2025 +0200 2.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 2.3 @@ -1,570 +0,0 @@ 2.4 -pgLatLon v0.15 documentation 2.5 -============================ 2.6 - 2.7 -pgLatLon is a spatial database extension for the PostgreSQL object-relational 2.8 -database management system providing geographic data types and spatial indexing 2.9 -for the WGS-84 spheroid. 2.10 - 2.11 -While many other spatial databases still use imprecise bounding boxes for 2.12 -many operations, pgLatLon aims to support more precise calculations for all 2.13 -implemented geographic operators. Efficient indexing of geographic objects 2.14 -is provided using space-filling fractal curves. Optimizations on bit level 2.15 -(including logarithmic compression) allow for a highly memory-efficient 2.16 -non-overlapping index suitable for huge datasets. 2.17 - 2.18 -pgLatLon is a lightweight solution as it only depends on PostgreSQL itself (and 2.19 -a C compiler for building). 2.20 - 2.21 -Unlike competing spatial extensions for PostgreSQL, pgLatLon is available under 2.22 -the permissive MIT/X11 license to avoid problems with viral licenses like the 2.23 -GPLv2/v3. 2.24 - 2.25 - 2.26 -Installation 2.27 ------------- 2.28 - 2.29 -### Automatic installation 2.30 - 2.31 -Prerequisites: 2.32 - 2.33 -* Ensure that the `pg_config` binary is in your path (shipped with PostgreSQL). 2.34 -* Ensure that GNU Make is available (either as `make` or `gmake`). 2.35 - 2.36 -Then simply type: 2.37 - 2.38 - make install 2.39 - 2.40 -### Manual installation 2.41 - 2.42 -It is also possible to compile and install the extension without GNU Make as 2.43 -follows: 2.44 - 2.45 - cc -Wall -O2 -fPIC -shared -I `pg_config --includedir-server` -o latlon-v0010.so latlon-v0010.c 2.46 - cp latlon-v0010.so `pg_config --pkglibdir` 2.47 - cp latlon.control `pg_config --sharedir`/extension/ 2.48 - cp latlon--*.sql `pg_config --sharedir`/extension/ 2.49 - 2.50 -### Loading the extension 2.51 - 2.52 -After installation, you can create a database and load the extension as 2.53 -follows: 2.54 - 2.55 - % createdb test_database 2.56 - % psql test_database 2.57 - psql (9.5.4) 2.58 - Type "help" for help. 2.59 - 2.60 - test_database=# CREATE EXTENSION latlon; 2.61 - 2.62 -### Updating 2.63 - 2.64 -Before updating your database cluster to a new version of pgLatLon, you may 2.65 -want to uninstall the old by calling "`make uninstall`" in the unpacked source 2.66 -code directory of your old pgLatLon version. You may also manually delete the 2.67 -`latlon-v????.so` files from your PostgreSQL library directory and the 2.68 -`latlon.control` and `latlon--*.sql` files from your PostgreSQL extension 2.69 -directory. 2.70 - 2.71 -The new version can be installed as described above. For altering an existing 2.72 -database to use the installed new version (mandatory if you removed the old 2.73 -version), execute the following SQL command in the respective databases: 2.74 - 2.75 - ALTER EXTENSION latlon UPDATE; 2.76 - 2.77 -If the update contains modifications to operator classes, it may be necessary 2.78 -to drop all indices on geographic data types first (you will get an error 2.79 -message in this case). These indices can be re-created after the update. 2.80 - 2.81 -Note that taking several update steps at once (e.g. updating from version 0.2 2.82 -directly to version 0.4) requires the intermediate versions to be installed 2.83 -(i.e. in this example version 0.3 would need to be installed). Whenever you 2.84 -install or uninstall an intermediate or old version, make sure to afterwards 2.85 -re-install the latest pgLatLon version to ensure that the `latlon.control` file 2.86 -is available and points to the latest version. 2.87 - 2.88 -If the update contains modifications to the internal data representation 2.89 -format, an update path might not be available. In this case, create a dump of 2.90 -your database, delete your database, and restore it from your dump. 2.91 - 2.92 -Be sure to always keep backups of all your data before attempting to update. 2.93 - 2.94 - 2.95 -Reference 2.96 ---------- 2.97 - 2.98 -### 1. Types 2.99 - 2.100 -pgLatLon provides four geographic types: `epoint`, `ebox`, `ecircle`, and 2.101 -`ecluster`. 2.102 - 2.103 -#### `epoint` 2.104 - 2.105 -A point on the Earth spheroid (WGS-84). 2.106 - 2.107 -The text input format is `'[N|S]<float> [E|W]<float>'`, where each float is in 2.108 -degrees. Note the required white space between the latitude and longitude 2.109 -components. Each floating point number may have a sign, in which case `N`/`S` 2.110 -or `E`/`W` are switched respectively (e.g. `E-5` is the same as `W5`). 2.111 - 2.112 -An `epoint` may also be created from two floating point numbers by calling 2.113 -`epoint(latitude, longitude)`, where positive latitudes are used for the 2.114 -northern hemisphere, negative latitudes are used for the southern hemisphere, 2.115 -positive longitudes indicate positions east of the prime meridian, and negative 2.116 -longitudes indicate positions west of the prime meridian. 2.117 - 2.118 -Latitudes exceeding -90 or +90 degrees are truncated to -90 or +90 2.119 -respectively, in which case a warning will be issued. Longitudes exceeding -180 2.120 -or +180 degrees will be converted to values between -180 and +180 (both 2.121 -inclusive) by adding or substracting a multiple of 360 degrees, in which case a 2.122 -notice will be issued. 2.123 - 2.124 -If the latitude is -90 or +90 (south pole or north pole), a longitude value is 2.125 -still stored in the datum, and if a point is on the prime meridian or the 2.126 -180th meridian, the east/west bit is also stored in the datum. In case of the 2.127 -prime meridian, this is done by storing a floating point value of -0 for 2.128 -0 degrees west and a value of +0 for 0 degrees east. In case of the 2.129 -180th meridian, this is done by storing -180 or +180 respectively. The equality 2.130 -operator, however, returns true when the same points on Earth are described, 2.131 -i.e. the longitude is ignored for the poles, and 180 degrees west is considered 2.132 -to be equal to 180 degrees east. 2.133 - 2.134 -#### `ebox` 2.135 - 2.136 -An area on Earth demarcated by a southern and northern latitude, and a western 2.137 -and eastern longitude (all given in WGS-84). 2.138 - 2.139 -The text input format is 2.140 -`'{N|S}<float> {E|W}<float> {N|S}<float> {E|W}<float>'`, where each float is in 2.141 -degrees. The ordering of the four white-space separated blocks is not 2.142 -significant. To include the 180th meridian, one longitude boundary must be 2.143 -equal to or exceed `W180` or `E180`, e.g. `'N10 N20 E170 E190'`. 2.144 - 2.145 -A special value is the empty area, denoted by the text represenation `'empty'`. 2.146 -Such an `ebox` does not contain any point. 2.147 - 2.148 -An `ebox` may also be created from four floating point numbers by calling 2.149 -`ebox(min_latitude, max_latitude, min_longitude, max_longitude)`, where 2.150 -positive values are used for north and east, and negative values are used for 2.151 -south and west. If `min_latitude` is strictly greater than `max_latitude`, an 2.152 -empty `ebox` is created. If `min_longitude` is greater than `max_longitude` and 2.153 -if both longitudes are between -180 and +180 degrees, then the area oriented in 2.154 -such way that the 180th meridian is included. 2.155 - 2.156 -If the longitude span is less than 120 degrees, an `ebox` may be alternatively 2.157 -created from two `epoints` in the following way: `ebox(epoint(lat1, lon1), 2.158 -epoint(lat2, lon2))`. In this case `lat1` and `lat2` as well as `lon1` and 2.159 -`lon2` can be swapped without any impact. 2.160 - 2.161 -#### `ecircle` 2.162 - 2.163 -An area containing all points not farther away from a given center point 2.164 -(WGS-84) than a given radius. 2.165 - 2.166 -The text input format is `'{N|S}<float> {E|W}<float> <float>'`, where the first 2.167 -two floats denote the center point in degrees and the third float denotes the 2.168 -radius in meters. A radius equal to minus infinity denotes an empty circle 2.169 -which contains no point at all (despite having a center), while a radius equal 2.170 -to zero denotes a circle that includes a single point. 2.171 - 2.172 -An `ecircle` may also be created by calling `ecircle(epoint(...), radius)` or 2.173 -from three floating point numbers by calling `ecircle(latitude, longitude, 2.174 -radius)`. 2.175 - 2.176 -#### `ecluster` 2.177 - 2.178 -A collection of points, paths, polygons, and outlines on the WGS-84 spheroid. 2.179 -Each path, polygon, or outline must cover a longitude range of less than 2.180 -180 degrees to avoid ambiguities. 2.181 - 2.182 -The text input format is a white-space separated list of the following items: 2.183 - 2.184 -* `point ({N|S}<float> {E|W}<float>)` 2.185 -* `path ({N|S}<float> {E|W}<float> {N|S}<float> {E|W}<float> ...)` 2.186 -* `outline ({N|S}<float> {E|W}<float> {N|S}<float> {E|W}<float> {N|S}<float> {E|W}<float> ...)` 2.187 -* `polygon ({N|S}<float> {E|W}<float> {N|S}<float> {E|W}<float> {N|S}<float> {E|W}<float> ...)` 2.188 - 2.189 -Paths are open by default (i.e. there is no connection from the last point in 2.190 -the list to the first point in the list). Outlines and polygons, in contrast, 2.191 -are automatically closed (i.e. there is a line segment from the last point in 2.192 -the list to the first point in the list) which means the first point should not 2.193 -be repeated as last point in the list. Polygons are filled, outlines are not. 2.194 - 2.195 -### 2. Indices 2.196 - 2.197 -Two kinds of indices are supported: B-tree and GiST indices. 2.198 - 2.199 -#### B-tree indices 2.200 - 2.201 -A B-tree index can be used for simple equality searches and is supported by the 2.202 -`epoint`, `ebox`, and `ecircle` data types. B-tree indices can not be used for 2.203 -geographic searches. 2.204 - 2.205 -#### GiST indices 2.206 - 2.207 -For geographic searches, GiST indices must be used. The `epoint`, `ecircle`, 2.208 -and `ecluster` data types support GiST indexing. A GiST index for geographic 2.209 -searches can be created as follows: 2.210 - 2.211 - CREATE TABLE tbl ( 2.212 - id serial4 PRIMARY KEY, 2.213 - loc epoint NOT NULL ); 2.214 - 2.215 - CREATE INDEX name_of_index ON tbl USING gist (loc); 2.216 - 2.217 -GiST indices also support nearest neighbor searches when using the distance 2.218 -operator (`<->`) in the ORDER BY clause. 2.219 - 2.220 -#### Indices on other data types (e.g. GeoJSON) 2.221 - 2.222 -Note that further types can be indexed by using an index on an expression with 2.223 -a conversion function. One conversion function provided by pgLatLon is the 2.224 -`GeoJSON_to_ecluster(jsonb, text)` function: 2.225 - 2.226 - CREATE TABLE tbl ( 2.227 - id serial4 PRIMARY KEY, 2.228 - loc jsonb NOT NULL ); 2.229 - 2.230 - CREATE INDEX name_of_index ON tbl USING gist ((GeoJSON_to_ecluster("loc"))); 2.231 - 2.232 -When using the conversion function in an expression, the index will be used 2.233 -automatically: 2.234 - 2.235 - SELECT * FROM tbl WHERE GeoJSON_to_ecluster("loc") && 'N50 E10 10000'::ecircle; 2.236 - 2.237 -### 3. Operators 2.238 - 2.239 -#### Equality operator `=` 2.240 - 2.241 -Tests if two geographic objects are equal. 2.242 - 2.243 -The longitude is ignored for the poles, and 180 degrees west is considered to 2.244 -be equal to 180 degrees east. 2.245 - 2.246 -For boxes and circles, two empty objects are considered equal. (Note that a 2.247 -circle is not empty if the radius is zero but only if it is negative infinity, 2.248 -i.e. smaller than zero.) Two circles with a positive infinite radius are also 2.249 -considered equal. 2.250 - 2.251 -Implemented for: 2.252 - 2.253 -* `epoint = epoint` 2.254 -* `ebox = ebox` 2.255 -* `ecircle = ecircle` 2.256 - 2.257 -The negation is the inequality operator (`<>` or `!=`). 2.258 - 2.259 -#### Linear ordering operators `<<<`, `<<<=`, `>>>=`, `>>>` 2.260 - 2.261 -These operators create an arbitrary (but well-defined) linear ordering of 2.262 -geographic objects, which is used internally for B-tree indexing and merge 2.263 -joins. These operators will usually not be used by an application programmer. 2.264 - 2.265 -#### Overlap operator `&&` 2.266 - 2.267 -Tests if two geographic objects have at least one point in common. Currently 2.268 -implemented for: 2.269 - 2.270 -* `epoint && ebox` 2.271 -* `epoint && ecircle` 2.272 -* `epoint && ecluster` 2.273 -* `ebox && ebox` 2.274 -* `ebox && ecircle` 2.275 -* `ebox && ecluster` 2.276 -* `ecircle && ecircle` 2.277 -* `ecircle && ecluster` 2.278 -* `ecluster && ecluster` 2.279 - 2.280 -The `&&` operator is commutative, i.e. "`a && b`" is the same as "`b && a`". 2.281 -Each commutation is supported as well. 2.282 - 2.283 -#### Lossy overlap operator `&&+` 2.284 - 2.285 -Tests if two geographic objects may have at least one point in common. Opposed 2.286 -to the `&&` operator, the `&&+` operator may return false positives and is 2.287 -currently implemented for: 2.288 - 2.289 -* `epoint &&+ ecluster` 2.290 -* `ebox &&+ ecircle` 2.291 -* `ebox &&+ ecluster` 2.292 -* `ecircle &&+ ecluster` 2.293 -* `ecluster &&+ ecluster` 2.294 - 2.295 -The `&&+` operator is commutative, i.e. "`a &&+ b`" is the same as "`b &&+ a`". 2.296 -Each commutation is supported as well. 2.297 - 2.298 -Where two data types support both the `&&` and the `&&+` operator, the `&&+` 2.299 -operator computes faster. 2.300 - 2.301 -#### Contains operator `@>` 2.302 - 2.303 -Tests if the object right of the operator is contained in the object left of 2.304 -the operator. Currently implemented for: 2.305 - 2.306 -* `ebox @> epoint` (alias for `&&`) 2.307 -* `ebox @> ebox` 2.308 -* `ebox @> ecluster` 2.309 -* `ecluster @> epoint` (alias for `&&`) 2.310 -* `ecluster @> ebox` 2.311 -* `ecluster @> ecluster` 2.312 - 2.313 -The commutator of `@>` ("contains") is `<@` ("is contained in"), i.e. 2.314 -"`a @> b`" is the same as "`b <@ a`". 2.315 - 2.316 -Whether the perimeter of an object is taken into account is undefined and may 2.317 -differ between the left and the right hand side of the operator. The current 2.318 -implementation (where not an alias for `&&`) returns true only if an object is 2.319 -contained completely within the other object, not touching its perimeter, 2.320 -paths, outlines, or any singular points. 2.321 - 2.322 -#### Distance operator `<->` 2.323 - 2.324 -Calculates the shortest distance between two geographic objects in meters (zero 2.325 -if the objects are overlapping). Currently implemented for: 2.326 - 2.327 -* `epoint <-> epoint` 2.328 -* `epoint <-> ebox` 2.329 -* `epoint <-> ecircle` 2.330 -* `epoint <-> ecluster` 2.331 -* `ebox <-> ebox` 2.332 -* `ebox <-> ecircle` 2.333 -* `ebox <-> ecluster` 2.334 -* `ecircle <-> ecircle` 2.335 -* `ecircle <-> ecluster` 2.336 -* `ecluster <-> ecluster` 2.337 - 2.338 -The `<->` operator is commutative, i.e. "`a <-> b`" is the same as "`b <-> a`". 2.339 -Each commutation is supported as well. 2.340 - 2.341 -For short distances, the result is very accurate (i.e. respects the dimensions 2.342 -of the WGS-84 spheroid). For longer distances in the order of magnitude of 2.343 -Earth's radius or greater, the value is only approximate (but the error is 2.344 -still less than 0.2% as long as no polygons with very long edges are involved). 2.345 - 2.346 -The functions `distance(epoint, epoint)` and `distance(ecluster, epoint)` can 2.347 -be used as an alias for this operator. 2.348 - 2.349 -Note: In case of radial searches with a fixed radius, this operator should 2.350 -not be used. Instead, an `ecircle` should be created and used in combination 2.351 -with the overlap operator (`&&`). Alternatively, the functions 2.352 -`distance_within(epoint, epoint, float8)` or `distance_within(ecluster, epoint, 2.353 -float8)` can be used for fixed-radius searches. 2.354 - 2.355 -### 4. Functions 2.356 - 2.357 -#### `center(circle)` 2.358 - 2.359 -Returns the center of an `ecircle` as an `epoint`. 2.360 - 2.361 -#### `distance(epoint, epoint)` 2.362 - 2.363 -Calculates the distance between two `epoint` datums in meters. This function is 2.364 -an alias for the distance operator `<->`. 2.365 - 2.366 -Note: In case of radial searches with a fixed radius, this function should not be 2.367 -used. Use `distance_within(epoint, epoint, float8)` instead. 2.368 - 2.369 -#### `distance(ecluster, epoint)` 2.370 - 2.371 -Calculates the distance from an `ecluster` to an `epoint` in meters. This 2.372 -function is an alias for the distance operator `<->`. 2.373 - 2.374 -Note: In case of radial searches with a fixed radius, this function should not be 2.375 -used. Use `distance_within(epoint, epoint, float8)` instead. 2.376 - 2.377 -#### `distance_within(`variable `epoint,` fixed `epoint,` radius `float8)` 2.378 - 2.379 -Checks if the distance between two `epoint` datums is not greater than a given 2.380 -value (search radius). 2.381 - 2.382 -Note: In case of radial searches with a fixed radius, the first argument must 2.383 -be used for the table column, while the second argument must be used for the 2.384 -search center. Otherwise an existing index cannot be used. 2.385 - 2.386 -#### `distance_within(`variable `ecluster,` fixed `epoint,` radius `float8)` 2.387 - 2.388 -Checks if the distance from an `ecluster` to an `epoint` is not greater than a 2.389 -given value (search radius). 2.390 - 2.391 -#### `ebox(`latmin `float8,` latmax `float8,` lonmin `float8,` lonmax `float8)` 2.392 - 2.393 -Creates a new `ebox` with the given boundaries. 2.394 -See "1. Types", subsection `ebox` for details. 2.395 - 2.396 -#### `ebox(epoint, epoint)` 2.397 - 2.398 -Creates a new `ebox`. This function may only be used if the longitude 2.399 -difference is less than or equal to 120 degrees. 2.400 -See "1. Types", subsection `ebox` for details. 2.401 - 2.402 -#### `ecircle(epoint, float8)` 2.403 - 2.404 -Creates an `ecircle` with the given center point and radius. 2.405 - 2.406 -#### `ecircle(`latitude `float8,` longitude `float8,` radius `float8)` 2.407 - 2.408 -Creates an `ecircle` with the given center point and radius. 2.409 - 2.410 -#### `ecluster_concat(ecluster, ecluster)` 2.411 - 2.412 -Combines two clusters to form a new `ecluster` by uniting all entries of both 2.413 -clusters. Note that two overlapping areas of polygons annihilate each other 2.414 -(which may be used to create polygons with holes). 2.415 - 2.416 -#### `ecluster_concat(ecluster[])` 2.417 - 2.418 -Creates a new `ecluster` that unites all entries of all clusters in the passed 2.419 -array. Note that two overlapping areas of polygons annihilate each other (which 2.420 -may be used to create polygons with holes). 2.421 - 2.422 -#### `ecluster_create_multipoint(epoint[])` 2.423 - 2.424 -Creates a new `ecluster` which contains multiple points. 2.425 - 2.426 -#### `ecluster_create_outline(epoint[])` 2.427 - 2.428 -Creates a new `ecluster` that is an outline given by the passed points. 2.429 - 2.430 -#### `ecluster_create_path(epoint[])` 2.431 - 2.432 -Creates a new `ecluster` that is a path given by the passed points. 2.433 - 2.434 -#### `ecluster_create_polygon(epoint[])` 2.435 - 2.436 -Creates a new `ecluster` that is a polygon given by the passed points. 2.437 - 2.438 -#### `ecluster_extract_outlines(ecluster)` 2.439 - 2.440 -Set-returning function that returns the outlines of an `ecluster` as `epoint[]` 2.441 -rows. 2.442 - 2.443 -#### `ecluster_extract_paths(ecluster)` 2.444 - 2.445 -Set-returning function that returns the paths of an `ecluster` as `epoint[]` 2.446 -rows. 2.447 - 2.448 -#### `ecluster_extract_points(ecluster)` 2.449 - 2.450 -Set-returning function that returns the points of an `ecluster` as `epoint` 2.451 -rows. 2.452 - 2.453 -#### `ecluster_extract_polygons(ecluster)` 2.454 - 2.455 -Set-returning function that returns the polygons of an `ecluster` as `epoint[]` 2.456 -rows. 2.457 - 2.458 -#### `empty_ebox`() 2.459 - 2.460 -Returns the empty `ebox`. 2.461 -See "1. Types", subsection `ebox` for details. 2.462 - 2.463 -#### `epoint(`latitude `float8,` longitude `float8)` 2.464 - 2.465 -Returns an `epoint` with the given latitude and longitude. 2.466 - 2.467 -#### `epoint_latlon(`latitude `float8,` longitude `float8)` 2.468 - 2.469 -Alias for `epoint(float8, float8)`. 2.470 - 2.471 -#### `epoint_lonlat(`longitude `float8,` latitude `float8)` 2.472 - 2.473 -Same as `epoint(float8, float8)` but with arguments reversed. 2.474 - 2.475 -#### `fair_distance(ecluster, epoint,` samples `int4 = 10000)` 2.476 - 2.477 -When working with user-generated content, users may be tempted to create 2.478 -intentionally oversized objects in order to optimize search results in an 2.479 -unfair manner. The `fair_distance` function aims to handle this by returning an 2.480 -adjusted distance (i.e. distance increased by a penalty) if a geographic object 2.481 -(the `ecluster`) consists of more than one point. 2.482 - 2.483 -The first argument to this function is an `ecluster`, the second argument is a 2.484 -search point (`epoint`), and the third argument is an interger related to the 2.485 -precision (higher precision will require more computation time). 2.486 - 2.487 -The penalty by which the returned distance is increased fulfills (at least) the 2.488 -following properties: 2.489 - 2.490 -* The penalty function is continuous (except noise created by numerical 2.491 - integration, see paragraph after this list) as long as no objects are added 2.492 - to or removed from the `ecluster`. That particularly means: small changes in 2.493 - the search point (second argument) cause only small changes in the result. 2.494 -* For search points far away from the `ecluster` (i.e. large distances compared 2.495 - to the dimensions of the `ecluster`), the penalty approaches zero, i.e. the 2.496 - behavior of the `fair_distance` function approaches the behavior of the 2.497 - `distance` function. 2.498 -* If the `ecluster` consists of a set of points, the penalty for a search point 2.499 - close to one of those points (closer than half of the minimum distance 2.500 - between each pair of points in the `ecluster`) is chosen in such a way that 2.501 - the adjusted distance is equal to the distance from the search point to the 2.502 - closest point in the `ecluster` multiplied by the square root of the count of 2.503 - points in the `ecluster`. 2.504 -* If the `ecluster` does not cover any area (i.e. only consists of points, 2.505 - paths, and/or outlines), and if the search point (second argument) overlaps 2.506 - with the `ecluster`, then the penalty (and thus the result) is zero. 2.507 -* The integral (or average) of the square of the fair distance value (result of 2.508 - this function) over all possible search points is independent of the 2.509 - `ecluster` as long as the `ecluster` does not cover more than a half of 2.510 - earth's surface. 2.511 - 2.512 -The function uses numerical integration to compute the result. The third 2.513 -parameter (which defaults to 10000) can be used to adjust the number of samples 2.514 -taken. A higher sample count increases precision as well as execution time of 2.515 -the function. Because this function internally uses a spherical model of earth 2.516 -for certain steps of the calculation, the precision cannot be increased 2.517 -unboundedly. 2.518 - 2.519 -Despite the limitations explained above, it is ensured that the penalty is 2.520 -always positive, i.e. results returned by the `fair_distance` function are 2.521 -always equal to or greater than the results returned by the `distance` 2.522 -function regardless of stochastic effects. Furthermore, all results are 2.523 -deterministic and reproducible with the same version of pgLatLon. 2.524 - 2.525 -#### `GeoJSON_to_epoint(jsonb, text)` 2.526 - 2.527 -Maps a GeoJSON object of type "Point" or "Feature" (which contains a 2.528 -"Point") to an `epoint` datum. For any other JSON objects, NULL is returned. 2.529 - 2.530 -The second parameter (which defaults to `epoint_lonlat`) may be set to a name 2.531 -of a conversion function that transforms two coordinates (two `float8` 2.532 -parameters) to an `epoint`. 2.533 - 2.534 -#### `GeoJSON_to_ecluster(jsonb, text)` 2.535 - 2.536 -Maps a (valid) GeoJSON object to an `ecluster`. Note that this function 2.537 -does not check whether the JSONB object is a valid GeoJSON object. 2.538 - 2.539 -The second parameter (which defaults to `epoint_lonlat`) may be set to a name 2.540 -of a conversion function that transforms two coordinates (two `float8` 2.541 -parameters) to an `epoint`. 2.542 - 2.543 -#### `max_latitude(ebox)` 2.544 - 2.545 -Returns the northern boundary of a given `ebox` in degrees between -90 and +90. 2.546 - 2.547 -#### `max_longitude(ebox)` 2.548 - 2.549 -Returns the eastern boundary of a given `ebox` in degrees between -180 and +180 2.550 -(both inclusive). 2.551 - 2.552 -#### `min_latitude(ebox)` 2.553 - 2.554 -Returns the southern boundary of a given `ebox` in degrees between -90 and +90. 2.555 - 2.556 -#### `min_longitude(ebox)` 2.557 - 2.558 -Returns the western boundary of a given `ebox` in degrees between -180 and +180 2.559 -(both inclusive). 2.560 - 2.561 -#### `latitude(epoint)` 2.562 - 2.563 -Returns the latitude value of an `epoint` in degrees between -90 and +90. 2.564 - 2.565 -#### `longitude(epoint)` 2.566 - 2.567 -Returns the longitude value of an `epoint` in degrees between -180 and +180 2.568 -(both inclusive). 2.569 - 2.570 -#### `radius(ecircle)` 2.571 - 2.572 -Returns the radius of an `ecircle` in meters. 2.573 -
3.1 --- a/make-doc.sh Thu Oct 23 10:39:05 2025 +0200 3.2 +++ b/make-doc.sh Thu Oct 23 15:15:56 2025 +0200 3.3 @@ -1,8 +1,8 @@ 3.4 #!/bin/sh 3.5 # 3.6 # This command can be used to update the README.html file after changing the 3.7 -# README.mkd file. 3.8 +# README.md file. 3.9 3.10 -echo "<html><head><title>"`grep '[^ \t\r\n][^ \t\r\n]*' README.mkd | head -n 1`"</title></head><body>" > README.html 3.11 -markdown2 README.mkd >> README.html 3.12 +echo "<html><head><title>"`grep '[^ \t\r\n][^ \t\r\n]*' README.md | head -n 1`"</title></head><body>" > README.html 3.13 +markdown2 README.md >> README.html 3.14 echo "</body></html>" >> README.html