-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathREADME.html
589 lines (417 loc) · 26 KB
/
README.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
<html><head><title>pgLatLon v0.12 documentation</title></head><body>
<h1>pgLatLon v0.12 documentation</h1>
<p>pgLatLon is a spatial database extension for the PostgreSQL object-relational
database management system providing geographic data types and spatial indexing
for the WGS-84 spheroid.</p>
<p>While many other spatial databases still use imprecise bounding boxes for
many operations, pgLatLon aims to support more precise calculations for all
implemented geographic operators. Efficient indexing of geographic objects
is provided using space-filling fractal curves. Optimizations on bit level
(including logarithmic compression) allow for a highly memory-efficient
non-overlapping index suitable for huge datasets.</p>
<p>pgLatLon is a lightweight solution as it only depends on PostgreSQL itself (and
a C compiler for building).</p>
<p>Unlike competing spatial extensions for PostgreSQL, pgLatLon is available under
the permissive MIT/X11 license to avoid problems with viral licenses like the
GPLv2/v3.</p>
<h2>Installation</h2>
<h3>Automatic installation</h3>
<p>Prerequisites:</p>
<ul>
<li>Ensure that the <code>pg_config</code> binary is in your path (shipped with PostgreSQL).</li>
<li>Ensure that GNU Make is available (either as <code>make</code> or <code>gmake</code>).</li>
</ul>
<p>Then simply type:</p>
<pre><code>make install
</code></pre>
<h3>Manual installation</h3>
<p>It is also possible to compile and install the extension without GNU Make as
follows:</p>
<pre><code>cc -Wall -O2 -fPIC -shared -I `pg_config --includedir-server` -o latlon-v0009.so latlon-v0009.c
cp latlon-v0009.so `pg_config --pkglibdir`
cp latlon.control `pg_config --sharedir`/extension/
cp latlon--*.sql `pg_config --sharedir`/extension/
</code></pre>
<h3>Loading the extension</h3>
<p>After installation, you can create a database and load the extension as
follows:</p>
<pre><code>% createdb test_database
% psql test_database
psql (9.5.4)
Type "help" for help.
test_database=# CREATE EXTENSION latlon;
</code></pre>
<h3>Updating</h3>
<p>Before updating your database cluster to a new version of pgLatLon, you may
want to uninstall the old by calling "<code>make uninstall</code>" in the unpacked source
code directory of your old pgLatLon version. You may also manually delete the
<code>latlon-v????.so</code> files from your PostgreSQL library directory and the
<code>latlon.control</code> and <code>latlon--*.sql</code> files from your PostgreSQL extension
directory.</p>
<p>The new version can be installed as described above. For altering an existing
database to use the installed new version (mandatory if you removed the old
version), execute the following SQL command in the respective databases:</p>
<pre><code>ALTER EXTENSION latlon UPDATE;
</code></pre>
<p>If the update contains modifications to operator classes, it may be necessary
to drop all indices on geographic data types first (you will get an error
message in this case). These indices can be re-created after the update.</p>
<p>Note that taking several update steps at once (e.g. updating from version 0.2
directly to version 0.4) requires the intermediate versions to be installed
(i.e. in this example version 0.3 would need to be installed). Whenever you
install or uninstall an intermediate or old version, make sure to afterwards
re-install the latest pgLatLon version to ensure that the <code>latlon.control</code> file
is available and points to the latest version.</p>
<p>If the update contains modifications to the internal data representation
format, an update path might not be available. In this case, create a dump of
your database, delete your database, and restore it from your dump.</p>
<p>Be sure to always keep backups of all your data before attempting to update.</p>
<h2>Reference</h2>
<h3>1. Types</h3>
<p>pgLatLon provides four geographic types: <code>epoint</code>, <code>ebox</code>, <code>ecircle</code>, and
<code>ecluster</code>.</p>
<h4><code>epoint</code></h4>
<p>A point on the Earth spheroid (WGS-84).</p>
<p>The text input format is <code>'[N|S]<float> [E|W]<float>'</code>, where each float is in
degrees. Note the required white space between the latitude and longitude
components. Each floating point number may have a sign, in which case <code>N</code>/<code>S</code>
or <code>E</code>/<code>W</code> are switched respectively (e.g. <code>E-5</code> is the same as <code>W5</code>).</p>
<p>An <code>epoint</code> may also be created from two floating point numbers by calling
<code>epoint(latitude, longitude)</code>, where positive latitudes are used for the
northern hemisphere, negative latitudes are used for the southern hemisphere,
positive longitudes indicate positions east of the prime meridian, and negative
longitudes indicate positions west of the prime meridian.</p>
<p>Latitudes exceeding -90 or +90 degrees are truncated to -90 or +90
respectively, in which case a warning will be issued. Longitudes exceeding -180
or +180 degrees will be converted to values between -180 and +180 (both
inclusive) by adding or substracting a multiple of 360 degrees, in which case a
notice will be issued.</p>
<p>If the latitude is -90 or +90 (south pole or north pole), a longitude value is
still stored in the datum, and if a point is on the prime meridian or the
180th meridian, the east/west bit is also stored in the datum. In case of the
prime meridian, this is done by storing a floating point value of -0 for
0 degrees west and a value of +0 for 0 degrees east. In case of the
180th meridian, this is done by storing -180 or +180 respectively. The equality
operator, however, returns true when the same points on Earth are described,
i.e. the longitude is ignored for the poles, and 180 degrees west is considered
to be equal to 180 degrees east.</p>
<h4><code>ebox</code></h4>
<p>An area on Earth demarcated by a southern and northern latitude, and a western
and eastern longitude (all given in WGS-84).</p>
<p>The text input format is
<code>'{N|S}<float> {E|W}<float> {N|S}<float> {E|W}<float>'</code>, where each float is in
degrees. The ordering of the four white-space separated blocks is not
significant. To include the 180th meridian, one longitude boundary must be
equal to or exceed <code>W180</code> or <code>E180</code>, e.g. <code>'N10 N20 E170 E190'</code>.</p>
<p>A special value is the empty area, denoted by the text represenation <code>'empty'</code>.
Such an <code>ebox</code> does not contain any point.</p>
<p>An <code>ebox</code> may also be created from four floating point numbers by calling
<code>ebox(min_latitude, max_latitude, min_longitude, max_longitude)</code>, where
positive values are used for north and east, and negative values are used for
south and west. If <code>min_latitude</code> is strictly greater than <code>max_latitude</code>, an
empty <code>ebox</code> is created. If <code>min_longitude</code> is greater than <code>max_longitude</code> and
if both longitudes are between -180 and +180 degrees, then the area oriented in
such way that the 180th meridian is included.</p>
<p>If the longitude span is less than 120 degrees, an <code>ebox</code> may be alternatively
created from two <code>epoints</code> in the following way: <code>ebox(epoint(lat1, lon1),
epoint(lat2, lon2))</code>. In this case <code>lat1</code> and <code>lat2</code> as well as <code>lon1</code> and
<code>lon2</code> can be swapped without any impact.</p>
<h4><code>ecircle</code></h4>
<p>An area containing all points not farther away from a given center point
(WGS-84) than a given radius.</p>
<p>The text input format is <code>'{N|S}<float> {E|W}<float> <float>'</code>, where the first
two floats denote the center point in degrees and the third float denotes the
radius in meters. A radius equal to minus infinity denotes an empty circle
which contains no point at all (despite having a center), while a radius equal
to zero denotes a circle that includes a single point.</p>
<p>An <code>ecircle</code> may also be created by calling <code>ecircle(epoint(...), radius)</code> or
from three floating point numbers by calling <code>ecircle(latitude, longitude,
radius)</code>.</p>
<h4><code>ecluster</code></h4>
<p>A collection of points, paths, polygons, and outlines on the WGS-84 spheroid.
Each path, polygon, or outline must cover a longitude range of less than
180 degrees to avoid ambiguities.</p>
<p>The text input format is a white-space separated list of the following items:</p>
<ul>
<li><code>point ({N|S}<float> {E|W}<float>)</code></li>
<li><code>path ({N|S}<float> {E|W}<float> {N|S}<float> {E|W}<float> ...)</code></li>
<li><code>outline ({N|S}<float> {E|W}<float> {N|S}<float> {E|W}<float> {N|S}<float> {E|W}<float> ...)</code></li>
<li><code>polygon ({N|S}<float> {E|W}<float> {N|S}<float> {E|W}<float> {N|S}<float> {E|W}<float> ...)</code></li>
</ul>
<p>Paths are open by default (i.e. there is no connection from the last point in
the list to the first point in the list). Outlines and polygons, in contrast,
are automatically closed (i.e. there is a line segment from the last point in
the list to the first point in the list) which means the first point should not
be repeated as last point in the list. Polygons are filled, outlines are not.</p>
<h3>2. Indices</h3>
<p>Two kinds of indices are supported: B-tree and GiST indices.</p>
<h4>B-tree indices</h4>
<p>A B-tree index can be used for simple equality searches and is supported by the
<code>epoint</code>, <code>ebox</code>, and <code>ecircle</code> data types. B-tree indices can not be used for
geographic searches.</p>
<h4>GiST indices</h4>
<p>For geographic searches, GiST indices must be used. The <code>epoint</code>, <code>ecircle</code>,
and <code>ecluster</code> data types support GiST indexing. A GiST index for geographic
searches can be created as follows:</p>
<pre><code>CREATE TABLE tbl (
id serial4 PRIMARY KEY,
loc epoint NOT NULL );
CREATE INDEX name_of_index ON tbl USING gist (loc);
</code></pre>
<p>GiST indices also support nearest neighbor searches when using the distance
operator (<code><-></code>) in the ORDER BY clause.</p>
<h4>Indices on other data types (e.g. GeoJSON)</h4>
<p>Note that further types can be indexed by using an index on an expression with
a conversion function. One conversion function provided by pgLatLon is the
<code>GeoJSON_to_ecluster(jsonb, text)</code> function:</p>
<pre><code>CREATE TABLE tbl (
id serial4 PRIMARY KEY,
loc jsonb NOT NULL );
CREATE INDEX name_of_index ON tbl USING gist((GeoJSON_to_ecluster("loc")));
</code></pre>
<p>When using the conversion function in an expression, the index will be used
automatically:</p>
<pre><code>SELECT * FROM tbl WHERE GeoJSON_to_ecluster("loc") && 'N50 E10 10000'::ecircle;
</code></pre>
<h3>3. Operators</h3>
<h4>Equality operator <code>=</code></h4>
<p>Tests if two geographic objects are equal.</p>
<p>The longitude is ignored for the poles, and 180 degrees west is considered to
be equal to 180 degrees east.</p>
<p>For boxes and circles, two empty objects are considered equal. (Note that a
circle is not empty if the radius is zero but only if it is negative infinity,
i.e. smaller than zero.) Two circles with a positive infinite radius are also
considered equal.</p>
<p>Implemented for:</p>
<ul>
<li><code>epoint = epoint</code></li>
<li><code>ebox = ebox</code></li>
<li><code>ecircle = ecircle</code></li>
</ul>
<p>The negation is the inequality operator (<code><></code> or <code>!=</code>).</p>
<h4>Linear ordering operators <code><<<</code>, <code><<<=</code>, <code>>>>=</code>, <code>>>></code></h4>
<p>These operators create an arbitrary (but well-defined) linear ordering of
geographic objects, which is used internally for B-tree indexing and merge
joins. These operators will usually not be used by an application programmer.</p>
<h4>Overlap operator <code>&&</code></h4>
<p>Tests if two geographic objects have at least one point in common. Currently
implemented for:</p>
<ul>
<li><code>epoint && ebox</code></li>
<li><code>epoint && ecircle</code></li>
<li><code>epoint && ecluster</code></li>
<li><code>ebox && ebox</code></li>
<li><code>ebox && ecircle</code></li>
<li><code>ebox && ecluster</code></li>
<li><code>ecircle && ecircle</code></li>
<li><code>ecircle && ecluster</code></li>
<li><code>ecluster && ecluster</code></li>
</ul>
<p>The <code>&&</code> operator is commutative, i.e. "<code>a && b</code>" is the same as "<code>b && a</code>".
Each commutation is supported as well.</p>
<h4>Lossy overlap operator <code>&&+</code></h4>
<p>Tests if two geographic objects may have at least one point in common. Opposed
to the <code>&&</code> operator, the <code>&&+</code> operator may return false positives and is
currently implemented for:</p>
<ul>
<li><code>epoint &&+ ecluster</code></li>
<li><code>ebox &&+ ecircle</code></li>
<li><code>ebox &&+ ecluster</code></li>
<li><code>ecircle &&+ ecluster</code></li>
<li><code>ecluster &&+ ecluster</code></li>
</ul>
<p>The <code>&&+</code> operator is commutative, i.e. "<code>a &&+ b</code>" is the same as "<code>b &&+ a</code>".
Each commutation is supported as well.</p>
<p>Where two data types support both the <code>&&</code> and the <code>&&+</code> operator, the <code>&&+</code>
operator computes faster.</p>
<h4>Contains operator <code>@></code></h4>
<p>Tests if the object right of the operator is contained in the object left of
the operator. Currently implemented for:</p>
<ul>
<li><code>ebox @> epoint</code> (alias for <code>&&</code>)</li>
<li><code>ebox @> ebox</code></li>
<li><code>ebox @> ecluster</code></li>
<li><code>ecluster @> epoint</code> (alias for <code>&&</code>)</li>
<li><code>ecluster @> ebox</code></li>
<li><code>ecluster @> ecluster</code></li>
</ul>
<p>The commutator of <code>@></code> ("contains") is <code><@</code> ("is contained in"), i.e.
"<code>a @> b</code>" is the same as "<code>b <@ a</code>".</p>
<p>Whether the perimeter of an object is taken into account is undefined and may
differ between the left and the right hand side of the operator. The current
implementation returns true only if an object is contained completely within
the other object, not touching its perimeter, paths, outlines, or any singular
points.</p>
<h4>Distance operator <code><-></code></h4>
<p>Calculates the shortest distance between two geographic objects in meters (zero
if the objects are overlapping). Currently implemented for:</p>
<ul>
<li><code>epoint <-> epoint</code></li>
<li><code>epoint <-> ebox</code></li>
<li><code>epoint <-> ecircle</code></li>
<li><code>epoint <-> ecluster</code></li>
<li><code>ebox <-> ebox</code></li>
<li><code>ebox <-> ecircle</code></li>
<li><code>ebox <-> ecluster</code></li>
<li><code>ecircle <-> ecircle</code></li>
<li><code>ecircle <-> ecluster</code></li>
<li><code>ecluster <-> ecluster</code></li>
</ul>
<p>The <code><-></code> operator is commutative, i.e. "<code>a <-> b</code>" is the same as "<code>b <-> a</code>".
Each commutation is supported as well.</p>
<p>For short distances, the result is very accurate (i.e. respects the dimensions
of the WGS-84 spheroid). For longer distances in the order of magnitude of
Earth's radius or greater, the value is only approximate (but the error is
still less than 0.2% as long as no polygons with very long edges are involved).</p>
<p>The functions <code>distance(epoint, epoint)</code> and <code>distance(ecluster, epoint)</code> can
be used as an alias for this operator.</p>
<p>Note: In case of radial searches with a fixed radius, this operator should
not be used. Instead, an <code>ecircle</code> should be created and used in combination
with the overlap operator (<code>&&</code>). Alternatively, the functions
<code>distance_within(epoint, epoint, float8)</code> or <code>distance_within(ecluster, epoint,
float8)</code> can be used for fixed-radius searches.</p>
<h3>4. Functions</h3>
<h4><code>center(circle)</code></h4>
<p>Returns the center of an <code>ecircle</code> as an <code>epoint</code>.</p>
<h4><code>distance(epoint, epoint)</code></h4>
<p>Calculates the distance between two <code>epoint</code> datums in meters. This function is
an alias for the distance operator <code><-></code>.</p>
<p>Note: In case of radial searches with a fixed radius, this function should not be
used. Use <code>distance_within(epoint, epoint, float8)</code> instead.</p>
<h4><code>distance(ecluster, epoint)</code></h4>
<p>Calculates the distance from an <code>ecluster</code> to an <code>epoint</code> in meters. This
function is an alias for the distance operator <code><-></code>.</p>
<p>Note: In case of radial searches with a fixed radius, this function should not be
used. Use <code>distance_within(epoint, epoint, float8)</code> instead.</p>
<h4><code>distance_within(</code>variable <code>epoint,</code> fixed <code>epoint,</code> radius <code>float8)</code></h4>
<p>Checks if the distance between two <code>epoint</code> datums is not greater than a given
value (search radius).</p>
<p>Note: In case of radial searches with a fixed radius, the first argument must
be used for the table column, while the second argument must be used for the
search center. Otherwise an existing index cannot be used.</p>
<h4><code>distance_within(</code>variable <code>ecluster,</code> fixed <code>epoint,</code> radius <code>float8)</code></h4>
<p>Checks if the distance from an <code>ecluster</code> to an <code>epoint</code> is not greater than a
given value (search radius).</p>
<h4><code>ebox(</code>latmin <code>float8,</code> latmax <code>float8,</code> lonmin <code>float8,</code> lonmax <code>float8)</code></h4>
<p>Creates a new <code>ebox</code> with the given boundaries.
See "1. Types", subsection <code>ebox</code> for details.</p>
<h4><code>ebox(epoint, epoint)</code></h4>
<p>Creates a new <code>ebox</code>. This function may only be used if the longitude
difference is less than or equal to 120 degrees.
See "1. Types", subsection <code>ebox</code> for details.</p>
<h4><code>ecircle(epoint, float8)</code></h4>
<p>Creates an <code>ecircle</code> with the given center point and radius.</p>
<h4><code>ecircle(</code>latitude <code>float8,</code> longitude <code>float8,</code> radius <code>float8)</code></h4>
<p>Creates an <code>ecircle</code> with the given center point and radius.</p>
<h4><code>ecluster_concat(ecluster, ecluster)</code></h4>
<p>Combines two clusters to form a new <code>ecluster</code> by uniting all entries of both
clusters. Note that two overlapping areas of polygons annihilate each other
(which may be used to create polygons with holes).</p>
<h4><code>ecluster_concat(ecluster[])</code></h4>
<p>Creates a new <code>ecluster</code> that unites all entries of all clusters in the passed
array. Note that two overlapping areas of polygons annihilate each other (which
may be used to create polygons with holes).</p>
<h4><code>ecluster_create_multipoint(epoint[])</code></h4>
<p>Creates a new <code>ecluster</code> which contains multiple points.</p>
<h4><code>ecluster_create_outline(epoint[])</code></h4>
<p>Creates a new <code>ecluster</code> that is an outline given by the passed points.</p>
<h4><code>ecluster_create_path(epoint[])</code></h4>
<p>Creates a new <code>ecluster</code> that is a path given by the passed points.</p>
<h4><code>ecluster_create_polygon(epoint[])</code></h4>
<p>Creates a new <code>ecluster</code> that is a polygon given by the passed points.</p>
<h4><code>ecluster_extract_outlines(ecluster)</code></h4>
<p>Set-returning function that returns the outlines of an <code>ecluster</code> as <code>epoint[]</code>
rows.</p>
<h4><code>ecluster_extract_paths(ecluster)</code></h4>
<p>Set-returning function that returns the paths of an <code>ecluster</code> as <code>epoint[]</code>
rows.</p>
<h4><code>ecluster_extract_points(ecluster)</code></h4>
<p>Set-returning function that returns the points of an <code>ecluster</code> as <code>epoint</code>
rows.</p>
<h4><code>ecluster_extract_polygons(ecluster)</code></h4>
<p>Set-returning function that returns the polygons of an <code>ecluster</code> as <code>epoint[]</code>
rows.</p>
<h4><code>empty_ebox</code>()</h4>
<p>Returns the empty <code>ebox</code>.
See "1. Types", subsection <code>ebox</code> for details.</p>
<h4><code>epoint(</code>latitude <code>float8,</code> longitude <code>float8)</code></h4>
<p>Returns an <code>epoint</code> with the given latitude and longitude.</p>
<h4><code>epoint_latlon(</code>latitude <code>float8,</code> longitude <code>float8)</code></h4>
<p>Alias for <code>epoint(float8, float8)</code>.</p>
<h4><code>epoint_lonlat(</code>longitude <code>float8,</code> latitude <code>float8)</code></h4>
<p>Same as <code>epoint(float8, float8)</code> but with arguments reversed.</p>
<h4><code>fair_distance(ecluster, epoint,</code> samples <code>int4 = 10000)</code></h4>
<p>When working with user-generated content, users may be tempted to create
intentionally oversized objects in order to optimize search results in an
unfair manner. The <code>fair_distance</code> function aims to handle this by returning an
adjusted distance (i.e. distance increased by a penalty) if a geographic object
(the <code>ecluster</code>) consists of more than one point.</p>
<p>The first argument to this function is an <code>ecluster</code>, the second argument is a
search point (<code>epoint</code>), and the third argument is an interger related to the
precision (higher precision will require more computation time).</p>
<p>The penalty by which the returned distance is increased fulfills (at least) the
following properties:</p>
<ul>
<li>The penalty function is continuous (except noise created by numerical
integration, see paragraph after this list) as long as no objects are added
to or removed from the <code>ecluster</code>. That particularly means: small changes in
the search point (second argument) cause only small changes in the result.</li>
<li>For search points far away from the <code>ecluster</code> (i.e. large distances compared
to the dimensions of the <code>ecluster</code>), the penalty approaches zero, i.e. the
behavior of the <code>fair_distance</code> function approaches the behavior of the
<code>distance</code> function.</li>
<li>If the <code>ecluster</code> consists of a set of points, the penalty for a search point
close to one of those points (closer than half of the minimum distance
between each pair of points in the <code>ecluster</code>) is chosen in such a way that
the adjusted distance is equal to the distance from the search point to the
closest point in the <code>ecluster</code> multiplied by the square root of the count of
points in the <code>ecluster</code>.</li>
<li>If the <code>ecluster</code> does not cover any area (i.e. only consists of points,
paths, and/or outlines), and if the search point (second argument) overlaps
with the <code>ecluster</code>, then the penalty (and thus the result) is zero.</li>
<li>The integral (or average) of the square of the fair distance value (result of
this function) over all possible search points is independent of the
<code>ecluster</code> as long as the <code>ecluster</code> does not cover more than a half of
earth's surface.</li>
</ul>
<p>The function uses numerical integration to compute the result. The third
parameter (which defaults to 10000) can be used to adjust the number of samples
taken. A higher sample count increases precision as well as execution time of
the function. Because this function internally uses a spherical model of earth
for certain steps of the calculation, the precision cannot be increased
unboundedly.</p>
<p>Despite the limitations explained above, it is ensured that the penalty is
always positive, i.e. results returned by the <code>fair_distance</code> function are
always equal to or greater than the results returned by the <code>distance</code>
function regardless of stochastic effects. Furthermore, all results are
deterministic and reproducible with the same version of pgLatLon.</p>
<h4><code>GeoJSON_to_epoint(jsonb, text)</code></h4>
<p>Maps a GeoJSON object of type "Point" or "Feature" (which contains a
"Point") to an <code>epoint</code> datum. For any other JSON objects, NULL is returned.</p>
<p>The second parameter (which defaults to <code>epoint_lonlat</code>) may be set to a name
of a conversion function that transforms two coordinates (two <code>float8</code>
parameters) to an <code>epoint</code>.</p>
<h4><code>GeoJSON_to_ecluster(jsonb, text)</code></h4>
<p>Maps a (valid) GeoJSON object to an <code>ecluster</code>. Note that this function
does not check whether the JSONB object is a valid GeoJSON object.</p>
<p>The second parameter (which defaults to <code>epoint_lonlat</code>) may be set to a name
of a conversion function that transforms two coordinates (two <code>float8</code>
parameters) to an <code>epoint</code>.</p>
<h4><code>max_latitude(ebox)</code></h4>
<p>Returns the northern boundary of a given <code>ebox</code> in degrees between -90 and +90.</p>
<h4><code>max_longitude(ebox)</code></h4>
<p>Returns the eastern boundary of a given <code>ebox</code> in degrees between -180 and +180
(both inclusive).</p>
<h4><code>min_latitude(ebox)</code></h4>
<p>Returns the southern boundary of a given <code>ebox</code> in degrees between -90 and +90.</p>
<h4><code>min_longitude(ebox)</code></h4>
<p>Returns the western boundary of a given <code>ebox</code> in degrees between -180 and +180
(both inclusive).</p>
<h4><code>latitude(epoint)</code></h4>
<p>Returns the latitude value of an <code>epoint</code> in degrees between -90 and +90.</p>
<h4><code>longitude(epoint)</code></h4>
<p>Returns the longitude value of an <code>epoint</code> in degrees between -180 and +180
(both inclusive).</p>
<h4><code>radius(ecircle)</code></h4>
<p>Returns the radius of an <code>ecircle</code> in meters.</p>
</body></html>