Compare commits

..

916 Commits

Author SHA1 Message Date
Sarah Hoffmann
edd77e3184 prepare for 3.2.1 release 2020-05-02 23:02:56 +02:00
Sarah Hoffmann
f549379e31 properly escape class parameter
The class parameter was used as is, allowing for potential
SQL injection via the API.

Thanks to @bladeswords for finding this.
2020-05-02 23:01:27 +02:00
Sarah Hoffmann
627a487fcf prepare release 3.2.0 2018-08-26 17:33:49 +02:00
Sarah Hoffmann
b0d0d046e7 add migration for 3.2 version 2018-08-26 17:27:31 +02:00
Sarah Hoffmann
e09c42a78a add docs for class parameter in /details 2018-08-26 16:40:52 +02:00
Sarah Hoffmann
28d7e11e4f Merge pull request #1155 from lonvia/namespace-for-phpunit
use namespaces for PHPUnit classes
2018-08-26 15:51:11 +02:00
Sarah Hoffmann
a5d35d6e84 use namespaces for PHPUnit classes
This is mandatory for PHPUnit 6.x. Older versions provide a
forward compatibility layer, so we should be good.

Fixes #1150.
2018-08-25 14:57:31 +02:00
Sarah Hoffmann
e8982068b6 fix quotes to make phpcs happy 2018-08-24 21:39:20 +02:00
Sarah Hoffmann
6e3670bce5 add vagrant and installation instructions for ubuntu 18 2018-08-24 21:33:24 +02:00
Sarah Hoffmann
e7b738fe35 cleanup documentation
Remove level 3 (page title) from TOC and add permalinks.
Also fix and update some minor stuff in the docs.
2018-08-23 23:14:41 +02:00
Sarah Hoffmann
1ee636461c Mute notices from postgresql during setup
They are mostly warnings about tables that do not exists. This
is intentional and would only confuse the casual user.
2018-08-23 21:14:34 +02:00
Sarah Hoffmann
c7e7d5e980 improve wording of error message 2018-08-23 20:58:15 +02:00
Sarah Hoffmann
57bf76a0e1 Merge branch 'customPHP1' of https://github.com/ThomasBarris/Nominatim into ThomasBarris-customPHP1 2018-08-23 20:41:44 +02:00
Sarah Hoffmann
c80c80200c fix links in details documentation
Thanks to @JamesKingdom.
2018-08-23 20:30:07 +02:00
ThomasBarris
5859f9a3cb just add missing semicolon in importWikipedia.php line 312 2018-08-23 19:36:13 +02:00
ThomasBarris
a825414558 push the right version of update.php 2018-08-23 10:02:34 +02:00
ThomasBarris
6577be3744 delete PHP_BIN from default and add @PHP_BIN@ to passthru function in update.php 2018-08-23 09:24:51 +02:00
ThomasBarris
e936041713 Revert "Split of setup.php into one file with functions and one with the control of the workflow. The functions will also be included by update.php to avoid the passthru"
This reverts commit 55fa051d3a.
2018-08-23 08:07:40 +02:00
ThomasBarris
a8b31090a1 Revert "code beauty improvements"
This reverts commit ee3973f507.
2018-08-23 08:07:08 +02:00
Sarah Hoffmann
14e708f366 ignore linked country nodes for reverse geocoding
Fixes #1145.
2018-08-22 23:33:11 +02:00
Sarah Hoffmann
3502ff837f Merge pull request #1151 from mtmail/documentation-for-details-endpoint
documentation for /details endpoint
2018-08-22 22:38:32 +02:00
Sarah Hoffmann
84cfe5db53 fix warning in keyword output of details 2018-08-22 22:35:46 +02:00
Sarah Hoffmann
26bd8304c6 fix formatting 2018-08-22 22:25:55 +02:00
ThomasBarris
ee3973f507 code beauty improvements 2018-08-22 21:33:17 +02:00
ThomasBarris
55fa051d3a Split of setup.php into one file with functions and one with the control of the workflow. The functions will also be included by update.php to avoid the passthru 2018-08-22 21:06:55 +02:00
marc tobias
4d38833170 documentation for /details endpoint 2018-08-22 13:55:43 +02:00
marc tobias
e47646ddba in /details JSON output add check if place (type) has an icon set 2018-08-22 13:34:34 +02:00
marc tobias
7081e2ab66 documentation for /details endpoint 2018-08-21 17:15:47 +02:00
ThomasBarris
e286536959 replaced all shebangs in utility scripts with @PHP_BIN@, to be replaced with detected PHP binary on install 2018-08-21 13:21:08 +02:00
Sarah Hoffmann
88374c2522 improve test coverage for reverse and debug output 2018-08-20 23:05:49 +02:00
Sarah Hoffmann
3fcfab9772 clean up reverse code
Removes unused variables, improves naming of internal functions
and makes structure of SQL calls a bit cleaner.
2018-08-20 23:04:33 +02:00
Sarah Hoffmann
de8888ec58 directly do country search for reverse zoom < 5
Fixes #1145.
2018-08-20 22:09:08 +02:00
Sarah Hoffmann
3af8dc9580 Merge pull request #1148 from mtmail/docs-review
small typos and wording in the API docs
2018-08-20 21:23:01 +02:00
marc tobias
71ae7f10f7 small typos and wording in the API docs 2018-08-20 19:11:38 +02:00
ThomasBarris
38304136d3 Allow custom locations for PHP binary - part 1 2018-08-20 17:24:20 +02:00
Sarah Hoffmann
ff4b1758e1 reduce search radius when searching for nodes within country 2018-08-19 18:08:05 +02:00
Sarah Hoffmann
a9b4894b07 update osm2pgsql to latest master 2018-08-17 22:43:08 +02:00
Sarah Hoffmann
28ba5fc8a4 Merge pull request #1138 from mtmail/php-test-for-sqlViewboxLarge
test for SearchContext::setViewboxFromBox
2018-08-14 21:59:24 +02:00
marc tobias
c7a4c2c88a test for SearchContext::setViewboxFromBox 2018-08-14 17:37:54 +02:00
Sarah Hoffmann
0617768ee2 Fix partial word computation
Partial word tokens have a space at the beginning of the
token not the word.
2018-08-13 21:22:45 +02:00
Sarah Hoffmann
62b60c70e6 reverse on street level should compute distance to object
The centroid of a building may be far away even when still inside
the building.

Fixes #1136.
2018-08-13 21:17:49 +02:00
Sarah Hoffmann
0394f32438 fix large viewbox computation
Fixes #1137.
2018-08-13 20:52:49 +02:00
Sarah Hoffmann
569184a5b0 add FAQ from nominatim.org 2018-08-11 14:47:36 +02:00
Sarah Hoffmann
41c4b51be5 add description of output of API 2018-08-11 14:17:41 +02:00
Sarah Hoffmann
513bf485f2 clean up docs for lookup call 2018-08-11 09:24:59 +02:00
Sarah Hoffmann
263240919c clean up and format search documentation 2018-08-09 23:06:52 +02:00
Sarah Hoffmann
d2b9493d72 clean up and format search documentation 2018-08-09 21:47:57 +02:00
Sarah Hoffmann
60cea6c8bf fixup use of indexes for latest reverse changes 2018-08-08 22:04:39 +02:00
Sarah Hoffmann
9b7f0627ea Merge pull request #1111 from lonvia/remove-postcode-nodes-from-address
Do not have postcode node appear in addresses directly
2018-08-05 17:04:54 +02:00
Sarah Hoffmann
2e9cebf025 define types for null returns in PlaceLookup
Fixes #1127.
2018-08-05 15:47:55 +02:00
Sarah Hoffmann
48d4ea5542 Do not have postcode node appear in addresses directly
Many of the postcode nodes are actually derived from
incomplete addresses and are as such not even centroids.
Better let them only take part in the address computation
via the postcode table.
2018-08-05 14:25:20 +02:00
Sarah Hoffmann
9bdbbec0c8 Merge pull request #1110 from lonvia/remove-address-check-for-long-lines
Remove special search for address part for long ways
2018-08-04 23:19:32 +02:00
Sarah Hoffmann
8f0b3cb00f Merge pull request #1126 from lonvia/improve-country-reverse
improve place node search when no areas found
2018-08-04 23:00:13 +02:00
Sarah Hoffmann
646fa53b44 improve place node search when no areas found
Only look for place nodes in a certain radius according
to the rank_search of the place node.
2018-08-04 21:51:23 +02:00
Sarah Hoffmann
7f10264fb6 Merge pull request #1095 from estadtherr/remote_postgres_pr
Enable Postgres to run on a different host than the web server
2018-08-02 23:16:07 +02:00
Sarah Hoffmann
7e0fdf5928 fall back to debugInfo() for printing objects
Fixes #1122.
2018-08-02 00:06:02 +02:00
Sarah Hoffmann
4a28d28c08 prefix function calls in make_standard_name() with schema
Fixes #1097.
2018-08-01 23:12:34 +02:00
Eric Stadtherr
bfea79f1e4 address phpcs issue (strange it didn't appear in earlier runs) 2018-07-30 11:20:43 -06:00
Eric Stadtherr
87d78e87d2 changed nominatim.so module path to be a runtime configuration setting as opposed to a command line argument 2018-07-24 15:25:12 -06:00
Sarah Hoffmann
c712c6e55e Merge pull request #1115 from mtmail/php-linting-for-all-not-just-tests
On Travis phpcs only ran against tests/php/ directory
2018-07-23 22:41:24 +02:00
Marc Tobias Metten
510054492c On Travis phpcs only ran against tests/php/ directory 2018-07-23 22:18:32 +02:00
Sarah Hoffmann
12db7a9af2 Merge pull request #1113 from mtmail/remove-empty-icon-configuration
ClassTypes: treat empty string for -icon-same as null
2018-07-23 20:37:31 +02:00
Sarah Hoffmann
fcab682231 Merge pull request #1114 from mtmail/fix-tiny-phplint-error
PHP code style: use long array syntax
2018-07-23 20:35:38 +02:00
marc tobias
0981a6403d PHP code style: use long array syntax 2018-07-23 17:24:31 +02:00
marc tobias
37bd4dfd83 ClassTypes: treat empty string for -icon-same as null 2018-07-23 17:10:27 +02:00
Eric Stadtherr
057d77fcd4 rework repeatability change in data/words.sql 2018-07-22 15:58:11 -06:00
Sarah Hoffmann
713ea080d2 Remove special search for address part for long ways
Ways now always have the complete set of crossing boundaries
independent of the length.

Fixes #1108.
2018-07-22 15:05:45 +02:00
Eric Stadtherr
bf5063de9a fix variable reference 2018-07-21 21:59:03 -06:00
Eric Stadtherr
13efedde34 fix omitted initialization 2018-07-21 21:53:41 -06:00
Eric Stadtherr
c1beefd543 PR review changes 2018-07-21 21:45:23 -06:00
Eric Stadtherr
1d81c17335 fix a couple errors with naming convention changes 2018-07-21 20:43:48 -06:00
Eric Stadtherr
b8b87716db adapt PR changes to use new variable naming convention 2018-07-21 17:09:59 -06:00
Eric Stadtherr
1108bf7d86 PR review changes 2018-07-21 12:09:47 -06:00
Eric Stadtherr
62747c934d Work on setup/update scripts, unit tests, and documentation to enable Postgres server to be optionally configured on a remote host 2018-07-21 12:09:47 -06:00
Sarah Hoffmann
81b90c9f15 add a note about variable naming for PHP 2018-07-21 08:47:37 +02:00
Sarah Hoffmann
5a772a5770 Don't add viewbox weight when no viewbox is given
Fixes #1068.
2018-07-20 23:29:36 +02:00
Sarah Hoffmann
3433ec306e fix operator type assignment
Fixes #1084.
2018-07-20 22:27:27 +02:00
Sarah Hoffmann
03039ebfa8 Merge pull request #1102 from mtmail/tests-for-tokenlist
tests for Nominatim::TokenList
2018-07-20 21:39:04 +02:00
Sarah Hoffmann
271c23f459 Merge pull request #1099 from lonvia/sanity-check-pyosmium
More sanity checks for pyosmium tools
2018-07-20 21:37:27 +02:00
Marc Tobias Metten
0892eab1d3 tests for Nominatim::TokenList 2018-07-19 14:19:50 +02:00
Sarah Hoffmann
d68996127d fix bad namespace for Operator class 2018-07-17 22:38:40 +02:00
Sarah Hoffmann
83270557a7 more sanity checks for pyosmium tools 2018-07-17 21:54:37 +02:00
Sarah Hoffmann
0e4f80bf1b Merge pull request #1090 from mtmail/add-more-nominatim.so-faq-entries
FAQ: more answers regarding nominatim.so file permissions
2018-07-13 21:33:13 +02:00
Sarah Hoffmann
b7abc8566e Merge pull request #1089 from lonvia/clean-up-address-computation
Classes for ClassTypes and AddressDetails and geocodejson cleanup
2018-07-13 21:27:00 +02:00
marc tobias
92f86de938 FAQ: more answers regarding nominatim.so file permissions 2018-07-13 18:43:51 +02:00
Sarah Hoffmann
b17019a21c fix unit tests for class types 2018-07-12 23:59:29 +02:00
Sarah Hoffmann
be58b929f2 add tests for geocodejson and fix syntax errors 2018-07-12 22:00:18 +02:00
Sarah Hoffmann
25baaf530d unify address details lookup
Introduces new AddressDetails class which is responsible
for address lookups. Saves always the complete result
and then allows filtering throught the different access
function. Remove special handling in Geocode() and use
there the lookup throught PlaceLookup() as well.
2018-07-10 23:54:35 +02:00
Sarah Hoffmann
320d488627 move ClassTypes into own namespace
Also adds some convenience functions for lookups.
2018-07-09 23:20:46 +02:00
marc tobias
879f818d81 add geojson,geocodejson formats to API documentation 2018-07-09 16:06:48 +02:00
Sarah Hoffmann
80a6751c51 make phpcs happy 2018-07-06 22:06:05 +02:00
Sarah Hoffmann
05bef92f0f ignore admin_level = 15 in geocodejson output
Level 15 is an artifical value.
2018-07-06 21:59:17 +02:00
Sarah Hoffmann
01d5ecb86b use already existing address field in geocodejson 2018-07-06 21:58:41 +02:00
Sarah Hoffmann
f50f46c1ce Merge branch 'geojson-output' of https://github.com/mtmail/Nominatim into mtmail-geojson-output 2018-07-06 20:26:33 +02:00
Sarah Hoffmann
adae49b184 remove trailing spaces 2018-07-05 19:28:17 +02:00
Sarah Hoffmann
2bd7c75a35 avoid 'SELECT *' 2018-07-05 19:27:21 +02:00
Sarah Hoffmann
9955155ce0 update tests for off-coast reverse geocoding 2018-07-04 21:03:04 +02:00
Sarah Hoffmann
b0e0f7ae76 make sure index is used when looking for places in country 2018-07-04 20:56:09 +02:00
Sarah Hoffmann
0315b87664 update indexes for new reverse algorithm 2018-07-02 23:56:56 +02:00
Sarah Hoffmann
ac29f8bc91 Merge branch 'better-reverse' of https://github.com/gemo1011/Nominatim into gemo1011-better-reverse 2018-07-02 21:33:27 +02:00
Unknown
ec6a427e0a edited indices an setup file to grant select for table country_osm_grid 2018-06-28 11:34:19 +02:00
Sarah Hoffmann
09b59bd56a increase search radius when looking for addr:place base objects
Fixes #1036.
2018-06-27 22:45:34 +02:00
Sarah Hoffmann
d0548caa76 use computed postcode by default in export script 2018-06-27 21:39:00 +02:00
Sarah Hoffmann
96d2a331a1 install export script in build directory 2018-06-27 21:26:50 +02:00
gemo1011
1d7ed6737e added comments and improved geOutline function 2018-06-27 14:55:24 +02:00
gemo1011
97b6656182 no polygon search over country-level 2018-06-27 14:55:23 +02:00
gemo1011
f108eac527 changed the lookupPolygon function
- Search for Polygons begins at rank_address 4
- $iMaxRank changed to 25 if its higher
2018-06-27 14:55:22 +02:00
gemo1011
144c3b3eb2 fixed syntax error 2018-06-27 14:55:19 +02:00
gemo1011
426e108b34 added case when for highways in subquery 2018-06-27 14:55:18 +02:00
gemo1011
229ad01042 added search diameter for the place node search, depending on rank 2018-06-27 14:55:17 +02:00
gemo1011
71e3d8b1de GRANT SELECT ON Table country_osm_grid 2018-06-27 14:55:16 +02:00
gemo1011
a5750a6ef6 fixed getoutlinesfunction 2018-06-27 14:55:15 +02:00
gemo1011
d5e39260b3 updated indices for reverse geocoding 2018-06-27 14:55:14 +02:00
gemo1011
0996fdfb55 improvements for pull request 2018-06-27 14:55:13 +02:00
gemo1011
07eb108a6d fixed typo 2018-06-27 14:55:12 +02:00
gemo1011
41249377d2 fixed getoutlines function if no coordinates are passed 2018-06-27 14:55:11 +02:00
gemo1011
be091b17d9 better search for interpolated housenumbers 2018-06-27 14:55:10 +02:00
gemo1011
398467b2f4 using ST_ClosestPoint and a subquery 2018-06-27 14:55:10 +02:00
gemo1011
796f069d74 test adjusting 2018-06-27 14:55:09 +02:00
gemo1011
82b6245aaa better place node search with rank_search 2018-06-27 14:55:08 +02:00
gemo1011
f0e5cf53b8 only starts the search in country_osm_grid if $iMaxRank > 4 2018-06-27 14:55:07 +02:00
gemo1011
7585d37818 edited test 2018-06-27 14:55:07 +02:00
gemo1011
ee54ebfe77 new query if no polygon is found
the new query searchs in the country_osm_grid table for a polygon
2018-06-27 14:55:06 +02:00
gemo1011
43ee4a8faf changed parameters for lookup function in the reverse.php 2018-06-27 14:55:05 +02:00
gemo1011
ab5bcd6d2f rebase 2018-06-27 14:55:05 +02:00
gemo1011
6b8c99a275 rebase 2018-06-27 14:55:03 +02:00
gemo1011
073221d321 changed export.php to work with current master 2018-06-27 14:17:08 +02:00
Sarah Hoffmann
dfb9579a73 initial version of an export script
So far supports type selection down to street level, restriction to
country or an OSM place and postcode printing. Output is standard CSV.
2018-06-27 14:11:14 +02:00
Sarah Hoffmann
26bc83c984 Merge pull request #1069 from woodpeck/patch-2
limit default threads to 15
2018-06-21 22:16:24 +02:00
Frederik Ramm
8139a079f8 limit default threads to 15
When no explicit number of threads is given, don't simply use getProcessorCount()-1, but limit to max. 15
2018-06-20 14:17:07 +02:00
Sarah Hoffmann
0d341c256b Merge pull request #1062 from mtmail/display-viewbox-on-map
Display viewbox on map
2018-06-14 23:16:05 +02:00
Marc Tobias Metten
5a17bfc9c9 display viewbox on map 2018-06-14 02:19:19 +02:00
Marc Tobias Metten
1d981b3171 update leaflet.js 1.0 => 1.3 2018-06-14 02:18:00 +02:00
Sarah Hoffmann
743ec43460 nearest place search should match any of given tokens not all
When multiple isin tokens are given, then these are duplicates
and it is enough that any one of them is found in the
name_vector.

Fixes #1056.
2018-06-14 00:11:19 +02:00
Sarah Hoffmann
87ee3a6f58 Merge pull request #1053 from mtmail/update-tiger-install-instructions
Update tiger install instructions. Mirror no longer working
2018-06-12 22:54:29 +02:00
gemo1011
10897787af deleted query for place nodes search if no polygon is found and added search for interpolation lines 2018-06-05 11:54:12 +02:00
gemo1011
4d073b0350 new query to search place nodes if no polygon was found 2018-06-05 11:54:12 +02:00
gemo1011
625018b654 adapted the coding style with phpcs 2018-06-05 11:54:12 +02:00
gemo1011
5f2410119d better performance 2018-06-05 11:54:12 +02:00
gemo1011
424c0d0ebb faster query through bbox preselection 2018-06-05 11:54:12 +02:00
gemo1011
71c9adfdba performence update through subquerry 2018-06-05 11:54:12 +02:00
gemo1011
723bb4d0b9 changing to from rank_search to rank_address 2018-06-05 11:54:12 +02:00
gemo1011
cb76635da7 better performance for place node search 2018-06-05 11:54:12 +02:00
gemo1011
237e31b3ce use the linked_place_id for adress search if a place node is found with a linked_place_id 2018-06-05 11:54:12 +02:00
gemo1011
d0741f21b1 changed reverse geocode algorithm 2018-06-05 11:54:12 +02:00
marc tobias
a376608344 Update tiger install instructions. Mirror no longer working 2018-05-29 17:42:58 +02:00
Marc Tobias Metten
7a964efb3a search/reverse/lookup with geojson,geocodejson output 2018-05-29 17:20:34 +02:00
Sarah Hoffmann
1d0da944a6 document polygon_threashold parameter
Fixes #1041.
2018-05-15 23:30:58 +02:00
Sarah Hoffmann
d0880694eb Merge pull request #1043 from lonvia/token-as-a-class
Token as a class
2018-05-15 20:21:32 +02:00
Sarah Hoffmann
1f689bdaae document tokens 2018-05-14 23:23:38 +02:00
Sarah Hoffmann
6a0361d0c6 add documentation for TokenList 2018-05-14 23:17:54 +02:00
Sarah Hoffmann
f29c7bf910 introduce classes for token list and token types 2018-05-14 23:04:15 +02:00
Sarah Hoffmann
2cc4c73b64 Merge pull request #1038 from mtmail/phpcs-array-key-alignment
add PHPCS Squiz.Arrays.ArrayDeclaration.KeyNotAligned rule
2018-05-08 09:04:03 +02:00
Marc Tobias Metten
8841a328c8 add PHPCS Squiz.Arrays.ArrayDeclaration.KeyNotAligned rule 2018-05-08 00:37:41 +02:00
Sarah Hoffmann
c555b60b36 narrow down search by house number when postcode is given
Fixes #1034.
2018-05-07 21:34:11 +02:00
Sarah Hoffmann
b30e2ab5dc Merge pull request #1033 from lonvia/remove-word-frequency-scores
Replace word frequency hash
2018-05-07 20:59:20 +02:00
Sarah Hoffmann
115792d1db replace word frequency hash
The word frequency hash was only used to determine if the
name of a SearchDescription is rare. Do this already when
building the SearchDescription (when the word frequency
is still available) and get gid of the extra hash.
2018-05-06 22:35:31 +02:00
mtmail
7075a5828e add JSON format to /status endpoint (#1013)
add JSON format to /status endpoint
2018-05-04 23:37:48 +02:00
Sarah Hoffmann
bd04ce62e0 Merge pull request #1032 from mtmail/tests-for-debughtml
PHP unit tests for DebugHtml
2018-05-04 21:24:08 +02:00
Sarah Hoffmann
3bb6ecdc3b Merge pull request #1029 from lonvia/streamline-sql
streamline SQL for parenting rank 30 places
2018-05-04 21:17:09 +02:00
Marc Tobias Metten
a885e7309a PHP unit tests for DebugHtml 2018-05-03 22:19:19 +02:00
Sarah Hoffmann
6706a23fb5 streamline SQL for parenting rank 30 places
- avoid select all
 - prefer direct select into
 - use early loop exit when possible
2018-05-01 15:44:18 +02:00
Sarah Hoffmann
c7faab4d7c adapt reverse index to changed reverse query
Thanks to @gemo1011.
2018-05-01 15:29:39 +02:00
Sarah Hoffmann
080ba00956 Merge pull request #1024 from lonvia/reduce-address-search-terms
Reduce address search terms
2018-04-26 22:28:53 +02:00
Sarah Hoffmann
2613ebfa01 Merge pull request #977 from lonvia/fix-byteswap-check
clean up byte order detection
2018-04-18 21:35:32 +02:00
Sarah Hoffmann
53c526c01d remove search_name_country table
The table is no longer used, country names are handled
directly via the word table.
2018-04-16 20:47:45 +02:00
Sarah Hoffmann
dc371618ba remove now unused getNearestNamedRoadFeature() function 2018-04-16 20:34:28 +02:00
Sarah Hoffmann
59288417f0 remove debug code 2018-04-16 20:29:30 +02:00
Sarah Hoffmann
1dd401b570 remove use of is_in terms for address computation
The code has been dead for a long time because all is_in
terms have been added to the nameaddress_vector so
that the IF condition would never hit.
2018-04-16 20:27:16 +02:00
Sarah Hoffmann
ee194ab369 remove special search for Tiger postcodes
Postcodes should no longer appear in the address search terms.
2018-04-16 20:25:19 +02:00
Sarah Hoffmann
b8113abd93 fix variable name 2018-04-16 20:16:11 +02:00
Sarah Hoffmann
5182da9f45 add tests for address tag parsing for search name 2018-04-15 22:52:42 +02:00
Sarah Hoffmann
14c25717ab restrict addr:* tags that are used for search term
Fixes #1001.
2018-04-15 22:17:20 +02:00
mtmail
3087ac1145 PHP code style: enforce long array initialisation (#1015) 2018-04-13 13:18:29 +02:00
mtmail
cdbde5b88d get rid of Python psycopg2 install warning (#1014) 2018-04-13 12:28:12 +02:00
marc tobias
7a1ee99345 return centroid on geojson format 2018-04-12 22:02:24 +02:00
marc tobias
7a31a3d106 remove rank_search_label field 2018-04-12 22:02:24 +02:00
marc tobias
fe3dba3fd7 use RFC3339 for human readable date 2018-04-12 22:02:24 +02:00
marc tobias
31c7f25541 rename parentof to hierarchy and other lonvia Mar/29 PR feedback 2018-04-12 22:02:24 +02:00
Marc Tobias Metten
45aef06d00 localname field is required by nominatim-ui 2018-04-12 22:01:10 +02:00
Marc Tobias Metten
0eb71cdce8 only return polygon if &polygon_geojson=1 is set 2018-04-12 22:01:10 +02:00
marc tobias
45bc511955 variable naming after lonvia PR feedback 2018-04-12 22:01:10 +02:00
marc tobias
dedf56b5f8 spacing changes after lonvia PR feedback 2018-04-12 22:01:10 +02:00
Marc Tobias Metten
1e28f2478c details support json output 2018-04-12 22:01:10 +02:00
mtmail
3cdbcbff8f get apt-get php-db package running on travis-ci (#973)
travis: /usr/bin/env php whenever calling PHP scripts to deal with phpenv
2018-04-12 00:54:59 +02:00
Sarah Hoffmann
9a3bc9cc1e Merge pull request #1010 from lonvia/ignore-unicode-format-characters
Ignore Unicode format characters for normalization
2018-04-10 23:48:58 +02:00
Sarah Hoffmann
6bd905ff43 update osm2pgsql (name:suffix)
Fixes #823.
2018-04-10 23:46:57 +02:00
Sarah Hoffmann
ae83ceab5e ignore Unicode format characters for normalization
Also adds tests.

Fixes #1007.
2018-04-10 22:48:17 +02:00
Sarah Hoffmann
28ee59dd64 test: drop template DB when something goes wrong during creation
Fixes #951.
2018-04-08 10:06:33 +02:00
Sarah Hoffmann
b4ef3d91ab Merge pull request #1005 from lonvia/no-limit-for-housenumber-search
do not apply limit to house number place searches
2018-04-06 22:46:23 +02:00
Sarah Hoffmann
efac4a135a do not apply limit to house number place searches
Searches for house numbers are already limited by the
number of parent places. In fact, the limit assumed that
every parent place has exactly one match against the
given housenumber. That is not true in reality and so
we were dropping relevant results.

Fixes #329.
2018-04-06 22:20:21 +02:00
Sarah Hoffmann
984e91e519 Merge pull request #1003 from mtmail/details-permalink
details page: add a perma-link
2018-04-06 21:15:48 +02:00
Sarah Hoffmann
49dc62201c Merge pull request #1002 from mtmail/sql-bracket-error-in-details
when looking for keywords on detail page SQL bracket error was possible
2018-04-06 21:09:52 +02:00
marc tobias
4791fc341e details page: move permalink next to page title 2018-04-06 17:45:25 +02:00
marc tobias
4743a5e166 details page: add a perma-link 2018-04-06 16:11:54 +02:00
marc tobias
908c66ca84 when looking for keywords on detail page a SQL bracket error was possible 2018-04-06 15:22:29 +02:00
Sarah Hoffmann
62719f58c9 update osm2pgsql 2018-04-03 21:11:13 +02:00
Sarah Hoffmann
d183cd3c78 Merge pull request #994 from mtmail/bugfix-when-calling-debug-printDebugArray
fix -undefined offset- error
2018-03-27 09:04:59 +02:00
Sarah Hoffmann
ac5a901daf Merge pull request #992 from mtmail/phpcs-whitespace-warnings
phpcs: remove trailing whitespace from comments
2018-03-27 08:56:11 +02:00
Sarah Hoffmann
aaee03d502 Merge pull request #991 from mtmail/rename-NominatimTest-php
NominatimTest.php => LibTest.php
2018-03-27 08:54:11 +02:00
Marc Tobias Metten
329948e685 fix -undefined offset- error 2018-03-27 03:00:07 +02:00
Marc Tobias Metten
f6a76ebcd5 phpcs: remove trailing whitespace from comments 2018-03-27 01:43:02 +02:00
Marc Tobias Metten
1cb87164d9 NominatimTest.php => LibTest.php 2018-03-27 01:38:39 +02:00
Sarah Hoffmann
64fa70ac0a Merge pull request #989 from lonvia/pretty-debug
nicer formatting for Geocode debug output
2018-03-26 20:56:57 +02:00
Sarah Hoffmann
2c42bda9ce nicer formatting for Geocode debug output 2018-03-25 22:28:18 +02:00
Sarah Hoffmann
1787892d32 Merge pull request #986 from mtmail/php-replace-sizeof
replace PHP sizeof() with either count() or empty()
2018-03-24 18:51:34 +01:00
Sarah Hoffmann
7cc8f63125 Merge pull request #981 from mtmail/api-documentation-from-wiki-to-docs
copied API endpoint documentation from wiki.osm.org to /docs
2018-03-24 18:12:43 +01:00
Sarah Hoffmann
2b6515e704 Merge pull request #979 from mtmail/bdd-paths-in-vagrant-documentation
use real paths in BDD examples
2018-03-23 20:30:21 +01:00
marc tobias
27bc8d4f7b replace PHP sizeof() with either count() or empty() 2018-03-22 12:36:24 +01:00
marc tobias
90d531c640 copied API endpoint documentation from wiki.osm.org to /docs 2018-03-19 17:10:22 +01:00
Marc Tobias Metten
2c24b9da5a use real paths in BDD examples 2018-03-18 02:13:42 +01:00
Sarah Hoffmann
d79a2bb17e increase search radius for named streets in addresses
Fixes #950.
2018-03-16 23:37:42 +01:00
Sarah Hoffmann
4ac1bf2d47 clean up byte order detection
Check for existence of the expected functions and macros
and error out if nothing appropriate can be found.
2018-03-16 23:09:40 +01:00
Sarah Hoffmann
8b4b647d77 Merge pull request #974 from mtmail/remove-two-minute-data-date-offset
remove the 2-minute offset hack from data date in HTML output
2018-03-16 21:18:49 +01:00
Sarah Hoffmann
6495717036 Merge pull request #969 from mtmail/update-vagrant-md
update Vagrant instructions. E.g. cucumber => behave
2018-03-16 20:25:52 +01:00
marc tobias
d23fa84471 remove the 2-minute offset hack from data date in HTML output 2018-03-14 16:42:41 +01:00
marc tobias
937c8ba231 update Vagrant instructions. E.g. cucumber => behave 2018-03-14 16:12:39 +01:00
Marc Tobias Metten
88beeb7916 merge json and jsonv2 templates, they were very similar 2018-03-13 23:49:04 +01:00
marc tobias
34a27c7cab update Vagrant instructions. E.g. cucumber => behave 2018-03-09 15:06:57 +01:00
Sarah Hoffmann
c04541b4da remove now unnecessary DOCS comments in vagrant script 2018-03-08 21:44:21 +01:00
Sarah Hoffmann
8d4a86635f Merge branch 'vagrant-centos-with-selinux' of https://github.com/mtmail/Nominatim 2018-03-08 21:37:24 +01:00
marc tobias
2dc6ee7e1c vagrant centos: update documentation. /build directory is sibling, not child of /Nominatim 2018-03-07 16:09:08 +01:00
marc tobias
ccab565a4a vagrant centos: make sure /home/vagrant/Nominatim directory doesnt get created 2018-03-07 16:05:22 +01:00
Sarah Hoffmann
5c8fbe8186 Merge pull request #941 from mtmail/parameter-parser-tests2
PHP tests for ParameterParser
2018-03-06 23:25:20 +01:00
marc tobias
7fd46dcee9 ParameterParser: getSet default value doesnt have to be part of the set 2018-03-06 14:53:23 +01:00
marc tobias
3ef4c4fbe7 ParameterParser: getStringList removes empty strings 2018-03-06 14:51:48 +01:00
marc tobias
47258f40ea ParameterParser: getFloat with empty string value throws exception 2018-03-06 13:35:27 +01:00
marc tobias
123a3c0347 ParameterParser: getInt with empty string value throws exception 2018-03-06 13:33:19 +01:00
mtmail
d60a2e693c Merge pull request #963 from matkoniecz/typo
fix two typos in docs
2018-03-03 22:41:25 +01:00
Mateusz Konieczny
db524a35c6 fix two typos in docs 2018-03-03 08:36:47 +01:00
Sarah Hoffmann
f23a860b33 second attempt at strict names in structured queries
If a term does not go into names it should go into
address terms.
2018-03-02 00:26:48 +01:00
Sarah Hoffmann
df008d99f5 do not allow importance to become 0
Importance is weighed against a viewbox factor which disappears
when the importance is 0.

Fixes #930.
2018-03-01 22:37:45 +01:00
Sarah Hoffmann
fd920fba9b for structured search only accept name terms from the first phrase
Fixes #952.
2018-03-01 22:35:34 +01:00
Marc Tobias Metten
d9cd8c6fff use assertSame to check array order, 0 vs false 2018-02-28 23:22:45 +01:00
marc tobias
b303c785e9 CentOS: move SELinux setup step so it can install in /srv 2018-02-27 17:06:25 +01:00
Sarah Hoffmann
36fa21d7ce fix more behave table formatting errors 2018-02-26 23:41:57 +01:00
Sarah Hoffmann
f1a388700f Merge branch 'patch-1' of https://github.com/NeilRickards/Nominatim into NeilRickards-patch-1 2018-02-26 20:54:44 +01:00
Sarah Hoffmann
2b66a7a39a test: fix format of behave table 2018-02-26 20:49:26 +01:00
Neil Rickards
4daa584b7d Update nominatim.c 2018-02-26 00:07:53 +01:00
Sarah Hoffmann
de9507bc63 add develop section to documentation 2018-02-24 23:24:25 +01:00
Sarah Hoffmann
2b48d09286 Merge pull request #948 from mtmail/phpcs-enable-3-spacing-rules
enable 3 spacing rules again, no PHP file needed changes
2018-02-24 20:49:41 +01:00
Marc Tobias Metten
97741aaf1c enable 3 spacing rules again, no PHP file needed changes 2018-02-24 18:40:45 +01:00
Marc Tobias Metten
146779340c use setExpectedException to make sure exceptions are really thrown 2018-02-24 18:14:34 +01:00
marc tobias
d1f6fab68a add links to docker, ansible respositories 2018-02-24 17:17:43 +01:00
Sarah Hoffmann
c835918123 Merge pull request #940 from mtmail/phpcs-deep-levels
phpcs deep levels
2018-02-23 21:59:42 +01:00
Marc Tobias Metten
fd9345cda3 PHP tests for ParameterParser 2018-02-23 01:46:18 +01:00
Marc Tobias Metten
8a615ad969 phpcs fixes. Mostly spacing and single quotes 2018-02-23 01:16:01 +01:00
Marc Tobias Metten
eaaa4a7b31 phpcs instructions only searched one level deep 2018-02-23 01:15:36 +01:00
marc tobias
c3e5654113 move CentOS Vagrant VM to a SELinux-enabled base image 2018-02-22 17:51:55 +01:00
Sarah Hoffmann
ff2a40b109 Merge pull request #928 from EdwardBetts/spelling
Correct spelling mistakes.
2018-02-18 14:31:15 +01:00
Edward Betts
7e00a6e2ff Correct spelling mistakes. 2018-02-18 13:11:35 +00:00
Neil Rickards
8ee36fb78c Avoid reading outside buffer
Current str_replace code will read outside buffer if `isspace` and `from` occurs at the start of `buffer`
2018-02-15 18:02:59 +00:00
Sarah Hoffmann
c3483747eb reimport boundaries from scratch when type is changed
Fixes #895.
2018-02-12 21:19:27 +01:00
Sarah Hoffmann
3fda792929 ignore empty flatnode file option
Fixes #902.
2018-02-12 20:47:04 +01:00
Sarah Hoffmann
ba57a9ba07 Merge pull request #915 from foodev/master
PlaceLookup::getAddressDetails() should be public
2018-02-12 20:00:13 +01:00
Jonas Hantelmann
a489ac07cd PlaceLookup::getAddressDetails() should be public, restore default values
PlaceLookup::getAddressDetails() is also used within the hierarchy.php
file so it must not be private.
2018-02-12 11:21:05 +01:00
Sarah Hoffmann
3505417e3f Merge pull request #905 from mtmail/illinois-li-case-insensitive
make sure Illinois,Alabama,Louisiana state code special handling is case insensitive
2018-02-10 15:50:42 +01:00
Sarah Hoffmann
29e78780e5 Merge pull request #909 from mtmail/decimal-coord-parsing-with-sub-seconds
parsing coordinates allows second with floats
2018-02-10 15:49:48 +01:00
Sarah Hoffmann
868caeaf1b Merge pull request #910 from mtmail/shorten-line-in-update-php
shorten line to please PHP style guide
2018-02-10 15:43:41 +01:00
Sarah Hoffmann
7f72c7b5fc Merge pull request #911 from mtmail/trivial-typo
typo in error message
2018-02-10 15:42:28 +01:00
marc tobias
e428019170 typo in error message 2018-02-08 18:02:19 +01:00
marc tobias
e9407cd48d shorten line to please PHP style guide 2018-02-08 17:52:26 +01:00
marc tobias
5042be1b72 parsing coordinates allows second with floats 2018-02-08 17:45:43 +01:00
Marc Tobias Metten
315713ff9a make sure Illinois,Alabama,Louisiana state code special handling is case insensitive 2018-02-07 00:48:18 +01:00
Sarah Hoffmann
7b3fb23216 Merge pull request #900 from mtmail/check-file-exist-before-delete
update.php - check file exists before deleting
2018-01-31 08:58:32 +01:00
Marc Tobias Metten
1d6861667b update.php - check file exists before deleting 2018-01-31 00:38:05 +01:00
Sarah Hoffmann
ae1df044e2 update links and remove MapQuest reference 2018-01-22 23:47:41 +01:00
Sarah Hoffmann
9d2de46c47 prepare for release 3.1.0 2018-01-17 21:36:37 +01:00
Sarah Hoffmann
dfa74daf52 Merge pull request #884 from lonvia/docs-tomkdocs
Switch to mkdocs for building documentation
2018-01-16 22:43:49 +01:00
Sarah Hoffmann
d4110eef7e improve syntax highlighting for vagrant scripts 2018-01-15 23:47:00 +01:00
Sarah Hoffmann
86833454a4 update vagrant scripts 2018-01-15 22:59:16 +01:00
Sarah Hoffmann
b8f7563da9 use mkdocs for compiling the documentation
Requires to shuffle around the documentation.
make doc will now compile the documentation
in the build directory. The markdowns created
from the vagrant files are no longer versioned.
2018-01-14 23:43:15 +01:00
Sarah Hoffmann
e080ccbcf8 update US postcode file from 2017 Tiger data
Location has been computed as the centroid over all
lines of a given postcodes. Then all postcodes which
cover a radius of more than 0.9 have been removed.
2018-01-14 20:18:29 +01:00
Sarah Hoffmann
13469e1576 convert remaining http links and shorten copyright URL 2018-01-11 23:05:28 +01:00
Sarah Hoffmann
8f23ba076b replace non-standard uint type with unsigned
See #879.
2018-01-10 23:27:49 +01:00
Sarah Hoffmann
2cf1ff41c0 move nominatim.org links to https
Solves #737.
2018-01-10 23:21:21 +01:00
Sarah Hoffmann
118517b076 Merge pull request #874 from lonvia/check-for-updates
Add function to check if new updates are available
2018-01-10 22:51:12 +01:00
Sarah Hoffmann
45abcbc301 update drop list for new postcode table
Fixes #875.
2018-01-05 22:41:25 +01:00
Sarah Hoffmann
d5df1c8ae3 fix setup when no us_postcode is available 2018-01-05 22:41:05 +01:00
Sarah Hoffmann
9712decefe update URLs in code and documentation
Use https for all openstreetmap addresses, remove defunct
mapquest link and redirect documentation links to
nominatim.org.
2018-01-05 22:38:51 +01:00
Sarah Hoffmann
6ba87c37d6 switch default replication source to https 2018-01-04 23:27:53 +01:00
Sarah Hoffmann
b06bc799bc add function to check if new updates are available 2018-01-01 22:23:29 +01:00
Sarah Hoffmann
a36b316079 Merge pull request #868 from JonathanMontane/feat/export
feat(export): added linked_place_id as an attribute to feature element
2017-12-20 22:00:39 +01:00
Jonathan Montane
c54fc44b33 feat(export): added linked_place_id as an attribute to feature element 2017-12-18 10:34:05 +01:00
Sarah Hoffmann
c7b903f4b0 assume name for special operator in bounded search
With bounded=1 we already have a restricted area, so it does
not make sense to interpret the query as a near search.

Fixes #311.
2017-12-17 23:50:16 +01:00
Sarah Hoffmann
cdfa31c390 Gives preference to special terms like postcode and housenumber
Fixes #846.
2017-12-17 20:23:34 +01:00
Sarah Hoffmann
3d51c2a4e7 show by default all entries from the broken polygon list
Fixes #854.
2017-12-17 17:29:08 +01:00
Sarah Hoffmann
b94229fb8e Give higher penalty to partial search terms
Avoids that the interpreation of a term as partial term
is ranked higher than as a special term like postcode
or house number.

Fixes #847.
2017-12-17 16:00:44 +01:00
Sarah Hoffmann
637c5c2936 add documentation for new word count compute 2017-12-17 16:00:28 +01:00
Sarah Hoffmann
cbaabe7c24 add function to recalculate counts for full-word search term 2017-12-17 16:00:28 +01:00
Sarah Hoffmann
35c7269bac when linking waterway ways and relations allow all river-like types
Fixes #848
2017-12-16 17:00:55 +01:00
Sarah Hoffmann
ed85388de5 fix address walk-up for reverse
Fixes the row for the join and completely drops parts that have
a linked_place_id.

Fixes #859.
2017-12-15 00:10:05 +01:00
mtmail
f79434f49d Merge pull request #843 from matejkrajcovic/patch-1
Fix typos in introduction.php
2017-10-30 12:38:55 +01:00
Matej Krajčovič
fcba2eabc4 Fix typos in introduction.php 2017-10-30 12:36:20 +01:00
Sarah Hoffmann
e523b34db9 precomputed postcodes must use dedicated import function 2017-10-28 18:24:01 +02:00
Sarah Hoffmann
96b5f8786b Merge pull request #842 from mtmail/updated-tiger-county-json-file
update utils/tiger_county_fips.json data
2017-10-28 16:20:05 +02:00
Marc Tobias Metten
1a1e0ef138 update utils/tiger_county_fips.json data 2017-10-28 00:08:59 +02:00
Sarah Hoffmann
2d3ea552c4 Merge branch 'fix-map-on-details-page' of https://github.com/mtmail/Nominatim into mtmail-fix-map-on-details-page 2017-10-27 22:55:47 +02:00
Marc Tobias Metten
c4e72e6ca9 UI: minimap causes main map not to initialize 2017-10-27 22:15:22 +02:00
Marc Tobias Metten
9f6f3dd75d UI: minimap causes main map not to initialize 2017-10-27 22:13:47 +02:00
Marc Tobias Metten
6b994cb5ff UI: minimap causes main map not to initialize 2017-10-27 22:06:48 +02:00
Sarah Hoffmann
c44324fda5 ignore linked places for address details
Fixes #816.
2017-10-27 21:57:35 +02:00
Sarah Hoffmann
8d91a88b22 allow unnamed roads for reverse geocoding
Should avoid that results are too far off in areas where
most roads are unnamed.
2017-10-27 20:10:32 +02:00
Sarah Hoffmann
f7258e314d ignore linked places for reverse geocoding
Fixes #838.
2017-10-27 20:06:53 +02:00
Sarah Hoffmann
6a3c6c43ea Merge pull request #835 from lonvia/fix-quoting
Replace double quoting with single quotes
2017-10-26 22:01:43 +02:00
Sarah Hoffmann
6c1977b448 replace double-quoting with single quotes where applicable 2017-10-26 21:40:33 +02:00
marc tobias
71602afcad PHP code style rule to enforce single quotes 2017-10-26 21:03:17 +02:00
Sarah Hoffmann
0c053431f5 Merge pull request #834 from mtmail/tests-for-closest-housenumber
tests for lib.php closestHouseNumber
2017-10-26 20:51:51 +02:00
Marc Tobias Metten
185a983c9d tests for lib.php closestHouseNumber 2017-10-25 23:58:13 +02:00
Sarah Hoffmann
adbbb1ce02 restrict number of results for reverse queries
When given a coordinate off the coast of a large town, the entire
town may end up in the potential results during the reverse query.
Postgres then needs to sort tens of thousands of results before it
can determine the clostest one. Given that the results at such a
large search radius are bound to be imprecise anyway, restrict
the number of results postgres should consider to 1000.
2017-10-25 22:34:29 +02:00
Sarah Hoffmann
f78d094483 fix variable typo when filtering results
Fixes #830 and #832.
2017-10-25 20:25:23 +02:00
Sarah Hoffmann
7eeb79ce67 placex must not return a lookup housenumber 2017-10-25 20:11:51 +02:00
Sarah Hoffmann
7caa67d8ec penalize housenumber after the postcode 2017-10-24 23:30:41 +02:00
Sarah Hoffmann
919b1b42fa fix uninitialised rank variable when regrouping searches 2017-10-24 23:17:47 +02:00
Sarah Hoffmann
760807c5e0 revert use of global penalty for a search direction
Adding a penalty to a search description because there
is a term at the beginning which looks like a country
turned out to be a bad idea as there are too many
abbreviations around that match against frequently
matched words.
2017-10-24 22:42:29 +02:00
Sarah Hoffmann
9ac401267a tiger import: convert counties to str
For python2 the gdal features come out as str and
cannot be combined with unicode strings.
2017-10-24 22:27:09 +02:00
marc tobias
a71200a57a huge cleanup of tigerAddressImport.py 2017-10-24 22:27:09 +02:00
marc tobias
b062e7e774 huge cleanup of tigerAddressImport.py 2017-10-24 22:27:09 +02:00
Sarah Hoffmann
d42aa08705 Merge pull request #829 from lonvia/result-as-a-class
Use PlaceLookup in search for retriving place details
2017-10-24 22:17:59 +02:00
Sarah Hoffmann
282c6777ee use PlaceLookup::loadParamArray in search and lookup 2017-10-23 23:30:53 +02:00
Sarah Hoffmann
9981d74ee1 add loadParamArray function to PlaceLookup and use for reverse 2017-10-23 23:30:53 +02:00
Sarah Hoffmann
1a4506f6ab use PlaceLookup in search 2017-10-23 23:30:53 +02:00
Sarah Hoffmann
914caab43d make PlaceLookup::lookup() accept multiple results 2017-10-23 23:30:53 +02:00
Sarah Hoffmann
5eb11800a7 replace SQL code in PlaceLookup with content of search's get_details 2017-10-23 23:30:53 +02:00
Sarah Hoffmann
1424e8e29b use Result class in reverse geocoding
Also simplifies the reverse algorithm slightly by no longer
having an additional distance lookup.
2017-10-23 23:30:53 +02:00
Sarah Hoffmann
42f079c355 introduce Result class in Geocode and SearchDescription 2017-10-23 23:30:53 +02:00
Sarah Hoffmann
8f884d7f23 Merge pull request #822 from mtmail/ui-allow-copypaste-combined-latlon
Ui allow copypaste combined latlon
2017-10-22 12:11:02 +02:00
Sarah Hoffmann
2cf21a3008 Merge pull request #819 from mtmail/tiger-2017-import
Tiger 2017 data no longer contains -divroad- field
2017-10-21 15:50:05 +02:00
marc tobias
2361ca2c71 UI: allow copy&pasting lat,lon into the lat search field 2017-10-21 14:28:28 +02:00
marc tobias
3cee2d185d UI: allow copy&pasting lat,lon into the lat search field 2017-10-21 14:11:46 +02:00
Sarah Hoffmann
cc785ccad0 Merge pull request #821 from mtmail/ui-scrollwheel-minimap
UI: scrollwheel, minimap
2017-10-21 13:53:24 +02:00
marc tobias
da4a2b7b6e UI: scrollwheel, minimap 2017-10-21 13:24:02 +02:00
Sarah Hoffmann
f17be2403f Merge pull request #820 from mtmail/php-test-path-changed
Vagrant documentation: update path to php tests
2017-10-21 12:17:50 +02:00
marc tobias
47bb49384e Vagrant documentation: update path to php tests 2017-10-21 11:46:12 +02:00
marc tobias
8eed1a8bec Tiger 2017 data no longer contains -divroad- field 2017-10-20 15:17:51 +02:00
Sarah Hoffmann
fcf7fcee03 Merge pull request #814 from lonvia/phrase-as-a-class
Make phrases a class and add early checking of token validity
2017-10-15 18:07:55 +02:00
Sarah Hoffmann
5c18d6865d adapt unit tests to new Phrase class 2017-10-14 20:45:20 +02:00
Sarah Hoffmann
cdf8c67898 fix CodeSniffer offences 2017-10-13 23:11:09 +02:00
Sarah Hoffmann
00265af528 move word recheck into token collection
Drop tokens for special and postcode searches already when
collecting them for ValidTokens when they cannot be found
in the normalized query.
2017-10-13 23:04:12 +02:00
Sarah Hoffmann
77b76ae51b simplify cross-check of country tokens
Drop country tokens that do not match the country code list
early. Remove in turn the special country code check for
structured phrases. It is sufficient to do this during
word list building.
2017-10-13 22:23:39 +02:00
Sarah Hoffmann
9ef2370a2a remove unused $aPossibleMainWordIDs array 2017-10-13 21:34:13 +02:00
Sarah Hoffmann
c700421aa7 add documentation for Phrase 2017-10-13 21:23:45 +02:00
Sarah Hoffmann
77abe882ab take frequency scores from token description
No need to hand them in separately.
2017-10-12 22:59:07 +02:00
Sarah Hoffmann
023f94b066 convert phrase array to class 2017-10-12 22:37:44 +02:00
Sarah Hoffmann
7ea1ef3feb take country names only from relations 2017-10-12 21:03:03 +02:00
Sarah Hoffmann
df463f4ea6 Show address rank in details and hide unset admin_level
Address rank explains better why the address parts are where
they are.

Fixes #766.
2017-10-11 22:17:59 +02:00
Sarah Hoffmann
3da4c9c384 Sort results for near searches by proximity
If a reference coordinate is given, results really should be
sorted by distance to this point ignoring importance completely.

Fixes #796.
2017-10-10 23:03:28 +02:00
Sarah Hoffmann
97bc185152 Merge pull request #812 from lonvia/search-as-a-class
Refactoring Search arrays
2017-10-10 21:08:11 +02:00
Sarah Hoffmann
c8780da19c documentation for SearchContext and SearchDescription 2017-10-10 00:15:56 +02:00
Sarah Hoffmann
c02bf4986f coding style and some documentation 2017-10-09 23:13:04 +02:00
Sarah Hoffmann
9a5d5d9aec move complete search query code into SearchDescription 2017-10-09 22:55:50 +02:00
Sarah Hoffmann
2c62a8dbbc adapt phpunit tests to new SearchContext class 2017-10-09 22:11:46 +02:00
Sarah Hoffmann
55629a4891 move country list to SearchContext 2017-10-08 23:33:54 +02:00
Sarah Hoffmann
907133a38c move excluded place list to SearchContext 2017-10-08 23:15:06 +02:00
Sarah Hoffmann
86c0858130 move viewbox sql to new SearchContext 2017-10-08 22:44:01 +02:00
Sarah Hoffmann
30511fd3ab replace NearPoint with a more generic context object
The NearPoint is actually common to all SearchDescriptions
and there is other context data as well. like viewbox, that
needs to be available to the search object but is common.
2017-10-08 21:23:31 +02:00
Sarah Hoffmann
614a6ab861 don't trust words from word table to be sanatized 2017-10-08 17:36:38 +02:00
Sarah Hoffmann
4bff2814a9 add missing include 2017-10-08 17:13:41 +02:00
Sarah Hoffmann
8e0ffde3e0 fix CodeSniffer violations 2017-10-08 17:00:59 +02:00
Sarah Hoffmann
795153b213 fix more syntax issues 2017-10-08 16:42:04 +02:00
Sarah Hoffmann
fd08d41962 move Search dump function into SearchDescription class 2017-10-08 16:05:27 +02:00
Sarah Hoffmann
75e35f3832 fix syntax errors from introduction of SearchDescription 2017-10-08 15:26:14 +02:00
Sarah Hoffmann
16268f92cc convert getGroupedSearches to SearchDescription class 2017-10-08 12:57:22 +02:00
Sarah Hoffmann
d72c863353 add function to convert array to SQL 2017-10-08 10:06:17 +02:00
Sarah Hoffmann
96b6a1a418 use SearchDescription class in query loop 2017-10-08 09:54:12 +02:00
Sarah Hoffmann
0067555c38 move initial search setup to new class type 2017-10-07 12:24:21 +02:00
Sarah Hoffmann
77d4453334 add new class for searches 2017-10-07 12:24:21 +02:00
Sarah Hoffmann
c563c2bfec drop searches with excluded country codes earlier 2017-10-07 12:23:46 +02:00
Sarah Hoffmann
266153f218 remove code for dropping address terms
This code has been inactive in quite a while and is a suboptimal
solution. We need to be much more selective in what gets dropped.
2017-10-07 11:53:33 +02:00
Sarah Hoffmann
73e737d775 fix variable names 2017-10-06 22:01:52 +02:00
Sarah Hoffmann
5029101048 further restrict use of partial terms in names 2017-10-06 21:36:28 +02:00
Sarah Hoffmann
0c9a241487 housenumbers may only appear before or after the name 2017-10-06 21:16:35 +02:00
Sarah Hoffmann
41d2cd318d penalize search order where a country comes first 2017-10-06 21:07:33 +02:00
Sarah Hoffmann
0d2cdb5c2f allow postcodes and housenumbers together
Fixes #805.
2017-10-06 20:48:35 +02:00
Sarah Hoffmann
f8d55b5448 sanitize special search term before normalizing 2017-10-06 00:22:27 +02:00
Sarah Hoffmann
00a3a8834b fix postcode search
Name token must be fully replaced with the postcode and
postcode search must be done only once.
2017-10-04 23:33:29 +02:00
Sarah Hoffmann
32f6ddf6db only allow either postcode or special search
Fixes #804.
2017-10-04 20:15:06 +02:00
Sarah Hoffmann
1220ff5da6 use correct source for radius column in debug view 2017-10-04 20:14:35 +02:00
Sarah Hoffmann
89c576fbe1 tests: more coverage for all API endpoints 2017-10-04 00:05:34 +02:00
Sarah Hoffmann
e276ec2e94 Merge pull request #803 from lonvia/update-postcodes
Add script to update table with artifical postcode centroids
2017-10-03 16:28:22 +02:00
Sarah Hoffmann
bafbf679b6 add script for updating postcodes 2017-10-03 15:58:14 +02:00
Sarah Hoffmann
8e2ef2842e move psqlRunScript implementation into cmd lib
Function needed for update.php as well.
2017-10-03 14:26:59 +02:00
Sarah Hoffmann
218b70fd96 test: remove road-fallback test from db tests
This should be tested in the api section.
2017-10-03 14:26:08 +02:00
Sarah Hoffmann
e3323e8888 fix search for postcode via structured query
Results from the artifical postcode table were dropped
when reevaluating rank of results.
2017-10-03 12:10:27 +02:00
Sarah Hoffmann
eacaf3489e more coverage tests for Geocode.php 2017-10-02 23:09:45 +02:00
Sarah Hoffmann
2deac34648 remove unnecessary size check 2017-10-02 22:31:52 +02:00
Sarah Hoffmann
e8c52c6780 be more strict with searches involving house numbers
Housenumber searches without a name cannot exist per
definition. Searches with only a name but no address
should not fall back on a search without house number.
This should improve postcode only search.
2017-10-02 22:22:50 +02:00
Sarah Hoffmann
e7e7ae0104 avoid unnecessary SQL when rechecking rank restrictions 2017-10-02 20:42:37 +02:00
Sarah Hoffmann
0d4c1e8460 fix viewbox related test
Coordinates are no longer specially ordered.
2017-10-02 20:39:33 +02:00
Sarah Hoffmann
cdabea7c76 docs: clarify how to run pip install
Fixes #792.
2017-10-01 22:48:57 +02:00
Sarah Hoffmann
749091bf3a order of viewbox coordinates does not matter 2017-10-01 22:48:57 +02:00
Sarah Hoffmann
28810e6ce0 Merge pull request #802 from mtmail/coordinate-extract-missing-first-minus-sign
NearPoint::extractFromQuery - greedy-match optional quote sign
2017-10-01 22:42:24 +02:00
Sarah Hoffmann
f2c15b73ad skip output of lat/lon in debug when no near point given 2017-09-30 12:24:37 +02:00
Sarah Hoffmann
a88527b2a0 fix index when rechecking postcode name 2017-09-30 12:19:16 +02:00
Sarah Hoffmann
b1e8db7ca7 return unchanged term if normalizer was not found 2017-09-30 09:39:47 +02:00
marc tobias
06657b3e10 NearPoint::extractFromQuery - greedy-match optional quote sign 2017-09-21 19:13:50 +02:00
Sarah Hoffmann
81a7ea36db more API tests (mostly for user errors) 2017-09-19 23:06:31 +02:00
Sarah Hoffmann
af74c037f4 enable coverage also for tests with HTTP errors 2017-09-19 22:42:09 +02:00
Sarah Hoffmann
6796749136 Merge pull request #798 from mtmail/coordinate-extract-missing-first-minus-sign
fix to NearPoint::extractFromQuery handling first minus sign
2017-09-19 21:23:49 +02:00
marc tobias
e67a6dc321 fix to NearPoint::extractFromQuery handling first minus sign 2017-09-19 12:40:10 +01:00
Sarah Hoffmann
15a215729e fix handling of near queries with special search
Make sure to use the classtype tables with near search and
allow to search for arbitrary key/values (forbidding it
for viewbox searches).

Add tests for near queries.
2017-09-19 00:07:11 +02:00
Sarah Hoffmann
ce95c55d65 fix display of nearpoint in debug view 2017-09-18 23:06:30 +02:00
Sarah Hoffmann
8eb066c692 reinstate key-value amenity search
Reenable search by the secret special term [key=value]
matching against the given main tag. Note that for most
cases that works only for tags that also have a special
search table.
2017-09-18 22:09:06 +02:00
Sarah Hoffmann
a0de20e9bc more API tests for code coverage
Also fixes two minor issues related to structured queries.
2017-09-17 23:30:08 +02:00
Sarah Hoffmann
2dbf58d461 improve code coverage documentation 2017-09-17 20:27:06 +02:00
Sarah Hoffmann
9a47e1834f reduce message frequency during indexing 2017-09-17 20:13:05 +02:00
Sarah Hoffmann
61ed3b8ab3 setup: bail out earl when something is wrong with nominatim.so 2017-09-17 20:07:03 +02:00
Sarah Hoffmann
bb1552be29 setup: error out when web site user does not exist
User is needed to be able to grant rights.
2017-09-17 19:51:00 +02:00
Sarah Hoffmann
5614ece9a1 run psql in quiet mode unless 'verbose' is enabled 2017-09-17 11:34:35 +02:00
Sarah Hoffmann
3546b30473 timestamp info message and repeat warnings at end 2017-09-17 11:06:52 +02:00
Sarah Hoffmann
cf32da3748 docs: add more requirements for running tests 2017-09-16 22:11:39 +02:00
Sarah Hoffmann
909b0c7462 Merge pull request #782 from lonvia/rework-postcodes
Rework handling of artificial postcode centroids
2017-09-16 15:54:55 +02:00
Sarah Hoffmann
15cd5c777b README: point to release instalation instructions 2017-09-06 20:36:59 +02:00
Sarah Hoffmann
37c653396b increase search rank of leisure=park
Fixes #786.
2017-08-31 21:10:48 +02:00
Sarah Hoffmann
8c4bcd36ea check that replication URL points to a repo of OSM diffs
Also check that pyosmium does not return None to work around
a bad return code in the current release of pyosmium-get-changes.

Fixes #784.
2017-08-29 21:05:54 +02:00
Sarah Hoffmann
88610b1b74 further restrict results for <postcode>, <term>
Disallow postcode operator together with housenumbers
and force results around a postcode when no address is
given.
2017-08-21 22:29:51 +02:00
Sarah Hoffmann
9aeb111fba tests: add new admin scene 2017-08-20 09:29:56 +02:00
Sarah Hoffmann
7ca5219297 fixup tests 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
f4a00eba26 enable details view for artificial postcodes 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
86a8900e21 fix subqueries when getting details for postcodes 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
67bb885900 throw away searches with two postcodes 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
e55ac77c94 add simple tests for postcode import 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
f9205caf22 adapt scene generation tool to newest libosmium 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
3c9af7f151 move adding postcodes to word table to calculation step 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
5e54e78176 add migration path for postcodes 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
caf018538f normalize all postcodes before use 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
ccae2c733b simplify search for artificial postcodes 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
5673c4cf91 special handling for estimated postcode in areas
Don't add a postcode at all if multiple estimated
postcodes fall into the area.
2017-08-19 19:37:06 +02:00
Sarah Hoffmann
ec8af1dd40 fix more tests 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
50c5abf6bb fix API tests wrt postcodes 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
a44377c7b0 fix postcode-related tests 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
5237f44c4a remove lat/lon check for search terms
Was only used with GB postcodes which were removed.
2017-08-19 19:37:06 +02:00
Sarah Hoffmann
99e9abe843 require postcodes to match exactly in normalised form 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
5b4bbab9be include GB CodePoint data into location_postcode table 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
413c69ddc9 improve calculation of postcode for interpolations 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
53f8459e97 move postcode indexing to end of setup
The search_name tables are needed for finding the parent,
so the rest of the database must be indexed.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
3714b7ea7d take postcode into account for other searches
Existence of postcode is still optional but if a matching
result is found, then non-matching ones will be discarded.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
0ecb920866 immediately drop searches where requested country code does not match 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
563099f7fa take address part into account in postcode search 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
ce76a25101 merging back postcodes is no longer necessary 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
57dc0304b5 add search for postcode
Implements the 'postcode' operator.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
872e73314e move postcodes into special operation for Searches
Introduces postcode field in searches and sorts out any marked
postcodes.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
727bd73d0b fix typo 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
a2a1901b09 add postcodes as special items in word table 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
43869b9938 make sure postcode gets recomputed on update 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
9a86c0cebc use only computed postcode when getting address
Postcodes from address parts are now ignored as they have
been already taken into account when computing the postcode.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
d0cc4006d3 remove unused get_address_postcode function 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
dc2911ae72 normalize postcodes before adding to location tables 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
16053e81bf show address tags and postcode in details 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
d59d57957c precompute postcodes
Set postcode column to the best guess for the postcode for
the place.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
4e792546e8 add postcode to location_area tables 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
79aa74b771 remove unused loaddata file
Load data is being done in the setup script.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
bdec4e6488 replace AddGeometryColumn() functions
Directly add the columns to the table definitions instead.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
71ddeb40a6 remove now useless getNearestPostcode function
Most postcodes are not in the location-area tables anymore.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
80ef6cbaab add indexing of artificial postcodes 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
15dbb6383c add new location_postcode table
Artifical postcode centroids are now saved in there.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
3e9fb0dc84 fix syntax typo 2017-08-14 22:34:53 +02:00
Sarah Hoffmann
95df39c292 prepare for release 3.0.1 2017-08-13 22:18:08 +02:00
Sarah Hoffmann
aab41b78af Merge pull request #779 from lonvia/update-osm2pgsql
update osm2pgsql
2017-07-26 23:53:47 +02:00
Sarah Hoffmann
96ecee431b Merge pull request #776 from lonvia/vagrant-fix-country-paths
vagrant: download country data into correct directory
2017-07-26 23:44:00 +02:00
Sarah Hoffmann
64bf44eaf0 update osm2pgsql
Fixes #770.
2017-07-26 23:40:14 +02:00
Sarah Hoffmann
9996cc495c Merge pull request #778 from woodpeck/patch-1
Mention explicitly that Osmosis is not required.
2017-07-23 21:01:51 +02:00
Frederik Ramm
bce11a5fc7 Mention explicitly that Osmosis is not required. 2017-07-21 09:23:38 +02:00
Sarah Hoffmann
cce57139cf Merge pull request #775 from lonvia/code-coverage
enable code coverage computation for API BDD tests
2017-07-17 23:19:41 +02:00
Sarah Hoffmann
937bead547 vagrant: download country data into correct directory 2017-07-17 23:17:26 +02:00
Sarah Hoffmann
3fba5e7867 enable code coverage computation for API BDD tests
Fixes #505.
2017-07-17 22:59:13 +02:00
Sarah Hoffmann
a27e191335 Merge pull request #771 from rksh/patch-1
Warn about operation order with Wikipedia data
2017-07-15 10:34:43 +02:00
Andy Carra
8c087e4cb8 Warn about operation order with Wikipedia data
Give first-time users a tip about installing Wikipedia data before performing initial import.
once https://github.com/openstreetmap/Nominatim/issues/255 has been addressed, this note is no-longer important.
2017-07-14 18:52:54 -07:00
Sarah Hoffmann
39bab5f4a1 Merge pull request #768 from SrihariThalla/update-typo-fix
[Minor] [/docs] Update file name of update.php to init updates command
2017-07-07 12:51:51 +02:00
Srihari Thalla
d004a0e3df Update file name of update.php to init updates 2017-07-07 15:57:01 +05:30
mtmail
bc0cf74ba7 Merge pull request #767 from manzari/patch-1
add country_osm_grid download to development (vagrant) setup instructions
2017-07-07 01:46:04 +02:00
manzari
e64e3b4939 Update VAGRANT.md 2017-07-06 18:05:14 +02:00
Sarah Hoffmann
6de0a854fb Merge pull request #763 from SrihariThalla/update-doc-links
Update incorrect internal links to docs
2017-06-29 21:00:29 +02:00
Srihari Thalla
97ad4e4654 Update incorrect internal links to docs 2017-06-29 17:29:15 +05:30
Sarah Hoffmann
748fa3e28f prepare for release 3.0.0 2017-06-25 20:58:59 +02:00
Sarah Hoffmann
7ef0239f19 make naming of documentation files consistent 2017-06-25 17:18:21 +02:00
Sarah Hoffmann
2daa4ed813 add extensive debug messages for placex 2017-06-15 23:17:34 +02:00
Sarah Hoffmann
8714fa7dec refine bug report information 2017-06-14 16:18:54 +02:00
Sarah Hoffmann
896421fe9f improve update interval computation
Don't do anything if a downloaded diff is empty after all
(may be happening when an empty diff was published upstream).

Correctly compute the waiting interval before checking for new
data. As the interval is now computed based on the date of the
newest object in the database, the configured intervals need
to be adjusted slightly to take into account the time it takes
for the server to publish a diff.
2017-06-11 09:21:24 +02:00
Sarah Hoffmann
4e6c75040e Guard against network failures in getDatabaseDate()
When updating use the date from the diff file instead
as we are guaranteed to get this if the file has been
successfully loaded.
2017-06-09 21:49:31 +02:00
Sarah Hoffmann
7448d3f171 recompile installation instructions 2017-06-09 20:12:29 +02:00
Sarah Hoffmann
5e5713b90f Ignore postcodes with comma and semicolon when computing address
OSM has sometimes postcode lists for cities which should
simply be ignored.

Fixes #673.
2017-06-07 23:19:56 +02:00
Sarah Hoffmann
9785aff76c restrict linked places to place nodes
Avoids getting the wrong entry when the linked place has
double tagging.

Fixes #573.
2017-06-07 21:32:02 +02:00
Sarah Hoffmann
f4e958a66d get precomputed housenumbers and postcodes from address column 2017-06-07 20:35:41 +02:00
Sarah Hoffmann
5a5691b5b7 force update of linker when linkee is updates
Potential name changes need to be added to the linker's
name hstore.

Fixes #170.
2017-06-06 23:46:44 +02:00
Sarah Hoffmann
9848381a04 remove wip tags from all tests 2017-06-06 22:01:52 +02:00
Sarah Hoffmann
623d58b67e Remove boundries when downgrading from polygon to line
Fixes #135.
2017-06-06 21:59:36 +02:00
Sarah Hoffmann
6985abc3fd Merge pull request #745 from lonvia/restrict-poi-queries-results
limit number of considered places in POI queries
2017-06-06 20:55:15 +02:00
Sarah Hoffmann
0628aa887f adapt postcode centroid import to new address hstore
The postcode now needs to be saved in address->'postcode'
not in the postcode column which is derived only later while
indexing.

Fixes #746.

Thanks to @kkoop.
2017-06-06 20:42:13 +02:00
Sarah Hoffmann
c13094acfd limit number of considered places in POI queries
When searching for POIs in place_classtype_ tables limit the number
of objects considered to 300. The distinct and order by clauses
forced until now to retrive all matching objects and order them
first which can cause long running queries when retriving them
for large areas like the US.

Fixes #735.
2017-06-05 22:40:42 +02:00
Sarah Hoffmann
308bfcbf25 advertise official location for test data on nominatim.org 2017-06-05 22:01:42 +02:00
Sarah Hoffmann
de0ad657ba fix formatting in test README 2017-06-05 21:53:45 +02:00
Sarah Hoffmann
13674c3939 update osm2pgsql (revert use of "char") 2017-06-05 09:08:23 +02:00
Sarah Hoffmann
b9cc47ee67 Revert "use "char" type when refering to osm_type column"
This reverts commit 2dd7f0156a.
2017-06-05 09:07:47 +02:00
Sarah Hoffmann
6db110f5cb Merge pull request #742 from lonvia/compare-normalized
Require more exact match for special search terms
2017-06-05 08:44:04 +02:00
Sarah Hoffmann
af81c6aa94 add special terms import to travis testing and fixup libs 2017-06-04 23:15:19 +02:00
Sarah Hoffmann
54393addd3 disregard special phrases that do not match fully
Compare the normalized terms imported with the special
terms script with the normalized version of the query string.
Disregard them if they cannot be found. This avoids a significant
number of mismatches due to transliteration issues.

The match will only be done when a normalized word has been set
making this change backwards compatible with older databases.
2017-06-04 23:12:09 +02:00
Sarah Hoffmann
e3fb706c65 add normalized version of special search terms on import
Requires the PHP bindings for libicu, so add that as a requirement.
2017-06-04 23:12:09 +02:00
Sarah Hoffmann
2dd7f0156a use "char" type when refering to osm_type column
When using an explicit cast to char(1) when refering to the
osm_type column postgres won't use the index in some cases.
Observed only on postgres 9.5 from the original Postgres
reporsitories.

Fixes #741.
2017-06-04 14:48:53 +02:00
Sarah Hoffmann
5b8672c10a also need postgres configuration changes for bug reports 2017-06-02 14:06:53 +02:00
Sarah Hoffmann
7a14792e21 update osm2pgsql (libosmium update and clubs)
Adds club key.

Fixes #725.
2017-06-01 20:10:10 +02:00
Sarah Hoffmann
d88c484fa1 remove PHP version check
5.4 is the minimum supported version now.
2017-06-01 20:10:10 +02:00
big-o
bdd90e890b Parameter to enable JSON pretty-printing 2017-06-01 20:10:10 +02:00
Sarah Hoffmann
b5fc5e0a71 Merge pull request #739 from lonvia/max-importance
when linking places compute maximum importance
2017-06-01 00:13:22 +02:00
Sarah Hoffmann
002fa35b92 when linking places compute maximum importance
The linker and the linkee might have different wikipedia
tags and thus different importances. Prefer the higher
value.

Fixes #562.
2017-05-30 23:36:59 +02:00
Sarah Hoffmann
d023578f90 add hints about bug reporting and pull requests 2017-05-27 17:47:39 +02:00
Sarah Hoffmann
1876fe42c9 updates: always remove output file and start with correct sequence id 2017-05-27 17:02:34 +02:00
Sarah Hoffmann
86acaa5264 fix name of constant 2017-05-27 16:42:01 +02:00
Sarah Hoffmann
d898f9aabf update word statistics 2017-05-26 21:58:52 +02:00
Sarah Hoffmann
33c919ab09 Merge pull request #734 from lonvia/use-pyosmium-for-updates
Use pyosmium for updates
2017-05-26 21:43:08 +02:00
Sarah Hoffmann
deca74bc3a Merge pull request #730 from SrihariThalla/update-vagrantmd-doc
Update the formatting in Vagrant markdown doc
2017-05-26 21:39:37 +02:00
Srihari Thalla
74b3251c7a Update the formatting in Vagrant markdown doc 2017-05-26 09:38:37 +05:30
Sarah Hoffmann
65afe13f0a update docs for osmosis to pyosmium change 2017-05-25 16:53:44 +02:00
Sarah Hoffmann
bd4b1b2d08 switch from osmosis to pyosmium for updates
Pyosmium comes with convenient functions for finding the
right state and does not require external files for
rembering the state. Updates can now conveniently
set up by simply running ./utils/update.php --init-updates
and state is kept directly in the import_status table.

This change requires an update in the database schema.
Run the following to update:

ALTER TABLE import_status ADD COLUMN sequence_id integer;
ALTER TABLE import_status ADD COLUMN indexed boolean;
ALTER TABLE import_osmosis_log ADD COLUMN batchseq integer;
2017-05-25 16:26:09 +02:00
Sarah Hoffmann
1a1526ec30 Add FAQ to documentation
For the moment only copies the FAQ entries for installation from the wiki and adds one on running multiple extracts.
2017-05-24 23:29:08 +02:00
Sarah Hoffmann
6830b1229e Merge pull request #724 from lonvia/update-country-list
Update country grid SQL file and move it to nominatim.org
2017-05-13 11:48:34 +02:00
Sarah Hoffmann
e7c8b498d1 update docs for new country grid location
Also updates some dependencies.
2017-05-13 00:13:56 +02:00
Sarah Hoffmann
b15b996cc4 remove base country grid from repo
The updated country grid is significantly larger, so expect it to
be downloaded from the nominatim.org website instead.
2017-05-12 23:02:50 +02:00
Sarah Hoffmann
d8ade1c527 remove another use of place.country_code 2017-04-23 22:46:54 +02:00
Sarah Hoffmann
6043cd5ad8 update osm2pgsql (geometry fix, column reordering) 2017-04-22 18:16:22 +02:00
Sarah Hoffmann
86d5209118 Merge branch 'roques-tetris' 2017-04-22 18:14:05 +02:00
Sarah Hoffmann
c629573230 Merge pull request #708 from lonvia/check-for-invalid-geoms
make sure no invalid geometries end up in placex
2017-04-22 18:12:18 +02:00
Sarah Hoffmann
291a161cc6 make sure no invalid geometries end up in placex 2017-04-22 10:34:03 +02:00
Sarah Hoffmann
4c7145c293 Merge branch 'tetris' of https://github.com/roques/Nominatim into roques-tetris 2017-04-20 20:56:44 +02:00
Christian von Roques
4d4b95923e use SMALLINT for ranks and partition; reorder columns for alignment 2017-04-19 02:18:44 +02:00
Sarah Hoffmann
71e6d5f9a6 fix typo 2017-04-18 22:44:39 +02:00
Sarah Hoffmann
446a5a95bc get pg error on correct connection 2017-04-18 22:29:21 +02:00
Sarah Hoffmann
19edbd3581 send address interpolation import to correct postgres conn 2017-04-18 22:11:58 +02:00
Sarah Hoffmann
166737fb76 also use address column for word count computation 2017-04-18 22:11:09 +02:00
Christian von Roques
b6be33cded explicitly name columns at INSERT 2017-04-18 13:36:02 +02:00
Christian von Roques
c80637b05c deduplicate words: do not look for duplicates in empty partitions 2017-04-15 19:12:25 +02:00
Christian von Roques
3ec67b9193 update: getPostgresVersion requires a database connection 2017-04-15 19:12:25 +02:00
Christian von Roques
40debbc7b5 with PHP7 the result of new() can no longer be assigned by reference 2017-04-15 19:12:25 +02:00
Christian von Roques
ccecabfbf4 correct warm.php --search-only help text 2017-04-15 19:12:25 +02:00
Sarah Hoffmann
1e30e578e0 Merge pull request #700 from lonvia/structured-address-info
Move address information into hstore column
2017-04-13 22:12:19 +02:00
Sarah Hoffmann
29e9683293 update osm2pgsql (structured addresses and new libosmium) 2017-04-11 21:29:10 +02:00
Sarah Hoffmann
8138729aea use centroid for near feature search on rank 30
Rank 30 has some very large geometries (peninsulas, time zones,
etc.) for which a near feature search for the full geometry is
too expensive, so do the search on the centroid only.
2017-04-09 23:12:35 +02:00
Sarah Hoffmann
9bb81731f8 fix operator precedence for hstore 2017-04-09 10:06:31 +02:00
Sarah Hoffmann
050b0a2ced remove street and addr_place columns in placex
The information is onyl needed for parenting,
so no need to store it permanently.
2017-04-08 19:58:10 +02:00
Sarah Hoffmann
3bb903cf92 Remove street and addr_place from location_property_osmline
Derived columns are not needed because parent information is
always computed from scratch. So the columns are just duplicate
information.

Also get address information on nodes from address columns. The
other columns are not necessarily reliable when the node have not
been indexed yet.
2017-04-08 19:58:10 +02:00
Sarah Hoffmann
41afcaddd5 adapt more BDD tests to hstore 2017-04-08 19:58:09 +02:00
Sarah Hoffmann
8c7fa0213f fix DB bd tests for address hstore 2017-04-08 19:57:36 +02:00
Sarah Hoffmann
49b5e4dbad adapt osm2pgsql tests for new address column 2017-04-08 18:58:26 +02:00
Sarah Hoffmann
c8e79397f5 introduce address column for place tables
The column is a hstore containing the full OSM tag with key and
value.
2017-04-08 18:58:26 +02:00
Sarah Hoffmann
43eedfd253 abort osmline update correctly when way nodes are missing
Fixes #695.
2017-03-30 22:14:47 +02:00
Sarah Hoffmann
ee1b25820e Merge pull request #690 from ImreSamu/fix_install_sql_warnings
fix table/sequence ... does not exist
2017-03-27 22:41:52 +02:00
ImreSamu
193cf66328 fix sql warnings
* ERROR:  sequence "seq_postcodes" does not exist
* ERROR:  table "import_polygon_error" does not exist
* ERROR:  table "import_polygon_delete" does not exist
* ERROR:  sequence "file" does not exist
2017-03-27 01:02:29 +02:00
Sarah Hoffmann
77e55fade2 Merge pull request #683 from lonvia/more-url-function
Factor out moreurl computation
2017-03-23 18:25:09 +01:00
Sarah Hoffmann
09f1661638 move moreURL computation into Geocode and include all params
Fixes #678.
2017-03-23 00:16:58 +01:00
Sarah Hoffmann
e841422b1f remove unused code 2017-03-22 23:02:19 +01:00
Sarah Hoffmann
97ade7dd7e Merge pull request #682 from mtmail/update-docs
update docs/*.md based on vagrant/*.sh
2017-03-21 20:54:52 +01:00
marc tobias
e24f53cb34 update docs/*.md based on vagrant/*.sh 2017-03-21 13:16:29 +01:00
Sarah Hoffmann
62b7b76662 Merge pull request #680 from mtmail/git-submodule-hint
Update CMakeLists.txt
2017-03-21 12:44:10 +01:00
mtmail
c7434264ae Update CMakeLists.txt
Ran into the issue this morning.
`git submodules` => `git submodule`
2017-03-21 12:34:24 +01:00
Sarah Hoffmann
026081e131 Merge pull request #676 from mtmail/html-map-position-box-disappeared
On /search.php the map-position box disappeared behind the map tiles
2017-03-20 20:19:41 +01:00
Sarah Hoffmann
47586fd861 Merge pull request #674 from mtmail/leaflet-image-path-changed
leaflet 1.0 changed the path of the marker icon
2017-03-20 20:18:29 +01:00
marc tobias
8e79ece203 On /search.php the map-position box disappeared behind the map tiles 2017-03-20 15:38:12 +01:00
marc tobias
a23bd80a31 leaflet 1.0 changed the path of the marker icon 2017-03-20 12:27:48 +01:00
Sarah Hoffmann
f4a86ff4c4 Merge pull request #671 from mtmail/html-view-use-geojson-geometries
Html view use geojson geometries
2017-03-19 22:53:22 +01:00
Marc Tobias Metten
73c151b3ac update leaflet CSS file as well. Fixes delayed layer animation 2017-03-19 22:38:23 +01:00
Sarah Hoffmann
0a10be6586 Merge pull request #669 from lonvia/address-part-on-intersect
Add all intersecting boundaries to address list for roads
2017-03-19 21:50:45 +01:00
Marc Tobias Metten
1e3bf9729e for search,details in format=HTML return geometry in geojson, not wkt. No longer need leaflet-omnivore plugin 2017-03-19 17:31:00 +01:00
Marc Tobias Metten
924d3a8d6e update leaflet.js 0.7.7 => 1.0.3 2017-03-19 15:53:52 +01:00
Marc Tobias Metten
2a07bb8a7f remove obsolete openlayers theme files 2017-03-19 15:50:00 +01:00
Sarah Hoffmann
b3186d07f5 for roads add all intersecting boundaries to address list
When roads cross boundaries, both administrative entities should
be added to the address list, so that both entities can be used
for searching. Also allows in a second step to better sort out
addresses of POIs on such roads.

Fixes #121.
2017-03-18 12:17:48 +01:00
Sarah Hoffmann
ecee3828b3 Merge pull request #667 from lonvia/refactor-nearpoint
Factor out near point into class
2017-03-18 09:25:07 +01:00
Sarah Hoffmann
a64f992092 Merge pull request #668 from lonvia/warn-on-missing-osm2pgsql
cmake: add a more explicit hint when osm2pgsql is missing
2017-03-18 09:24:47 +01:00
Sarah Hoffmann
5682d1688d cmake: add a more explicit hint when osm2pgsql is missing
Fixes #642.
2017-03-17 23:05:06 +01:00
Sarah Hoffmann
57b35654e7 fix style 2017-03-17 22:36:22 +01:00
Sarah Hoffmann
a67edd328e Merge pull request #665 from openstreetmap/lonvia-patch-1
add unzip tool to requirements for Tiger imports
2017-03-17 22:08:01 +01:00
Sarah Hoffmann
20a4cab57e add tests for nearpoint sql functions 2017-03-16 22:12:20 +01:00
Sarah Hoffmann
ab3b556144 use NearPoint class in Search array 2017-03-16 22:04:30 +01:00
Sarah Hoffmann
1649191ffd adapt unit tests for new NearPoint type 2017-03-15 23:58:51 +01:00
Sarah Hoffmann
41fce277cd make NearPoint its own class 2017-03-15 23:47:35 +01:00
Sarah Hoffmann
39c4c7fce8 add unzip tool to requirements for Tiger imports
Fixes #663
2017-03-15 20:44:06 +01:00
Sarah Hoffmann
3a696e1895 Merge pull request #661 from mtmail/travis-ci-badge
add travis-ci badge ("build passing") to README file
2017-03-12 14:00:11 +01:00
Sarah Hoffmann
a793f698f3 Merge pull request #660 from mtmail/new-github-URL
github.com/twain47 => github.com/openstreetmap
2017-03-12 13:59:11 +01:00
marc tobias
889637321b add travis-ci badge ("build passing") to README file 2017-03-12 13:11:56 +01:00
marc tobias
a52455f160 github.com/twain47 => github.com/openstreetmap 2017-03-12 13:06:25 +01:00
Sarah Hoffmann
9358243b66 Merge pull request #659 from lonvia/full-indexing-in-tests
Fix travis tests and update CONTRIBUTING.md
2017-03-11 17:38:46 +01:00
Sarah Hoffmann
9e54d1d6eb adapt CONTRIBUTING.md to new test locations and tools 2017-03-11 17:13:24 +01:00
Sarah Hoffmann
1aaeee19a1 test: rerun indexing after updates until really all is done
There are caess where indexing needs to be done a second round
because related objects need to be updated.
2017-03-11 17:09:14 +01:00
mtmail
6153ad3b31 Merge pull request #656 from EdwardBetts/master
correct spelling mistakes
2017-03-08 16:36:40 +01:00
Edward Betts
7e3af2debc correct spelling mistakes 2017-03-08 15:06:50 +00:00
Sarah Hoffmann
450a12c6be include housenumbers and postcodes when rechecking for exact matches 2017-02-28 21:40:05 +01:00
mtmail
196c55e341 Merge pull request #649 from ldgeo/master
UI: Extra HTML headers for compatibility on MSIE>8
2017-02-28 17:18:12 +01:00
Ludovic Delauné
2c3317f582 extra headers for compatibility on IE7 2017-02-28 17:08:34 +01:00
Sarah Hoffmann
e0c066d850 make sure the flatnode file is disabled while testing 2017-02-27 22:01:06 +01:00
Sarah Hoffmann
e1cbca2572 add behave settings
removes @Fail tests
2017-02-26 16:46:41 +01:00
Sarah Hoffmann
e1095205e4 fix geometry creation from scene 2017-02-26 16:46:41 +01:00
Sarah Hoffmann
e5c79a1d1f add more interpolation update scenarios (currently failing) 2017-02-26 16:46:41 +01:00
Sarah Hoffmann
6551399bcc test: enable grid support for DB tests 2017-02-26 16:46:41 +01:00
Sarah Hoffmann
c48fb88e6b move interpolaton computation into indexing step
The interpolaton computation needs information from the osm2pgsql
slim tables which may not be available when the data is inserted.

Insertion now only adds a line with basic address information to
location_property_osmline. The line is then split during the
indexing, leading to more lines (which are complete in that case)
being inserted.

Fixes #598.
2017-02-26 16:46:41 +01:00
Sarah Hoffmann
e04838cc71 add node grids for tests and test for interpolation update 2017-02-26 16:46:41 +01:00
Sarah Hoffmann
0916d72ddf Merge pull request #644 from ldgeo/master
fix compilation error (cannot find -lpq)
2017-02-25 09:45:35 +01:00
Ludovic Delauné
a933421860 fix compilation error (cannot find -lpq) 2017-02-23 10:17:25 +01:00
Melvyn Sopacua
66d7f1a058 Set osmosis if available 2017-02-18 17:58:11 +01:00
Sarah Hoffmann
e77a07cbb3 add Kosovo to list of country names
Kosovo will remain in the same partition as Serbia to not disrupt
existing databases.
2017-02-18 16:07:37 +01:00
Sarah Hoffmann
c897b96c41 don't delete names on unknown country boundaries
If a country boundary has a country_code that is unknown to
Nominatim, it would delete all names because the coalascing
with country_name would not yield any result.
2017-02-18 13:51:21 +01:00
Sarah Hoffmann
679e4c47ce Merge pull request #632 from melvyn-sopacua/libxml2-fixes
Fix warnings:
2017-02-15 21:31:42 +01:00
Melvyn Sopacua
13ab03a03a Fix warnings:
- be consistent with (const char *) casts when assigning
- use xmlStrlen instead of strlen when dealing with xmlChar *
2017-02-15 10:17:43 +01:00
Sarah Hoffmann
56962deb30 Merge pull request #630 from lonvia/cascading-make
use properly cascading make for external make file
2017-02-15 09:55:25 +01:00
Sarah Hoffmann
e86516bbaf use properly cascading make for external make file
If make is called directly then the -j option is not
properly propagated. Instead make gives a warning
'No jobserver avilable'.
2017-02-13 21:02:49 +01:00
Sarah Hoffmann
b6acd24e5a Merge pull request #629 from melvyn-sopacua/release-2.6.0a1
Build fixes for BSD-like systems
2017-02-13 20:51:00 +01:00
Melvyn Sopacua
e31cd9717c Use CMAKE_MAKE_PROGRAM instead of hardcoded make
FreeBSD uses `gmake` instead of `make` if GNU make is required to build
a port.
2017-02-13 14:33:14 +01:00
Melvyn Sopacua
6eb6f35f24 BSD compat: use sys/endian.h if available
<byteswap.h> is a linuxism. On BSD-like systems this is <sys/endian.h>
2017-02-13 14:30:48 +01:00
Sarah Hoffmann
e9decd2574 Merge pull request #626 from rory/patch-1
Syntax improvements
2017-02-07 23:32:37 +01:00
Rory McCann
2fd9ffda43 Syntax improvements
use backticks for more fixed-width type things
2017-02-07 14:57:54 +01:00
Sarah Hoffmann
a84a7a70f3 reverse: choose interpolation only when further than point
The ST_DWithin check also includes objects that are the same distance.

Another attempt at #545.
2017-02-05 23:02:21 +01:00
Sarah Hoffmann
dcab7a19e5 reverse: disable interpolation when going up the address hierarchy
Fixes #621.
2017-02-05 13:08:51 +01:00
Sarah Hoffmann
d4c78a982e Merge pull request #620 from sebkur/improve-readme-formatting
Improve markdown of Installation section
2017-02-02 12:12:30 +01:00
Sebastian Kürten
7716e0bc92 Improve markdown of Installation section
Due to indentation issues (code within numbered list needs at least 8
spaces instead of 4) the code would not appear as code but as plain text
without a fixed size font and also without newlines appearing in the
HTML.
2017-02-02 11:58:40 +01:00
Sarah Hoffmann
5dea0658e4 Merge pull request #613 from mtmail/travis-behave-and-split-tests
Replace lettuce with behave in tests. Use python3 Split import and (p…
2017-01-21 09:14:36 +01:00
Marc Tobias Metten
cfd03d7be3 Replace lettuce with behave in tests. Use python3 Split import and (python,php) tests into two travis executions 2017-01-21 02:38:04 +01:00
Sarah Hoffmann
9240e83802 Merge pull request #610 from lonvia/set-lanugage-of-indexer
force language of pgsql to C
2017-01-16 21:09:32 +01:00
Sarah Hoffmann
2c07d5e000 Merge pull request #605 from lonvia/fix-fraction-on-interpolations
Better search radius for interpolations when reverse geocoding
2017-01-15 21:33:47 +01:00
Sarah Hoffmann
ea5fe54c6b force language of pgsql to C
Fixes #558.
2017-01-15 21:31:14 +01:00
Sarah Hoffmann
08d1ec09cc fix viewbox tests
Hamburg may not be complete in the test set
2017-01-09 21:15:41 +01:00
Sarah Hoffmann
b8db8301df reverse: reduce search radius for interpolations
Interpolations should have the same maximum search radius as
address points. Change search strategy and only search for
interpolations either before decreasing the maxRank to road
or when a POI was found and we need to check that there isn't
an interpolation that is closer.
2017-01-09 20:51:16 +01:00
Sarah Hoffmann
d18bd14045 add test for moreURL issue and debugging of test query contents 2017-01-01 17:58:21 +01:00
Sarah Hoffmann
65500927c2 Merge branch 'moreurl-with-countrycodes' of https://github.com/mtmail/Nominatim into mtmail-moreurl-with-countrycodes 2017-01-01 17:36:07 +01:00
Sarah Hoffmann
4a5a997e18 Merge pull request #600 from lonvia/behave-tests-rebased
Rework tests
2017-01-01 10:57:23 +01:00
Sarah Hoffmann
fadffeaa2d remove old bdd tests 2016-12-30 23:16:21 +01:00
Sarah Hoffmann
c0e4a74c71 add mention of required Tiger files for test database 2016-12-30 23:15:41 +01:00
Sarah Hoffmann
b2be8c3ab7 move php tests in common test dir and unify READMEs 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
5252051291 add source files for test database 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
ccaea09a65 move scenes directory to new test directory 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
b2c1d086b5 add api tests for language, details and lookup 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
3a787df934 add remaining reverse tests 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
635ce30db5 add simple reverse API tests 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
201f618cc7 finish search API tests 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
81922fc057 more API search tests
also move directory name back to api
2016-12-30 22:58:58 +01:00
Sarah Hoffmann
b9a58b8f24 add simple direct API search tests
API tests now no longer require a running Apache installation,
instead the website php scripts are called directly using the
appropriate enivronment.
2016-12-30 22:58:58 +01:00
Sarah Hoffmann
b75aadfb6b more backslash tests 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
80a74181e4 add osm2pgsql update tests 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
6f4f19004c add remianing osm2pgsql import tests 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
e2f23e391b add osm2pgsql broken data tests 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
f2debbef19 add simple osm2pgsql tests 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
21a3fc4b0f add remaining db update tests 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
0e9e2bbdca add tests for updating linked features 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
4f2d73aa7c add tests for interpolation updates 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
c20f8b13a5 add simple db update tests 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
7f4e7a2579 add interpolation tests 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
82a0e23265 tests for linking 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
e36e485698 add naming tests 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
ddb7296663 add parenting tests 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
604706a827 ad search_name import tests 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
c594644aa7 add placex import tests 2016-12-30 22:58:58 +01:00
Sarah Hoffmann
47f94c6988 simple search steps 2016-12-30 22:58:57 +01:00
Sarah Hoffmann
c56c09e2c0 rename and add basic tests 2016-12-30 22:58:57 +01:00
Sarah Hoffmann
65bf6dbff7 environment for behave tests 2016-12-30 22:58:57 +01:00
Sarah Hoffmann
7273b58bbe make path to wikipedia files configurable 2016-12-28 23:38:48 +01:00
Marc Tobias Metten
adb6ea546f sMoreURL now includes countrycodes values 2016-12-22 02:06:08 +01:00
Sarah Hoffmann
3ff8bb55a7 update osm2pgsql (quoting fix) 2016-12-17 18:33:15 +01:00
Sarah Hoffmann
99c58706d3 Merge pull request #595 from mtmail/set-webserver-directoryindex
set directoryindex in Apache,nginx configuration
2016-12-16 08:51:18 +01:00
Marc Tobias Metten
523873fe16 set directoryindex in Apache,nginx configuration 2016-12-16 02:16:47 +01:00
Sarah Hoffmann
de01c5b23d Merge pull request #581 from lonvia/update-osm2pgsql
update osm2pgsql
2016-11-20 17:00:43 +01:00
Sarah Hoffmann
57dc135844 do not build osm2pgsql tests 2016-11-19 13:09:11 +01:00
Sarah Hoffmann
e24129febe update osm2pgsql (new libosmium) 2016-11-19 13:04:34 +01:00
marc tobias
b27926fd4d fix PHP warnings when reverse search was called without parameters
... or empty results
2016-11-17 22:55:05 +01:00
Sarah Hoffmann
cfb0f3f94c Merge pull request #548 from lonvia/query-ckeck-utf8
check if query is valid unicode string
2016-11-02 19:21:29 +01:00
Sarah Hoffmann
eaee6b700d adapt tiger reverse test to changed api 2016-11-02 00:11:17 +01:00
Sarah Hoffmann
032f24bfef Merge branch 'ui-easy-switch-coords' of https://github.com/mtmail/Nominatim 2016-11-01 23:49:02 +01:00
marc tobias
d93209ee48 Tiger: set osmtype=way and correct osm_id 2016-11-01 23:34:29 +01:00
marc tobias
eb79e655e6 cleanup of SQL for readability. No logic change 2016-11-01 23:33:47 +01:00
marc tobias
4f3074e538 cleanup of SQL for readability. No logic change 2016-11-01 23:33:47 +01:00
marc tobias
8312e8f539 UI: keep map position when switch to reverse. Easy switching of lat,lon to lon,lat 2016-10-30 17:45:45 +01:00
Sarah Hoffmann
d4daa0c4fa Merge pull request #568 from mtmail/z-index-fix-for-mapbounds-button
fix dropdown menu not overlapping map button
2016-10-29 12:21:49 +02:00
marc tobias
a9ad69efae add missing newline in CSS file 2016-10-29 11:25:21 +02:00
marc tobias
0a45dbf5f6 fix drodown menu not overlapping map button 2016-10-29 11:14:30 +02:00
Sarah Hoffmann
a61f852cd2 fix parameter list for renamed postgis functions
fixes #560
2016-10-24 20:39:49 +02:00
Sarah Hoffmann
26ba5bf0be Merge pull request #556 from lonvia/drop-php-53-support
Drop support for PHP < 5.4
2016-10-20 22:00:18 +02:00
Sarah Hoffmann
702f9477ab Merge pull request #557 from mtmail/test-failure-after-c0b4411
PHP unit test failed after change in c0b4411
2016-10-18 23:06:29 +02:00
Marc Tobias Metten
179542f938 PHP unit test failed after change in c0b4411 2016-10-18 22:54:01 +02:00
Sarah Hoffmann
b77e2503f5 drop support for PHP < 5.4 2016-10-17 22:28:39 +02:00
Sarah Hoffmann
1542a006cb Merge pull request #550 from lonvia/decrease-line-length
Reduce maximum line length to 199
2016-10-16 09:55:13 +02:00
Sarah Hoffmann
bb1c3f23ab reduce maximum line length to 199 for all php files 2016-10-14 00:01:16 +02:00
Sarah Hoffmann
8650e0fedd slightly relax viewbox parameter check
Allow out of bounds parameters as long as the resulting box
covers some legal coodinates.
2016-10-13 08:03:28 +02:00
Sarah Hoffmann
abac5d8ebd split long lines in Geocode.php 2016-10-13 00:27:17 +02:00
Sarah Hoffmann
aa7c8b6b5b fix viewbox parameters in tests 2016-10-13 00:26:04 +02:00
Sarah Hoffmann
e69115fd8f remove debug output 2016-10-12 22:27:46 +02:00
Sarah Hoffmann
7b1f35426d check if query is valid unicode string 2016-10-12 22:25:04 +02:00
Sarah Hoffmann
6757e1b865 properly check format of viewbox parameter 2016-10-12 22:13:07 +02:00
Sarah Hoffmann
c72e6a93dc fix typo in error message 2016-10-12 20:21:12 +02:00
Sarah Hoffmann
c0b4411337 reduce search depth when splitting word sets
Too many out-of-memory conditions with the current algorithm.
2016-10-12 20:09:20 +02:00
Sarah Hoffmann
0e613a362e fix variable name typos 2016-10-10 22:22:35 +02:00
Sarah Hoffmann
4123a3fd6b note phpcs command in contribution readme 2016-10-09 23:08:20 +02:00
Sarah Hoffmann
087522c601 details: check for unknown object and icons 2016-10-09 22:14:19 +02:00
Sarah Hoffmann
fb51d51582 fix syntax error for route boxes 2016-10-09 21:41:23 +02:00
Sarah Hoffmann
f5641037cf avoid passing temporary array by reference
PHP7 complains: Only variables should be passed by reference.
2016-10-09 21:14:59 +02:00
Sarah Hoffmann
39580057fc better error message for missing osm2pgsql 2016-10-09 21:04:53 +02:00
Sarah Hoffmann
a855ffe58e replace deprecated postgis functions
ST_Line_Locate_Point and ST_Distance_Spheroid have changed
spelling in newer version and throw a deprecation warning.
2016-10-09 20:09:59 +02:00
Sarah Hoffmann
42d473968f check for correct array for country codes
fixes trac ticket 5427
2016-10-04 20:32:22 +02:00
Rémi BOURGAREL
8a2e401025 Change on get_addressdata check for matching the condition in placex_update
On placex_update we stop the indexing to the first parent if the rank_search is above 27. We should do the same check in get_adressdata, because place with a rank_address != 30 and a search_rank > 27 will have only 1 parent.
https://github.com/twain47/Nominatim/issues/534
2016-10-04 15:49:31 +02:00
Sarah Hoffmann
a912b3448f docs: fix link 2016-10-02 17:33:49 +02:00
Sarah Hoffmann
8b896f37f3 fill interpolation array for reverse lookups via search endpoint
Fixes #540
2016-10-01 13:03:31 +02:00
Sarah Hoffmann
6bf90eb22f fix namespace use 2016-09-30 22:43:11 +02:00
Sarah Hoffmann
421174ce0c Merge pull request #538 from lonvia/update-default-languages
Update default languages and move country search term creation to setup.php
2016-09-30 20:01:20 +02:00
Sarah Hoffmann
1982978f74 move country search term creation into setup script
Search results can become odd without the country search
terms, so make their inclusion a mandatory part of the
setup.

Also adds a new configuration variable to restrict the
languages taken into account by Nominatim.
2016-09-28 23:30:44 +02:00
Sarah Hoffmann
6fd2887543 update per-country language defaults
Added missing defaults for all mono-lingual countries as per
http://wiki.openstreetmap.org/wiki/Nominatim/Country_Codes
2016-09-28 22:04:29 +02:00
Sarah Hoffmann
44ee8d9ce3 Merge pull request #533 from mtmail/PSR2-php-tests
fix PSR2 warnings in php tests
2016-09-16 21:57:38 +02:00
Sarah Hoffmann
bf77b444bf Merge pull request #532 from mtmail/PSR2-namespaces
add namespaces, method visibility according to PSR2 standard
2016-09-16 21:55:44 +02:00
Marc Tobias Metten
a7da0c90bf fix PSR2 warnings in php tests 2016-09-16 02:45:42 +02:00
Marc Tobias Metten
6238ae6032 add namespaces, method visibility according to PSR2 standard 2016-09-16 02:27:36 +02:00
Sarah Hoffmann
d437a14f25 vagrant: use old configs when updating
Otherwise we may overwrite vagrant-specific settings like
nopassword for sudo.
2016-09-15 23:08:54 +02:00
Sarah Hoffmann
e1be3d9f48 Merge branch 'PSR2-fixes-for-settings' of https://github.com/mtmail/Nominatim into mtmail-misc-psr-fixes 2016-09-15 21:53:12 +02:00
Sarah Hoffmann
e686ce8680 Merge branch 'PSR2-fixes-for-wikidata' of https://github.com/mtmail/Nominatim into mtmail-misc-psr-fixes 2016-09-15 21:51:48 +02:00
Marc Tobias Metten
93c26a0e65 half-reverting 51155b63, We dont need two of three break statements after all 2016-09-15 19:36:32 +02:00
Marc Tobias Metten
02550cc4dc PSR2 fixes for /settings 2016-09-14 03:50:18 +02:00
Marc Tobias Metten
b243aa84e2 PSR2 fixes for /wikidata and /tests-php directories 2016-09-14 03:39:17 +02:00
Marc Tobias Metten
cfed4bc204 PHP linter looks for phpcs.xml by default. Also removed a couple of exceptions that didnt cause warnings 2016-09-14 03:23:43 +02:00
Marc Tobias Metten
4a321487f3 fix indentation and misc errors according to PSR2 coding style guide 2016-09-14 03:16:46 +02:00
Marc Tobias Metten
74c06ef877 PHP linter looks for phpcs.xml by default. Also removed a couple of exceptions that didnt cause warnings 2016-09-14 03:15:46 +02:00
Marc Tobias Metten
51155b639b case statement need : instead of ;. Added more breaks 2016-09-14 03:00:57 +02:00
Marc Tobias Metten
775fdeb8e4 UI: viewbox parameter was set in wrong parameter order 2016-09-13 14:41:56 +02:00
Sarah Hoffmann
eb0b3bfa4c Merge pull request #524 from mtmail/PSR2-function-declarations
fix function declaration errors according to PSR2 coding style guide
2016-09-11 12:07:35 +02:00
Marc Tobias Metten
2a784fa3d4 fix function declaration errors according to PSR2 coding style guide 2016-09-11 05:22:51 +02:00
Marc Tobias Metten
5c40100b57 code style definitions: we no longer use tabs 2016-09-11 05:21:51 +02:00
Marc Tobias Metten
ae5cc28a1a add PHP code-sniffer to installation instructions (marked optional) 2016-09-11 05:21:15 +02:00
Sarah Hoffmann
cf39e07dba Merge pull request #522 from mtmail/PSR2-arrays
fix array-related errors according to PSR2 coding style guide
2016-09-10 23:35:25 +02:00
marc tobias
e49ed1bb13 make apt-get noninteractive. Also fixes the grub error state
grub complains about disc unique identifier having changed
2016-09-10 23:29:59 +02:00
marc tobias
3887423381 fix array-related errors according to PSR2 coding style guide 2016-09-10 21:10:52 +02:00
marc tobias
f05ea577f4 bracket spacing for if/else/for/foreach/while/switch according to PSR2 standard 2016-09-08 02:16:22 +01:00
Sarah Hoffmann
effd8e12af Merge branch 'delete-us-postcode-without-name' of https://github.com/mtmail/Nominatim 2016-09-05 23:09:32 +02:00
Sarah Hoffmann
89c157a6c1 adapt coding style for new spaces-only policy 2016-09-05 22:13:08 +02:00
Marc Tobias Metten
832547f192 tabs-to-spaces 2016-09-04 03:19:48 +02:00
Marc Tobias Metten
36fdfd92ad one US postcode has no name. Unable to find secondary source what it would have been 2016-09-04 02:15:51 +02:00
Sarah Hoffmann
cd6dcfa574 Merge pull request #498 from mtmail/move-mouse-position-info-on-map
HTML map: new button -show map bounds-
2016-08-24 22:19:48 +02:00
Sarah Hoffmann
8a796db3c9 Merge pull request #508 from mtmail/addtype-in-installation.md
typo in Installation.md
2016-08-24 08:49:45 +02:00
Marc Tobias Metten
87b6810eba HTML map: new button -show map bounds- in top right corner 2016-08-24 04:21:28 +02:00
mtmail
50c994be93 Update Installation.md
trivial typo: AddTpe => AddType
2016-08-24 01:45:36 +02:00
Marc Tobias Metten
797c2d1e74 Merge remote-tracking branch 'upstream/master' into move-mouse-position-info-on-map 2016-08-24 00:03:40 +02:00
Sarah Hoffmann
d7c469d94e Merge pull request #504 from lonvia/parameter-parser-class
factor out parameter parsing into its own class
2016-08-23 21:57:06 +02:00
Sarah Hoffmann
3b7baca46c Merge pull request #506 from mtmail/primary-vagrant-vm
specify ubuntu as primary Vagrant VM
2016-08-22 09:41:46 +02:00
marc tobias
0957bd27c6 specify ubuntu as primary Vagrant VM 2016-08-22 05:47:26 +02:00
Sarah Hoffmann
5464dec057 factor out parameter parsing into its own class
Allows to use the parsing functions in website/search.php and
utils/query.php as well.
2016-08-20 13:43:50 +02:00
Sarah Hoffmann
feb458f8dd update tests for newer planet 2016-08-19 23:57:23 +02:00
Sarah Hoffmann
9c1e0c49bf docs: give recomendations about flatnode file size
closes #501
2016-08-10 22:02:10 +02:00
Sarah Hoffmann
36f2afea8a mark checkpoint_segments parameter as deprecated
Postgresql 9.5 has checkpoint_segments removed and fails to start
if the options is given. Adds a comment to that effect.

Fixes #494.
2016-08-04 22:17:05 +02:00
Sarah Hoffmann
5c187e131a Merge pull request #499 from mtmail/travis-ci
Travis ci setup - tests pass
2016-08-03 08:35:32 +02:00
Marc Tobias Metten
cb68a2cdd2 Merge remote-tracking branch 'upstream/master' into travis-ci 2016-08-03 01:10:30 +02:00
Marc Tobias Metten
3499ed7b82 travis-ci: enable river tests again, numpy package was missing 2016-08-03 00:57:30 +02:00
Marc Tobias Metten
9ff24b9107 travis-ci: enable river tests again, numpy package was missing 2016-08-03 00:54:49 +02:00
Sarah Hoffmann
ee7a6e8f92 update paths in vagrant docs 2016-08-02 22:55:13 +02:00
Sarah Hoffmann
88d623b631 Merge pull request #497 from lonvia/forbid-execution-from-sourcedir
fail on execution of util scripts from source directory
2016-08-02 22:42:20 +02:00
mtmail
2a97ce6aed Merge pull request #476 from mtmail/travis-ci
travis-ci setup
2016-08-01 02:03:45 +02:00
Marc Tobias Metten
bb403e2e58 HTML map: new button -show map bounds- 2016-08-01 01:34:03 +02:00
Sarah Hoffmann
496d6bf168 fail on execution of util scripts from source directory
Utils scripts must be run from the build directory to make sure
we get the right paths. Rename the settings file in source and
replace the original one with an error, so that scripts
fail with an understandable error message when run from the
source directory.
2016-07-31 22:55:38 +02:00
Marc Tobias Metten
b00169e634 travis: exclude poldi, waterway tests 2016-07-31 02:33:47 +02:00
Marc Tobias Metten
9be58ffc7c travis: exclude poldi, waterway tests 2016-07-31 02:18:27 +02:00
Marc Tobias Metten
1fb847a5ad travis: exclude poldi, waterway tests 2016-07-31 02:17:28 +02:00
Marc Tobias Metten
8a823d1361 Merge remote-tracking branch 'upstream/master' into travis-ci 2016-07-30 21:53:27 +02:00
Sarah Hoffmann
ab30a69ad9 Merge pull request #490 from lonvia/streamline-class-interfaces
Code cleanup for geocode classes
2016-07-27 20:56:10 +02:00
Sarah Hoffmann
0a95bdc5f5 remove unused functions in Geocode 2016-07-26 23:10:50 +02:00
Sarah Hoffmann
d594bb238b cleanup interface of PlaceLookup
Move lookup parameters (place id, type, frac etc.) from members
to parameters for lookup().
2016-07-26 20:54:14 +02:00
Sarah Hoffmann
0d179b8c97 remove unnecessary local variable 2016-07-26 20:54:14 +02:00
Sarah Hoffmann
1b33999f10 refactor ReverseGeocode
- remove unused functions and members
- move coordinates from being members to being parameters of lookup()
2016-07-26 20:54:14 +02:00
Sarah Hoffmann
3f06d9d3ba fix typos and grammar in installation instructions 2016-07-26 20:38:44 +02:00
Sarah Hoffmann
7da9178b83 Merge pull request #487 from lonvia/unify-reverse
Remove duplicate reverse geocoding code
2016-07-25 22:15:28 +02:00
Sarah Hoffmann
a766240c06 remove duplicate reverse geocoding code
Geocode now uses ReverseGeocode directly. Note that it currently
cannot support any interpolations, neither OSM nor Tiger. But
neither did the previous version.
2016-07-24 23:58:39 +02:00
Sarah Hoffmann
a827367a2f adapt Tiger reverse test to new output format 2016-07-24 23:58:21 +02:00
Sarah Hoffmann
4f75f4cb6e remove IP blocking and rate-limiting code
Closes #472.
2016-07-18 21:33:09 +02:00
Sarah Hoffmann
975c30afba Merge pull request #486 from IrlJidel/patch-1
pgsqlRunPartitionScript needs global $aCMDResult
2016-07-16 10:09:09 +02:00
IrlJidel
ca92442601 pgsqlRunPartitionScript needs global $aCMDResult
function pgsqlRunPartitionScript  was missing global $aCMDResult

setup was failing with

...
PHP Notice:  Undefined variable: aCMDResult in /home/roles/nominatim/app/Nominatim/build/utils/setup.php on line 768
NOTICE:  type "nearplace" does not exist, skipping
..
ERROR:  relation "location_area_large_0" already exists
ERROR: pgsql returned with error code (3)
pgsql returned with error code (3)
Command exited with non-zero status 255
2016-07-14 19:49:58 +01:00
Marc Tobias Metten
77ca079688 travis-ci setup, some tests fails 2016-06-21 23:42:36 +02:00
Sarah Hoffmann
665de339e5 allow coordinates in query only with name or classtype
Coordinates with country or housenumber only do not make much
sense. Currently these combination result in queries that
require a sequential scan of search_name and normally time
out before yielding any results.

fixes #462
2016-06-15 22:41:48 +02:00
Sarah Hoffmann
84495489d9 fix links to documentation in README 2016-06-14 23:11:14 +02:00
Sarah Hoffmann
8eb0e09ce3 more instructions for Tiger imports 2016-06-14 21:44:18 +02:00
Sarah Hoffmann
2ab43f6367 reverse do not downgrade tiger and interpolation results
Also fix the type that is returned for Tiger data.

Fixes #470
2016-06-14 21:38:03 +02:00
Sarah Hoffmann
b14bc75dc4 Merge pull request #469 from lonvia/refactor-php
Some refactoring of website php
2016-06-13 20:13:38 +02:00
Sarah Hoffmann
860acbf6af add instructions to enable use of Tiger data 2016-06-13 20:07:57 +02:00
Sarah Hoffmann
10c5d7f6f6 fix more syntax errors in error functions 2016-06-12 23:25:47 +02:00
Sarah Hoffmann
e842d8793c allow parameters to be empty
Consider empty parameters as unset and use the default. Simplifies
use in forms.
2016-06-12 23:22:14 +02:00
Sarah Hoffmann
348a3082c9 fix syntax errors and update tests
Some of the tests with bad parameters now return a HTTP 400.
2016-06-12 22:51:13 +02:00
Sarah Hoffmann
033b9590bd use chksql everywhere in lib/
Replaces manual PEAR error checks and adds the chksql wrapper
where the error checks were still missing.
2016-06-12 14:58:05 +02:00
Sarah Hoffmann
95961d098d introduce chksql function for website code and move other fail functions
The default error screen now reports the full SQL even when not
in debug mode as this message is often more helpful than our
custom error message.
2016-06-12 14:34:57 +02:00
Sarah Hoffmann
7a50d2f996 factor out link formatting function and osm type translation 2016-06-12 12:39:09 +02:00
Sarah Hoffmann
6fef943e49 update links to OSM objects
/browse/ is no longer necesary in the URL
2016-06-12 09:26:58 +02:00
Sarah Hoffmann
76b9eb8098 remove now unused bAsPoints in reverse API 2016-06-11 23:27:21 +02:00
Sarah Hoffmann
d45524cbfb introduce accessor function for URL parameter
These functions take care of type conversion and check that
the parameters contain legal values. The API now returns a
Bad Request error if the format is wrong.
2016-06-11 23:07:06 +02:00
Sarah Hoffmann
aa9fff9199 polygons.php: print total number of broken polygons 2016-06-11 00:01:24 +02:00
Sarah Hoffmann
1a47376040 remove dead code 2016-06-11 00:01:24 +02:00
Sarah Hoffmann
051998dd80 Merge pull request #219 from mizabrik/master
Fix case sensitivity of cyrillic ghe
2016-06-09 21:53:56 +02:00
Sarah Hoffmann
cf4a44aaf7 introduce chksql function for phpscripts
Checks SQL query results for errors and bails out if it finds one.
Avoids some heavy code duplication all over the place.
2016-06-09 20:37:51 +02:00
Sarah Hoffmann
85c72cdccd remove --create-website function
Symlinking does not go well with the separate build directory.
The recommended method is now to serve the website directly from
build/website via an alias. 'website installation' may be
reintroduced later via cmake.
2016-06-08 23:41:36 +02:00
Sarah Hoffmann
3a41b0dfbf Merge pull request #464 from lonvia/vagrant-with-docs
Move installation documentation from wiki into /docs directory
2016-06-08 23:25:50 +02:00
Sarah Hoffmann
6436bab1be remove old vagrant scripts 2016-06-08 23:23:09 +02:00
Sarah Hoffmann
91e1e4d614 fix formatting of docs 2016-06-08 23:17:48 +02:00
Sarah Hoffmann
af93973237 add compiled vagrant docs in docs/ directory 2016-06-08 23:06:15 +02:00
Sarah Hoffmann
2e08a61565 add vagrant script for ubuntu 16 and polish everything 2016-06-08 23:03:11 +02:00
Sarah Hoffmann
0adb8cb765 fix cut&paste error in php tests 2016-06-08 22:51:56 +02:00
Sarah Hoffmann
f71e9dd187 move installation instructions from wiki page here 2016-06-07 22:47:57 +02:00
Sarah Hoffmann
186a633185 fix apache permission problems in CentOS vagrant script 2016-06-07 00:27:20 +02:00
Sarah Hoffmann
d1b1acaf1d split instruction into software installation and import
Basically leaves the part that needs to be done by the automatic
vagrant script in the bash script and moves the remaining part
into an OS-independent md file.

Also fixes some of the instructions for CentOS. Now almost runs
through (some minor issue with permission remains).
2016-06-07 00:17:15 +02:00
Sarah Hoffmann
ff6c3a705b initial version of documented CentOS7 vagrant script 2016-06-05 16:15:26 +02:00
Sarah Hoffmann
badd2e46aa provide srcdir for postgres module in VPATH and CPPFLAGS
The pgxs makefile in Postgres <= 9.2 cannot yet handle VPATH
correctly. Provide header paths explicitly and overwrite
VPATH after sourcing the pgxs file.

Fixes #454.
2016-06-05 00:35:07 +02:00
markigail
98e5ba6b61 use place_id instead of parent_place_id for excluded place_ids in interpolation lines query 2016-06-04 23:54:17 +02:00
Sarah Hoffmann
2156fb1ad7 remove reference assignment where unnecessary
Avoids a number of warnings on PHP7.
2016-06-04 23:46:19 +02:00
Sarah Hoffmann
92095c9247 Merge branch 'interpolations' 2016-06-04 23:29:11 +02:00
Sarah Hoffmann
524bd47315 fill place and osmline independently for interpolations on update
interpolation lines may be missing in osmline when the interpolation
is broken, so we cannot conclude that a way is not in place, just
because there are no entries in location_property_osmline.
2016-05-28 18:18:18 +02:00
Sarah Hoffmann
c3e21ea388 reinstate tests for geometrytype 2016-05-27 23:36:01 +02:00
Sarah Hoffmann
f0d962f8a0 fix variable name in search xml output 2016-05-27 23:35:24 +02:00
Sarah Hoffmann
e4963256e1 cmake: use explicit VPATH when calling pgxs makefile
Some postgres installations report problems with the makefile
magic that should look for the source where the Makefile is
located. So hand in the path explicitly via VPATH instead.

Fixes #453.
2016-05-24 00:24:23 +02:00
Sarah Hoffmann
362f259f47 cmake: force-set options and explicitly check for pgxs makefile
fixes #443
2016-05-23 22:20:59 +02:00
Sarah Hoffmann
8b91284f7f reintroduce addr:place for interpolation
It is perfectly valid that interpolated addresses refer to
something else than a street.

Also gets rid of the maximum interpolation size. As we don't
expand, arbitrary sizes are fine.
2016-05-15 14:24:43 +02:00
Sarah Hoffmann
2a0c7fb57a tests: permit duplicate entries in interpolation table
fixes self-intersecting interpolation test
2016-05-15 14:24:12 +02:00
Sarah Hoffmann
2fecc0c465 tests for interpolation to building type change 2016-05-15 12:37:49 +02:00
Sarah Hoffmann
94d795883f update comments and formatting 2016-05-15 12:37:20 +02:00
Sarah Hoffmann
f0f6fcf256 fix scene making scripts and add building-parallel-road scene
Scripts updated to newest libosmium and shebang fixed.
2016-05-15 12:36:16 +02:00
Sarah Hoffmann
28041cbbd9 remove duplicate index 2016-05-15 11:44:54 +02:00
Sarah Hoffmann
821949f087 get housenumber data for interpolations from place table
The placex table may not yet be filled when the interpolation
lines are computed.
2016-05-15 09:44:00 +02:00
Sarah Hoffmann
0fcab79486 fix syntax in load-data function
Also makes sure that load data runs with at least 2 threads: one
for loading placex and one for loading osmline.
2016-05-15 09:41:11 +02:00
Sarah Hoffmann
234b1b0293 Merge remote-tracking branch 'markus/master' into master 2016-05-14 21:09:57 +02:00
markigail
f07d620ee8 Change load-data in setup.php. 2016-05-11 10:22:03 +02:00
markigail
190a72cab5 Fix bug in index.c and remove column admin_level from location_property_osmline. 2016-05-08 16:46:42 +02:00
markigail
1a4f369e2b fix small bug in index.c 2016-05-03 12:52:08 +02:00
mtmail
ce112f7c20 Merge pull request #447 from lonvia/fix-array-expression
replace new-style [] expression with old-style array()
2016-05-01 11:53:54 +02:00
Sarah Hoffmann
4e0e0c1797 replace new-style [] expression with old-style array()
Also removes some unused code.

fixes #444
2016-05-01 11:22:53 +02:00
Sarah Hoffmann
54ef9105d0 Merge pull request #446 from mtmail/make-outline-clickable-in-ui
UI: the result outline (geojson/polygon) now lets the map handle clicks
2016-05-01 11:11:21 +02:00
marc tobias
9e1421fb6c UI: the result outline (geojson/polygon) now lets the map handle its clicks 2016-05-01 10:47:13 +02:00
Markus Gail
2ba9c11dd0 fix bug in Geocode.php 2016-04-29 10:24:30 +02:00
Markus Gail
db719d489f index on geometry of interpolation lines, and more improvements. 2016-04-27 17:42:59 +02:00
Sarah Hoffmann
7a5aab61ae Merge pull request #441 from mtmail/update-php-to-check-for-correct-js-file
update.php was checking for static file which is no longer part of the project
2016-04-26 21:03:58 +02:00
Marc Tobias Metten
7b4806b2e8 update.php was checking for static file which is no longer part of the project 2016-04-26 20:45:48 +02:00
Markus Gail
a10f537131 Correct merge error in Geocode.php. 2016-04-25 17:44:34 +02:00
Markus Gail
89c556d163 Coding style adaptions and correcting small errors from merge. 2016-04-25 13:58:28 +02:00
Markus Gail
b03be15442 Merge remote-tracking branch 'origin/master' into osmline
Conflicts:
	lib/Geocode.php
	lib/PlaceLookup.php
	sql/functions.sql
	sql/tables.sql
	utils/setup.php
2016-04-25 11:01:04 +02:00
Markus Gail
7879ad44cd Remove interpolation lines from placex and save them in an extra table. 2016-04-25 09:44:01 +02:00
Sarah Hoffmann
131527bdab Merge pull request #436 from lonvia/remove-location-property-tables
remove unused location_property_-partion- tables
2016-04-24 16:05:10 +02:00
Sarah Hoffmann
a244c41ea7 create_sql_functions() needs the commandline parameters
Fixes one failing test.
2016-04-23 11:07:12 +02:00
Sarah Hoffmann
a32f6c66b8 remove unused location_property_-partion- tables 2016-04-23 10:07:57 +02:00
Sarah Hoffmann
b4f0b8b728 apply marker filtering to functions.sql also after table creation
fixes #430
2016-04-21 00:00:15 +02:00
Sarah Hoffmann
af06d31d21 remove duplicate CORS header
fixes #427
2016-04-12 23:04:38 +02:00
Sarah Hoffmann
d01d0c13f4 Merge pull request #425 from lonvia/disable-aux-tables
make tables for external data (Tiger and aux) configurable
2016-04-12 23:00:24 +02:00
Sarah Hoffmann
be268f95e6 Merge pull request #424 from lonvia/cleanup-logging
clean up query logging
2016-04-12 22:58:14 +02:00
Sarah Hoffmann
a86563cfb1 make tables for external data (Tiger and aux) configurable
Introduces two new settings CONST_Use_US_Tiger_Data and
CONST_Use_Aux_Location_data, which are disabled by default.
When false the corresponding tables are ignored in queries
and updates.

Aux and tiger tables are no longer created by default. This
has to be done by the corresponding import scripts. The former
aux table creation can be found in sql/aux_tables.sql for
reference.
2016-04-07 21:47:51 +02:00
Sarah Hoffmann
009882999f clean up query logging
- remove query_log table, keeping only new_query_log
- drop unused import_npi_log table
- disable DB logging per default
- use file logging structure from osm.org
2016-04-07 20:37:27 +02:00
Sarah Hoffmann
1da4fed9b5 Merge pull request #420 from lonvia/remove-explicit-software-versions
Remove unsupported/unused features and settings
2016-04-01 23:03:01 +02:00
Sarah Hoffmann
6ee4b30ee9 remove deleted us_state* tables from tests as well 2016-04-01 22:59:54 +02:00
Sarah Hoffmann
4f9f21f661 remove state and county data for US and make postcode import optional 2016-03-30 23:21:13 +02:00
Sarah Hoffmann
527c3390f4 remove unused settings 2016-03-30 23:03:10 +02:00
Sarah Hoffmann
f9a488cd5a remove 'closed for indexing' feature
Simultanous updates are fine these days.
2016-03-30 22:53:19 +02:00
Sarah Hoffmann
02bd322c1d remove explicitly set postgres/postgis version
Get the version from the database where necessary or simply
probe for existence of features. Fake hstore_to_json when
necessary.

Bumps the minimum required versions fro postgres to 9.1 and
for postgis to 2.0.
2016-03-30 22:48:18 +02:00
Sarah Hoffmann
a0acc6e913 Merge pull request #416 from lonvia/dead-code-removal
Remove unused and/or unmaintained php code
2016-03-30 20:33:54 +02:00
Sarah Hoffmann
0419aada6e test: catch script output in as debug log output 2016-03-29 23:14:03 +02:00
Sarah Hoffmann
6f442b6617 remove unused functions in php library 2016-03-28 22:55:21 +02:00
Sarah Hoffmann
a0a5100807 remove unused files 2016-03-28 22:30:56 +02:00
Sarah Hoffmann
a769fc4ff3 remove unused/unmaintained options in import scripts 2016-03-28 22:20:31 +02:00
Sarah Hoffmann
83cca343c3 Fix fixing of coding style 2016-03-28 22:04:08 +02:00
Sarah Hoffmann
bfcbb94aed exclude Tiger stuff from required tests 2016-03-28 17:17:56 +02:00
Sarah Hoffmann
5d928d5187 adapt tests to new tiger algorithm 2016-03-28 17:08:27 +02:00
Sarah Hoffmann
23fa6018a4 make sure linked places get recomputed when unlinked
When linked the place may not be in the search index,
so it must be reindexed when being unlinked. The status
change will only have an effect during the subsequent
update, so change tests to that effect.
2016-03-28 09:51:29 +02:00
Sarah Hoffmann
53eb9a5f14 fix syntax errors in tiger code and adapt format of dummy tables 2016-03-27 23:45:20 +02:00
Sarah Hoffmann
443bfec035 Merge branch 'tigerlines' of https://github.com/markigail/Nominatim 2016-03-27 20:00:15 +02:00
Sarah Hoffmann
8534ce5ec2 tests: update for osm2gsql changes
Also fixes a missing type set for query.php tests.
2016-03-25 12:07:22 +01:00
Sarah Hoffmann
92bedbb881 Add hints about coding style
heavily borrowed from osm2pgsql
2016-03-25 12:06:30 +01:00
Sarah Hoffmann
7090604de7 reinstate NOMINATIM_SETTINGS variable
Move sourcing of this script to settings.php so that
it is loaded before anything else.
2016-03-24 22:06:54 +01:00
Markus Gail
7dd0a63b68 Fix coding style. 2016-03-23 09:34:36 +01:00
Markus Gail
a4ecd9d73e Merge branch 'tigerlines' of /home/markus/Nominatim into tiger
Conflicts:
	lib/Geocode.php
	lib/ReverseGeocode.php
	lib/lib.php
2016-03-22 11:26:39 +01:00
Markus Gail
e94b667e16 adapt to code style conventions 2016-03-21 14:15:22 +01:00
Markus Gail
f6127df15d add osm_type='tiger' to json, jsonv2 and xml output 2016-03-21 14:14:01 +01:00
Markus Gail
a8afb9bd3c Removed unnecessary test for tiger. 2016-03-21 14:14:01 +01:00
Markus Gail
86622662bf Removed some files for the commit. 2016-03-21 14:14:01 +01:00
Markus Gail
291fdd1894 Tested Version of new Tiger line storage format. 2016-03-21 14:14:01 +01:00
Markus Gail
46cef36184 Implement geocoding and reverse geocoding with tiger interpolation lines instead of points. 2016-03-21 14:14:01 +01:00
Markus Gail
bc449e10be change tiger housenumber format to save as lines instead of points and thus new interpolation 2016-03-21 14:07:12 +01:00
Markus Gail
d8703c223b adapt to code style conventions 2016-03-21 13:32:44 +01:00
Markus Gail
28166c5bb1 add osm_type='tiger' to json, jsonv2 and xml output 2016-03-21 13:32:44 +01:00
Markus Gail
54fdc572c1 Removed unnecessary test for tiger. 2016-03-21 13:32:44 +01:00
Markus Gail
6fb8fab665 Removed some files for the commit. 2016-03-21 13:32:44 +01:00
Markus Gail
df6b433066 Tested Version of new Tiger line storage format. 2016-03-21 13:32:44 +01:00
Markus Gail
26e30bf8e1 Implement geocoding and reverse geocoding with tiger interpolation lines instead of points. 2016-03-21 13:32:44 +01:00
Markus Gail
49d0ce1de4 change tiger housenumber format to save as lines instead of points and thus new interpolation 2016-03-21 13:32:44 +01:00
marc tobias
d020e05f5b query the last updated timestamp only if output format is HTML 2016-03-21 13:32:44 +01:00
marc tobias
c346c57341 corrected layout of keywords on HTML details page 2016-03-21 13:32:44 +01:00
Marc Tobias Metten
d237549496 moved bIncludePolygonAsPoints related logic into lib.php, added tests 2016-03-21 13:32:44 +01:00
Marc Tobias Metten
607fef2d8f moved bIncludePolygonAsPoints related logic into lib.php, added tests 2016-03-21 13:32:44 +01:00
Sarah Hoffmann
a50bf1c944 update osm2pgsql (WITH_LUA switch) 2016-03-16 20:05:52 +01:00
Sarah Hoffmann
4ea0074548 fix path for website installations 2016-03-16 20:02:09 +01:00
Sarah Hoffmann
4b46c73088 fix nominatim paths 2016-03-16 19:56:10 +01:00
Sarah Hoffmann
6fc32d9645 Merge branch 'cmake-port' into master
Conflicts:
	CMakeLists.txt
	lib/init.php
	settings/settings.php
2016-03-16 19:45:18 +01:00
Sarah Hoffmann
279ea25e7d Merge pull request #381 from lonvia/cmake-port
Replace autotools with cmake and update osm2pgsql
2016-03-13 21:40:38 +01:00
Sarah Hoffmann
50f17666fa Merge pull request #395 from mtmail/php7-support
fix for PHP7, added test setup
2016-03-13 21:38:57 +01:00
Sarah Hoffmann
b097840ba4 Merge pull request #396 from mtmail/fix-array-merge-warning
second argument of array_merge can be empty
2016-03-13 21:37:40 +01:00
Marc Tobias Metten
22ebd1c7a9 second argument of array_merge can be empty 2016-03-13 03:01:19 +01:00
Marc Tobias Metten
df764a3f3b fix for PHP7, added test setup 2016-03-13 02:06:46 +01:00
Sarah Hoffmann
5ccb499a6f install executables and call settings.php explicitly
Executables (including websites) need to be installed in the
build directory, so that they can find the right settings.php.
settings now defines build and source dir.
2016-03-12 09:40:43 +01:00
Sarah Hoffmann
b24ef60b33 enable test execution using ctest 2016-03-12 09:40:43 +01:00
Sarah Hoffmann
6450126933 adapt README and vagrant scripts to cmake 2016-03-12 09:40:43 +01:00
Sarah Hoffmann
314a9e52e9 use external makefile for pgxs with cmake 2016-03-12 09:40:43 +01:00
Sarah Hoffmann
5d7bd37ab2 introduce InstallPath, so that stuff can be executed from build dir 2016-03-12 09:40:43 +01:00
Sarah Hoffmann
c96e71a3d7 add actual cmake file 2016-03-12 09:40:43 +01:00
Sarah Hoffmann
e3f9581a69 move from autotools to cmake and update osm2pgsql 2016-03-12 09:40:43 +01:00
Sarah Hoffmann
1d89098f77 Merge pull request #389 from mtmail/reverse-geocode-include-geometry2
Reverse geocode include geometry (v2)
2016-03-09 23:16:51 +01:00
Marc Tobias Metten
71b3aa9cca Reverse geocode include geometry - added bounding box tests 2016-03-09 19:43:03 +01:00
Marc Tobias Metten
991bd0004a Reverse geocode include geometry 2016-03-04 20:29:09 +01:00
Marc Tobias Metten
d3ff9600b5 Merge remote-tracking branch 'upstream/master' 2016-03-04 15:42:29 +01:00
Sarah Hoffmann
df9850f5ca Merge pull request #385 from mtmail/query-lastupdated-only-for-html-output
query the last updated timestamp only if output format is HTML
2016-03-02 21:36:34 +01:00
Sarah Hoffmann
fa9677242c Merge pull request #384 from mtmail/detail-page-name-keywords-with-wordids
corrected layout of keywords on HTML details page
2016-03-02 21:34:42 +01:00
Marc Tobias Metten
131b06fec3 Merge branch 'master' of https://github.com/mtmail/Nominatim 2016-03-02 15:07:22 +01:00
marc tobias
8e2b5d7ce3 query the last updated timestamp only if output format is HTML 2016-03-02 01:22:19 +01:00
marc tobias
edaa1f7fcd corrected layout of keywords on HTML details page 2016-03-02 00:53:56 +01:00
Sarah Hoffmann
30d56b7064 enable test execution using ctest 2016-02-29 23:45:30 +01:00
Sarah Hoffmann
1ed793f000 adapt README and vagrant scripts to cmake 2016-02-29 22:26:55 +01:00
Sarah Hoffmann
ae9291f625 use external makefile for pgxs with cmake 2016-02-29 22:26:55 +01:00
Sarah Hoffmann
1ad6f4a1ce introduce InstallPath, so that stuff can be executed from build dir 2016-02-29 22:26:55 +01:00
Sarah Hoffmann
932abeb0e2 add actual cmake file 2016-02-29 22:26:55 +01:00
Sarah Hoffmann
35a0f1b246 move from autotools to cmake and update osm2pgsql 2016-02-29 22:26:55 +01:00
Sarah Hoffmann
cb3af09ebd Merge pull request #380 from mtmail/geometryText2Points
Geometry text2 points
2016-02-29 20:53:49 +01:00
Marc Tobias Metten
9fb413a126 corrected layout of keywords on HTML details page 2016-02-29 13:59:16 +01:00
Marc Tobias Metten
27406c8daa corrected layout of keywords on HTML details page 2016-02-29 13:55:19 +01:00
Marc Tobias Metten
f6129ebfee moved bIncludePolygonAsPoints related logic into lib.php, added tests 2016-02-28 17:08:20 +01:00
Marc Tobias Metten
7f5fe8c877 moved bIncludePolygonAsPoints related logic into lib.php, added tests 2016-02-28 17:06:52 +01:00
Sarah Hoffmann
07628dc05d Merge pull request #378 from mtmail/spaces-to-tabs
spaces-to-tabs for all *.php files
2016-02-27 09:56:36 +01:00
Marc Tobias Metten
78a29b5a87 spaces-to-tabs for all *.php files 2016-02-27 00:02:20 +01:00
Alexander Vasilyev
6704f7bbb0 fix case sensitivity of cyrillic ghe 2014-12-31 05:59:48 +03:00
325 changed files with 95680 additions and 138294 deletions

26
.gitignore vendored
View File

@@ -1,33 +1,11 @@
*.log
*.pyc
nominatim/*.d
nominatim/*.o
nominatim/nominatim
module/nominatim.so
module/nominatim.o
settings/configuration.txt
settings/download.lock
settings/state.txt
build
settings/local.php
.deps/
autom4te.cache/
config.*
configure
Makefile
!tests/scenes/bin/Makefile
Makefile.in
stamp-h1
missing
INSTALL
aclocal.m4
depcomp
install-sh
compile
data/wiki_import.sql
data/wiki_specialphrases.sql
data/osmosischange.osc
.vagrant
.vagrant

32
.travis.yml Normal file
View File

@@ -0,0 +1,32 @@
---
sudo: required
dist: trusty
language: python
python:
- "3.6"
addons:
postgresql: "9.6"
git:
depth: 3
env:
- TEST_SUITE=tests
- TEST_SUITE=monaco
install:
- vagrant/install-on-travis-ci.sh
before_script:
- psql -U postgres -c "create extension postgis"
script:
- cd $TRAVIS_BUILD_DIR/
- if [[ $TEST_SUITE == "tests" ]]; then phpcs --report-width=120 . ; fi
- cd $TRAVIS_BUILD_DIR/test/php
- if [[ $TEST_SUITE == "tests" ]]; then phpunit ./ ; fi
- cd $TRAVIS_BUILD_DIR/test/bdd
- # behave --format=progress3 api
- if [[ $TEST_SUITE == "tests" ]]; then behave --format=progress3 db ; fi
- if [[ $TEST_SUITE == "tests" ]]; then behave --format=progress3 osm2pgsql ; fi
- cd $TRAVIS_BUILD_DIR/build
- if [[ $TEST_SUITE == "monaco" ]]; then wget --no-verbose --output-document=../data/monaco.osm.pbf http://download.geofabrik.de/europe/monaco-latest.osm.pbf; fi
- if [[ $TEST_SUITE == "monaco" ]]; then /usr/bin/env php ./utils/setup.php --osm-file ../data/monaco.osm.pbf --osm2pgsql-cache 1000 --all 2>&1 | grep -v 'ETA (seconds)'; fi
- if [[ $TEST_SUITE == "monaco" ]]; then /usr/bin/env php ./utils/specialphrases.php --wiki-import | psql -d test_api_nominatim >/dev/null; fi
notifications:
email: false

22
AUTHORS
View File

@@ -2,18 +2,14 @@ Nominatim was written by:
Brian Quinion
Sarah Hoffmann
Frederik Ramm
Michael Spreng
Daniele Forsi
mfn
Grant Slater
Andree Klattenhoff
IrlJidel
appelflap
b3nn0
Spin0us
Kurt Roeckx
Rodolphe Quiédeville
Marc Tobias Metten
Reverse geocoding using Tiger data feature made possible with support from Guru Labs
markigail
gemo1011
IrlJidel
Frederik Ramm
and many more.
For a full list of contributors see
https://github.com/openstreetmap/Nominatim/graphs/contributors

162
CMakeLists.txt Normal file
View File

@@ -0,0 +1,162 @@
#-----------------------------------------------------------------------------
#
# CMake Config
#
# Nominatim
#
#-----------------------------------------------------------------------------
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
#-----------------------------------------------------------------------------
#
# Project version
#
#-----------------------------------------------------------------------------
project(nominatim)
set(NOMINATIM_VERSION_MAJOR 3)
set(NOMINATIM_VERSION_MINOR 2)
set(NOMINATIM_VERSION_PATCH 1)
set(NOMINATIM_VERSION "${NOMINATIM_VERSION_MAJOR}.${NOMINATIM_VERSION_MINOR}.${NOMINATIM_VERSION_PATCH}")
add_definitions(-DNOMINATIM_VERSION="${NOMINATIM_VERSION}")
#-----------------------------------------------------------------------------
#
# Find external dependencies
#
#-----------------------------------------------------------------------------
set(BUILD_TESTS off CACHE BOOL "Build test suite" FORCE)
set(WITH_LUA off CACHE BOOL "Build with lua support" FORCE)
if (NOT EXISTS "${CMAKE_SOURCE_DIR}/osm2pgsql/CMakeLists.txt")
message(FATAL_ERROR "The osm2pgsql directory is empty.\
Did you forget to check out Nominatim recursively?\
\nTry updating submodules with: git submodule update --init")
endif()
add_subdirectory(osm2pgsql)
find_package(Threads REQUIRED)
unset(PostgreSQL_TYPE_INCLUDE_DIR CACHE)
set(PostgreSQL_TYPE_INCLUDE_DIR "/usr/include/")
find_package(PostgreSQL REQUIRED)
include_directories(${PostgreSQL_INCLUDE_DIRS})
link_directories(${PostgreSQL_LIBRARY_DIRS})
find_program(PYOSMIUM pyosmium-get-changes)
if (NOT EXISTS "${PYOSMIUM}")
set(PYOSMIUM_PATH "")
message(WARNING "pyosmium-get-changes not found (required for updates)")
else()
set(PYOSMIUM_PATH "${PYOSMIUM}")
message(STATUS "Using pyosmium-get-changes at ${PYOSMIUM_PATH}")
endif()
find_program(PG_CONFIG pg_config)
execute_process(COMMAND ${PG_CONFIG} --pgxs
OUTPUT_VARIABLE PGXS
OUTPUT_STRIP_TRAILING_WHITESPACE)
if (NOT EXISTS "${PGXS}")
message(FATAL_ERROR "Postgresql server package not found.")
endif()
find_package(ZLIB REQUIRED)
find_package(BZip2 REQUIRED)
find_package(LibXml2 REQUIRED)
include_directories(${LIBXML2_INCLUDE_DIR})
# Setting PHP binary variable as to command line (prevailing) or auto detect
if (NOT PHP_BIN)
find_program (PHP_BIN php)
endif()
# sanity check if PHP binary exists
if (NOT EXISTS ${PHP_BIN})
message(FATAL_ERROR "PHP binary not found. Install php or provide location with -DPHP_BIN=/path/php ")
endif()
message (STATUS "Using PHP binary " ${PHP_BIN})
#-----------------------------------------------------------------------------
#
# Setup settings and paths
#
#-----------------------------------------------------------------------------
set(CUSTOMFILES
settings/phrase_settings.php
website/deletable.php
website/details.php
website/hierarchy.php
website/lookup.php
website/polygons.php
website/reverse.php
website/search.php
website/status.php
utils/blocks.php
utils/country_languages.php
utils/imports.php
utils/importWikipedia.php
utils/export.php
utils/query.php
utils/server_compare.php
utils/setup.php
utils/specialphrases.php
utils/update.php
utils/warm.php
)
foreach (cfile ${CUSTOMFILES})
configure_file(${PROJECT_SOURCE_DIR}/${cfile} ${PROJECT_BINARY_DIR}/${cfile})
endforeach()
configure_file(${PROJECT_SOURCE_DIR}/settings/defaults.php ${PROJECT_BINARY_DIR}/settings/settings.php)
set(WEBPATHS css images js)
foreach (wp ${WEBPATHS})
execute_process(
COMMAND ln -sf ${PROJECT_SOURCE_DIR}/website/${wp} ${PROJECT_BINARY_DIR}/website/
)
endforeach()
#-----------------------------------------------------------------------------
#
# Tests
#
#-----------------------------------------------------------------------------
include(CTest)
set(TEST_BDD db osm2pgsql api)
foreach (test ${TEST_BDD})
add_test(NAME bdd_${test}
COMMAND lettuce features/${test}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests)
set_tests_properties(bdd_${test}
PROPERTIES ENVIRONMENT "NOMINATIM_DIR=${PROJECT_BINARY_DIR}")
endforeach()
add_test(NAME php
COMMAND phpunit ./
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests-php)
#-----------------------------------------------------------------------------
add_subdirectory(module)
add_subdirectory(nominatim)
add_subdirectory(docs)
#-----------------------------------------------------------------------------

102
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,102 @@
# Nominatim contribution guidelines
## Reporting Bugs
Bugs can be reported at https://github.com/openstreetmap/Nominatim/issues.
Please always open a separate issue for each problem. In particular, do
not add your bugs to closed issues. They may looks similar to you but
often are completely different from the maintainer's point of view.
### When Reporting Bad Search Results...
Please make sure to add the following information:
* the URL of the query that produces the bad result
* the result you are getting
* the expected result, preferably a link to the OSM object you want to find,
otherwise an address that is as precise as possible
To get the link to the OSM object, you can try the following:
* go to https://openstreetmap.org
* zoom to the area of the map where you expect the result and
zoom in as much as possible
* click on the question mark on the right side of the map,
then with the queston cursor on the map where your object is located
* find the object of interest in the list that appears on the left side
* click on the object and report the URL back that the browser shows
### When Reporting Problems with your Installation...
Please add the following information to your issue:
* hardware configuration: RAM size, CPUs, kind and size of disks
* Operating system (also mention if you are running on a cloud service)
* Postgres and Postgis version
* list of settings you changed in your Postgres configuration
* Nominatim version (release version or,
if you run from the git repo, the output of `git rev-parse HEAD`)
* (if applicable) exact command line of the command that was causing the issue
## Workflow for Pull Requests
We love to get pull requests from you. We operate the "Fork & Pull" model
explained at
https://help.github.com/articles/using-pull-requests
You should fork the project into your own repo, create a topic branch
there and then make one or more pull requests back to the openstreetmap repository.
Your pull requests will then be reviewed and discussed. Please be aware
that you are responsible for your pull requests. You should be prepared
to get change requests because as the maintainers we have to make sure
that your contribution fits well with the rest of the code. Please make
sure that you have time to react to these comments and amend the code or
engage in a conversion. Do not expect that others will pick up your code,
it will almost never happen.
Please open a separate pull request for each issue you want to address.
Don't mix multiple changes. In particular, don't mix style cleanups with
feature pull requests. If you plan to make larger changes, please open
an issue first or comment on the appropriate issue already existing so
that duplicate work can be avoided.
## Coding style
Nominatim historically hasn't followed a particular coding style but we
are in process of consolidating the style. The following rules apply:
* Python code uses the official Python style
* indention
* SQL use 2 spaces
* all other file types use 4 spaces
* [BSD style](https://en.wikipedia.org/wiki/Indent_style#Allman_style) for braces
* spaces
* spaces before and after equal signs and operators
* no trailing spaces
* no spaces after opening and before closing bracket
* leave out space between a function name and bracket
but add one between control statement(if, while, etc.) and bracket
* for PHP variables use CamelCase with a prefixing letter indicating the type
(i - integer, f - float, a - array, s - string, o - object)
The coding style is enforced with PHPCS and can be tested with:
```
phpcs --report-width=120 --colors .
```
## Testing
Before submitting a pull request make sure that the following tests pass:
```
cd test/bdd
behave -DBUILDDIR=<builddir> db osm2pgsql
```
```
cd test/php
phpunit ./
```

14
COPYING
View File

@@ -1,12 +1,12 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
@@ -56,7 +56,7 @@ patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
@@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
@@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it

View File

@@ -1,3 +1,88 @@
3.2.1
* security fix: fix possible SQL injection via details API
3.2.0
* complete rewrite of reverse search algorithm
* add new geojson and geocodejson output formats
* add simple export script to exprot addresses to CSV
* remove is_in terms from address computation
* remove unused search_name_country tables
* various smaller fixes to query parsing
* convert Tokens and token types to class types
* correctly handle update when boundary object type is changed
* improve debug output for /search endpoint
* update to latest osm2pgsql and leaflet.js
* overhaul of /details endpoint:
* new class parameter when using osmtype/osmid parameters
* permalink to instance-independent osmtype/osmid parameter format
* new json output format
* update CentOS vagrant machine to use SELinux
* add vagrant scripts for Ubuntu 18.04
* fix build process for BSD
* enable running the database on a different host than the setup scripts
* allow to configure use of custom PHP binaries (PHP_BIN)
* extensive coding style improvements to PHP code
* more PHP unit tests for new classes
* increase coverage for API tests
* add documentation for API
3.1.0
* rework postcode handling and introduce location_postcode table
* make setup less verbose and print a summary in the end
* setup: error out when web site user does not exist
* add more API tests to complete code coverage
* reinstate key-value amenity search (special term [key=value])
* fix detection of coordinates in query
* various smaller tweaks to ranking of search interpretations
* complete overhaul of PHP frontend code using OOP
* add address rank to details page
* update Tiger scripts for 2017 data and clean up unused code
* various bug fixes and improvements to UI
* improve reverse geocoding performance close to coasts
* more PHP style cleanup (quoting)
* allow unnamed road in reverse geocoding to avoid too far off results
* add function to recalculate counts for full-word search term
* add function to check if new updates are available
* update documentation and switch to mkdocs for generating HTML
3.0.1
* fix bug in geometry building algorithm in osm2pgsql
* fix typos in build instructions
3.0.0
* move to cmake build system
* various fixes to HTML output
* reverse endpoint now can return geometries
* add support for PHP7
* move to on-the-fly computation of interpolations
* improve handling of linked places (updating)
* improve test framework:
* replace lettuce with behave
* use smaller database for API tests
* drop support for postgres < 9.1, postgis < 2.0 and PHP < 5.4
* make external data use optional (useful for imports without US)
* detect postgres and postgis versions automatically
* clean up query logging and remove unused tables
* move installation documentation into this repo
* add self-documenting vagrant scripts
* remove --create-website, recommend to use website directory in build
* add accessor functions for URL parameters and improve erro checking
* remove IP blocking and rate-limiting code
* enable CI via travis
* reformatting for more consistent coding style
* make country search term creation part of setup
* update country names and country grid
* handle roads that cross boundaries better
* keep full information on address tags
* update to refactored osm2pgsql which use libosmium based types
* switch from osmosis to pyosmium for updates
* be more strict when matching against special search terms
* handle postcode entries with mutliple values correctly
2.5
* reverse geocoding includes looking up housenumbers from Tiger data

View File

@@ -1,27 +0,0 @@
ACLOCAL_AMFLAGS = -I osm2pgsql/m4
AUTOMAKE_OPTIONS = -Wno-portability
SUBDIRS = osm2pgsql module nominatim
NOMINATIM_SERVER ?= $(shell echo a | php -F lib/init.php -E 'echo CONST_Website_BaseURL."\n";')
NOMINATIM_DATABASE ?= $(shell echo a | php -F lib/init.php -E 'echo DB::parseDSN(CONST_Database_DSN)["database"];')
install:
@echo Nominatim needs to be executed directly from this directory. No install necessary.
test:
cd tests; NOMINATIM_SERVER=${NOMINATIM_SERVER} lettuce -t -Fail -t -poldi-only
test-fast:
cd tests; NOMINATIM_SERVER=${NOMINATIM_SERVER} NOMINATIM_REUSE_TEMPLATE=1 lettuce -t -Fail -t -poldi-only
test-db:
cd tests; NOMINATIM_SERVER=${NOMINATIM_SERVER} lettuce -t -Fail -t -poldi-only features/db
test-db-fast:
cd tests; NOMINATIM_SERVER=${NOMINATIM_SERVER} NOMINATIM_REUSE_TEMPLATE=1 lettuce -t -Fail -t -poldi-only features/db
test-api:
cd tests; NOMINATIM_SERVER=${NOMINATIM_SERVER} lettuce -t -Fail -t -poldi-only features/api
.PHONY: test test-fast test-db test-db-fast test-api

0
NEWS
View File

59
README
View File

@@ -1,59 +0,0 @@
Nominatim
=========
Nominatim (from the Latin, 'by name') is a tool to search OpenStreetMap data
by name and address (geocoding) and to generate synthetic addresses of
OSM points (reverse geocoding). An instance with up-to-date data can be found
at http://nominatim.openstreetmap.org. Nominatim is also used as one of the
sources for the Search box on the OpenStreetMap home page and powers the search
on the MapQuest Open Initiative websites.
Documentation
=============
More information about Nominatim, including usage and installation instructions,
can be found in the OSM wiki at:
http://wiki.openstreetmap.org/wiki/Nominatim
Installation
============
The following instructions is a quick guide to installation. A more detailed guide
how to set up your own instance of Nominatim can be found in the wiki:
http://wiki.openstreetmap.org/wiki/Nominatim/Installation
Note that this repository contains a submodule called osm2pgsql. Make sure it
is cloned as well by running `git submodule update --init`.
Installation steps:
0. If checking out from git run:
./autogen.sh
1. Compile Nominatim:
./configure
make
2. Get OSM data and import:
./utils/setup.php --osm-file <your planet file> --all
3. Point your webserver to the ./website directory.
License
=======
The source code is available under a GPLv2 license.
Contact and Bugreports
======================
For questions you can join the geocoding mailinglist, see
http://lists.openstreetmap.org/listinfo/geocoding
Bugs may be reported on the github project site:
https://github.com/twain47/Nominatim

57
README.md Normal file
View File

@@ -0,0 +1,57 @@
[![Build Status](https://travis-ci.org/openstreetmap/Nominatim.svg?branch=master)](https://travis-ci.org/openstreetmap/Nominatim)
Nominatim
=========
Nominatim (from the Latin, 'by name') is a tool to search OpenStreetMap data
by name and address (geocoding) and to generate synthetic addresses of
OSM points (reverse geocoding). An instance with up-to-date data can be found
at https://nominatim.openstreetmap.org. Nominatim is also used as one of the
sources for the Search box on the OpenStreetMap home page.
Documentation
=============
The documentation of the latest development version is in the
`docs/` subdirectory. A HTML version can be found at
https://nominatim.org/release-docs/develop/ .
Installation
============
The latest stable release can be downloaded from https://nominatim.org.
There you can also find [installation instructions for the release](https://nominatim.org/release-docs/latest/admin/Installation).
Detailed installation instructions for the development version can be
found at [nominatim.org](https://nominatim.org/release-docs/develop/admin/Installation)
as well.
A quick summary of the necessary steps:
1. Compile Nominatim:
mkdir build
cd build
cmake ..
make
2. Get OSM data and import:
./build/utils/setup.php --osm-file <your planet file> --all
3. Point your webserver to the ./build/website directory.
License
=======
The source code is available under a GPLv2 license.
Contact and Bug reports
======================
For questions you can join the geocoding mailinglist, see
https://lists.openstreetmap.org/listinfo/geocoding
Bugs may be reported on the github project site:
https://github.com/openstreetmap/Nominatim

View File

@@ -1,11 +1,11 @@
# Install Nominatim in a virtual machine for development and testing
This document describes how you can install Nominatim inside a Ubuntu 14
This document describes how you can install Nominatim inside a Ubuntu 16
virtual machine on your desktop/laptop (host machine). The goal is to give
you a development environment to easily edit code and run the test suite
without affecting the rest of your system.
The installation can run largely unsupervised. You should expect 1-2h from
The installation can run largely unsupervised. You should expect 1h from
start to finish depending on how fast your computer and download speed
is.
@@ -17,9 +17,9 @@ is.
3. Nominatim
git clone --recursive https://github.com/twain47/Nominatim.git
git clone --recursive https://github.com/openstreetmap/Nominatim.git
If you haven't used `--recursive`, then you can load the submodules using
If you forgot `--recursive`, it you can later load the submodules using
git submodule init
git submodule update
@@ -37,24 +37,19 @@ is.
vagrant ssh ubuntu
3. Import a small country (Monaco)
You need to give the virtual machine more memory (2GB) for an import,
see `Vagrantfile`. Otherwise 1GB is enough.
See the FAQ how to skip this step and point Nominatim to an existing database.
```
# inside the virtual machine:
cd Nominatim
wget --no-verbose --output-document=data/monaco.osm.pbf http://download.geofabrik.de/europe/monaco-latest.osm.pbf
./utils/setup.php --osm-file data/monaco.osm.pbf --osm2pgsql-cache 1000 --all 2>&1 | tee monaco.$$.log
./utils/specialphrases.php --countries > data/specialphrases_countries.sql
psql -d nominatim -f data/specialphrases_countries.sql
```
```
# inside the virtual machine:
cd build
wget --no-verbose --output-document=/tmp/monaco.osm.pbf http://download.geofabrik.de/europe/monaco-latest.osm.pbf
./utils/setup.php --osm-file /tmp/monaco.osm.pbf --osm2pgsql-cache 1000 --all 2>&1 | tee monaco.$$.log
```
To repeat an import you'd need to delete the database first
To repeat an import you'd need to delete the database first
dropdb -if-exists nominatim
dropdb --if-exists nominatim
@@ -66,45 +61,62 @@ see Nominatim in action on [locahost:8089](http://localhost:8089/nominatim/).
You edit code on your host machine in any editor you like. There is no need to
restart any software: just refresh your browser window.
Note that the webserver uses files from the /build directory. If you change
files in Nominatim/website or Nominatim/utils for example you first need to
copy them into the /build directory by running the `cmake` step from the
installation.
PHP errors are written to `/var/log/apache2/error.log`.
With `echo` and `var_dump()` you write into the output (HTML/XML/JSON) when
you either add `&debug=1` to the URL (preferred) or set
`@define('CONST_Debug', true);` in `settings/local.php`.
In the Python BDD test you can use `logger.info()` for temporary debug
statements.
## Running unit tests
cd ~/Nominatim/tests/php
phpunit ./
## Running PHP code style tests
cd ~/Nominatim
phpcs --colors .
## Running functional tests
Tests in `/features/db` and `/features/osm2pgsql` have to pass 100%. Other
Tests in `test/bdd/db` and `test/bdd/osm2pgsql` have to pass 100%. Other
tests might require full planet-wide data. Sadly even if you have your own
planet-wide data there will be enough differences to the openstreetmap.org
installation to cause false positives in the other tests (see FAQ).
To run the full test suite
cd ~/Nominatim/tests
NOMINATIM_SERVER=http://localhost:8089/nominatim lettuce features
cd ~/Nominatim/test/bdd
behave -DBUILDDIR=/home/vagrant/build/ db osm2pgsql
To run a single file
NOMINATIM_SERVER=http://localhost:8089/nominatim lettuce features/api/reverse.feature
behave -DBUILDDIR=/home/vagrant/build/ api/lookup/simple.feature
Or a single test by line number
behave -DBUILDDIR=/home/vagrant/build/ api/lookup/simple.feature:34
To run specific tests you can add tags just before the `Scenario line`, e.g.
To run specific groups of tests you can add tags just before the `Scenario line`, e.g.
@bug-34
Scenario: address lookup for non-existing or invalid node, way, relation
and then
NOMINATIM_SERVER=http://localhost:8089/nominatim lettuce -t bug-34
## Running unit tests
cd ~/Nominatim/tests-php
phpunit ./
behave -DBUILDDIR=/home/vagrant/build/ --tags @bug-34
@@ -129,19 +141,20 @@ No. Long running Nominatim installations will differ once new import features (o
bug fixes) get added since those usually only get applied to new/changed data.
Also this document skips the optional Wikipedia data import which affects ranking
of search results. See [Nominatim installation](http://wiki.openstreetmap.org/wiki/Nominatim/Installation) for details.
of search results. See [Nominatim installation](http://nominatim.org/release-docs/latest/Installation) for details.
##### Why Ubuntu and CentOS, can I test CentOS/CoreOS/FreeBSD?
##### Why Ubuntu? Can I test CentOS/Fedora/CoreOS/FreeBSD?
There is a Vagrant script for CentOS available. Simply start your box
with `vagrant up centos` and then log in with `vagrant ssh centos`.
In general Nominatim will also run in the other environments. The installation steps
There is a Vagrant script for CentOS available, but the Nominatim directory
isn't symlinked/mounted to the host which makes development trickier. We used
it mainly for debugging installation with SELinux.
In general Nominatim will run in the other environments. The installation steps
are slightly different, e.g. the name of the package manager, Apache2 package
name, location of files. We chose Ubuntu because that is closest to the
nominatim.openstreetmap.org production environment.
You can configure/download other Vagrant boxes from [vagrantbox.es](http://www.vagrantbox.es/).
You can configure/download other Vagrant boxes from [https://app.vagrantup.com/boxes/search](https://app.vagrantup.com/boxes/search).
##### How can I connect to an existing database?
@@ -149,7 +162,7 @@ Let's say you have a Postgres database named `nominatim_it` on server `your-serv
pgsql://postgres@your-server.com:5432/nominatim_it
No data import necessary, no restarting necessary.
No data import necessary or restarting necessary.
If the Postgres installation is behind a firewall, you can try
@@ -158,14 +171,15 @@ If the Postgres installation is behind a firewall, you can try
inside the virtual machine. It will map the port to `localhost:9999` and then
you edit `settings/local.php` with
pgsql://postgres@localhost:9999/nominatim_it
@define('CONST_Database_DSN', 'pgsql://postgres@localhost:9999/nominatim_it');
To access postgres directly remember to specify the hostname, e.g. `psql --host localhost --port 9999 nominatim_it`
##### My computer is slow and the import takes too long. Can I start the virtual machine "in the cloud"?
Yes. It's possible to start the virtual machine on [Amazon AWS (plugin)](https://github.com/mitchellh/vagrant-aws) or [DigitalOcean (plugin)](https://github.com/smdahlen/vagrant-digitalocean).
Yes. It's possible to start the virtual machine on [Amazon AWS (plugin)](https://github.com/mitchellh/vagrant-aws)
or [DigitalOcean (plugin)](https://github.com/smdahlen/vagrant-digitalocean).

72
Vagrantfile vendored
View File

@@ -3,45 +3,59 @@
Vagrant.configure("2") do |config|
# Apache webserver
config.vm.network "forwarded_port", guest: 8089, host: 8089
config.vm.network "forwarded_port", guest: 80, host: 8089
# If true, then any SSH connections made will enable agent forwarding.
config.ssh.forward_agent = true
config.vm.synced_folder ".", "/home/vagrant/Nominatim"
config.vm.define "ubuntu" do |sub|
sub.vm.box = "ubuntu/trusty64"
sub.vm.provision :shell, :path => "vagrant/ubuntu-trusty-provision.sh"
checkout = "yes"
if ENV['CHECKOUT'] != 'y' then
config.vm.synced_folder ".", "/home/vagrant/Nominatim"
checkout = "no"
end
config.vm.define "ubuntu", primary: true do |sub|
sub.vm.box = "bento/ubuntu-18.04"
sub.vm.provision :shell do |s|
s.path = "vagrant/Install-on-Ubuntu-18.sh"
s.privileged = false
s.args = [checkout]
end
end
config.vm.define "ubuntu16" do |sub|
sub.vm.box = "bento/ubuntu-16.04"
sub.vm.provision :shell do |s|
s.path = "vagrant/Install-on-Ubuntu-16.sh"
s.privileged = false
s.args = [checkout]
end
end
config.vm.define "travis" do |sub|
sub.vm.box = "bento/ubuntu-14.04"
sub.vm.provision :shell do |s|
s.path = "vagrant/install-on-travis-ci.sh"
s.privileged = false
s.args = [checkout]
end
end
config.vm.define "centos" do |sub|
sub.vm.box = "bento/centos-7.2"
sub.vm.provision :shell, :path => "vagrant/centos-7-provision.sh"
sub.vm.box = "centos/7"
sub.vm.provision :shell do |s|
s.path = "vagrant/Install-on-Centos-7.sh"
s.privileged = false
s.args = "yes"
end
sub.vm.synced_folder ".", "/home/vagrant/Nominatim", disabled: true
sub.vm.synced_folder ".", "/vagrant", disabled: true
end
# configure shared package cache if possible
#if Vagrant.has_plugin?("vagrant-cachier")
# config.cache.enable :apt
# config.cache.scope = :box
#end
config.vm.provider "virtualbox" do |vb|
vb.gui = false
vb.customize ["modifyvm", :id, "--memory", "2048"]
vb.memory = 2048
vb.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate//vagrant","0"]
end
# config.vm.provider :digital_ocean do |provider, override|
# override.ssh.private_key_path = '~/.ssh/id_rsa'
# override.vm.box = 'digital_ocean'
# override.vm.box_url = "https://github.com/smdahlen/vagrant-digitalocean/raw/master/box/digital_ocean.box"
# provider.token = ''
# # provider.token = 'YOUR TOKEN'
# provider.image = 'ubuntu-14-04-x64'
# provider.region = 'nyc2'
# provider.size = '512mb'
# end
end

View File

@@ -1,2 +0,0 @@
#!/bin/sh
autoreconf -vfi

View File

@@ -1,67 +0,0 @@
AC_INIT(Nominatim,2.5)
if git rev-parse HEAD 2>/dev/null >/dev/null; then
AC_SUBST([PACKAGE_VERSION], [$PACKAGE_VERSION-git-`git rev-parse --short HEAD`])
fi
dnl Required autoconf version
AC_PREREQ(2.61)
AM_INIT_AUTOMAKE([1.9.6 dist-bzip2 std-options check-news])
dnl Additional macro definitions are in here
m4_include([m4/ax_lib_postgresql_svr.m4])
AC_CONFIG_MACRO_DIR([osm2pgsql/m4])
dnl Generate configuration header file
AC_CONFIG_HEADER(nominatim/config.h)
dnl Find C compiler
AC_PROG_CC
dnl Find C++ compiler
AC_PROG_CXX
dnl pthread
AX_PTHREAD([], [AC_MSG_ERROR([pthread library required])])
dnl Check for Geos library
AX_LIB_GEOS
if test "x$GEOS_VERSION" = "x"
then
AC_MSG_ERROR([required library not found]);
fi
dnl Check for Proj library
AX_LIB_PROJ
if test "$HAVE_PROJ" = "no"
then
AC_MSG_ERROR([required library not found]);
fi
dnl Check for PostgresSQL client library
AX_LIB_POSTGRESQL(9.0)
if test "x$POSTGRESQL_VERSION" = "x"
then
AC_MSG_ERROR([postgresql client library not found])
fi
AX_LIB_POSTGRESQL_SVR(9.0)
if test ! -f "$POSTGRESQL_PGXS"
then
AC_MSG_ERROR([postgresql server development library not found])
fi
dnl Check for bzip2 library
AX_LIB_BZIP2
if test "$HAVE_BZIP2" = "no"
then
AC_MSG_ERROR([required library not found]);
fi
dnl Check for libxml2 library
AM_PATH_XML2
AC_CONFIG_SUBDIRS([osm2pgsql])
AC_OUTPUT(Makefile nominatim/Makefile module/Makefile)

View File

@@ -1,36 +0,0 @@
# This file includes a small subset of OpenLayers code, designed to be
# integrated into another application. It includes only the Layer types
# neccesary to create tiled or untiled WMS, and does not include any Controls.
# This is the result of what was at the time called "Webmap.js" at the FOSS4G
# Web Mapping BOF.
[first]
[last]
[include]
OpenLayers/Map.js
OpenLayers/Kinetic.js
OpenLayers/Geometry/MultiLineString.js
OpenLayers/Geometry/MultiPolygon.js
OpenLayers/Format/WKT.js
OpenLayers/Layer/OSM.js
OpenLayers/Layer/Vector.js
OpenLayers/Layer/SphericalMercator.js
OpenLayers/Control/Attribution.js
OpenLayers/Control/KeyboardDefaults.js
OpenLayers/Control/Navigation.js
OpenLayers/Control/MousePosition.js
OpenLayers/Control/PanZoomBar.js
OpenLayers/Control/Permalink.js
OpenLayers/Control/TouchNavigation.js
OpenLayers/Style.js
OpenLayers/Protocol/HTTP.js
OpenLayers/Projection.js
OpenLayers/Renderer/SVG.js
OpenLayers/Renderer/VML.js
OpenLayers/Renderer/Canvas.js
[exclude]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

21
docs/CMakeLists.txt Normal file
View File

@@ -0,0 +1,21 @@
# Auto-generated vagrant install documentation
# build the actual documentation
configure_file(mkdocs.yml ../mkdocs.yml)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/appendix)
ADD_CUSTOM_TARGET(doc
COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/admin ${CMAKE_CURRENT_BINARY_DIR}/admin
COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/develop ${CMAKE_CURRENT_BINARY_DIR}/develop
COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/api ${CMAKE_CURRENT_BINARY_DIR}/api
COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/index.md ${CMAKE_CURRENT_BINARY_DIR}/index.md
COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/extra.css ${CMAKE_CURRENT_BINARY_DIR}/extra.css
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Centos-7.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Centos-7.md
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Ubuntu-16.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Ubuntu-16.md
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Ubuntu-18.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Ubuntu-18.md
COMMAND mkdocs build -d ${CMAKE_CURRENT_BINARY_DIR}/../site-html -f ${CMAKE_CURRENT_BINARY_DIR}/../mkdocs.yml
)

185
docs/admin/Faq.md Normal file
View File

@@ -0,0 +1,185 @@
# Troubleshooting Nominatim Installations
## Installation Issues
### Can a stopped/killed import process be resumed?
"I accidentally killed the import process after it has been running for many hours. Can it be resumed?"
It is possible if the import already got to the indexing stage.
Check the last line of output that was logged before the process
was killed. If it looks like this:
Done 844 in 13 @ 64.923080 per second - Rank 26 ETA (seconds): 7.886255
then you can resume with the following command:
```sh
./utils/setup.php --index --create-search-indices --create-country-names
```
If the reported rank is 26 or higher, you can also safely add `--index-noanalyse`.
### PHP "open_basedir restriction in effect" warnings
`PHP Warning: file_get_contents(): open_basedir restriction in effect.`
You need to adjust the [open_basedir](http://www.php.net/manual/en/ini.core.php#ini.open-basedir) setting
in your PHP configuration (`php.ini file`). By default this setting may look like this:
open_basedir = /srv/http/:/home/:/tmp/:/usr/share/pear/
Either add reported directories to the list or disable this setting temporarily by
dding ";" at the beginning of the line. Don't forget to enable this setting again
once you are done with the PHP command line operations.
### PHP timzeone warnings
The Apache log may contain lots of PHP warnings like this:
`PHP Warning: date_default_timezone_set() function.`
You should set the default time zone as instructed in the warning in
your `php.ini` file. Find the entry about timezone and set it to
something like this:
; Defines the default timezone used by the date functions
; http://php.net/date.timezone
date.timezone = 'America/Denver'
Or
```
echo "date.timezone = 'America/Denver'" > /etc/php.d/timezone.ini
```
### nominatim.so version mismatch
When running the import you may get a version mismatch:
`COPY_END for place failed: ERROR: incompatible library "/srv/Nominatim/nominatim/build/module/nominatim.so": version mismatch`
pg_config seems to use bad includes sometimes when multiple versions
of PostgreSQL are available in the system. Make sure you remove the
server development libraries (`postgresql-server-dev-9.5` on Ubuntu)
and recompile (`cmake .. && make`).
### I see the error: "function transliteration(text) does not exist"
Reinstall the nominatim functions with `setup.php --create--functions`
and check for any errors, e.g. a missing `nominatim.so` file.
### The website shows: "Could not get word tokens"
The server cannot access your database. Add `&debug=1` to your URL
to get the full error message.
### On CentOS the website shows "Could not connect to server"
`could not connect to server: No such file or directory`
On CentOS v7 the PostgreSQL server is started with `systemd`.
Check if `/usr/lib/systemd/system/httpd.service` contains a line `PrivateTmp=true`.
If so then Apache cannot see the `/tmp/.s.PGSQL.5432` file. It's a good security feature,
so use the [preferred solution](../appendix/Install-on-Centos-7/#adding-selinux-security-settings).
However, you can solve this the quick and dirty way by commenting out that line and then run
sudo systemctl daemon-reload
sudo systemctl restart httpd
### Website reports "DB Error: insufficient permissions"
The user the webserver, e.g. Apache, runs under needs to have access to the Nominatim database. You can find the user like [this](https://serverfault.com/questions/125865/finding-out-what-user-apache-is-running-as), for default Ubuntu operating system for example it's `www-data`.
1. Repeat the `createuser` step of the installation instructions.
2. Give the user permission to existing tables
```
GRANT usage ON SCHEMA public TO "www-data";
GRANT SELECT ON ALL TABLES IN SCHEMA public TO "www-data";
```
### Website reports "Could not load library "nominatim.so"
Example error message
```
SELECT make_standard_name('3039 E MEADOWLARK LN') [nativecode=ERROR: could not
load library "/srv/nominatim/Nominatim-3.1.0/build/module/nominatim.so":
/srv/nominatim/Nominatim-3.1.0/build/module/nominatim.so: cannot open shared
object file: Permission denied
CONTEXT: PL/pgSQL function make_standard_name(text) line 5 at assignment]
```
The Postgresql database, i.e. user postgres, needs to have access to that file.
The permission need to be read & executable by everybody, e.g.
```
-rwxr-xr-x 1 nominatim nominatim 297984 build/module/nominatim.so
```
Try `chmod a+r nominatim.so; chmod a+x nominatim.so`.
When running SELinux, make sure that the
[context is set up correctly](../appendix/Install-on-Centos-7/#adding-selinux-security-settings).
### Setup.php fails with "DB Error: extension not found"
Make sure you have the Postgres extensions hstore and postgis installed.
See the installation instruction for a full list of required packages.
### Setup.php reports "Cannot redeclare getDB()"
`Cannot redeclare getDB() (previously declared in /your/path/Nominatim/lib/db.php:4)`
The message is a bit misleading as PHP needs to load the file `DB.php` and
instead re-loads Nominatim's `db.php`. To solve this make sure you
have the [Pear module 'DB'](http://pear.php.net/package/DB/) installed.
sudo pear install DB
### I forgot to delete the flatnodes file before starting an import.
That's fine. For each import the flatnodes file get overwritten.
See [https://help.openstreetmap.org/questions/52419/nominatim-flatnode-storage]()
for more information.
## Running your own instance
### Can I import multiple countries and keep them up to date?
You should use the extracts and updates from https://download.geofabrik.de.
For the initial import, download the countries you need and merge them.
See [OSM Help](https://help.openstreetmap.org/questions/48843/merging-two-or-more-geographical-areas-to-import-two-or-more-osm-files-in-nominatim)
for examples how to do that. Use the resulting single osm file when
running `setup.php`.
For updates you need to download the change files for each country
once per day and apply them **separately** using
./utils/update.php --import-diff <filename> --index
See [this issue](https://github.com/openstreetmap/Nominatim/issues/60#issuecomment-18679446)
for a script that runs the updates using osmosis.
### Can I import negative OSM ids into Nominatim?
See [this question of Stackoverflow](https://help.openstreetmap.org/questions/64662/nominatim-flatnode-with-negative-id).
### Missing XML or text declaration
The website might show: `XML Parsing Error: XML or text declaration not at start of entity Location.`
Make sure there are no spaces at the beginning of your `settings/local.php` file.

View File

@@ -0,0 +1,212 @@
# Importing and Updating the Database
The following instructions explain how to create a Nominatim database
from an OSM planet file and how to keep the database up to date. It
is assumed that you have already successfully installed the Nominatim
software itself, if not return to the [installation page](Installation.md).
## Configuration setup in settings/local.php
The Nominatim server can be customized via the file `settings/local.php`
in the build directory. Note that this is a PHP file, so it must always
start like this:
<?php
without any leading spaces.
There are lots of configuration settings you can tweak. Have a look
at `settings/default.php` for a full list. Most should have a sensible default.
#### Flatnode files
If you plan to import a large dataset (e.g. Europe, North America, planet),
you should also enable flatnode storage of node locations. With this
setting enabled, node coordinates are stored in a simple file instead
of the database. This will save you import time and disk storage.
Add to your `settings/local.php`:
@define('CONST_Osm2pgsql_Flatnode_File', '/path/to/flatnode.file');
Replace the second part with a suitable path on your system and make sure
the directory exists. There should be at least 40GB of free space.
## Downloading additional data
### Wikipedia rankings
Wikipedia can be used as an optional auxiliary data source to help indicate
the importance of osm features. Nominatim will work without this information
but it will improve the quality of the results if this is installed.
This data is available as a binary download:
cd $NOMINATIM_SOURCE_DIR/data
wget https://www.nominatim.org/data/wikipedia_article.sql.bin
wget https://www.nominatim.org/data/wikipedia_redirect.sql.bin
Combined the 2 files are around 1.5GB and add around 30GB to the install
size of nominatim. They also increase the install time by an hour or so.
*NOTE:* you'll need to download the Wikipedia rankings before performing
the initial import of the data if you want the rankings applied to the
loaded data.
### UK postcodes
Nominatim can use postcodes from an external source to improve searches that involve a UK postcode. This data can be optionally downloaded:
cd $NOMINATIM_SOURCE_DIR/data
wget https://www.nominatim.org/data/gb_postcode_data.sql.gz
## Initial import of the data
**Important:** first try the import with a small excerpt, for example from
[Geofabrik](https://download.geofabrik.de).
Download the data to import and load the data with the following command:
```sh
./utils/setup.php --osm-file <data file> --all [--osm2pgsql-cache 28000] 2>&1 | tee setup.log
```
The `--osm2pgsql-cache` parameter is optional but strongly recommended for
planet imports. It sets the node cache size for the osm2pgsql import part
(see `-C` parameter in osm2pgsql help). As a rule of thumb, this should be
about the same size as the file you are importing but never more than
2/3 of RAM available. If your machine starts swapping reduce the size.
Computing word frequency for search terms can improve the performance of
forward geocoding in particular under high load as it helps Postgres' query
planner to make the right decisions. To recompute word counts run:
```sh
./utils/update.php --recompute-word-counts
```
This will take a couple of hours for a full planet installation. You can
also defer that step to a later point in time when you realise that
performance becomes an issue. Just make sure that updates are stopped before
running this function.
If you want to be able to search for places by their type through
[special key phrases](https://wiki.openstreetmap.org/wiki/Nominatim/Special_Phrases)
you also need to enable these key phrases like this:
./utils/specialphrases.php --wiki-import > specialphrases.sql
psql -d nominatim -f specialphrases.sql
Note that this command downloads the phrases from the wiki link above.
## Installing Tiger housenumber data for the US
Nominatim is able to use the official TIGER address set to complement the
OSM house number data in the US. You can add TIGER data to your own Nominatim
instance by following these steps:
1. Install the GDAL library and python bindings and the unzip tool
* Ubuntu: `sudo apt-get install python-gdal unzip`
* CentOS: `sudo yum install gdal-python unzip`
2. Get preprocessed TIGER 2017 data and unpack it into the
data directory in your Nominatim sources:
cd Nominatim/data
wget https://nominatim.org/data/tiger2017-nominatim-preprocessed.tar.gz
tar xf tiger2017-nominatim-preprocessed.tar.gz
3. Import the data into your Nominatim database:
./utils/setup.php --import-tiger-data
4. Enable use of the Tiger data in your `settings/local.php` by adding:
@define('CONST_Use_US_Tiger_Data', true);
5. Apply the new settings:
```sh
./utils/setup.php --create-functions --enable-diff-updates --create-partition-functions
```
The entire US adds about 10GB to your database.
You can also process the data from the original TIGER data to create the
SQL files, Nominatim needs for the import:
1. Get the TIGER 2017 data. You will need the EDGES files
(3,234 zip files, 11GB total).
wget -r ftp://ftp2.census.gov/geo/tiger/TIGER2017/EDGES/
2. Convert the data into SQL statements:
./utils/imports.php --parse-tiger <tiger edge data directory>
Be warned that this can take quite a long time. After this process is finished,
the same preprocessed files as above are available in `data/tiger`.
## Updates
There are many different possibilities to update your Nominatim database.
The following section describes how to keep it up-to-date with Pyosmium.
For a list of other methods see the output of `./utils/update.php --help`.
#### Installing the newest version of Pyosmium
It is recommended to install Pyosmium via pip. Run (as the same user who
will later run the updates):
```sh
pip install --user osmium
```
Nominatim needs a tool called `pyosmium-get-updates`, which comes with
Pyosmium. You need to tell Nominatim where to find it. Add the
following line to your `settings/local.php`:
@define('CONST_Pyosmium_Binary', '/home/user/.local/bin/pyosmium-get-changes');
The path above is fine if you used the `--user` parameter with pip.
Replace `user` with your user name.
#### Setting up the update process
Next the update needs to be initialised. By default Nominatim is configured
to update using the global minutely diffs.
If you want a different update source you will need to add some settings
to `settings/local.php`. For example, to use the daily country extracts
diffs for Ireland from geofabrik add the following:
// base URL of the replication service
@define('CONST_Replication_Url', 'https://download.geofabrik.de/europe/ireland-and-northern-ireland-updates');
// How often upstream publishes diffs
@define('CONST_Replication_Update_Interval', '86400');
// How long to sleep if no update found yet
@define('CONST_Replication_Recheck_Interval', '900');
To set up the update process now run the following command:
./utils/update.php --init-updates
It outputs the date where updates will start. Recheck that this date is
what you expect.
The --init-updates command needs to be rerun whenever the replication service
is changed.
#### Updating Nominatim
The following command will keep your database constantly up to date:
./utils/update.php --import-osmosis-all
(Note that even though the old name "import-osmosis-all" has been kept for compatibility reasons, Osmosis is not required to run this - it uses pyosmium behind the scenes.)
If you have imported multiple country extracts and want to keep them
up-to-date, have a look at the script in
[issue #60](https://github.com/openstreetmap/Nominatim/issues/60).

158
docs/admin/Installation.md Normal file
View File

@@ -0,0 +1,158 @@
# Basic Installation
This page contains generic installation instructions for Nominatim and its
prerequisites. There are also step-by-step instructions available for
the following operating systems:
* [Ubuntu 18.04](../appendix/Install-on-Ubuntu-18.md)
* [Ubuntu 16.04](../appendix/Install-on-Ubuntu-16.md)
* [CentOS 7.2](../appendix/Install-on-Centos-7.md)
These OS-specific instructions can also be found in executable form
in the `vagrant/` directory.
Users have created instructions for other frameworks. We haven't tested those
and can't offer support.
* [Docker](https://github.com/mediagis/nominatim-docker)
* [Docker on Kubernetes](https://github.com/peter-evans/nominatim-k8s)
* [Ansible](https://github.com/synthesio/infra-ansible-nominatim)
## Prerequisites
### Software
For compiling:
* [cmake](https://cmake.org/)
* [libxml2](http://xmlsoft.org/)
* a recent C++ compiler
Nominatim comes with its own version of osm2pgsql. See the
osm2pgsql README for additional dependencies required for compiling osm2pgsql.
For running tests:
* [behave](http://pythonhosted.org/behave/)
* [Psycopg2](http://initd.org/psycopg)
* [nose](https://nose.readthedocs.io)
* [phpunit](https://phpunit.de)
For running Nominatim:
* [PostgreSQL](http://www.postgresql.org) (9.1 or later)
* [PostGIS](http://postgis.refractions.net) (2.0 or later)
* [PHP](http://php.net) (5.4 or later)
* PHP-pgsql
* PHP-intl (bundled with PHP)
* [PEAR::DB](http://pear.php.net/package/DB)
* a webserver (apache or nginx are recommended)
For running continuous updates:
* [pyosmium](http://osmcode.org/pyosmium/)
### Hardware
A minimum of 2GB of RAM is required or installation will fail. For a full
planet import 32GB of RAM or more strongly are recommended.
For a full planet install you will need at least 700GB of hard disk space
(take into account that the OSM database is growing fast). SSD disks
will help considerably to speed up import and queries.
On a 6-core machine with 32GB RAM and SSDs the import of a full planet takes
a bit more than 2 days. Without SSDs 7-8 days are more realistic.
## Setup of the server
### PostgreSQL tuning
You might want to tune your PostgreSQL installation so that the later steps
make best use of your hardware. You should tune the following parameters in
your `postgresql.conf` file.
shared_buffers (2GB)
maintenance_work_mem (10GB)
work_mem (50MB)
effective_cache_size (24GB)
synchronous_commit = off
checkpoint_segments = 100 # only for postgresql <= 9.4
checkpoint_timeout = 10min
checkpoint_completion_target = 0.9
The numbers in brackets behind some parameters seem to work fine for
32GB RAM machine. Adjust to your setup.
For the initial import, you should also set:
fsync = off
full_page_writes = off
Don't forget to reenable them after the initial import or you risk database
corruption. Autovacuum must not be switched off because it ensures that the
tables are frequently analysed.
### Webserver setup
The `website/` directory in the build directory contains the configured
website. Include the directory into your webbrowser to serve php files
from there.
#### Configure for use with Apache
Make sure your Apache configuration contains the required permissions for the
directory and create an alias:
<Directory "/srv/nominatim/build/website">
Options FollowSymLinks MultiViews
AddType text/html .php
DirectoryIndex search.php
Require all granted
</Directory>
Alias /nominatim /srv/nominatim/build/website
`/srv/nominatim/build` should be replaced with the location of your
build directory.
After making changes in the apache config you need to restart apache.
The website should now be available on http://localhost/nominatim.
#### Configure for use with Nginx
Use php-fpm as a deamon for serving PHP cgi. Install php-fpm together with nginx.
By default php listens on a network socket. If you want it to listen to a
Unix socket instead, change the pool configuration (`pool.d/www.conf`) as
follows:
; Comment out the tcp listener and add the unix socket
;listen = 127.0.0.1:9000
listen = /var/run/php5-fpm.sock
; Ensure that the daemon runs as the correct user
listen.owner = www-data
listen.group = www-data
listen.mode = 0666
Tell nginx that php files are special and to fastcgi_pass to the php-fpm
unix socket by adding the location definition to the default configuration.
root /srv/nominatim/build/website;
index search.php index.html;
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index search.php;
include fastcgi.conf;
}
Restart the nginx and php5-fpm services and the website should now be available
at `http://localhost/`.
Now continue with [importing the database](Import-and-Update.md).

115
docs/admin/Migration.md Normal file
View File

@@ -0,0 +1,115 @@
# Database Migrations
This page describes database migrations necessary to update existing databases
to newer versions of Nominatim.
SQL statements should be executed from the postgres commandline. Execute
`psql nominiatim` to enter command line mode.
## 3.1.0 -> 3.2.0
### New reverse algorithm
The reverse algorithm has changed and requires new indexes. Run the following
SQL statements to create the indexes:
```
CREATE INDEX idx_placex_geometry_reverse_lookupPoint
ON placex USING gist (geometry) {ts:search-index}
WHERE (name is not null or housenumber is not null or rank_address between 26 and 27)
AND class not in ('railway','tunnel','bridge','man_made')
AND rank_address >= 26 AND indexed_status = 0 AND linked_place_id is null;
CREATE INDEX idx_placex_geometry_reverse_lookupPolygon
ON placex USING gist (geometry) {ts:search-index}
WHERE St_GeometryType(geometry) in ('ST_Polygon', 'ST_MultiPolygon')
AND rank_address between 4 and 25 AND type != 'postcode'
AND name is not null AND indexed_status = 0 AND linked_place_id is null;
CREATE INDEX idx_placex_geometry_reverse_placeNode
ON placex USING gist (geometry) {ts:search-index}
WHERE osm_type = 'N' AND rank_search between 5 and 25
AND class = 'place' AND type != 'postcode'
AND name is not null AND indexed_status = 0 AND linked_place_id is null;
```
You also need to grant the website user access to the `country_osm_grid` table:
```
GRANT SELECT ON table country_osm_grid to "www-user";
```
Replace the `www-user` with the user name of your website server if necessary.
Finally, you can drop the now unused indexes:
```
DROP INDEX idx_placex_reverse_geometry;
```
## 3.0.0 -> 3.1.0
### Postcode Table
A new separate table for artificially computed postcode centroids was introduced.
Migration to the new format is possible but **not recommended**.
Create postcode table and indexes, running the following SQL statements:
```sql
CREATE TABLE location_postcode
(place_id BIGINT, parent_place_id BIGINT, rank_search SMALLINT,
rank_address SMALLINT, indexed_status SMALLINT, indexed_date TIMESTAMP,
country_code varchar(2), postcode TEXT,
geometry GEOMETRY(Geometry, 4326));
CREATE INDEX idx_postcode_geometry ON location_postcode USING GIST (geometry);
CREATE UNIQUE INDEX idx_postcode_id ON location_postcode USING BTREE (place_id);
CREATE INDEX idx_postcode_postcode ON location_postcode USING BTREE (postcode);
GRANT SELECT ON location_postcode TO "www-data";
drop type if exists nearfeaturecentr cascade;
create type nearfeaturecentr as (
place_id BIGINT,
keywords int[],
rank_address smallint,
rank_search smallint,
distance float,
isguess boolean,
postcode TEXT,
centroid GEOMETRY
);
```
Add postcode column to `location_area` tables with SQL statement:
```sql
ALTER TABLE location_area ADD COLUMN postcode TEXT;
```
Then reimport the functions:
```sh
./utils/setup.php --create-functions --enable-diff-updates --create-partition-functions
```
Create appropriate triggers with SQL:
```sql
CREATE TRIGGER location_postcode_before_update BEFORE UPDATE ON location_postcode
FOR EACH ROW EXECUTE PROCEDURE postcode_update();
```
Finally populate the postcode table (will take a while):
```sh
./utils/setup.php --calculate-postcodes --index --index-noanalyse
```
This will create a working database. You may also delete the old artificial
postcodes now. Note that this may be expensive and is not absolutely necessary.
The following SQL statement will remove them:
```sql
DELETE FROM place_addressline a USING placex p
WHERE a.address_place_id = p.place_id and p.osm_type = 'P';
ALTER TABLE placex DISABLE TRIGGER USER;
DELETE FROM placex WHERE osm_type = 'P';
ALTER TABLE placex ENABLE TRIGGER USER;
```

152
docs/api/Details.md Normal file
View File

@@ -0,0 +1,152 @@
# Place details
Lookup details about a single place by id. The default output is HTML for debugging search logic and results.
**The details page (including JSON output) exists for debugging only and must not be downloaded automatically**, see [Nominatim Usage Policy](https://operations.osmfoundation.org/policies/nominatim/).
## Parameters
The details API supports the following two request formats:
```
https://nominatim.openstreetmap.org/details?osmtype=[N|W|R]&osmid=<value>&class=<value>
```
`osmtype` and `osmid` are required parameter. The type is one of node (N), way (W)
or relation (R). The id must be a number. The `class` parameter is optional and
allows to distinguish between entries, when the corresponding OSM object has more
than one main tag. For example, when a place is tagged with `tourism=hotel` and
`amenity=restaurant`, there will be two place entries in Nominatim, one for a
restaurant, one for a hotel. You need to specify `class=tourism` or `class=amentity`
to get exactly the one you want. If there are multiple places in the database
but the `class` parameter is left out, then one of the places will be chosen
at random and displayed.
```
https://nominatim.openstreetmap.org/details?placeid=<value>
```
Placeids are assigned sequentially during Nominatim data import. The id for a place is different between Nominatim installation (servers) and changes when data gets reimported. Therefore it can't be used as permanent id and shouldn't be used in bug reports.
Additional optional parameters are explained below.
### Output format
* `format=[html|json]`
See [Place Output Formats](Output.md) for details on each format. (Default: html)
* `json_callback=<string>`
Wrap json output in a callback function (JSONP) i.e. `<string>(<json>)`.
Only has an effect for JSON output formats.
* `pretty=[0|1]`
For JSON output will add indentation to make it more human-readable. (Default: 0)
### Output details
* `addressdetails=[0|1]`
Include a breakdown of the address into elements. (Default for JSON: 0, for HTML: 1)
* `keywords=[0|1]`
Include a list of name keywords and address keywords (word ids). (Default: 0)
* `linkedplaces=[0|1]`
Include details of places higher in the address hierarchy. E.g. for a street this is usually the city, state, postal code, country. (Default: 1)
* `hierarchy=[0|1]`
Include details of places lower in the address hierarchy. E.g. for a city this usually a list of streets, suburbs, rivers. (Default for JSON: 0, for HTML: 1)
* `group_hierarchy=[0|1]`
For JSON output will group the places by type. (Default: 0)
* `polygon_geojson=[0|1]`
Include geometry of result. (Default for JSON: 0, for HTML: 1)
### Language of results
* `accept-language=<browser language string>`
Preferred language order for showing result, overrides the value
specified in the "Accept-Language" HTTP header.
Either use a standard RFC2616 accept-language string or a simple
comma-separated list of language codes.
## Examples
##### HTML
[https://nominatim.openstreetmap.org/details.php?osmtype=W&osmid=38210407](https://nominatim.openstreetmap.org/details.php?osmtype=W&osmid=38210407)
##### JSON
[https://nominatim.openstreetmap.org/details.php?osmtype=W&osmid=38210407&format=json](https://nominatim.openstreetmap.org/details.php?osmtype=W&osmid=38210407&format=json)
```json
{
"place_id": 85993608,
"parent_place_id": 72765313,
"osm_type": "W",
"osm_id": 38210407,
"category": "place",
"type": "square",
"admin_level": "15",
"localname": "Pariser Platz",
"names": {
"name": "Pariser Platz",
"name:be": "Парыжская плошча",
"name:de": "Pariser Platz",
"name:es": "Plaza de París",
"name:he": "פאריזר פלאץ",
"name:ko": "파리저 광장",
"name:la": "Forum Parisinum",
"name:ru": "Парижская площадь",
"name:uk": "Паризька площа",
"name:zh": "巴黎廣場"
},
"addresstags": {
"postcode": "10117"
},
"housenumber": null,
"calculated_postcode": "10117",
"country_code": "de",
"indexed_date": "2018-08-18T17:02:45+00:00",
"importance": 0.339401620591472,
"calculated_importance": 0.339401620591472,
"extratags": {
"wikidata": "Q156716",
"wikipedia": "de:Pariser Platz"
},
"calculated_wikipedia": "de:Pariser_Platz",
"rank_address": 30,
"rank_search": 30,
"isarea": true,
"centroid": {
"type": "Point",
"coordinates": [
13.3786822618517,
52.5163654
]
},
"geometry": {
"type": "Point",
"coordinates": [
13.3786822618517,
52.5163654
]
}
}
```

43
docs/api/Faq.md Normal file
View File

@@ -0,0 +1,43 @@
# Frequently Asked Questions
## API Results
#### 1. The address of my search results contains far-away places that don't belong there.
Nominatim computes the address from two sources in the OpenStreetMap data:
from administrative boundaries and from place nodes. Boundaries are the more
useful source. They precisely describe an area. So it is very clear for
Nominatim if a point belongs to an area of not. Place nodes are more complicated.
These are only points without any precise extend. So Nominatim has to take a
guess and assume that an address belongs to the closest place nose it can find.
In an ideal world, Nominatim would not need the place nodes but there are
many places on earth where there are not precise boundaries available for
all parts that make up an address. This is in particular true for the more
local address parts, like villages and suburbs. Therefore it is not possible
to completely dismiss place nodes. And sometimes they sneak in where they
don't belong.
As a OpenStreetMap mapper, you can improve the situation in two ways: if you
see a place node for which already an administrative area exists, then you
should _link_ the two by adding the node with a 'label' role to the boundary
relation. If there is no administrative area, you can add the approximate
extend of the place and tag it place=<something> as well.
#### 2. When doing reverse search, the address details have parts that don't contain the point I was looking up.
There is a common misconception how the reverse API call works in Nominatim.
Reverse does not give you the address of the point you asked for. Reverse
returns the closest object to the point you asked for and then returns the
address of that object. Now, if you are close to a border, then the closest
object may be across that border. When Nominatim then returns the address,
contains the county/state/country across the border.
#### 3. I get different counties/states/countries when I change the zoom parameter in the reverse query. How is that possible?
This is basically the same problem as in the previous answer.
The zoom level influences at which [search rank](https://wiki.openstreetmap.org/wiki/Nominatim/Development_overview#Country_to_street_level) Nominatim starts looking
for the closest object. So the closest house number maybe on one side of the
border while the closest street is on the other. As the address details contain
the address of the closest object found, you might sometimes get one result,
sometimes the other for the closest point.

147
docs/api/Lookup.md Normal file
View File

@@ -0,0 +1,147 @@
# Address lookup
The lookup API allows to query the address and other details of one or
multiple OSM objects like node, way or relation.
## Parameters
The lookup API has the following format:
```
https://nominatim.openstreetmap.org/lookup?osm_ids=[N|W|R]<value>,…,…,&<params>
```
`osm_ids` is mandatory and must contain a comma-separated list of OSM ids each
prefixed with its type, one of node(N), way(W) or relation(R). Up to 50 ids
can be queried at the same time.
Additional optional parameters are explained below.
### Output format
* `format=[html|xml|json|jsonv2|geojson|geocodejson]`
See [Place Output Formats](Output.md) for details on each format. (Default: xml)
* `json_callback=<string>`
Wrap json output in a callback function (JSONP) i.e. `<string>(<json>)`.
Only has an effect for JSON output formats.
### Output details
* `addressdetails=[0|1]`
Include a breakdown of the address into elements. (Default: 0)
* `extratags=[0|1]`
Include additional information in the result if available,
e.g. wikipedia link, opening hours. (Default: 0)
* `namedetails=[0|1]`
Include a list of alternative names in the results. These may include
language variants, references, operator and brand. (Default: 0)
### Language of results
* `accept-language=<browser language string>`
Preferred language order for showing search results, overrides the value
specified in the "Accept-Language" HTTP header.
Either use a standard RFC2616 accept-language string or a simple
comma-separated list of language codes.
### Other
* `email=<valid email address>`
If you are making large numbers of request please include an appropriate email
address to identify your requests. See Nominatim's [Usage Policy](https://operations.osmfoundation.org/policies/nominatim/) for more details.
* `debug=[0|1]`
Output assorted developer debug information. Data on internals of Nominatim's
"Search Loop" logic, and SQL queries. The output is (rough) HTML format.
This overrides the specified machine readable format. (Default: 0)
## Examples
##### XML
[https://nominatim.openstreetmap.org/lookup?osm_ids=R146656,W104393803,N240109189](https://nominatim.openstreetmap.org/lookup?osm_ids=R146656,W104393803,N240109189)
```xml
<lookupresults timestamp="Mon, 29 Jun 15 18:01:33 +0000" attribution="Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright" querystring="R146656,W104393803,N240109189" polygon="false">
<place place_id="127761056" osm_type="relation" osm_id="146656" place_rank="16" lat="53.4791466" lon="-2.2447445" display_name="Manchester, Greater Manchester, North West England, England, United Kingdom" class="boundary" type="administrative" importance="0.704893333438333">
<city>Manchester</city>
<county>Greater Manchester</county>
<state_district>North West England</state_district>
<state>England</state>
<country>United Kingdom</country>
<country_code>gb</country_code>
</place>
<place place_id="77769745" osm_type="way" osm_id="104393803" place_rank="30" lat="52.5162024" lon="13.3777343363579" display_name="Brandenburg Gate, 1, Pariser Platz, Mitte, Berlin, 10117, Germany" class="tourism" type="attraction" importance="0.443472858361592">
<attraction>Brandenburg Gate</attraction>
<house_number>1</house_number>
<pedestrian>Pariser Platz</pedestrian>
<suburb>Mitte</suburb>
<city_district>Mitte</city_district>
<city>Berlin</city>
<state>Berlin</state>
<postcode>10117</postcode>
<country>Germany</country>
<country_code>de</country_code>
</place>
<place place_id="2570600569" osm_type="node" osm_id="240109189" place_rank="15" lat="52.5170365" lon="13.3888599" display_name="Berlin, Germany" class="place" type="city" importance="0.822149797630868">
<city>Berlin</city>
<state>Berlin</state>
<country>Germany</country>
<country_code>de</country_code>
</place>
</lookupresults>
```
##### JSON with extratags
[https://nominatim.openstreetmap.org/lookup?osm_ids=W50637691&format=json](https://nominatim.openstreetmap.org/lookup?osm_ids=W50637691&format=json)
```json
[
{
"place_id": "84271358",
"licence": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
"osm_type": "way",
"osm_id": "50637691",
"lat": "52.39955055",
"lon": "13.04806574678",
"display_name": "Brandenburger Tor, Brandenburger Straße, Nördliche Innenstadt, Innenstadt, Potsdam, Brandenburg, 14467, Germany",
"class": "historic",
"type": "city_gate",
"importance": "0.221233780277011",
"address": {
"address29": "Brandenburger Tor",
"pedestrian": "Brandenburger Straße",
"suburb": "Nördliche Innenstadt",
"city": "Potsdam",
"state": "Brandenburg",
"postcode": "14467",
"country": "Germany",
"country_code": "de"
},
"extratags": {
"image": "http://commons.wikimedia.org/wiki/File:Potsdam_brandenburger_tor.jpg",
"wikidata": "Q695045",
"wikipedia": "de:Brandenburger Tor (Potsdam)",
"wheelchair": "yes",
"description": "Kleines Brandenburger Tor in Potsdam"
}
}
]
```

222
docs/api/Output.md Normal file
View File

@@ -0,0 +1,222 @@
# Place Output
The [\reverse](Reverse.md), [\search](Search.md) and [\lookup](Lookup.md)
API calls produce very similar output which is explained in this section.
There is one section for each format which is selectable via the `format`
parameter.
## Formats
### JSON
The JSON format returns an array of places (for search and lookup) or
a single place (for reverse) of the following format:
```
{
"place_id": "100149",
"licence": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
"osm_type": "node",
"osm_id": "107775",
"boundingbox": ["51.3473219", "51.6673219", "-0.2876474", "0.0323526"],
"lat": "51.5073219",
"lon": "-0.1276474",
"display_name": "London, Greater London, England, SW1A 2DU, United Kingdom",
"class": "place",
"type": "city",
"importance": 0.9654895765402,
"icon": "https://nominatim.openstreetmap.org/images/mapicons/poi_place_city.p.20.png",
"address": {
"city": "London",
"state_district": "Greater London",
"state": "England",
"postcode": "SW1A 2DU",
"country": "United Kingdom",
"country_code": "gb"
},
"extratags": {
"capital": "yes",
"website": "http://www.london.gov.uk",
"wikidata": "Q84",
"wikipedia": "en:London",
"population": "8416535"
}
},
```
The possible fields are:
* `place_id` - reference to the Nominatim internal database ID
* `osm_type`, `osm_id` - reference to the OSM object
* `boundingbox` - area of corner coordinates
* `lat`, `lon` - latitude and longitude of the centroid of the object
* `display_name` - full comma-separated address
* `class`, `type` - key and value of the main OSM tag
* `importance` - computed importance rank
* `icon` - link to class icon (if available)
* `address` - dictionary of address details (only with `addressdetails=1`)
* `extratags` - dictionary with additional useful tags like website or maxspeed
(only with `extratags=1`)
* `namedetails` - dictionary with full list of available names including ref etc.
* `geojson`, `svg`, `geotext`, `geokml` - full geometry
(only with the appropriate `polygon_*` parameter)
### JSONv2
This is the same as the JSON format with two changes:
* `class` renamed to `category`
* additional field `place_rank` with the search rank of the object
### GeoJSON
This format follows the [RFC7946](http://geojson.org). Every feature includes
a bounding box (`bbox`).
The feature list has the following fields:
* `place_id` - reference to the Nominatim internal database ID
* `osm_type`, `osm_id` - reference to the OSM object
* `category`, `type` - key and value of the main OSM tag
* `display_name` - full comma-separated address
* `place_rank` - class search rank
* `importance` - computed importance rank
* `icon` - link to class icon (if available)
* `address` - dictionary of address details (only with `addressdetails=1`)
* `extratags` - dictionary with additional useful tags like website or maxspeed
(only with `extratags=1`)
* `namedetails` - dictionary with full list of available names including ref etc.
Use `polygon_geojson` to output the full geometry of the object instead
of the centroid.
### GeocodeJSON
The GeocodeJSON format follows the
[GeocodeJSON spec 0.1.0](https://github.com/geocoders/geocodejson-spec).
The following feature attributes are implemented:
* `osm_type`, `osm_id` - reference to the OSM object (unofficial extension)
* `type` - value of the main tag of the object (e.g. residential, restaurant, ...)
* `label` - full comma-separated address
* `name` - localised name of the place
* `housenumber`, `street`, `locality`, `postcode`, `city`,
`district`, `county`, `state`, `country` -
provided when it can be determined from the address
(see [this issue](https://github.com/openstreetmap/Nominatim/issues/1080) for
current limitations on the correctness of the address) and `addressdetails=1`
was given
* `admin` - list of localised names of administrative boundaries (only with `addressdetails=1`)
Use `polygon_geojson` to output the full geometry of the object instead
of the centroid.
### XML
The XML response returns one or more place objects in slightly different
formats depending on the API call.
#### Reverse
```
<reversegeocode timestamp="Sat, 11 Aug 18 11:53:21 +0000"
attribution="Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright"
querystring="lat=48.400381&lon=11.745876&zoom=5&format=xml">
<result place_id="179509537" osm_type="relation" osm_id="2145268" ref="BY"
lat="48.9467562" lon="11.4038717"
boundingbox="47.2701114,50.5647142,8.9763497,13.8396373">
Bavaria, Germany
</result>
<addressparts>
<state>Bavaria</state>
<country>Germany</country>
<country_code>de</country_code>
</addressparts>
<extratags>
<tag key="place" value="state"/>
<tag key="wikidata" value="Q980"/>
<tag key="wikipedia" value="de:Bayern"/>
<tag key="population" value="12520000"/>
<tag key="name:prefix" value="Freistaat"/>
</extratags>
</reversegeocode>
```
The attributes of the outer `reversegeocode` element return generic information
about the query, including the time when the response was sent (in UTC),
attribution to OSM and the original querystring.
The place information can be found in the `result` element. The attributes of that element contain:
* `place_id` - reference to the Nominatim internal database ID
* `osm_type`, `osm_id` - reference to the OSM object
* `ref` - content of `ref` tag if it exists
* `lat`, `lon` - latitude and longitude of the centroid of the object
* `boundingbox` - comma-separated list of corner coordinates
The full address address of the result can be found in the content of the
`result` element as a comma-separated list.
Additional information requested with `addressdetails=1`, `extratags=1` and
`namedetails=1` can be found in extra elements.
#### Search and Lookup
```
<searchresults timestamp="Sat, 11 Aug 18 11:55:35 +0000"
attribution="Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright"
querystring="london" polygon="false" exclude_place_ids="100149"
more_url="https://nominatim.openstreetmap.org/search.php?q=london&addressdetails=1&extratags=1&exclude_place_ids=100149&format=xml&accept-language=en-US%2Cen%3Bq%3D0.7%2Cde%3Bq%3D0.3">
<place place_id="100149" osm_type="node" osm_id="107775" place_rank="15"
boundingbox="51.3473219,51.6673219,-0.2876474,0.0323526" lat="51.5073219" lon="-0.1276474"
display_name="London, Greater London, England, SW1A 2DU, United Kingdom"
class="place" type="city" importance="0.9654895765402"
icon="https://nominatim.openstreetmap.org/images/mapicons/poi_place_city.p.20.png">
<extratags>
<tag key="capital" value="yes"/>
<tag key="website" value="http://www.london.gov.uk"/>
<tag key="wikidata" value="Q84"/>
<tag key="wikipedia" value="en:London"/>
<tag key="population" value="8416535"/>
</extratags>
<city>London</city>
<state_district>Greater London</state_district>
<state>England</state>
<postcode>SW1A 2DU</postcode>
<country>United Kingdom</country>
<country_code>gb</country_code>
</place>
</searchresults>
```
The attributes of the outer `searchresults` or `lookupresults` element return
generic information about the query:
* `timestamp` - UTC time when the response was sent
* `attribution` - OSM licensing information
* `querystring` - original query
* `polygon` - true when extra geometry information was requested
* `exclude_place_ids` - IDs of places that should be ignored in a follow-up request
* `more_url` - search call that will yield additional results for the query
just sent
The place information can be found in the `place` elements, of which there may
be more than one. The attributes of that element contain:
* `place_id` - reference to the Nominatim internal database ID
* `osm_type`, `osm_id` - reference to the OSM object
* `ref` - content of `ref` tag if it exists
* `lat`, `lon` - latitude and longitude of the centroid of the object
* `boundingbox` - comma-separated list of corner coordinates
* `place_rank` - class search rank
* `display_name` - full comma-separated address
* `class`, `type` - key and value of the main OSM tag
* `importance` - computed importance rank
* `icon` - link to class icon (if available)
When `addressdetails=1` is requested, the localised address parts appear
as subelements with the type of the address part.
Additional information requested with `extratags=1` and `namedetails=1` can
be found in extra elements as sub-element of each place.

14
docs/api/Overview.md Normal file
View File

@@ -0,0 +1,14 @@
### Nominatim API
Nominatim indexes named (or numbered) features within the OpenStreetMap (OSM) dataset and a subset of other unnamed features (pubs, hotels, churches, etc).
Its API has the following endpoints for querying the data:
* __[/search](Search.md)__ - search OSM objects by name or type
* __[/reverse](Reverse.md)__ - search OSM object by their location
* __[/lookup](Lookup.md)__ - look up address details for OSM objects by their ID
* __/status__ - query the status of the server
* __/deletable__ - list objects that have been deleted in OSM but are held
back in Nominatim in case the deletion was accidental
* __/polygons__ - list of broken polygons detected by Nominatim
* __[/details](Details.md)__ - show internal details for an object (for debugging only)

271
docs/api/Reverse.md Normal file
View File

@@ -0,0 +1,271 @@
# Reverse Geocoding
Reverse geocoding generates an address from a latitude and longitude or from
an OSM object.
## Parameters
The main format of the reverse API is
```
https://nominatim.openstreetmap.org/reverse?<query>
```
There are two ways how the requested location can be specified:
* `lat=<value>` `lon=<value>`
A geographic location to generate an address for. The coordiantes must be
in WGS84 format.
* `osm_type=[N|W|R]` `osm_id=<value>`
A specific OSM node(N), way(W) or relation(R) to return an address for.
In both cases exactly one object is returned. The two input paramters cannot
be used at the same time. Both accept the additional optional parameters listed
below.
### Output format
* `format=[xml|json|jsonv2|geojson|geocodejson]`
See [Place Output Formats](Output.md) for details on each format. (Default: html)
* `json_callback=<string>`
Wrap json output in a callback function ([JSONP](https://en.wikipedia.org/wiki/JSONP)) i.e. `<string>(<json>)`.
Only has an effect for JSON output formats.
### Output details
* `addressdetails=[0|1]`
Include a breakdown of the address into elements. (Default: 1)
* `extratags=[0|1]`
Include additional information in the result if available,
e.g. wikipedia link, opening hours. (Default: 0)
* `namedetails=[0|1]`
Include a list of alternative names in the results. These may include
language variants, references, operator and brand. (Default: 0)
### Language of results
* `accept-language=<browser language string>`
Preferred language order for showing search results, overrides the value
specified in the "Accept-Language" HTTP header.
Either use a standard RFC2616 accept-language string or a simple
comma-separated list of language codes.
### Result limitation
* `zoom=[0-18]`
Level of detail required for the address. Default: 18. This is a number that corresponds
roughly to the zoom level used in map frameworks like Leaflet.js, Openlayers etc.
In terms of address details the zoom levels are as follows:
zoom | address detail
-----|---------------
3 | country
5 | state
8 | county
10 | city
14 | suburb
16 | street
18 | building
### Polygon output
* `polygon_geojson=1`
* `polygon_kml=1`
* `polygon_svg=1`
* `polygon_text=1`
Output geometry of results as a GeoJSON, KML, SVG or WKT. Only one of these
options can be used at a time. (Default: 0)
* `polygon_threshold=0.0`
Simplify the output geometry before returning. The parameter is the
tolerance in degrees with which the geometry may differ from the original
geometry. Topology is preserved in the result. (Default: 0.0)
### Other
* `email=<valid email address>`
If you are making large numbers of request please include an appropriate email
address to identify your requests. See Nominatim's [Usage Policy](https://operations.osmfoundation.org/policies/nominatim/) for more details.
* `debug=[0|1]`
Output assorted developer debug information. Data on internals of Nominatim's
"Search Loop" logic, and SQL queries. The output is (rough) HTML format.
This overrides the specified machine readable format. (Default: 0)
## Examples
* [https://nominatim.openstreetmap.org/reverse?format=xml&lat=52.5487429714954&lon=-1.81602098644987&zoom=18&addressdetails=1](https://nominatim.openstreetmap.org/reverse?format=xml&lat=52.5487429714954&lon=-1.81602098644987&zoom=18&addressdetails=1)
```xml
<reversegeocode timestamp="Fri, 06 Nov 09 16:33:54 +0000" querystring="...">
<result place_id="1620612" osm_type="node" osm_id="452010817">
135, Pilkington Avenue, Wylde Green, City of Birmingham, West Midlands (county), B72, United Kingdom
</result>
<addressparts>
<house_number>135</house_number>
<road>Pilkington Avenue</road>
<village>Wylde Green</village>
<town>Sutton Coldfield</town>
<city>City of Birmingham</city>
<county>West Midlands (county)</county>
<postcode>B72</postcode>
<country>United Kingdom</country>
<country_code>gb</country_code>
</addressparts>
</reversegeocode>
```
##### Example with `format=jsonv2`
* [https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=-34.44076&lon=-58.70521](https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=-34.44076&lon=-58.70521)
```json
{
"place_id":"134140761",
"licence":"Data © OpenStreetMap contributors, ODbL 1.0. http:\/\/www.openstreetmap.org\/copyright",
"osm_type":"way",
"osm_id":"280940520",
"lat":"-34.4391708",
"lon":"-58.7064573",
"place_rank":"26",
"category":"highway",
"type":"motorway",
"importance":"0.1",
"addresstype":"road",
"display_name":"Autopista Pedro Eugenio Aramburu, El Triángulo, Partido de Malvinas Argentinas, Buenos Aires, 1.619, Argentina",
"name":"Autopista Pedro Eugenio Aramburu",
"address":{
"road":"Autopista Pedro Eugenio Aramburu",
"village":"El Triángulo",
"state_district":"Partido de Malvinas Argentinas",
"state":"Buenos Aires",
"postcode":"1.619",
"country":"Argentina",
"country_code":"ar"
},
"boundingbox":["-34.44159","-34.4370994","-58.7086067","-58.7044712"]
}
```
##### Example with `format=geojson`
* [https://nominatim.openstreetmap.org/reverse?format=geojson&lat=44.50155&lon=11.33989](https://nominatim.openstreetmap.org/reverse?format=geojson&lat=44.50155&lon=11.33989)
```json
{
"type": "FeatureCollection",
"licence": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
"features": [
{
"type": "Feature",
"properties": {
"place_id": "18512203",
"osm_type": "node",
"osm_id": "1704756187",
"place_rank": "30",
"category": "place",
"type": "house",
"importance": "0",
"addresstype": "place",
"name": null,
"display_name": "71, Via Guglielmo Marconi, Saragozza-Porto, Bologna, BO, Emilia-Romagna, 40122, Italy",
"address": {
"house_number": "71",
"road": "Via Guglielmo Marconi",
"suburb": "Saragozza-Porto",
"city": "Bologna",
"county": "BO",
"state": "Emilia-Romagna",
"postcode": "40122",
"country": "Italy",
"country_code": "it"
}
},
"bbox": [
11.3397676,
44.5014307,
11.3399676,
44.5016307
],
"geometry": {
"type": "Point",
"coordinates": [
11.3398676,
44.5015307
]
}
}
]
}
```
##### Example with `format=geocodejson`
[https://nominatim.openstreetmap.org/reverse?format=geocodejson&lat=60.2299&lon=11.1663](https://nominatim.openstreetmap.org/reverse?format=geocodejson&lat=60.2299&lon=11.1663)
```json
{
"type": "FeatureCollection",
"geocoding": {
"version": "0.1.0",
"attribution": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
"licence": "ODbL",
"query": "60.229917843587,11.16630979382"
},
"features": {
"type": "Feature",
"properties": {
"geocoding": {
"place_id": "42700574",
"osm_type": "node",
"osm_id": "3110596255",
"type": "house",
"accuracy": 0,
"label": "1, Løvenbergvegen, Mogreina, Ullensaker, Akershus, 2054, Norway",
"name": null,
"housenumber": "1",
"street": "Løvenbergvegen",
"postcode": "2054",
"county": "Akershus",
"country": "Norway",
"admin": {
"level7": "Ullensaker",
"level4": "Akershus",
"level2": "Norway"
}
}
},
"geometry": {
"type": "Point",
"coordinates": [
11.1658572,
60.2301296
]
}
}
}
```

349
docs/api/Search.md Normal file
View File

@@ -0,0 +1,349 @@
# Search queries
The search API allows to look up a location from a textual description.
Nominatim supports structured as well as free-form search queries.
The search query may also contain
[special phrases](https://wiki.openstreetmap.org/wiki/Nominatim/Special_Phrases)
which are translated into specific OpenStreetMap (OSM) tags (e.g. Pub => `amenity=pub`).
Note that this only limits the items to be found, it's not suited to return complete
lists of OSM objects of a specific type. For those use [Overpass API](https://overpass-api.de/).
## Parameters
The search API has the following two formats:
```
https://nominatim.openstreetmap.org/search/<query>?<params>
```
This format only accepts a free-form query string where the
parts of the query are separated by slashes.
```
https://nominatim.openstreetmap.org/search?<params>
```
In this form, the query may be given through two different sets of parameters:
* `q=<query>`
Free-form query string to search for.
Free-form queries are processed first left-to-right and then right-to-left if that fails. So you may search for
[pilkington avenue, birmingham](//nominatim.openstreetmap.org/search?q=pilkington+avenue,birmingham) as well as for
[birmingham, pilkington avenue](//nominatim.openstreetmap.org/search?q=birmingham,+pilkington+avenue).
Commas are optional, but improve performance by reducing the complexity of the search.
* `street=<housenumber> <streetname>`
* `city=<city>`
* `county=<county>`
* `state=<state>`
* `country=<country>`
* `postalcode=<postalcode>`
Alternative query string format split into several parameters for structured requests.
Structured requests are faster but are less robust against alternative
OSM tagging schemas. **Do not combine with** `q=<query>` **parameter**.
All three query forms accept the additional paramters listed below.
### Output format
* `format=[html|xml|json|jsonv2|geojson|geocodejson]`
See [Place Output Formats](Output.md) for details on each format. (Default: html)
* `json_callback=<string>`
Wrap json output in a callback function ([JSONP](https://en.wikipedia.org/wiki/JSONP)) i.e. `<string>(<json>)`.
Only has an effect for JSON output formats.
### Output details
* `addressdetails=[0|1]`
Include a breakdown of the address into elements. (Default: 0)
* `extratags=[0|1]`
Include additional information in the result if available,
e.g. wikipedia link, opening hours. (Default: 0)
* `namedetails=[0|1]`
Include a list of alternative names in the results. These may include
language variants, references, operator and brand. (Default: 0)
### Language of results
* `accept-language=<browser language string>`
Preferred language order for showing search results, overrides the value
specified in the ["Accept-Language" HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language).
Either use a standard RFC2616 accept-language string or a simple
comma-separated list of language codes.
### Result limitation
* `countrycodes=<countrycode>[,<countrycode>][,<countrycode>]...`
Limit search results to one or more countries. `<countrycode>` must be the
ISO 3166-1alpha2 code, e.g. `gb` for the United Kingdom, `de` for Germany.
* `exclude_place_ids=<place_id,[place_id],[place_id]`
If you do not want certain OSM objects to appear in the search
result, give a comma separated list of the `place_id`s you want to skip.
This can be used to broaden search results. For example, if a previous
query only returned a few results, then including those here would cause
the search to return other, less accurate, matches (if possible).
* `limit=<integer>`
Limit the number of returned results. (Default: 10, Maximum: 50)
* `viewbox=<x1>,<y1>,<x2>,<y2>`
The preferred area to find search results. Any two corner points of the box
are accepted in any order as long as they span a real box.
* `bounded=[0|1]`
When a viewbox is given, restrict the result to items contained with that
viewbox (see above). When `viewbox` and `bounded=1` are given, an amenity
only search is allowed. In this case, give the special keyword for the
amenity in square brackets, e.g. `[pub]`. (Default: 0)
### Polygon output
* `polygon_geojson=1`
* `polygon_kml=1`
* `polygon_svg=1`
* `polygon_text=1`
Output geometry of results as a GeoJSON, KML, SVG or WKT. Only one of these
options can be used at a time. (Default: 0)
* `polygon_threshold=0.0`
Simplify the output geometry before returning. The parameter is the
tolerance in degrees with which the geometry may differ from the original
geometry. Topology is preserved in the result. (Default: 0.0)
### Other
* `email=<valid email address>`
If you are making large numbers of request please include an appropriate email
address to identify your requests. See Nominatim's [Usage Policy](https://operations.osmfoundation.org/policies/nominatim/) for more details.
* `dedupe=[0|1]`
Sometimes you have several objects in OSM identifying the same place or
object in reality. The simplest case is a street being split in many
different OSM ways due to different characteristics. Nominatim will
attempt to detect such duplicates and only return one match unless
this parameter is set to 0. (Default: 1)
* `debug=[0|1]`
Output assorted developer debug information. Data on internals of Nominatim's
"Search Loop" logic, and SQL queries. The output is (rough) HTML format.
This overrides the specified machine readable format. (Default: 0)
## Examples
##### XML with polygon points
* [https://nominatim.openstreetmap.org/search?q=135+pilkington+avenue,+birmingham&format=xml&polygon=1&addressdetails=1](https://nominatim.openstreetmap.org/search?q=135+pilkington+avenue,+birmingham&format=xml&polygon=1&addressdetails=1)
* [https://nominatim.openstreetmap.org/search/gb/birmingham/pilkington%20avenue/135?format=xml&polygon=1&addressdetails=1](https://nominatim.openstreetmap.org/search/gb/birmingham/pilkington%20avenue/135?format=xml&polygon=1&addressdetails=1)
* [https://nominatim.openstreetmap.org/search/135%20pilkington%20avenue,%20birmingham?format=xml&polygon=1&addressdetails=1](https://nominatim.openstreetmap.org/search/135%20pilkington%20avenue,%20birmingham?format=xml&polygon=1&addressdetails=1)
```xml
<searchresults timestamp="Sat, 07 Nov 09 14:42:10 +0000" querystring="135 pilkington, avenue birmingham" polygon="true">
<place
place_id="1620612" osm_type="node" osm_id="452010817"
boundingbox="52.548641204834,52.5488433837891,-1.81612110137939,-1.81592094898224"
polygonpoints="[['-1.81592098644987','52.5487429714954'],['-1.81592290792183','52.5487234624632'],...]"
lat="52.5487429714954" lon="-1.81602098644987"
display_name="135, Pilkington Avenue, Wylde Green, City of Birmingham, West Midlands (county), B72, United Kingdom"
class="place" type="house">
<house_number>135</house_number>
<road>Pilkington Avenue</road>
<village>Wylde Green</village>
<town>Sutton Coldfield</town>
<city>City of Birmingham</city>
<county>West Midlands (county)</county>
<postcode>B72</postcode>
<country>United Kingdom</country>
<country_code>gb</country_code>
</place>
</searchresults>
```
##### JSON with SVG polygon
[https://nominatim.openstreetmap.org/search/Unter%20den%20Linden%201%20Berlin?format=json&addressdetails=1&limit=1&polygon_svg=1](https://nominatim.openstreetmap.org/search/Unter%20den%20Linden%201%20Berlin?format=json&addressdetails=1&limit=1&polygon_svg=1)
```json
{
"address": {
"city": "Berlin",
"city_district": "Mitte",
"construction": "Unter den Linden",
"continent": "European Union",
"country": "Deutschland",
"country_code": "de",
"house_number": "1",
"neighbourhood": "Scheunenviertel",
"postcode": "10117",
"public_building": "Kommandantenhaus",
"state": "Berlin",
"suburb": "Mitte"
},
"boundingbox": [
"52.5170783996582",
"52.5173187255859",
"13.3975105285645",
"13.3981599807739"
],
"class": "amenity",
"display_name": "Kommandantenhaus, 1, Unter den Linden, Scheunenviertel, Mitte, Berlin, 10117, Deutschland, European Union",
"importance": 0.73606775332943,
"lat": "52.51719785",
"licence": "Data \u00a9 OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright",
"lon": "13.3978352028938",
"osm_id": "15976890",
"osm_type": "way",
"place_id": "30848715",
"svg": "M 13.397511 -52.517283599999999 L 13.397829400000001 -52.517299800000004 13.398131599999999 -52.517315099999998 13.398159400000001 -52.517112099999999 13.3975388 -52.517080700000001 Z",
"type": "public_building"
}
```
##### JSON with address details
[https://nominatim.openstreetmap.org/?format=json&addressdetails=1&q=bakery+in+berlin+wedding&format=json&limit=1](https://nominatim.openstreetmap.org/?format=json&addressdetails=1&q=bakery+in+berlin+wedding&format=json&limit=1)
```json
{
"address": {
"bakery": "B\u00e4cker Kamps",
"city_district": "Mitte",
"continent": "European Union",
"country": "Deutschland",
"country_code": "de",
"footway": "Bahnsteig U6",
"neighbourhood": "Sprengelkiez",
"postcode": "13353",
"state": "Berlin",
"suburb": "Wedding"
},
"boundingbox": [
"52.5460929870605",
"52.5460968017578",
"13.3591794967651",
"13.3591804504395"
],
"class": "shop",
"display_name": "B\u00e4cker Kamps, Bahnsteig U6, Sprengelkiez, Wedding, Mitte, Berlin, 13353, Deutschland, European Union",
"icon": "https://nominatim.openstreetmap.org/images/mapicons/shopping_bakery.p.20.png",
"importance": 0.201,
"lat": "52.5460941",
"licence": "Data \u00a9 OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright",
"lon": "13.35918",
"osm_id": "317179427",
"osm_type": "node",
"place_id": "1453068",
"type": "bakery"
}
```
##### GeoJSON
[https://nominatim.openstreetmap.org/search?q=17+Strada+Pictor+Alexandru+Romano%2C+Bukarest&format=geojson](https://nominatim.openstreetmap.org/search?q=17+Strada+Pictor+Alexandru+Romano%2C+Bukarest&format=geojson)
```json
{
"type": "FeatureCollection",
"licence": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
"features": [
{
"type": "Feature",
"properties": {
"place_id": "35811445",
"osm_type": "node",
"osm_id": "2846295644",
"display_name": "17, Strada Pictor Alexandru Romano, Bukarest, Bucharest, Sector 2, Bucharest, 023964, Romania",
"place_rank": "30",
"category": "place",
"type": "house",
"importance": 0.62025
},
"bbox": [
26.1156689,
44.4354754,
26.1157689,
44.4355754
],
"geometry": {
"type": "Point",
"coordinates": [
26.1157189,
44.4355254
]
}
}
]
}
```
##### GeocodeJSON
[https://nominatim.openstreetmap.org/search?q=%CE%91%CE%B3%CE%AF%CE%B1+%CE%A4%CF%81%CE%B9%CE%AC%CE%B4%CE%B1%2C+%CE%91%CE%B4%CF%89%CE%BD%CE%B9%CE%B4%CE%BF%CF%82%2C+Athens%2C+Greece&format=geocodejson](https://nominatim.openstreetmap.org/search?q=%CE%91%CE%B3%CE%AF%CE%B1+%CE%A4%CF%81%CE%B9%CE%AC%CE%B4%CE%B1%2C+%CE%91%CE%B4%CF%89%CE%BD%CE%B9%CE%B4%CE%BF%CF%82%2C+Athens%2C+Greece&format=geocodejson)
```json
{
"type": "FeatureCollection",
"geocoding": {
"version": "0.1.0",
"attribution": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
"licence": "ODbL",
"query": "Αγία Τριάδα, Αδωνιδος, Athens, Greece"
},
"features": [
{
"type": "Feature",
"properties": {
"geocoding": {
"type": "place_of_worship",
"label": "Αγία Τριάδα, Αδωνιδος, Άγιος Νικόλαος, 5º Δημοτικό Διαμέρισμα Αθηνών, Athens, Municipality of Athens, Regional Unit of Central Athens, Region of Attica, Attica, 11472, Greece",
"name": "Αγία Τριάδα",
"admin": null
}
},
"geometry": {
"type": "Point",
"coordinates": [
23.72949633941,
38.0051697
]
}
}
]
}
```

7
docs/bash2md.sh Executable file
View File

@@ -0,0 +1,7 @@
#!/bin/sh
#
# Extract markdown-formatted documentation from a source file
#
# Usage: bash2md.sh <infile> <outfile>
sed '/^#!/d;s:^#\( \|$\)::;s/.*#DOCS://' $1 > $2

24
docs/develop/overview.md Normal file
View File

@@ -0,0 +1,24 @@
# Basic Architecture
Nominatim provides geocoding based on OpenStreetMap data. It uses a Postgresql
database as a backend for storing the data.
There are three basic parts to Nominatim's architecture: the data import,
the address computation and the search frontend.
The __data import__ stage reads the raw OSM data and extracts all information
that is useful for geocoding. This part is done by osm2pgsql, the same tool
that can also be used to import a rendering database. It uses the special
gazetteer output plugin in `osm2pgsql/output-gazetter.[ch]pp`. The result of
the import can be found in the database table `place`.
The __address computation__ or __indexing__ stage takes the data from `place`
and adds additional information needed for geocoding. It ranks the places by
importance, links objects that belong together and computes addresses and
the search index. Most of this work is done in Pl/pqSQL via database triggers
and can be found in the file `sql/functions.sql`.
The __search frontend__ implements the actual API. It takes queries for
search and reverse geocoding queries from the user, looks up the data and
returns the results in the requested format. This part is written in PHP
and can be found in the `lib/` and `website/` directories.

3
docs/extra.css Normal file
View File

@@ -0,0 +1,3 @@
.toctree-l3 {
display: none!important
}

8
docs/index.md Normal file
View File

@@ -0,0 +1,8 @@
Nominatim (from the Latin, 'by name') is a tool to search OSM data by name and address and to generate synthetic addresses of OSM points (reverse geocoding).
This guide comes in three parts:
* __[API reference](api/Overview.md)__ for users of Nominatim
* __[Administration Guide](admin/Installation.md)__ for those who want
to install their own Nominatim server
* __[Developer's Guide](develop/overview.md)__ for developers of the software

32
docs/mkdocs.yml Normal file
View File

@@ -0,0 +1,32 @@
site_name: Nominatim Documentation
theme: readthedocs
docs_dir: ${CMAKE_CURRENT_BINARY_DIR}
site_url: http://nominatim.org
repo_url: https://github.com/openstreetmap/Nominatim
pages:
- 'Introduction' : 'index.md'
- 'API Reference':
- 'Overview': 'api/Overview.md'
- 'Search': 'api/Search.md'
- 'Reverse': 'api/Reverse.md'
- 'Address Lookup': 'api/Lookup.md'
- 'Details' : 'api/Details.md'
- 'Place Output Formats': 'api/Output.md'
- 'FAQ': 'api/Faq.md'
- 'Administration Guide':
- 'Basic Installation': 'admin/Installation.md'
- 'Importing and Updating' : 'admin/Import-and-Update.md'
- 'Migration from older Versions' : 'admin/Migration.md'
- 'Troubleshooting' : 'admin/Faq.md'
- 'Developers Guide':
- 'Overview' : 'develop/overview.md'
- 'Appendix':
- 'Installation on CentOS 7' : 'appendix/Install-on-Centos-7.md'
- 'Installation on Ubuntu 16' : 'appendix/Install-on-Ubuntu-16.md'
- 'Installation on Ubuntu 18' : 'appendix/Install-on-Ubuntu-18.md'
markdown_extensions:
- codehilite:
use_pygments: False
- toc:
permalink:
extra_css: [extra.css]

122
lib/AddressDetails.php Normal file
View File

@@ -0,0 +1,122 @@
<?php
namespace Nominatim;
require_once(CONST_BasePath.'/lib/ClassTypes.php');
/**
* Detailed list of address parts for a single result
*/
class AddressDetails
{
private $aAddressLines;
public function __construct(&$oDB, $iPlaceID, $sHousenumber, $mLangPref)
{
if (is_array($mLangPref)) {
$mLangPref = 'ARRAY['.join(',', array_map('getDBQuoted', $mLangPref)).']';
}
if (!$sHousenumber) {
$sHousenumber = -1;
}
$sSQL = 'SELECT *,';
$sSQL .= ' get_name_by_language(name,'.$mLangPref.') as localname';
$sSQL .= ' FROM get_addressdata('.$iPlaceID.','.$sHousenumber.')';
$sSQL .= ' ORDER BY rank_address desc,isaddress DESC';
$this->aAddressLines = chksql($oDB->getAll($sSQL));
}
private static function isAddress($aLine)
{
return $aLine['isaddress'] == 't' || $aLine['type'] == 'country_code';
}
public function getAddressDetails($bAll = false)
{
if ($bAll) {
return $this->aAddressLines;
}
return array_filter($this->aAddressLines, 'AddressDetails::isAddress');
}
public function getLocaleAddress()
{
$aParts = array();
$sPrevResult = '';
foreach ($this->aAddressLines as $aLine) {
if ($aLine['isaddress'] == 't' && $sPrevResult != $aLine['localname']) {
$sPrevResult = $aLine['localname'];
$aParts[] = $sPrevResult;
}
}
return join(', ', $aParts);
}
public function getAddressNames()
{
$aAddress = array();
$aFallback = array();
foreach ($this->aAddressLines as $aLine) {
if (!self::isAddress($aLine)) {
continue;
}
$bFallback = false;
$aTypeLabel = ClassTypes\getInfo($aLine);
if ($aTypeLabel === false) {
$aTypeLabel = ClassTypes\getFallbackInfo($aLine);
$bFallback = true;
}
$sName = false;
if (isset($aLine['localname']) && $aLine['localname']) {
$sName = $aLine['localname'];
} elseif (isset($aLine['housenumber']) && $aLine['housenumber']) {
$sName = $aLine['housenumber'];
}
if ($sName) {
$sTypeLabel = strtolower(isset($aTypeLabel['simplelabel']) ? $aTypeLabel['simplelabel'] : $aTypeLabel['label']);
$sTypeLabel = str_replace(' ', '_', $sTypeLabel);
if (!isset($aAddress[$sTypeLabel])
|| isset($aFallback[$sTypeLabel])
|| $aLine['class'] == 'place'
) {
$aAddress[$sTypeLabel] = $sName;
if ($bFallback) {
$aFallback[$sTypeLabel] = $bFallback;
}
}
}
}
return $aAddress;
}
public function getAdminLevels()
{
$aAddress = array();
foreach ($this->aAddressLines as $aLine) {
if (self::isAddress($aLine)
&& isset($aLine['admin_level'])
&& $aLine['admin_level'] < 15
&& !isset($aAddress['level'.$aLine['admin_level']])
) {
$aAddress['level'.$aLine['admin_level']] = $aLine['localname'];
}
}
return $aAddress;
}
public function debugInfo()
{
return $this->aAddressLines;
}
}

374
lib/ClassTypes.php Normal file
View File

@@ -0,0 +1,374 @@
<?php
namespace Nominatim\ClassTypes;
function getInfo($aPlace)
{
$aClassType = getList();
if (isset($aPlace['admin_level'])) {
$sName = $aPlace['class'].':'.$aPlace['type'].':'.$aPlace['admin_level'];
if (isset($aClassType[$sName])) {
return $aClassType[$sName];
}
}
$sName = $aPlace['class'].':'.$aPlace['type'];
if (isset($aClassType[$sName])) {
return $aClassType[$sName];
}
return false;
}
function getFallbackInfo($aPlace)
{
$aClassType = getList();
$sFallback = 'boundary:administrative:'.((int)($aPlace['rank_address']/2));
if (isset($aClassType[$sFallback])) {
return $aClassType[$sFallback];
}
return array('simplelabel' => 'address'.$aPlace['rank_address']);
}
function getProperty($aPlace, $sProp, $mDefault = false)
{
$aClassType = getList();
if (isset($aPlace['admin_level'])) {
$sName = $aPlace['class'].':'.$aPlace['type'].':'.$aPlace['admin_level'];
if (isset($aClassType[$sName]) && isset($aClassType[$sName][$sProp])) {
return $aClassType[$sName][$sProp];
}
}
$sName = $aPlace['class'].':'.$aPlace['type'];
if (isset($aClassType[$sName]) && isset($aClassType[$sName][$sProp])) {
return $aClassType[$sName][$sProp];
}
return $mDefault;
}
function getListWithImportance()
{
static $aOrders = null;
if ($aOrders === null) {
$aOrders = getList();
$i = 1;
foreach ($aOrders as $sID => $a) {
$aOrders[$sID]['importance'] = $i++;
}
}
return $aOrders;
}
function getList()
{
return array(
'boundary:administrative:1' => array('label' => 'Continent', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'boundary:administrative:2' => array('label' => 'Country', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'place:country' => array('label' => 'Country', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defzoom' => 6, 'defdiameter' => 15),
'boundary:administrative:3' => array('label' => 'State', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'boundary:administrative:4' => array('label' => 'State', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'place:state' => array('label' => 'State', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defzoom' => 8, 'defdiameter' => 5.12),
'boundary:administrative:5' => array('label' => 'State District', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'boundary:administrative:6' => array('label' => 'County', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'boundary:administrative:7' => array('label' => 'County', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'place:county' => array('label' => 'County', 'frequency' => 108, 'icon' => 'poi_boundary_administrative', 'defzoom' => 10, 'defdiameter' => 1.28),
'boundary:administrative:8' => array('label' => 'City', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'place:city' => array('label' => 'City', 'frequency' => 66, 'icon' => 'poi_place_city', 'defzoom' => 12, 'defdiameter' => 0.32),
'boundary:administrative:9' => array('label' => 'City District', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'boundary:administrative:10' => array('label' => 'Suburb', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'boundary:administrative:11' => array('label' => 'Neighbourhood', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'place:region' => array('label' => 'Region', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defzoom' => 8, 'defdiameter' => 0.04),
'place:island' => array('label' => 'Island', 'frequency' => 288, 'defzoom' => 11, 'defdiameter' => 0.64),
'boundary:administrative' => array('label' => 'Administrative', 'frequency' => 413, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'boundary:postal_code' => array('label' => 'Postcode', 'frequency' => 413, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'place:town' => array('label' => 'Town', 'frequency' => 1497, 'icon' => 'poi_place_town', 'defzoom' => 14, 'defdiameter' => 0.08),
'place:village' => array('label' => 'Village', 'frequency' => 11230, 'icon' => 'poi_place_village', 'defzoom' => 15, 'defdiameter' => 0.04),
'place:hamlet' => array('label' => 'Hamlet', 'frequency' => 7075, 'icon' => 'poi_place_village', 'defzoom' => 15, 'defdiameter' => 0.04),
'place:suburb' => array('label' => 'Suburb', 'frequency' => 2528, 'icon' => 'poi_place_village', 'defdiameter' => 0.04),
'place:locality' => array('label' => 'Locality', 'frequency' => 4113, 'icon' => 'poi_place_village', 'defdiameter' => 0.02),
'landuse:farm' => array('label' => 'Farm', 'frequency' => 1201, 'defdiameter' => 0.02),
'place:farm' => array('label' => 'Farm', 'frequency' => 1162, 'defdiameter' => 0.02),
'highway:motorway_junction' => array('label' => 'Motorway Junction', 'frequency' => 1126, 'simplelabel' => 'Junction'),
'highway:motorway' => array('label' => 'Motorway', 'frequency' => 4627, 'simplelabel' => 'Road'),
'highway:trunk' => array('label' => 'Trunk', 'frequency' => 23084, 'simplelabel' => 'Road'),
'highway:primary' => array('label' => 'Primary', 'frequency' => 32138, 'simplelabel' => 'Road'),
'highway:secondary' => array('label' => 'Secondary', 'frequency' => 25807, 'simplelabel' => 'Road'),
'highway:tertiary' => array('label' => 'Tertiary', 'frequency' => 29829, 'simplelabel' => 'Road'),
'highway:residential' => array('label' => 'Residential', 'frequency' => 361498, 'simplelabel' => 'Road'),
'highway:unclassified' => array('label' => 'Unclassified', 'frequency' => 66441, 'simplelabel' => 'Road'),
'highway:living_street' => array('label' => 'Living Street', 'frequency' => 710, 'simplelabel' => 'Road'),
'highway:service' => array('label' => 'Service', 'frequency' => 9963, 'simplelabel' => 'Road'),
'highway:track' => array('label' => 'Track', 'frequency' => 2565, 'simplelabel' => 'Road'),
'highway:road' => array('label' => 'Road', 'frequency' => 591, 'simplelabel' => 'Road'),
'highway:byway' => array('label' => 'Byway', 'frequency' => 346, 'simplelabel' => 'Road'),
'highway:bridleway' => array('label' => 'Bridleway', 'frequency' => 1556),
'highway:cycleway' => array('label' => 'Cycleway', 'frequency' => 2419),
'highway:pedestrian' => array('label' => 'Pedestrian', 'frequency' => 2757),
'highway:footway' => array('label' => 'Footway', 'frequency' => 15008),
'highway:steps' => array('label' => 'Steps', 'frequency' => 444, 'simplelabel' => 'Footway'),
'highway:motorway_link' => array('label' => 'Motorway Link', 'frequency' => 795, 'simplelabel' => 'Road'),
'highway:trunk_link' => array('label' => 'Trunk Link', 'frequency' => 1258, 'simplelabel' => 'Road'),
'highway:primary_link' => array('label' => 'Primary Link', 'frequency' => 313, 'simplelabel' => 'Road'),
'landuse:industrial' => array('label' => 'Industrial', 'frequency' => 1062),
'landuse:residential' => array('label' => 'Residential', 'frequency' => 886),
'landuse:retail' => array('label' => 'Retail', 'frequency' => 754),
'landuse:commercial' => array('label' => 'Commercial', 'frequency' => 657),
'place:airport' => array('label' => 'Airport', 'frequency' => 36, 'icon' => 'transport_airport2', 'defdiameter' => 0.03),
'aeroway:aerodrome' => array('label' => 'Aerodrome', 'frequency' => 36, 'icon' => 'transport_airport2', 'defdiameter' => 0.03),
'aeroway' => array('label' => 'Aeroway', 'frequency' => 36, 'icon' => 'transport_airport2', 'defdiameter' => 0.03),
'railway:station' => array('label' => 'Station', 'frequency' => 3431, 'icon' => 'transport_train_station2', 'defdiameter' => 0.01),
'amenity:place_of_worship' => array('label' => 'Place Of Worship', 'frequency' => 9049, 'icon' => 'place_of_worship_unknown3'),
'amenity:pub' => array('label' => 'Pub', 'frequency' => 18969, 'icon' => 'food_pub'),
'amenity:bar' => array('label' => 'Bar', 'frequency' => 164, 'icon' => 'food_bar'),
'amenity:university' => array('label' => 'University', 'frequency' => 607, 'icon' => 'education_university'),
'tourism:museum' => array('label' => 'Museum', 'frequency' => 543, 'icon' => 'tourist_museum'),
'amenity:arts_centre' => array('label' => 'Arts Centre', 'frequency' => 136, 'icon' => 'tourist_art_gallery2'),
'tourism:zoo' => array('label' => 'Zoo', 'frequency' => 47, 'icon' => 'tourist_zoo'),
'tourism:theme_park' => array('label' => 'Theme Park', 'frequency' => 24, 'icon' => 'poi_point_of_interest'),
'tourism:attraction' => array('label' => 'Attraction', 'frequency' => 1463, 'icon' => 'poi_point_of_interest'),
'leisure:golf_course' => array('label' => 'Golf Course', 'frequency' => 712, 'icon' => 'sport_golf'),
'historic:castle' => array('label' => 'Castle', 'frequency' => 316, 'icon' => 'tourist_castle'),
'amenity:hospital' => array('label' => 'Hospital', 'frequency' => 879, 'icon' => 'health_hospital'),
'amenity:school' => array('label' => 'School', 'frequency' => 8192, 'icon' => 'education_school'),
'amenity:theatre' => array('label' => 'Theatre', 'frequency' => 371, 'icon' => 'tourist_theatre'),
'amenity:public_building' => array('label' => 'Public Building', 'frequency' => 985),
'amenity:library' => array('label' => 'Library', 'frequency' => 794, 'icon' => 'amenity_library'),
'amenity:townhall' => array('label' => 'Townhall', 'frequency' => 242),
'amenity:community_centre' => array('label' => 'Community Centre', 'frequency' => 157),
'amenity:fire_station' => array('label' => 'Fire Station', 'frequency' => 221, 'icon' => 'amenity_firestation3'),
'amenity:police' => array('label' => 'Police', 'frequency' => 334, 'icon' => 'amenity_police2'),
'amenity:bank' => array('label' => 'Bank', 'frequency' => 1248, 'icon' => 'money_bank2'),
'amenity:post_office' => array('label' => 'Post Office', 'frequency' => 859, 'icon' => 'amenity_post_office'),
'leisure:park' => array('label' => 'Park', 'frequency' => 2378),
'amenity:park' => array('label' => 'Park', 'frequency' => 53),
'landuse:park' => array('label' => 'Park', 'frequency' => 50),
'landuse:recreation_ground' => array('label' => 'Recreation Ground', 'frequency' => 517),
'tourism:hotel' => array('label' => 'Hotel', 'frequency' => 2150, 'icon' => 'accommodation_hotel2'),
'tourism:motel' => array('label' => 'Motel', 'frequency' => 43),
'amenity:cinema' => array('label' => 'Cinema', 'frequency' => 277, 'icon' => 'tourist_cinema'),
'tourism:artwork' => array('label' => 'Artwork', 'frequency' => 171, 'icon' => 'tourist_art_gallery2'),
'historic:archaeological_site' => array('label' => 'Archaeological Site', 'frequency' => 407, 'icon' => 'tourist_archaeological2'),
'amenity:doctors' => array('label' => 'Doctors', 'frequency' => 581, 'icon' => 'health_doctors'),
'leisure:sports_centre' => array('label' => 'Sports Centre', 'frequency' => 767, 'icon' => 'sport_leisure_centre'),
'leisure:swimming_pool' => array('label' => 'Swimming Pool', 'frequency' => 24, 'icon' => 'sport_swimming_outdoor'),
'shop:supermarket' => array('label' => 'Supermarket', 'frequency' => 2673, 'icon' => 'shopping_supermarket'),
'shop:convenience' => array('label' => 'Convenience', 'frequency' => 1469, 'icon' => 'shopping_convenience'),
'amenity:restaurant' => array('label' => 'Restaurant', 'frequency' => 3179, 'icon' => 'food_restaurant'),
'amenity:fast_food' => array('label' => 'Fast Food', 'frequency' => 2289, 'icon' => 'food_fastfood'),
'amenity:cafe' => array('label' => 'Cafe', 'frequency' => 1780, 'icon' => 'food_cafe'),
'tourism:guest_house' => array('label' => 'Guest House', 'frequency' => 223, 'icon' => 'accommodation_bed_and_breakfast'),
'amenity:pharmacy' => array('label' => 'Pharmacy', 'frequency' => 733, 'icon' => 'health_pharmacy_dispensing'),
'amenity:fuel' => array('label' => 'Fuel', 'frequency' => 1308, 'icon' => 'transport_fuel'),
'natural:peak' => array('label' => 'Peak', 'frequency' => 3212, 'icon' => 'poi_peak'),
'waterway:waterfall' => array('label' => 'Waterfall', 'frequency' => 24),
'natural:wood' => array('label' => 'Wood', 'frequency' => 1845, 'icon' => 'landuse_coniferous_and_deciduous'),
'natural:water' => array('label' => 'Water', 'frequency' => 1790),
'landuse:forest' => array('label' => 'Forest', 'frequency' => 467),
'landuse:cemetery' => array('label' => 'Cemetery', 'frequency' => 463),
'landuse:allotments' => array('label' => 'Allotments', 'frequency' => 408),
'landuse:farmyard' => array('label' => 'Farmyard', 'frequency' => 397),
'railway:rail' => array('label' => 'Rail', 'frequency' => 4894),
'waterway:canal' => array('label' => 'Canal', 'frequency' => 1723),
'waterway:river' => array('label' => 'River', 'frequency' => 4089),
'waterway:stream' => array('label' => 'Stream', 'frequency' => 2684),
'shop:bicycle' => array('label' => 'Bicycle', 'frequency' => 349, 'icon' => 'shopping_bicycle'),
'shop:clothes' => array('label' => 'Clothes', 'frequency' => 315, 'icon' => 'shopping_clothes'),
'shop:hairdresser' => array('label' => 'Hairdresser', 'frequency' => 312, 'icon' => 'shopping_hairdresser'),
'shop:doityourself' => array('label' => 'Doityourself', 'frequency' => 247, 'icon' => 'shopping_diy'),
'shop:estate_agent' => array('label' => 'Estate Agent', 'frequency' => 162, 'icon' => 'shopping_estateagent2'),
'shop:car' => array('label' => 'Car', 'frequency' => 159, 'icon' => 'shopping_car'),
'shop:garden_centre' => array('label' => 'Garden Centre', 'frequency' => 143, 'icon' => 'shopping_garden_centre'),
'shop:car_repair' => array('label' => 'Car Repair', 'frequency' => 141, 'icon' => 'shopping_car_repair'),
'shop:newsagent' => array('label' => 'Newsagent', 'frequency' => 132),
'shop:bakery' => array('label' => 'Bakery', 'frequency' => 129, 'icon' => 'shopping_bakery'),
'shop:furniture' => array('label' => 'Furniture', 'frequency' => 124),
'shop:butcher' => array('label' => 'Butcher', 'frequency' => 105, 'icon' => 'shopping_butcher'),
'shop:apparel' => array('label' => 'Apparel', 'frequency' => 98, 'icon' => 'shopping_clothes'),
'shop:electronics' => array('label' => 'Electronics', 'frequency' => 96),
'shop:department_store' => array('label' => 'Department Store', 'frequency' => 86),
'shop:books' => array('label' => 'Books', 'frequency' => 85),
'shop:yes' => array('label' => 'Shop', 'frequency' => 68),
'shop:outdoor' => array('label' => 'Outdoor', 'frequency' => 67),
'shop:mall' => array('label' => 'Mall', 'frequency' => 63),
'shop:florist' => array('label' => 'Florist', 'frequency' => 61),
'shop:charity' => array('label' => 'Charity', 'frequency' => 60),
'shop:hardware' => array('label' => 'Hardware', 'frequency' => 59),
'shop:laundry' => array('label' => 'Laundry', 'frequency' => 51, 'icon' => 'shopping_laundrette'),
'shop:shoes' => array('label' => 'Shoes', 'frequency' => 49),
'shop:beverages' => array('label' => 'Beverages', 'frequency' => 48, 'icon' => 'shopping_alcohol'),
'shop:dry_cleaning' => array('label' => 'Dry Cleaning', 'frequency' => 46),
'shop:carpet' => array('label' => 'Carpet', 'frequency' => 45),
'shop:computer' => array('label' => 'Computer', 'frequency' => 44),
'shop:alcohol' => array('label' => 'Alcohol', 'frequency' => 44, 'icon' => 'shopping_alcohol'),
'shop:optician' => array('label' => 'Optician', 'frequency' => 55, 'icon' => 'health_opticians'),
'shop:chemist' => array('label' => 'Chemist', 'frequency' => 42, 'icon' => 'health_pharmacy'),
'shop:gallery' => array('label' => 'Gallery', 'frequency' => 38, 'icon' => 'tourist_art_gallery2'),
'shop:mobile_phone' => array('label' => 'Mobile Phone', 'frequency' => 37),
'shop:sports' => array('label' => 'Sports', 'frequency' => 37),
'shop:jewelry' => array('label' => 'Jewelry', 'frequency' => 32, 'icon' => 'shopping_jewelry'),
'shop:pet' => array('label' => 'Pet', 'frequency' => 29),
'shop:beauty' => array('label' => 'Beauty', 'frequency' => 28),
'shop:stationery' => array('label' => 'Stationery', 'frequency' => 25),
'shop:shopping_centre' => array('label' => 'Shopping Centre', 'frequency' => 25),
'shop:general' => array('label' => 'General', 'frequency' => 25),
'shop:electrical' => array('label' => 'Electrical', 'frequency' => 25),
'shop:toys' => array('label' => 'Toys', 'frequency' => 23),
'shop:jeweller' => array('label' => 'Jeweller', 'frequency' => 23),
'shop:betting' => array('label' => 'Betting', 'frequency' => 23),
'shop:household' => array('label' => 'Household', 'frequency' => 21),
'shop:travel_agency' => array('label' => 'Travel Agency', 'frequency' => 21),
'shop:hifi' => array('label' => 'Hifi', 'frequency' => 21),
'amenity:shop' => array('label' => 'Shop', 'frequency' => 61),
'tourism:information' => array('label' => 'Information', 'frequency' => 224, 'icon' => 'amenity_information'),
'place:house' => array('label' => 'House', 'frequency' => 2086, 'defzoom' => 18),
'place:house_name' => array('label' => 'House', 'frequency' => 2086, 'defzoom' => 18),
'place:house_number' => array('label' => 'House Number', 'frequency' => 2086, 'defzoom' => 18),
'place:country_code' => array('label' => 'Country Code', 'frequency' => 2086, 'defzoom' => 18),
//
'leisure:pitch' => array('label' => 'Pitch', 'frequency' => 762),
'highway:unsurfaced' => array('label' => 'Unsurfaced', 'frequency' => 492),
'historic:ruins' => array('label' => 'Ruins', 'frequency' => 483, 'icon' => 'tourist_ruin'),
'amenity:college' => array('label' => 'College', 'frequency' => 473, 'icon' => 'education_school'),
'historic:monument' => array('label' => 'Monument', 'frequency' => 470, 'icon' => 'tourist_monument'),
'railway:subway' => array('label' => 'Subway', 'frequency' => 385),
'historic:memorial' => array('label' => 'Memorial', 'frequency' => 382, 'icon' => 'tourist_monument'),
'leisure:nature_reserve' => array('label' => 'Nature Reserve', 'frequency' => 342),
'leisure:common' => array('label' => 'Common', 'frequency' => 322),
'waterway:lock_gate' => array('label' => 'Lock Gate', 'frequency' => 321),
'natural:fell' => array('label' => 'Fell', 'frequency' => 308),
'amenity:nightclub' => array('label' => 'Nightclub', 'frequency' => 292),
'highway:path' => array('label' => 'Path', 'frequency' => 287),
'leisure:garden' => array('label' => 'Garden', 'frequency' => 285),
'landuse:reservoir' => array('label' => 'Reservoir', 'frequency' => 276),
'leisure:playground' => array('label' => 'Playground', 'frequency' => 264),
'leisure:stadium' => array('label' => 'Stadium', 'frequency' => 212),
'historic:mine' => array('label' => 'Mine', 'frequency' => 193, 'icon' => 'poi_mine'),
'natural:cliff' => array('label' => 'Cliff', 'frequency' => 193),
'tourism:caravan_site' => array('label' => 'Caravan Site', 'frequency' => 183, 'icon' => 'accommodation_caravan_park'),
'amenity:bus_station' => array('label' => 'Bus Station', 'frequency' => 181, 'icon' => 'transport_bus_station'),
'amenity:kindergarten' => array('label' => 'Kindergarten', 'frequency' => 179),
'highway:construction' => array('label' => 'Construction', 'frequency' => 176),
'amenity:atm' => array('label' => 'Atm', 'frequency' => 172, 'icon' => 'money_atm2'),
'amenity:emergency_phone' => array('label' => 'Emergency Phone', 'frequency' => 164),
'waterway:lock' => array('label' => 'Lock', 'frequency' => 146),
'waterway:riverbank' => array('label' => 'Riverbank', 'frequency' => 143),
'natural:coastline' => array('label' => 'Coastline', 'frequency' => 142),
'tourism:viewpoint' => array('label' => 'Viewpoint', 'frequency' => 140, 'icon' => 'tourist_view_point'),
'tourism:hostel' => array('label' => 'Hostel', 'frequency' => 140),
'tourism:bed_and_breakfast' => array('label' => 'Bed And Breakfast', 'frequency' => 140, 'icon' => 'accommodation_bed_and_breakfast'),
'railway:halt' => array('label' => 'Halt', 'frequency' => 135),
'railway:platform' => array('label' => 'Platform', 'frequency' => 134),
'railway:tram' => array('label' => 'Tram', 'frequency' => 130, 'icon' => 'transport_tram_stop'),
'amenity:courthouse' => array('label' => 'Courthouse', 'frequency' => 129, 'icon' => 'amenity_court'),
'amenity:recycling' => array('label' => 'Recycling', 'frequency' => 126, 'icon' => 'amenity_recycling'),
'amenity:dentist' => array('label' => 'Dentist', 'frequency' => 124, 'icon' => 'health_dentist'),
'natural:beach' => array('label' => 'Beach', 'frequency' => 121, 'icon' => 'tourist_beach'),
'place:moor' => array('label' => 'Moor', 'frequency' => 118),
'amenity:grave_yard' => array('label' => 'Grave Yard', 'frequency' => 110),
'waterway:drain' => array('label' => 'Drain', 'frequency' => 108),
'landuse:grass' => array('label' => 'Grass', 'frequency' => 106),
'landuse:village_green' => array('label' => 'Village Green', 'frequency' => 106),
'natural:bay' => array('label' => 'Bay', 'frequency' => 102),
'railway:tram_stop' => array('label' => 'Tram Stop', 'frequency' => 101, 'icon' => 'transport_tram_stop'),
'leisure:marina' => array('label' => 'Marina', 'frequency' => 98),
'highway:stile' => array('label' => 'Stile', 'frequency' => 97),
'natural:moor' => array('label' => 'Moor', 'frequency' => 95),
'railway:light_rail' => array('label' => 'Light Rail', 'frequency' => 91),
'railway:narrow_gauge' => array('label' => 'Narrow Gauge', 'frequency' => 90),
'natural:land' => array('label' => 'Land', 'frequency' => 86),
'amenity:village_hall' => array('label' => 'Village Hall', 'frequency' => 82),
'waterway:dock' => array('label' => 'Dock', 'frequency' => 80),
'amenity:veterinary' => array('label' => 'Veterinary', 'frequency' => 79),
'landuse:brownfield' => array('label' => 'Brownfield', 'frequency' => 77),
'leisure:track' => array('label' => 'Track', 'frequency' => 76),
'railway:historic_station' => array('label' => 'Historic Station', 'frequency' => 74),
'landuse:construction' => array('label' => 'Construction', 'frequency' => 72),
'amenity:prison' => array('label' => 'Prison', 'frequency' => 71, 'icon' => 'amenity_prison'),
'landuse:quarry' => array('label' => 'Quarry', 'frequency' => 71),
'amenity:telephone' => array('label' => 'Telephone', 'frequency' => 70),
'highway:traffic_signals' => array('label' => 'Traffic Signals', 'frequency' => 66),
'natural:heath' => array('label' => 'Heath', 'frequency' => 62),
'historic:house' => array('label' => 'House', 'frequency' => 61),
'amenity:social_club' => array('label' => 'Social Club', 'frequency' => 61),
'landuse:military' => array('label' => 'Military', 'frequency' => 61),
'amenity:health_centre' => array('label' => 'Health Centre', 'frequency' => 59),
'historic:building' => array('label' => 'Building', 'frequency' => 58),
'amenity:clinic' => array('label' => 'Clinic', 'frequency' => 57),
'highway:services' => array('label' => 'Services', 'frequency' => 56),
'amenity:ferry_terminal' => array('label' => 'Ferry Terminal', 'frequency' => 55),
'natural:marsh' => array('label' => 'Marsh', 'frequency' => 55),
'natural:hill' => array('label' => 'Hill', 'frequency' => 54),
'highway:raceway' => array('label' => 'Raceway', 'frequency' => 53),
'amenity:taxi' => array('label' => 'Taxi', 'frequency' => 47),
'amenity:take_away' => array('label' => 'Take Away', 'frequency' => 45),
'amenity:car_rental' => array('label' => 'Car Rental', 'frequency' => 44),
'place:islet' => array('label' => 'Islet', 'frequency' => 44),
'amenity:nursery' => array('label' => 'Nursery', 'frequency' => 44),
'amenity:nursing_home' => array('label' => 'Nursing Home', 'frequency' => 43),
'amenity:toilets' => array('label' => 'Toilets', 'frequency' => 38),
'amenity:hall' => array('label' => 'Hall', 'frequency' => 38),
'waterway:boatyard' => array('label' => 'Boatyard', 'frequency' => 36),
'highway:mini_roundabout' => array('label' => 'Mini Roundabout', 'frequency' => 35),
'historic:manor' => array('label' => 'Manor', 'frequency' => 35),
'tourism:chalet' => array('label' => 'Chalet', 'frequency' => 34),
'amenity:bicycle_parking' => array('label' => 'Bicycle Parking', 'frequency' => 34),
'amenity:hotel' => array('label' => 'Hotel', 'frequency' => 34),
'waterway:weir' => array('label' => 'Weir', 'frequency' => 33),
'natural:wetland' => array('label' => 'Wetland', 'frequency' => 33),
'natural:cave_entrance' => array('label' => 'Cave Entrance', 'frequency' => 32),
'amenity:crematorium' => array('label' => 'Crematorium', 'frequency' => 31),
'tourism:picnic_site' => array('label' => 'Picnic Site', 'frequency' => 31),
'landuse:wood' => array('label' => 'Wood', 'frequency' => 30),
'landuse:basin' => array('label' => 'Basin', 'frequency' => 30),
'natural:tree' => array('label' => 'Tree', 'frequency' => 30),
'leisure:slipway' => array('label' => 'Slipway', 'frequency' => 29),
'landuse:meadow' => array('label' => 'Meadow', 'frequency' => 29),
'landuse:piste' => array('label' => 'Piste', 'frequency' => 28),
'amenity:care_home' => array('label' => 'Care Home', 'frequency' => 28),
'amenity:club' => array('label' => 'Club', 'frequency' => 28),
'amenity:medical_centre' => array('label' => 'Medical Centre', 'frequency' => 27),
'historic:roman_road' => array('label' => 'Roman Road', 'frequency' => 27),
'historic:fort' => array('label' => 'Fort', 'frequency' => 26),
'railway:subway_entrance' => array('label' => 'Subway Entrance', 'frequency' => 26),
'historic:yes' => array('label' => 'Historic', 'frequency' => 25),
'highway:gate' => array('label' => 'Gate', 'frequency' => 25),
'leisure:fishing' => array('label' => 'Fishing', 'frequency' => 24),
'historic:museum' => array('label' => 'Museum', 'frequency' => 24),
'amenity:car_wash' => array('label' => 'Car Wash', 'frequency' => 24),
'railway:level_crossing' => array('label' => 'Level Crossing', 'frequency' => 23),
'leisure:bird_hide' => array('label' => 'Bird Hide', 'frequency' => 23),
'natural:headland' => array('label' => 'Headland', 'frequency' => 21),
'tourism:apartments' => array('label' => 'Apartments', 'frequency' => 21),
'amenity:shopping' => array('label' => 'Shopping', 'frequency' => 21),
'natural:scrub' => array('label' => 'Scrub', 'frequency' => 20),
'natural:fen' => array('label' => 'Fen', 'frequency' => 20),
'building:yes' => array('label' => 'Building', 'frequency' => 200),
'mountain_pass:yes' => array('label' => 'Mountain Pass', 'frequency' => 200),
'amenity:parking' => array('label' => 'Parking', 'frequency' => 3157),
'highway:bus_stop' => array('label' => 'Bus Stop', 'frequency' => 35777, 'icon' => 'transport_bus_stop2'),
'place:postcode' => array('label' => 'Postcode', 'frequency' => 27267),
'amenity:post_box' => array('label' => 'Post Box', 'frequency' => 9613),
'place:houses' => array('label' => 'Houses', 'frequency' => 85),
'railway:preserved' => array('label' => 'Preserved', 'frequency' => 227),
'waterway:derelict_canal' => array('label' => 'Derelict Canal', 'frequency' => 21),
'amenity:dead_pub' => array('label' => 'Dead Pub', 'frequency' => 20),
'railway:disused_station' => array('label' => 'Disused Station', 'frequency' => 114),
'railway:abandoned' => array('label' => 'Abandoned', 'frequency' => 641),
'railway:disused' => array('label' => 'Disused', 'frequency' => 72),
);
}

180
lib/DebugHtml.php Normal file
View File

@@ -0,0 +1,180 @@
<?php
namespace Nominatim;
class Debug
{
public static function newFunction($sHeading)
{
echo "<pre><h2>Debug output for $sHeading</h2></pre>\n";
}
public static function newSection($sHeading)
{
echo "<hr><pre><h3>$sHeading</h3></pre>\n";
}
public static function printVar($sHeading, $mVar)
{
echo '<pre><b>'.$sHeading. ':</b> ';
Debug::outputVar($mVar, str_repeat(' ', strlen($sHeading) + 3));
echo "</pre>\n";
}
public static function fmtArrayVals($aArr)
{
return array('__debug_format' => 'array_vals', 'data' => $aArr);
}
public static function printDebugArray($sHeading, $oVar)
{
if ($oVar === null) {
Debug::printVar($sHeading, 'null');
} else {
Debug::printVar($sHeading, $oVar->debugInfo());
}
}
public static function printDebugTable($sHeading, $aVar)
{
echo '<b>'.$sHeading.":</b>\n";
echo "<table border='1'>\n";
if (!empty($aVar)) {
echo " <tr>\n";
$aKeys = array();
$aInfo = reset($aVar);
if (!is_array($aInfo)) {
$aInfo = $aInfo->debugInfo();
}
foreach ($aInfo as $sKey => $mVal) {
echo ' <th><small>'.$sKey.'</small></th>'."\n";
$aKeys[] = $sKey;
}
echo " </tr>\n";
foreach ($aVar as $oRow) {
$aInfo = $oRow;
if (!is_array($oRow)) {
$aInfo = $oRow->debugInfo();
}
echo " <tr>\n";
foreach ($aKeys as $sKey) {
echo ' <td><pre>';
if (isset($aInfo[$sKey])) {
Debug::outputVar($aInfo[$sKey], '');
}
echo '</pre></td>'."\n";
}
echo " </tr>\n";
}
}
echo "</table>\n";
}
public static function printGroupedSearch($aSearches, $aWordsIDs)
{
echo '<table border="1">';
echo '<tr><th>rank</th><th>Name Tokens</th><th>Name Not</th>';
echo '<th>Address Tokens</th><th>Address Not</th>';
echo '<th>country</th><th>operator</th>';
echo '<th>class</th><th>type</th><th>postcode</th><th>housenumber</th></tr>';
foreach ($aSearches as $iRank => $aRankedSet) {
foreach ($aRankedSet as $aRow) {
$aRow->dumpAsHtmlTableRow($aWordsIDs);
}
}
echo '</table>';
}
public static function printGroupTable($sHeading, $aVar)
{
echo '<b>'.$sHeading.":</b>\n";
echo "<table border='1'>\n";
if (!empty($aVar)) {
echo " <tr>\n";
echo ' <th><small>Group</small></th>'."\n";
$aKeys = array();
$aInfo = reset($aVar)[0];
if (!is_array($aInfo)) {
$aInfo = $aInfo->debugInfo();
}
foreach ($aInfo as $sKey => $mVal) {
echo ' <th><small>'.$sKey.'</small></th>'."\n";
$aKeys[] = $sKey;
}
echo " </tr>\n";
foreach ($aVar as $sGrpKey => $aGroup) {
foreach ($aGroup as $oRow) {
$aInfo = $oRow;
if (!is_array($oRow)) {
$aInfo = $oRow->debugInfo();
}
echo " <tr>\n";
echo ' <td><pre>'.$sGrpKey.'</pre></td>'."\n";
foreach ($aKeys as $sKey) {
echo ' <td><pre>';
if (!empty($aInfo[$sKey])) {
Debug::outputVar($aInfo[$sKey], '');
}
echo '</pre></td>'."\n";
}
echo " </tr>\n";
}
}
}
echo "</table>\n";
}
public static function printSQL($sSQL)
{
echo '<p><tt><font color="#aaa">'.$sSQL.'</font></tt></p>'."\n";
}
private static function outputVar($mVar, $sPreNL)
{
if (is_array($mVar) && !isset($mVar['__debug_format'])) {
$sPre = '';
foreach ($mVar as $mKey => $aValue) {
echo $sPre;
$iKeyLen = Debug::outputSimpleVar($mKey);
echo ' => ';
Debug::outputVar(
$aValue,
$sPreNL.str_repeat(' ', $iKeyLen + 4)
);
$sPre = "\n".$sPreNL;
}
} elseif (is_array($mVar) && isset($mVar['__debug_format'])) {
if (!empty($mVar['data'])) {
$sPre = '';
foreach ($mVar['data'] as $mValue) {
echo $sPre;
Debug::outputSimpleVar($mValue);
$sPre = ', ';
}
}
} elseif (is_object($mVar) && method_exists($mVar, 'debugInfo')) {
Debug::outputVar($mVar->debugInfo(), $sPreNL);
} elseif (is_a($mVar, 'stdClass')) {
Debug::outputVar(json_decode(json_encode($mVar), true), $sPreNL);
} else {
Debug::outputSimpleVar($mVar);
}
}
private static function outputSimpleVar($mVar)
{
if (is_bool($mVar)) {
echo '<i>'.($mVar ? 'True' : 'False').'</i>';
return $mVar ? 4 : 5;
}
if (is_string($mVar)) {
echo "'$mVar'";
return strlen($mVar) + 2;
}
echo (string)$mVar;
return strlen((string)$mVar);
}
}

11
lib/DebugNone.php Normal file
View File

@@ -0,0 +1,11 @@
<?php
namespace Nominatim;
class Debug
{
public static function __callStatic($name, $arguments)
{
// nothing
}
}

File diff suppressed because it is too large Load Diff

121
lib/ParameterParser.php Normal file
View File

@@ -0,0 +1,121 @@
<?php
namespace Nominatim;
class ParameterParser
{
private $aParams;
public function __construct($aParams = null)
{
$this->aParams = ($aParams === null) ? $_GET : $aParams;
}
public function getBool($sName, $bDefault = false)
{
if (!isset($this->aParams[$sName]) || strlen($this->aParams[$sName]) == 0) {
return $bDefault;
}
return (bool) $this->aParams[$sName];
}
public function getInt($sName, $bDefault = false)
{
if (!isset($this->aParams[$sName])) {
return $bDefault;
}
if (!preg_match('/^[+-]?[0-9]+$/', $this->aParams[$sName])) {
userError("Integer number expected for parameter '$sName'");
}
return (int) $this->aParams[$sName];
}
public function getFloat($sName, $bDefault = false)
{
if (!isset($this->aParams[$sName])) {
return $bDefault;
}
if (!preg_match('/^[+-]?[0-9]*\.?[0-9]+$/', $this->aParams[$sName])) {
userError("Floating-point number expected for parameter '$sName'");
}
return (float) $this->aParams[$sName];
}
public function getString($sName, $bDefault = false)
{
if (!isset($this->aParams[$sName]) || strlen($this->aParams[$sName]) == 0) {
return $bDefault;
}
return $this->aParams[$sName];
}
public function getSet($sName, $aValues, $sDefault = false)
{
if (!isset($this->aParams[$sName]) || strlen($this->aParams[$sName]) == 0) {
return $sDefault;
}
if (!in_array($this->aParams[$sName], $aValues)) {
userError("Parameter '$sName' must be one of: ".join(', ', $aValues));
}
return $this->aParams[$sName];
}
public function getStringList($sName, $aDefault = false)
{
$sValue = $this->getString($sName);
if ($sValue) {
// removes all NULL, FALSE and Empty Strings but leaves 0 (zero) values
return array_values(array_filter(explode(',', $sValue), 'strlen'));
}
return $aDefault;
}
public function getPreferredLanguages($sFallback = null)
{
if ($sFallback === null && isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$sFallback = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
}
$aLanguages = array();
$sLangString = $this->getString('accept-language', $sFallback);
if ($sLangString) {
if (preg_match_all('/(([a-z]{1,8})(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $sLangString, $aLanguagesParse, PREG_SET_ORDER)) {
foreach ($aLanguagesParse as $iLang => $aLanguage) {
$aLanguages[$aLanguage[1]] = isset($aLanguage[5])?(float)$aLanguage[5]:1 - ($iLang/100);
if (!isset($aLanguages[$aLanguage[2]])) $aLanguages[$aLanguage[2]] = $aLanguages[$aLanguage[1]]/10;
}
arsort($aLanguages);
}
}
if (empty($aLanguages) && CONST_Default_Language) {
$aLanguages[CONST_Default_Language] = 1;
}
foreach ($aLanguages as $sLanguage => $fLanguagePref) {
$aLangPrefOrder['short_name:'.$sLanguage] = 'short_name:'.$sLanguage;
$aLangPrefOrder['name:'.$sLanguage] = 'name:'.$sLanguage;
}
$aLangPrefOrder['short_name'] = 'short_name';
$aLangPrefOrder['name'] = 'name';
$aLangPrefOrder['brand'] = 'brand';
foreach ($aLanguages as $sLanguage => $fLanguagePref) {
$aLangPrefOrder['official_name:'.$sLanguage] = 'official_name:'.$sLanguage;
}
$aLangPrefOrder['official_name'] = 'official_name';
$aLangPrefOrder['ref'] = 'ref';
$aLangPrefOrder['type'] = 'type';
return $aLangPrefOrder;
}
}

126
lib/Phrase.php Normal file
View File

@@ -0,0 +1,126 @@
<?php
namespace Nominatim;
/**
* Segment of a query string.
*
* The parts of a query strings are usually separated by commas.
*/
class Phrase
{
const MAX_DEPTH = 7;
// Complete phrase as a string.
private $sPhrase;
// Element type for structured searches.
private $sPhraseType;
// Space-separated words of the phrase.
private $aWords;
// Possible segmentations of the phrase.
private $aWordSets;
public function __construct($sPhrase, $sPhraseType)
{
$this->sPhrase = trim($sPhrase);
$this->sPhraseType = $sPhraseType;
$this->aWords = explode(' ', $this->sPhrase);
$this->aWordSets = $this->createWordSets($this->aWords, 0);
}
/**
* Return the element type of the phrase.
*
* @return string Pharse type if the phrase comes from a structured query
* or empty string otherwise.
*/
public function getPhraseType()
{
return $this->sPhraseType;
}
/**
* Return the array of possible segmentations of the phrase.
*
* @return string[][] Array of segmentations, each consisting of an
* array of terms.
*/
public function getWordSets()
{
return $this->aWordSets;
}
/**
* Add the tokens from this phrase to the given list of tokens.
*
* @param string[] $aTokens List of tokens to append.
*
* @return void
*/
public function addTokens(&$aTokens)
{
foreach ($this->aWordSets as $aSet) {
foreach ($aSet as $sWord) {
$aTokens[' '.$sWord] = ' '.$sWord;
$aTokens[$sWord] = $sWord;
}
}
}
/**
* Invert the set of possible segmentations.
*
* @return void
*/
public function invertWordSets()
{
$this->aWordSets = $this->createInverseWordSets($this->aWords, 0);
}
private function createWordSets($aWords, $iDepth)
{
$aResult = array(array(join(' ', $aWords)));
$sFirstToken = '';
if ($iDepth < Phrase::MAX_DEPTH) {
while (count($aWords) > 1) {
$sWord = array_shift($aWords);
$sFirstToken .= ($sFirstToken?' ':'').$sWord;
$aRest = $this->createWordSets($aWords, $iDepth + 1);
foreach ($aRest as $aSet) {
$aResult[] = array_merge(array($sFirstToken), $aSet);
}
}
}
return $aResult;
}
private function createInverseWordSets($aWords, $iDepth)
{
$aResult = array(array(join(' ', $aWords)));
$sFirstToken = '';
if ($iDepth < Phrase::MAX_DEPTH) {
while (count($aWords) > 1) {
$sWord = array_pop($aWords);
$sFirstToken = $sWord.($sFirstToken?' ':'').$sFirstToken;
$aRest = $this->createInverseWordSets($aWords, $iDepth + 1);
foreach ($aRest as $aSet) {
$aResult[] = array_merge(array($sFirstToken), $aSet);
}
}
}
return $aResult;
}
public function debugInfo()
{
return array(
'Type' => $this->sPhraseType,
'Phrase' => $this->sPhrase,
'Words' => $this->aWords,
'WordSets' => $this->aWordSets
);
}
}

View File

@@ -1,223 +1,573 @@
<?php
class PlaceLookup
{
protected $oDB;
protected $iPlaceID;
namespace Nominatim;
protected $sType = false;
require_once(CONST_BasePath.'/lib/AddressDetails.php');
require_once(CONST_BasePath.'/lib/Result.php');
protected $aLangPrefOrder = array();
class PlaceLookup
{
protected $oDB;
protected $bAddressDetails = false;
protected $aLangPrefOrderSql = "''";
protected $bExtraTags = false;
protected $bAddressDetails = false;
protected $bExtraTags = false;
protected $bNameDetails = false;
protected $bNameDetails = false;
protected $bIncludePolygonAsPoints = false;
protected $bIncludePolygonAsText = false;
protected $bIncludePolygonAsGeoJSON = false;
protected $bIncludePolygonAsKML = false;
protected $bIncludePolygonAsSVG = false;
protected $fPolygonSimplificationThreshold = 0.0;
function PlaceLookup(&$oDB)
{
$this->oDB =& $oDB;
}
function setLanguagePreference($aLangPrefOrder)
{
$this->aLangPrefOrder = $aLangPrefOrder;
}
function setIncludeAddressDetails($bAddressDetails = true)
{
$this->bAddressDetails = $bAddressDetails;
}
function setIncludeExtraTags($bExtraTags = false)
{
if ((float) CONST_Postgresql_Version > 9.2)
{
$this->bExtraTags = $bExtraTags;
}
}
function setIncludeNameDetails($bNameDetails = false)
{
if ((float) CONST_Postgresql_Version > 9.2)
{
$this->bNameDetails = $bNameDetails;
}
}
function setPlaceID($iPlaceID)
{
$this->iPlaceID = $iPlaceID;
}
function setOSMID($sType, $iID)
{
$sSQL = "select place_id from placex where osm_type = '".pg_escape_string($sType)."' and osm_id = ".(int)$iID." order by type = 'postcode' asc";
$this->iPlaceID = $this->oDB->getOne($sSQL);
}
function lookupPlace($details)
{
if (isset($details['place_id'])) $this->iPlaceID = $details['place_id'];
if (isset($details['type'])) $this->sType = $details['type'];
if (isset($details['osm_type']) && isset($details['osm_id']))
{
$this->setOSMID($details['osm_type'], $details['osm_id']);
}
return $this->lookup();
}
function lookup()
{
if (!$this->iPlaceID) return null;
$sLanguagePrefArraySQL = "ARRAY[".join(',',array_map("getDBQuoted", $this->aLangPrefOrder))."]";
if ($this->sType == 'tiger')
{
$sSQL = "select place_id,partition, 'T' as osm_type, place_id as osm_id, 'place' as class, 'house' as type, null as admin_level, housenumber, null as street, null as isin, postcode,";
$sSQL .= " 'us' as country_code, parent_place_id, null as linked_place_id, 30 as rank_address, 30 as rank_search,";
$sSQL .= " coalesce(null,0.75-(30::float/40)) as importance, null as indexed_status, null as indexed_date, null as wikipedia, 'us' as calculated_country_code, ";
$sSQL .= " get_address_by_language(place_id, $sLanguagePrefArraySQL) as langaddress,";
$sSQL .= " null as placename,";
$sSQL .= " null as ref,";
if ($this->bExtraTags) $sSQL .= " null as extra,";
if ($this->bNameDetails) $sSQL .= " null as names,";
$sSQL .= " st_y(centroid) as lat,";
$sSQL .= " st_x(centroid) as lon";
$sSQL .= " from location_property_tiger where place_id = ".(int)$this->iPlaceID;
}
else
{
$sSQL = "select placex.place_id, partition, osm_type, osm_id, class, type, admin_level, housenumber, street, isin, postcode, country_code, parent_place_id, linked_place_id, rank_address, rank_search, ";
$sSQL .= " coalesce(importance,0.75-(rank_search::float/40)) as importance, indexed_status, indexed_date, wikipedia, calculated_country_code, ";
$sSQL .= " get_address_by_language(place_id, $sLanguagePrefArraySQL) as langaddress,";
$sSQL .= " get_name_by_language(name, $sLanguagePrefArraySQL) as placename,";
$sSQL .= " get_name_by_language(name, ARRAY['ref']) as ref,";
if ($this->bExtraTags) $sSQL .= " hstore_to_json(extratags) as extra,";
if ($this->bNameDetails) $sSQL .= " hstore_to_json(name) as names,";
$sSQL .= " (case when centroid is null then st_y(st_centroid(geometry)) else st_y(centroid) end) as lat,";
$sSQL .= " (case when centroid is null then st_x(st_centroid(geometry)) else st_x(centroid) end) as lon";
$sSQL .= " from placex where place_id = ".(int)$this->iPlaceID;
}
$aPlace = $this->oDB->getRow($sSQL);
protected $sAnchorSql = null;
protected $sAddressRankListSql = null;
protected $sAllowedTypesSQLList = null;
protected $bDeDupe = true;
if (PEAR::IsError($aPlace))
{
failInternalError("Could not lookup place.", $sSQL, $aPlace);
}
public function __construct(&$oDB)
{
$this->oDB =& $oDB;
}
if (!$aPlace['place_id']) return null;
public function doDeDupe()
{
return $this->bDeDupe;
}
if ($this->bAddressDetails)
{
$aAddress = $this->getAddressNames();
$aPlace['aAddress'] = $aAddress;
}
public function setIncludePolygonAsPoints($b = true)
{
$this->bIncludePolygonAsPoints = $b;
}
if ($this->bExtraTags)
{
if ($aPlace['extra'])
{
$aPlace['sExtraTags'] = json_decode($aPlace['extra']);
}
else
{
$aPlace['sExtraTags'] = (object) array();
}
}
public function setIncludeAddressDetails($b)
{
$this->bAddressDetails = $b;
}
if ($this->bNameDetails)
{
if ($aPlace['names'])
{
$aPlace['sNameDetails'] = json_decode($aPlace['names']);
}
else
{
$aPlace['sNameDetails'] = (object) array();
}
}
public function loadParamArray($oParams, $sGeomType = null)
{
$aLangs = $oParams->getPreferredLanguages();
$this->aLangPrefOrderSql =
'ARRAY['.join(',', array_map('getDBQuoted', $aLangs)).']';
$aClassType = getClassTypes();
$sAddressType = '';
$sClassType = $aPlace['class'].':'.$aPlace['type'].':'.$aPlace['admin_level'];
if (isset($aClassType[$sClassType]) && isset($aClassType[$sClassType]['simplelabel']))
{
$sAddressType = $aClassType[$aClassType]['simplelabel'];
}
else
{
$sClassType = $aPlace['class'].':'.$aPlace['type'];
if (isset($aClassType[$sClassType]) && isset($aClassType[$sClassType]['simplelabel']))
$sAddressType = $aClassType[$sClassType]['simplelabel'];
else $sAddressType = $aPlace['class'];
}
$this->bExtraTags = $oParams->getBool('extratags', false);
$this->bNameDetails = $oParams->getBool('namedetails', false);
$aPlace['addresstype'] = $sAddressType;
$this->bDeDupe = $oParams->getBool('dedupe', $this->bDeDupe);
return $aPlace;
}
if ($sGeomType === null || $sGeomType == 'geojson') {
$this->bIncludePolygonAsGeoJSON = $oParams->getBool('polygon_geojson');
$this->bIncludePolygonAsPoints = false;
}
function getAddressDetails($bAll = false)
{
if (!$this->iPlaceID) return null;
if ($oParams->getString('format', '') !== 'geojson') {
if ($sGeomType === null || $sGeomType == 'text') {
$this->bIncludePolygonAsText = $oParams->getBool('polygon_text');
}
if ($sGeomType === null || $sGeomType == 'kml') {
$this->bIncludePolygonAsKML = $oParams->getBool('polygon_kml');
}
if ($sGeomType === null || $sGeomType == 'svg') {
$this->bIncludePolygonAsSVG = $oParams->getBool('polygon_svg');
}
}
$this->fPolygonSimplificationThreshold
= $oParams->getFloat('polygon_threshold', 0.0);
$sLanguagePrefArraySQL = "ARRAY[".join(',',array_map("getDBQuoted", $this->aLangPrefOrder))."]";
$iWantedTypes =
($this->bIncludePolygonAsText ? 1 : 0) +
($this->bIncludePolygonAsGeoJSON ? 1 : 0) +
($this->bIncludePolygonAsKML ? 1 : 0) +
($this->bIncludePolygonAsSVG ? 1 : 0);
if ($iWantedTypes > CONST_PolygonOutput_MaximumTypes) {
if (CONST_PolygonOutput_MaximumTypes) {
userError('Select only '.CONST_PolygonOutput_MaximumTypes.' polgyon output option');
} else {
userError('Polygon output is disabled');
}
}
}
$sSQL = "select *,get_name_by_language(name,$sLanguagePrefArraySQL) as localname from get_addressdata(".$this->iPlaceID.")";
if (!$bAll) $sSQL .= " WHERE isaddress OR type = 'country_code'";
$sSQL .= " order by rank_address desc,isaddress desc";
public function getMoreUrlParams()
{
$aParams = array();
$aAddressLines = $this->oDB->getAll($sSQL);
if (PEAR::IsError($aAddressLines))
{
var_dump($aAddressLines);
exit;
}
return $aAddressLines;
}
if ($this->bAddressDetails) $aParams['addressdetails'] = '1';
if ($this->bExtraTags) $aParams['extratags'] = '1';
if ($this->bNameDetails) $aParams['namedetails'] = '1';
function getAddressNames()
{
$aAddressLines = $this->getAddressDetails(false);
if ($this->bIncludePolygonAsPoints) $aParams['polygon'] = '1';
if ($this->bIncludePolygonAsText) $aParams['polygon_text'] = '1';
if ($this->bIncludePolygonAsGeoJSON) $aParams['polygon_geojson'] = '1';
if ($this->bIncludePolygonAsKML) $aParams['polygon_kml'] = '1';
if ($this->bIncludePolygonAsSVG) $aParams['polygon_svg'] = '1';
$aAddress = array();
$aFallback = array();
$aClassType = getClassTypes();
foreach($aAddressLines as $aLine)
{
$bFallback = false;
$aTypeLabel = false;
if (isset($aClassType[$aLine['class'].':'.$aLine['type'].':'.$aLine['admin_level']])) $aTypeLabel = $aClassType[$aLine['class'].':'.$aLine['type'].':'.$aLine['admin_level']];
elseif (isset($aClassType[$aLine['class'].':'.$aLine['type']])) $aTypeLabel = $aClassType[$aLine['class'].':'.$aLine['type']];
elseif (isset($aClassType['boundary:administrative:'.((int)($aLine['rank_address']/2))]))
{
$aTypeLabel = $aClassType['boundary:administrative:'.((int)($aLine['rank_address']/2))];
$bFallback = true;
}
else
{
$aTypeLabel = array('simplelabel'=>'address'.$aLine['rank_address']);
$bFallback = true;
}
if ($aTypeLabel && ((isset($aLine['localname']) && $aLine['localname']) || (isset($aLine['housenumber']) && $aLine['housenumber'])))
{
$sTypeLabel = strtolower(isset($aTypeLabel['simplelabel'])?$aTypeLabel['simplelabel']:$aTypeLabel['label']);
$sTypeLabel = str_replace(' ','_',$sTypeLabel);
if (!isset($aAddress[$sTypeLabel]) || (isset($aFallback[$sTypeLabel]) && $aFallback[$sTypeLabel]) || $aLine['class'] == 'place')
{
$aAddress[$sTypeLabel] = $aLine['localname']?$aLine['localname']:$aLine['housenumber'];
}
$aFallback[$sTypeLabel] = $bFallback;
}
}
return $aAddress;
}
if ($this->fPolygonSimplificationThreshold > 0.0) {
$aParams['polygon_threshold'] = $this->fPolygonSimplificationThreshold;
}
}
?>
if (!$this->bDeDupe) $aParams['dedupe'] = '0';
return $aParams;
}
public function setAnchorSql($sPoint)
{
$this->sAnchorSql = $sPoint;
}
public function setAddressRankList($aList)
{
$this->sAddressRankListSql = '('.join(',', $aList).')';
}
public function setAllowedTypesSQLList($sSql)
{
$this->sAllowedTypesSQLList = $sSql;
}
public function setLanguagePreference($aLangPrefOrder)
{
$this->aLangPrefOrderSql =
'ARRAY['.join(',', array_map('getDBQuoted', $aLangPrefOrder)).']';
}
private function addressImportanceSql($sGeometry, $sPlaceId)
{
if ($this->sAnchorSql) {
$sSQL = 'ST_Distance('.$this->sAnchorSql.','.$sGeometry.')';
} else {
$sSQL = '(SELECT max(ai_p.importance * (ai_p.rank_address + 2))';
$sSQL .= ' FROM place_addressline ai_s, placex ai_p';
$sSQL .= ' WHERE ai_s.place_id = '.$sPlaceId;
$sSQL .= ' AND ai_p.place_id = ai_s.address_place_id ';
$sSQL .= ' AND ai_s.isaddress ';
$sSQL .= ' AND ai_p.importance is not null)';
}
return $sSQL.' AS addressimportance,';
}
private function langAddressSql($sHousenumber)
{
if ($this->bAddressDetails)
return ''; // langaddress will be computed from address details
return 'get_address_by_language(place_id,'.$sHousenumber.','.$this->aLangPrefOrderSql.') AS langaddress,';
}
public function lookupOSMID($sType, $iID)
{
$sSQL = "select place_id from placex where osm_type = '".$sType."' and osm_id = ".$iID;
$iPlaceID = chksql($this->oDB->getOne($sSQL));
if (!$iPlaceID) {
return null;
}
$aResults = $this->lookup(array($iPlaceID => new Result($iPlaceID)));
return empty($aResults) ? null : reset($aResults);
}
public function lookup($aResults, $iMinRank = 0, $iMaxRank = 30)
{
Debug::newFunction('Place lookup');
if (empty($aResults)) {
return array();
}
$aSubSelects = array();
$sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_PLACEX);
if ($sPlaceIDs) {
Debug::printVar('Ids from placex', $sPlaceIDs);
$sSQL = 'SELECT ';
$sSQL .= ' osm_type,';
$sSQL .= ' osm_id,';
$sSQL .= ' class,';
$sSQL .= ' type,';
$sSQL .= ' admin_level,';
$sSQL .= ' rank_search,';
$sSQL .= ' rank_address,';
$sSQL .= ' min(place_id) AS place_id,';
$sSQL .= ' min(parent_place_id) AS parent_place_id,';
$sSQL .= ' -1 as housenumber,';
$sSQL .= ' country_code,';
$sSQL .= $this->langAddressSql('-1');
$sSQL .= ' get_name_by_language(name,'.$this->aLangPrefOrderSql.') AS placename,';
$sSQL .= " get_name_by_language(name, ARRAY['ref']) AS ref,";
if ($this->bExtraTags) {
$sSQL .= 'hstore_to_json(extratags)::text AS extra,';
}
if ($this->bNameDetails) {
$sSQL .= 'hstore_to_json(name)::text AS names,';
}
$sSQL .= ' avg(ST_X(centroid)) AS lon, ';
$sSQL .= ' avg(ST_Y(centroid)) AS lat, ';
$sSQL .= ' COALESCE(importance,0.75-(rank_search::float/40)) AS importance, ';
$sSQL .= $this->addressImportanceSql(
'ST_Collect(centroid)',
'min(CASE WHEN placex.rank_search < 28 THEN placex.place_id ELSE placex.parent_place_id END)'
);
$sSQL .= " (extratags->'place') AS extra_place ";
$sSQL .= ' FROM placex';
$sSQL .= " WHERE place_id in ($sPlaceIDs) ";
$sSQL .= ' AND (';
$sSQL .= " placex.rank_address between $iMinRank and $iMaxRank ";
if (14 >= $iMinRank && 14 <= $iMaxRank) {
$sSQL .= " OR (extratags->'place') = 'city'";
}
if ($this->sAddressRankListSql) {
$sSQL .= ' OR placex.rank_address in '.$this->sAddressRankListSql;
}
$sSQL .= ' ) ';
if ($this->sAllowedTypesSQLList) {
$sSQL .= 'AND placex.class in '.$this->sAllowedTypesSQLList;
}
$sSQL .= ' AND linked_place_id is null ';
$sSQL .= ' GROUP BY ';
$sSQL .= ' osm_type, ';
$sSQL .= ' osm_id, ';
$sSQL .= ' class, ';
$sSQL .= ' type, ';
$sSQL .= ' admin_level, ';
$sSQL .= ' rank_search, ';
$sSQL .= ' rank_address, ';
$sSQL .= ' housenumber,';
$sSQL .= ' country_code, ';
$sSQL .= ' importance, ';
if (!$this->bDeDupe) $sSQL .= 'place_id,';
if (!$this->bAddressDetails) $sSQL .= 'langaddress, ';
$sSQL .= ' placename, ';
$sSQL .= ' ref, ';
if ($this->bExtraTags) $sSQL .= 'extratags, ';
if ($this->bNameDetails) $sSQL .= 'name, ';
$sSQL .= " extratags->'place' ";
$aSubSelects[] = $sSQL;
}
// postcode table
$sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_POSTCODE);
if ($sPlaceIDs) {
Debug::printVar('Ids from location_postcode', $sPlaceIDs);
$sSQL = 'SELECT';
$sSQL .= " 'P' as osm_type,";
$sSQL .= ' (SELECT osm_id from placex p WHERE p.place_id = lp.parent_place_id) as osm_id,';
$sSQL .= " 'place' as class, 'postcode' as type,";
$sSQL .= ' null::smallint as admin_level, rank_search, rank_address,';
$sSQL .= ' place_id, parent_place_id,';
$sSQL .= ' -1 as housenumber,';
$sSQL .= ' country_code,';
$sSQL .= $this->langAddressSql('-1');
$sSQL .= ' postcode as placename,';
$sSQL .= ' postcode as ref,';
if ($this->bExtraTags) $sSQL .= 'null::text AS extra,';
if ($this->bNameDetails) $sSQL .= 'null::text AS names,';
$sSQL .= ' ST_x(geometry) AS lon, ST_y(geometry) AS lat,';
$sSQL .= ' (0.75-(rank_search::float/40)) AS importance, ';
$sSQL .= $this->addressImportanceSql('geometry', 'lp.parent_place_id');
$sSQL .= ' null::text AS extra_place ';
$sSQL .= 'FROM location_postcode lp';
$sSQL .= " WHERE place_id in ($sPlaceIDs) ";
$sSQL .= " AND lp.rank_address between $iMinRank and $iMaxRank";
$aSubSelects[] = $sSQL;
}
// All other tables are rank 30 only.
if ($iMaxRank == 30) {
// TIGER table
if (CONST_Use_US_Tiger_Data) {
$sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_TIGER);
if ($sPlaceIDs) {
Debug::printVar('Ids from Tiger table', $sPlaceIDs);
$sHousenumbers = Result::sqlHouseNumberTable($aResults, Result::TABLE_TIGER);
// Tiger search only if a housenumber was searched and if it was found
// (realized through a join)
$sSQL = ' SELECT ';
$sSQL .= " 'T' AS osm_type, ";
$sSQL .= ' (SELECT osm_id from placex p WHERE p.place_id=blub.parent_place_id) as osm_id, ';
$sSQL .= " 'place' AS class, ";
$sSQL .= " 'house' AS type, ";
$sSQL .= ' null::smallint AS admin_level, ';
$sSQL .= ' 30 AS rank_search, ';
$sSQL .= ' 30 AS rank_address, ';
$sSQL .= ' place_id, ';
$sSQL .= ' parent_place_id, ';
$sSQL .= ' housenumber_for_place as housenumber,';
$sSQL .= " 'us' AS country_code, ";
$sSQL .= $this->langAddressSql('housenumber_for_place');
$sSQL .= ' null::text AS placename, ';
$sSQL .= ' null::text AS ref, ';
if ($this->bExtraTags) $sSQL .= 'null::text AS extra,';
if ($this->bNameDetails) $sSQL .= 'null::text AS names,';
$sSQL .= ' st_x(centroid) AS lon, ';
$sSQL .= ' st_y(centroid) AS lat,';
$sSQL .= ' -1.15 AS importance, ';
$sSQL .= $this->addressImportanceSql('centroid', 'blub.parent_place_id');
$sSQL .= ' null::text AS extra_place ';
$sSQL .= ' FROM (';
$sSQL .= ' SELECT place_id, '; // interpolate the Tiger housenumbers here
$sSQL .= ' ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float) AS centroid, ';
$sSQL .= ' parent_place_id, ';
$sSQL .= ' housenumber_for_place';
$sSQL .= ' FROM (';
$sSQL .= ' location_property_tiger ';
$sSQL .= ' JOIN (values '.$sHousenumbers.') AS housenumbers(place_id, housenumber_for_place) USING(place_id)) ';
$sSQL .= ' WHERE ';
$sSQL .= ' housenumber_for_place >= startnumber';
$sSQL .= ' AND housenumber_for_place <= endnumber';
$sSQL .= ' ) AS blub'; //postgres wants an alias here
$aSubSelects[] = $sSQL;
}
}
// osmline - interpolated housenumbers
$sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_OSMLINE);
if ($sPlaceIDs) {
Debug::printVar('Ids from interpolation', $sPlaceIDs);
$sHousenumbers = Result::sqlHouseNumberTable($aResults, Result::TABLE_OSMLINE);
// interpolation line search only if a housenumber was searched
// (realized through a join)
$sSQL = 'SELECT ';
$sSQL .= " 'W' AS osm_type, ";
$sSQL .= ' osm_id, ';
$sSQL .= " 'place' AS class, ";
$sSQL .= " 'house' AS type, ";
$sSQL .= ' null::smallint AS admin_level, ';
$sSQL .= ' 30 AS rank_search, ';
$sSQL .= ' 30 AS rank_address, ';
$sSQL .= ' place_id, ';
$sSQL .= ' parent_place_id, ';
$sSQL .= ' housenumber_for_place as housenumber,';
$sSQL .= ' country_code, ';
$sSQL .= $this->langAddressSql('housenumber_for_place');
$sSQL .= ' null::text AS placename, ';
$sSQL .= ' null::text AS ref, ';
if ($this->bExtraTags) $sSQL .= 'null::text AS extra, ';
if ($this->bNameDetails) $sSQL .= 'null::text AS names, ';
$sSQL .= ' st_x(centroid) AS lon, ';
$sSQL .= ' st_y(centroid) AS lat, ';
// slightly smaller than the importance for normal houses
$sSQL .= ' -0.1 AS importance, ';
$sSQL .= $this->addressImportanceSql('centroid', 'blub.parent_place_id');
$sSQL .= ' null::text AS extra_place ';
$sSQL .= ' FROM (';
$sSQL .= ' SELECT ';
$sSQL .= ' osm_id, ';
$sSQL .= ' place_id, ';
$sSQL .= ' country_code, ';
$sSQL .= ' CASE '; // interpolate the housenumbers here
$sSQL .= ' WHEN startnumber != endnumber ';
$sSQL .= ' THEN ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float) ';
$sSQL .= ' ELSE ST_LineInterpolatePoint(linegeo, 0.5) ';
$sSQL .= ' END as centroid, ';
$sSQL .= ' parent_place_id, ';
$sSQL .= ' housenumber_for_place ';
$sSQL .= ' FROM (';
$sSQL .= ' location_property_osmline ';
$sSQL .= ' JOIN (values '.$sHousenumbers.') AS housenumbers(place_id, housenumber_for_place) USING(place_id)';
$sSQL .= ' ) ';
$sSQL .= ' WHERE housenumber_for_place >= 0 ';
$sSQL .= ' ) as blub'; //postgres wants an alias here
$aSubSelects[] = $sSQL;
}
if (CONST_Use_Aux_Location_data) {
$sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_AUX);
if ($sPlaceIDs) {
$sHousenumbers = Result::sqlHouseNumberTable($aResults, Result::TABLE_AUX);
$sSQL = ' SELECT ';
$sSQL .= " 'L' AS osm_type, ";
$sSQL .= ' place_id AS osm_id, ';
$sSQL .= " 'place' AS class,";
$sSQL .= " 'house' AS type, ";
$sSQL .= ' null::smallint AS admin_level, ';
$sSQL .= ' 30 AS rank_search,';
$sSQL .= ' 30 AS rank_address, ';
$sSQL .= ' place_id,';
$sSQL .= ' parent_place_id, ';
$sSQL .= ' housenumber,';
$sSQL .= " 'us' AS country_code, ";
$sSQL .= $this->langAddressSql('-1');
$sSQL .= ' null::text AS placename, ';
$sSQL .= ' null::text AS ref, ';
if ($this->bExtraTags) $sSQL .= 'null::text AS extra, ';
if ($this->bNameDetails) $sSQL .= 'null::text AS names, ';
$sSQL .= ' ST_X(centroid) AS lon, ';
$sSQL .= ' ST_Y(centroid) AS lat, ';
$sSQL .= ' -1.10 AS importance, ';
$sSQL .= $this->addressImportanceSql(
'centroid',
'location_property_aux.parent_place_id'
);
$sSQL .= ' null::text AS extra_place ';
$sSQL .= ' FROM location_property_aux ';
$sSQL .= " WHERE place_id in ($sPlaceIDs) ";
$aSubSelects[] = $sSQL;
}
}
}
if (empty($aSubSelects)) {
return array();
}
$sSQL = join(' UNION ', $aSubSelects);
Debug::printSQL($sSQL);
$aPlaces = chksql($this->oDB->getAll($sSQL), 'Could not lookup place');
foreach ($aPlaces as &$aPlace) {
if ($this->bAddressDetails) {
// to get addressdetails for tiger data, the housenumber is needed
$aPlace['address'] = new AddressDetails(
$this->oDB,
$aPlace['place_id'],
$aPlace['housenumber'],
$this->aLangPrefOrderSql
);
$aPlace['langaddress'] = $aPlace['address']->getLocaleAddress();
}
if ($this->bExtraTags) {
if ($aPlace['extra']) {
$aPlace['sExtraTags'] = json_decode($aPlace['extra']);
} else {
$aPlace['sExtraTags'] = (object) array();
}
}
if ($this->bNameDetails) {
if ($aPlace['names']) {
$aPlace['sNameDetails'] = json_decode($aPlace['names']);
} else {
$aPlace['sNameDetails'] = (object) array();
}
}
$aPlace['addresstype'] = ClassTypes\getProperty(
$aPlace,
'simplelabel',
$aPlace['class']
);
}
Debug::printVar('Places', $aPlaces);
return $aPlaces;
}
/* returns an array which will contain the keys
* aBoundingBox
* and may also contain one or more of the keys
* asgeojson
* askml
* assvg
* astext
* lat
* lon
*/
public function getOutlines($iPlaceID, $fLon = null, $fLat = null, $fRadius = null, $fLonReverse = null, $fLatReverse = null)
{
$aOutlineResult = array();
if (!$iPlaceID) return $aOutlineResult;
if (CONST_Search_AreaPolygons) {
// Get the bounding box and outline polygon
$sSQL = 'select place_id,0 as numfeatures,st_area(geometry) as area,';
if ($fLonReverse != null && $fLatReverse != null) {
$sSQL .= ' ST_Y(closest_point) as centrelat,';
$sSQL .= ' ST_X(closest_point) as centrelon,';
} else {
$sSQL .= ' ST_Y(centroid) as centrelat, ST_X(centroid) as centrelon,';
}
$sSQL .= ' ST_YMin(geometry) as minlat,ST_YMax(geometry) as maxlat,';
$sSQL .= ' ST_XMin(geometry) as minlon,ST_XMax(geometry) as maxlon';
if ($this->bIncludePolygonAsGeoJSON) $sSQL .= ',ST_AsGeoJSON(geometry) as asgeojson';
if ($this->bIncludePolygonAsKML) $sSQL .= ',ST_AsKML(geometry) as askml';
if ($this->bIncludePolygonAsSVG) $sSQL .= ',ST_AsSVG(geometry) as assvg';
if ($this->bIncludePolygonAsText || $this->bIncludePolygonAsPoints) $sSQL .= ',ST_AsText(geometry) as astext';
if ($fLonReverse != null && $fLatReverse != null) {
$sFrom = ' from (SELECT * , CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN ';
$sFrom .=' ST_ClosestPoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326))';
$sFrom .=' ELSE centroid END AS closest_point';
$sFrom .= ' from placex where place_id = '.$iPlaceID.') as plx';
} else {
$sFrom = ' from placex where place_id = '.$iPlaceID;
}
if ($this->fPolygonSimplificationThreshold > 0) {
$sSQL .= ' from (select place_id,centroid,ST_SimplifyPreserveTopology(geometry,'.$this->fPolygonSimplificationThreshold.') as geometry'.$sFrom.') as plx';
} else {
$sSQL .= $sFrom;
}
$aPointPolygon = chksql($this->oDB->getRow($sSQL), 'Could not get outline');
if ($aPointPolygon['place_id']) {
if ($aPointPolygon['centrelon'] !== null && $aPointPolygon['centrelat'] !== null) {
$aOutlineResult['lat'] = $aPointPolygon['centrelat'];
$aOutlineResult['lon'] = $aPointPolygon['centrelon'];
}
if ($this->bIncludePolygonAsGeoJSON) $aOutlineResult['asgeojson'] = $aPointPolygon['asgeojson'];
if ($this->bIncludePolygonAsKML) $aOutlineResult['askml'] = $aPointPolygon['askml'];
if ($this->bIncludePolygonAsSVG) $aOutlineResult['assvg'] = $aPointPolygon['assvg'];
if ($this->bIncludePolygonAsText) $aOutlineResult['astext'] = $aPointPolygon['astext'];
if ($this->bIncludePolygonAsPoints) $aOutlineResult['aPolyPoints'] = geometryText2Points($aPointPolygon['astext'], $fRadius);
if (abs($aPointPolygon['minlat'] - $aPointPolygon['maxlat']) < 0.0000001) {
$aPointPolygon['minlat'] = $aPointPolygon['minlat'] - $fRadius;
$aPointPolygon['maxlat'] = $aPointPolygon['maxlat'] + $fRadius;
}
if (abs($aPointPolygon['minlon'] - $aPointPolygon['maxlon']) < 0.0000001) {
$aPointPolygon['minlon'] = $aPointPolygon['minlon'] - $fRadius;
$aPointPolygon['maxlon'] = $aPointPolygon['maxlon'] + $fRadius;
}
$aOutlineResult['aBoundingBox'] = array(
(string)$aPointPolygon['minlat'],
(string)$aPointPolygon['maxlat'],
(string)$aPointPolygon['minlon'],
(string)$aPointPolygon['maxlon']
);
}
}
// as a fallback we generate a bounding box without knowing the size of the geometry
if ((!isset($aOutlineResult['aBoundingBox'])) && isset($fLon)) {
//
if ($this->bIncludePolygonAsPoints) {
$sGeometryText = 'POINT('.$fLon.','.$fLat.')';
$aOutlineResult['aPolyPoints'] = geometryText2Points($sGeometryText, $fRadius);
}
$aBounds = array();
$aBounds['minlat'] = $fLat - $fRadius;
$aBounds['maxlat'] = $fLat + $fRadius;
$aBounds['minlon'] = $fLon - $fRadius;
$aBounds['maxlon'] = $fLon + $fRadius;
$aOutlineResult['aBoundingBox'] = array(
(string)$aBounds['minlat'],
(string)$aBounds['maxlat'],
(string)$aBounds['minlon'],
(string)$aBounds['maxlon']
);
}
return $aOutlineResult;
}
}

71
lib/Result.php Normal file
View File

@@ -0,0 +1,71 @@
<?php
namespace Nominatim;
/**
* A single result of a search operation or a reverse lookup.
*
* This object only contains the id of the result. It does not yet
* have any details needed to format the output document.
*/
class Result
{
const TABLE_PLACEX = 0;
const TABLE_POSTCODE = 1;
const TABLE_OSMLINE = 2;
const TABLE_AUX = 3;
const TABLE_TIGER = 4;
/// Database table that contains the result.
public $iTable;
/// Id of the result.
public $iId;
/// House number (only for interpolation results).
public $iHouseNumber = -1;
/// Number of exact matches in address (address searches only).
public $iExactMatches = 0;
/// Subranking within the results (the higher the worse).
public $iResultRank = 0;
public function debugInfo()
{
return array(
'Table' => $this->iTable,
'ID' => $this->iId,
'House number' => $this->iHouseNumber,
'Exact Matches' => $this->iExactMatches,
'Result rank' => $this->iResultRank
);
}
public function __construct($sId, $iTable = Result::TABLE_PLACEX)
{
$this->iTable = $iTable;
$this->iId = (int) $sId;
}
public static function joinIdsByTable($aResults, $iTable)
{
return join(',', array_keys(array_filter(
$aResults,
function ($aValue) use ($iTable) {
return $aValue->iTable == $iTable;
}
)));
}
public static function sqlHouseNumberTable($aResults, $iTable)
{
$sHousenumbers = '';
$sSep = '';
foreach ($aResults as $oResult) {
if ($oResult->iTable == $iTable) {
$sHousenumbers .= $sSep.'('.$oResult->iId.',';
$sHousenumbers .= $oResult->iHouseNumber.')';
$sSep = ',';
}
}
return $sHousenumbers;
}
}

View File

@@ -1,171 +1,367 @@
<?php
class ReverseGeocode
{
protected $oDB;
protected $fLat;
protected $fLon;
protected $iMaxRank = 28;
namespace Nominatim;
protected $aLangPrefOrder = array();
require_once(CONST_BasePath.'/lib/Result.php');
function ReverseGeocode(&$oDB)
{
$this->oDB =& $oDB;
}
function setLanguagePreference($aLangPref)
{
$this->aLangPrefOrder = $aLangPref;
}
function setLatLon($fLat, $fLon)
{
$this->fLat = (float)$fLat;
$this->fLon = (float)$fLon;
}
function setRank($iRank)
{
$this->iMaxRank = $iRank;
}
function setZoom($iZoom)
{
// Zoom to rank, this could probably be calculated but a lookup gives fine control
$aZoomRank = array(
0 => 2, // Continent / Sea
1 => 2,
2 => 2,
3 => 4, // Country
4 => 4,
5 => 8, // State
6 => 10, // Region
7 => 10,
8 => 12, // County
9 => 12,
10 => 17, // City
11 => 17,
12 => 18, // Town / Village
13 => 18,
14 => 22, // Suburb
15 => 22,
16 => 26, // Street, TODO: major street?
17 => 26,
18 => 30, // or >, Building
19 => 30, // or >, Building
);
$this->iMaxRank = (isset($iZoom) && isset($aZoomRank[$iZoom]))?$aZoomRank[$iZoom]:28;
}
function lookup()
{
$sPointSQL = 'ST_SetSRID(ST_Point('.$this->fLon.','.$this->fLat.'),4326)';
$iMaxRank = $this->iMaxRank;
$iMaxRank_orig = $this->iMaxRank;
// Find the nearest point
$fSearchDiam = 0.0004;
$iPlaceID = null;
$aArea = false;
$fMaxAreaDistance = 1;
$bIsInUnitedStates = false;
$bPlaceIsTiger = false;
while(!$iPlaceID && $fSearchDiam < $fMaxAreaDistance)
{
$fSearchDiam = $fSearchDiam * 2;
// If we have to expand the search area by a large amount then we need a larger feature
// then there is a limit to how small the feature should be
if ($fSearchDiam > 2 && $iMaxRank > 4) $iMaxRank = 4;
if ($fSearchDiam > 1 && $iMaxRank > 9) $iMaxRank = 8;
if ($fSearchDiam > 0.8 && $iMaxRank > 10) $iMaxRank = 10;
if ($fSearchDiam > 0.6 && $iMaxRank > 12) $iMaxRank = 12;
if ($fSearchDiam > 0.2 && $iMaxRank > 17) $iMaxRank = 17;
if ($fSearchDiam > 0.1 && $iMaxRank > 18) $iMaxRank = 18;
if ($fSearchDiam > 0.008 && $iMaxRank > 22) $iMaxRank = 22;
if ($fSearchDiam > 0.001 && $iMaxRank > 26) $iMaxRank = 26;
$sSQL = 'select place_id,parent_place_id,rank_search,calculated_country_code from placex';
$sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, '.$fSearchDiam.')';
$sSQL .= ' and rank_search != 28 and rank_search >= '.$iMaxRank;
$sSQL .= ' and (name is not null or housenumber is not null)';
$sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')';
$sSQL .= ' and indexed_status = 0 ';
$sSQL .= ' and (ST_GeometryType(geometry) not in (\'ST_Polygon\',\'ST_MultiPolygon\') ';
$sSQL .= ' OR ST_DWithin('.$sPointSQL.', centroid, '.$fSearchDiam.'))';
$sSQL .= ' ORDER BY ST_distance('.$sPointSQL.', geometry) ASC limit 1';
if (CONST_Debug) var_dump($sSQL);
$aPlace = $this->oDB->getRow($sSQL);
if (PEAR::IsError($aPlace))
{
failInternalError("Could not determine closest place.", $sSQL, $aPlace);
}
$iPlaceID = $aPlace['place_id'];
$iParentPlaceID = $aPlace['parent_place_id'];
$bIsInUnitedStates = ($aPlace['calculated_country_code'] == 'us');
}
// Only street found? If it's in the US we can check TIGER data for nearest housenumber
if ($bIsInUnitedStates && $iMaxRank_orig >= 28 && $iPlaceID && ($aPlace['rank_search'] == 26 || $aPlace['rank_search'] == 27 ))
{
$fSearchDiam = 0.001;
$sSQL = 'SELECT place_id,parent_place_id,30 as rank_search ';
if (CONST_Debug) { $sSQL .= ', housenumber, ST_distance('.$sPointSQL.', centroid) as distance, st_y(centroid) as lat, st_x(centroid) as lon'; }
$sSQL .= ' FROM location_property_tiger WHERE parent_place_id = '.$iPlaceID;
$sSQL .= ' AND ST_DWithin('.$sPointSQL.', centroid, '.$fSearchDiam.')';
$sSQL .= ' ORDER BY ST_distance('.$sPointSQL.', centroid) ASC limit 1';
class ReverseGeocode
{
protected $oDB;
protected $iMaxRank = 28;
// print all house numbers in the parent (street)
if (CONST_Debug)
{
$sSQL = preg_replace('/limit 1/', 'limit 100', $sSQL);
var_dump($sSQL);
public function __construct(&$oDB)
{
$this->oDB =& $oDB;
}
$aAllHouses = $this->oDB->getAll($sSQL);
foreach($aAllHouses as $i)
{
echo $i['housenumber'] . ' | ' . $i['distance'] * 1000 . ' | ' . $i['lat'] . ' | ' . $i['lon']. ' | '. "<br>\n";
}
}
$aPlaceTiger = $this->oDB->getRow($sSQL);
if (PEAR::IsError($aPlace))
{
failInternalError("Could not determine closest Tiger place.", $sSQL, $aPlaceTiger);
}
if ($aPlaceTiger)
{
if (CONST_Debug) var_dump('found Tiger place', $aPlaceTiger);
$bPlaceIsTiger = true;
$aPlace = $aPlaceTiger;
$iPlaceID = $aPlaceTiger['place_id'];
$iParentPlaceID = $aPlaceTiger['parent_place_id']; // the street
}
}
public function setZoom($iZoom)
{
// Zoom to rank, this could probably be calculated but a lookup gives fine control
$aZoomRank = array(
0 => 2, // Continent / Sea
1 => 2,
2 => 2,
3 => 4, // Country
4 => 4,
5 => 8, // State
6 => 10, // Region
7 => 10,
8 => 12, // County
9 => 12,
10 => 17, // City
11 => 17,
12 => 18, // Town / Village
13 => 18,
14 => 22, // Suburb
15 => 22,
16 => 26, // Street, TODO: major street?
17 => 26,
18 => 30, // or >, Building
19 => 30, // or >, Building
);
$this->iMaxRank = (isset($iZoom) && isset($aZoomRank[$iZoom]))?$aZoomRank[$iZoom]:28;
}
// The point we found might be too small - use the address to find what it is a child of
if ($iPlaceID && $iMaxRank < 28)
{
if ($aPlace['rank_search'] > 28 && $iParentPlaceID && !$bPlaceIsTiger)
{
$iPlaceID = $iParentPlaceID;
}
$sSQL = "select address_place_id from place_addressline where place_id = $iPlaceID order by abs(cached_rank_address - $iMaxRank) asc,cached_rank_address desc,isaddress desc,distance desc limit 1";
$iPlaceID = $this->oDB->getOne($sSQL);
if (PEAR::IsError($iPlaceID))
{
failInternalError("Could not get parent for place.", $sSQL, $iPlaceID);
}
if (!$iPlaceID)
{
$iPlaceID = $aPlace['place_id'];
}
}
/**
* Find the closest interpolation with the given search diameter.
*
* @param string $sPointSQL Reverse geocoding point as SQL
* @param float $fSearchDiam Search diameter
*
* @return Record of the interpolation or null.
*/
protected function lookupInterpolation($sPointSQL, $fSearchDiam)
{
$sSQL = 'SELECT place_id, parent_place_id, 30 as rank_search,';
$sSQL .= ' ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction,';
$sSQL .= ' startnumber, endnumber, interpolationtype,';
$sSQL .= ' ST_Distance(linegeo,'.$sPointSQL.') as distance';
$sSQL .= ' FROM location_property_osmline';
$sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', linegeo, '.$fSearchDiam.')';
$sSQL .= ' and indexed_status = 0 and startnumber is not NULL ';
$sSQL .= ' ORDER BY distance ASC limit 1';
return array('place_id' => $iPlaceID,
'type' => $bPlaceIsTiger ? 'tiger' : 'osm');
}
}
?>
return chksql(
$this->oDB->getRow($sSQL),
'Could not determine closest housenumber on an osm interpolation line.'
);
}
protected function lookupLargeArea($sPointSQL, $iMaxRank)
{
$oResult = null;
if ($iMaxRank > 4) {
$aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank);
if ($aPlace) {
return new Result($aPlace['place_id']);
}
}
// If no polygon which contains the searchpoint is found,
// searches in the country_osm_grid table for a polygon.
return $this->lookupInCountry($sPointSQL, $iMaxRank);
}
protected function lookupInCountry($sPointSQL, $iMaxRank)
{
// searches for polygon in table country_osm_grid which contains the searchpoint
// and searches for the nearest place node to the searchpoint in this polygon
$sSQL = 'SELECT country_code FROM country_osm_grid';
$sSQL .= ' WHERE ST_CONTAINS(geometry, '.$sPointSQL.') LIMIT 1';
$sCountryCode = chksql(
$this->oDB->getOne($sSQL),
'Could not determine country polygon containing the point.'
);
if ($sCountryCode) {
if ($iMaxRank > 4) {
// look for place nodes with the given country code
$sSQL = 'SELECT place_id FROM';
$sSQL .= ' (SELECT place_id, rank_search,';
$sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance';
$sSQL .= ' FROM placex';
$sSQL .= ' WHERE osm_type = \'N\'';
$sSQL .= ' AND country_code = \''.$sCountryCode.'\'';
$sSQL .= ' AND rank_search between 5 and ' .min(25, $iMaxRank);
$sSQL .= ' AND class = \'place\' AND type != \'postcode\'';
$sSQL .= ' AND name IS NOT NULL ';
$sSQL .= ' and indexed_status = 0 and linked_place_id is null';
$sSQL .= ' AND ST_DWithin('.$sPointSQL.', geometry, 1.8)) p ';
$sSQL .= 'WHERE distance <= reverse_place_diameter(rank_search)';
$sSQL .= ' ORDER BY rank_search DESC, distance ASC';
$sSQL .= ' LIMIT 1';
if (CONST_Debug) var_dump($sSQL);
$aPlace = chksql(
$this->oDB->getRow($sSQL),
'Could not determine place node.'
);
if ($aPlace) {
return new Result($aPlace['place_id']);
}
}
// still nothing, then return the country object
$sSQL = 'SELECT place_id, ST_distance('.$sPointSQL.', centroid) as distance';
$sSQL .= ' FROM placex';
$sSQL .= ' WHERE country_code = \''.$sCountryCode.'\'';
$sSQL .= ' AND rank_search = 4 AND rank_address = 4';
$sSQL .= ' AND class in (\'boundary\', \'place\')';
$sSQL .= ' AND linked_place_id is null';
$sSQL .= ' ORDER BY distance ASC';
if (CONST_Debug) var_dump($sSQL);
$aPlace = chksql(
$this->oDB->getRow($sSQL),
'Could not determine place node.'
);
if ($aPlace) {
return new Result($aPlace['place_id']);
}
}
return null;
}
/**
* Search for areas or nodes for areas or nodes between state and suburb level.
*
* @param string $sPointSQL Search point as SQL string.
* @param int $iMaxRank Maximum address rank of the feature.
*
* @return Record of the found feature or null.
*
* Searches first for polygon that contains the search point.
* If such a polygon is found, place nodes with a higher rank are
* searched inside the polygon.
*/
protected function lookupPolygon($sPointSQL, $iMaxRank)
{
// polygon search begins at suburb-level
if ($iMaxRank > 25) $iMaxRank = 25;
// no polygon search over country-level
if ($iMaxRank < 5) $iMaxRank = 5;
// search for polygon
$sSQL = 'SELECT place_id, parent_place_id, rank_address, rank_search FROM';
$sSQL .= '(select place_id, parent_place_id, rank_address, rank_search, country_code, geometry';
$sSQL .= ' FROM placex';
$sSQL .= ' WHERE ST_GeometryType(geometry) in (\'ST_Polygon\', \'ST_MultiPolygon\')';
$sSQL .= ' AND rank_address Between 5 AND ' .$iMaxRank;
$sSQL .= ' AND geometry && '.$sPointSQL;
$sSQL .= ' AND type != \'postcode\' ';
$sSQL .= ' AND name is not null';
$sSQL .= ' AND indexed_status = 0 and linked_place_id is null';
$sSQL .= ' ORDER BY rank_address DESC LIMIT 50 ) as a';
$sSQL .= ' WHERE ST_CONTAINS(geometry, '.$sPointSQL.' )';
$sSQL .= ' ORDER BY rank_address DESC LIMIT 1';
$aPoly = chksql(
$this->oDB->getRow($sSQL),
'Could not determine polygon containing the point.'
);
if ($aPoly) {
// if a polygon is found, search for placenodes begins ...
$iParentPlaceID = $aPoly['parent_place_id'];
$iRankAddress = $aPoly['rank_address'];
$iRankSearch = $aPoly['rank_search'];
$iPlaceID = $aPoly['place_id'];
if ($iRankAddress != $iMaxRank) {
$sSQL = 'SELECT place_id FROM ';
$sSQL .= '(SELECT place_id, rank_search, country_code, geometry,';
$sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance';
$sSQL .= ' FROM placex';
$sSQL .= ' WHERE osm_type = \'N\'';
// using rank_search because of a better differentiation
// for place nodes at rank_address 16
$sSQL .= ' AND rank_search > '.$iRankSearch;
$sSQL .= ' AND rank_search <= '.$iMaxRank;
$sSQL .= ' AND class = \'place\'';
$sSQL .= ' AND type != \'postcode\'';
$sSQL .= ' AND name IS NOT NULL ';
$sSQL .= ' AND indexed_status = 0 AND linked_place_id is null';
$sSQL .= ' AND ST_DWithin('.$sPointSQL.', geometry, reverse_place_diameter('.$iRankSearch.'::smallint))';
$sSQL .= ' ORDER BY distance ASC,';
$sSQL .= ' rank_address DESC';
$sSQL .= ' limit 500) as a';
$sSQL .= ' WHERE ST_CONTAINS((SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.'), geometry )';
$sSQL .= ' AND distance <= reverse_place_diameter(rank_search)';
$sSQL .= ' ORDER BY distance ASC, rank_search DESC';
$sSQL .= ' LIMIT 1';
if (CONST_Debug) var_dump($sSQL);
$aPlacNode = chksql(
$this->oDB->getRow($sSQL),
'Could not determine place node.'
);
if ($aPlacNode) {
return $aPlacNode;
}
}
}
return $aPoly;
}
public function lookup($fLat, $fLon, $bDoInterpolation = true)
{
return $this->lookupPoint(
'ST_SetSRID(ST_Point('.$fLon.','.$fLat.'),4326)',
$bDoInterpolation
);
}
public function lookupPoint($sPointSQL, $bDoInterpolation = true)
{
// starts if the search is on POI or street level,
// searches for the nearest POI or street,
// if a street is found and a POI is searched for,
// the nearest POI which the found street is a parent of is choosen.
$iMaxRank = $this->iMaxRank;
// Find the nearest point
$fSearchDiam = 0.006;
$oResult = null;
$aPlace = null;
// for POI or street level
if ($iMaxRank >= 26) {
$sSQL = 'select place_id,parent_place_id,rank_address,country_code,';
$sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance';
$sSQL .= ' FROM ';
$sSQL .= ' placex';
$sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, '.$fSearchDiam.')';
$sSQL .= ' AND';
// only streets
if ($iMaxRank == 26) {
$sSQL .= ' rank_address = 26';
} else {
$sSQL .= ' rank_address between 26 and '.$iMaxRank;
}
$sSQL .= ' and (name is not null or housenumber is not null';
$sSQL .= ' or rank_address between 26 and 27)';
$sSQL .= ' and class not in (\'railway\',\'tunnel\',\'bridge\',\'man_made\')';
$sSQL .= ' and indexed_status = 0 and linked_place_id is null';
$sSQL .= ' and (ST_GeometryType(geometry) not in (\'ST_Polygon\',\'ST_MultiPolygon\') ';
$sSQL .= ' OR ST_DWithin('.$sPointSQL.', centroid, '.$fSearchDiam.'))';
$sSQL .= ' ORDER BY distance ASC limit 1';
if (CONST_Debug) var_dump($sSQL);
$aPlace = chksql(
$this->oDB->getRow($sSQL),
'Could not determine closest place.'
);
if (CONST_Debug) var_dump($aPlace);
if ($aPlace) {
$iPlaceID = $aPlace['place_id'];
$oResult = new Result($iPlaceID);
$iRankAddress = $aPlace['rank_address'];
$iParentPlaceID = $aPlace['parent_place_id'];
}
if ($bDoInterpolation && $iMaxRank >= 30) {
$fDistance = $fSearchDiam;
if ($aPlace) {
// We can't reliably go from the closest street to an
// interpolation line because the closest interpolation
// may have a different street segments as a parent.
// Therefore allow an interpolation line to take precendence
// even when the street is closer.
$fDistance = $iRankAddress < 28 ? 0.001 : $aPlace['distance'];
}
$aHouse = $this->lookupInterpolation($sPointSQL, $fDistance);
if ($aHouse) {
$oResult = new Result($aHouse['place_id'], Result::TABLE_OSMLINE);
$oResult->iHouseNumber = closestHouseNumber($aHouse);
$aPlace = $aHouse;
$iRankAddress = 30;
}
}
if ($aPlace) {
// if street and maxrank > streetlevel
if ($iRankAddress <= 27 && $iMaxRank > 27) {
// find the closest object (up to a certain radius) of which the street is a parent of
$sSQL = ' select place_id,';
$sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance';
$sSQL .= ' FROM ';
$sSQL .= ' placex';
// radius ?
$sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, 0.001)';
$sSQL .= ' AND parent_place_id = '.$iPlaceID;
$sSQL .= ' and rank_address != 28';
$sSQL .= ' and (name is not null or housenumber is not null)';
$sSQL .= ' and class not in (\'railway\',\'tunnel\',\'bridge\',\'man_made\')';
$sSQL .= ' and indexed_status = 0 and linked_place_id is null';
$sSQL .= ' ORDER BY distance ASC limit 1';
if (CONST_Debug) var_dump($sSQL);
$aStreet = chksql(
$this->oDB->getRow($sSQL),
'Could not determine closest place.'
);
if ($aStreet) {
if (CONST_Debug) var_dump($aStreet);
$oResult = new Result($aStreet['place_id']);
}
}
// In the US we can check TIGER data for nearest housenumber
if (CONST_Use_US_Tiger_Data
&& $iRankAddress <= 27
&& $aPlace['country_code'] == 'us'
&& $this->iMaxRank >= 28
) {
$sSQL = 'SELECT place_id,parent_place_id,30 as rank_search,';
$sSQL .= 'ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction,';
$sSQL .= 'ST_distance('.$sPointSQL.', linegeo) as distance,';
$sSQL .= 'startnumber,endnumber,interpolationtype';
$sSQL .= ' FROM location_property_tiger WHERE parent_place_id = '.$oResult->iId;
$sSQL .= ' AND ST_DWithin('.$sPointSQL.', linegeo, 0.001)';
$sSQL .= ' ORDER BY distance ASC limit 1';
if (CONST_Debug) var_dump($sSQL);
$aPlaceTiger = chksql(
$this->oDB->getRow($sSQL),
'Could not determine closest Tiger place.'
);
if ($aPlaceTiger) {
if (CONST_Debug) var_dump('found Tiger housenumber', $aPlaceTiger);
$oResult = new Result($aPlaceTiger['place_id'], Result::TABLE_TIGER);
$oResult->iHouseNumber = closestHouseNumber($aPlaceTiger);
}
}
} else {
// if no POI or street is found ...
$oResult = $this->lookupLargeArea($sPointSQL, 25);
}
} else {
// lower than street level ($iMaxRank < 26 )
$oResult = $this->lookupLargeArea($sPointSQL, $iMaxRank);
}
return $oResult;
}
}

284
lib/SearchContext.php Normal file
View File

@@ -0,0 +1,284 @@
<?php
namespace Nominatim;
require_once(CONST_BasePath.'/lib/lib.php');
/**
* Collection of search constraints that are independent of the
* actual interpretation of the search query.
*
* The search context is shared between all SearchDescriptions. This
* object mainly serves as context provider for the database queries.
* Therefore most data is directly cached as SQL statements.
*/
class SearchContext
{
/// Search radius around a given Near reference point.
private $fNearRadius = false;
/// True if search must be restricted to viewbox only.
public $bViewboxBounded = false;
/// Reference point for search (as SQL).
public $sqlNear = '';
/// Viewbox selected for search (as SQL).
public $sqlViewboxSmall = '';
/// Viewbox with a larger buffer around (as SQL).
public $sqlViewboxLarge = '';
/// Reference along a route (as SQL).
public $sqlViewboxCentre = '';
/// List of countries to restrict search to (as SQL).
public $sqlCountryList = '';
/// List of place IDs to exclude (as SQL).
private $sqlExcludeList = '';
/**
* Check if a reference point is defined.
*
* @return bool True if a reference point is defined.
*/
public function hasNearPoint()
{
return $this->fNearRadius !== false;
}
/**
* Get radius around reference point.
*
* @return float Search radius around reference point.
*/
public function nearRadius()
{
return $this->fNearRadius;
}
/**
* Set search reference point in WGS84.
*
* If set, then only places around this point will be taken into account.
*
* @param float $fLat Latitude of point.
* @param float $fLon Longitude of point.
* @param float $fRadius Search radius around point.
*
* @return void
*/
public function setNearPoint($fLat, $fLon, $fRadius = 0.1)
{
$this->fNearRadius = $fRadius;
$this->sqlNear = 'ST_SetSRID(ST_Point('.$fLon.','.$fLat.'),4326)';
}
/**
* Check if the search is geographically restricted.
*
* Searches are restricted if a reference point is given or if
* a bounded viewbox is set.
*
* @return bool True, if the search is geographically bounded.
*/
public function isBoundedSearch()
{
return $this->hasNearPoint() || ($this->sqlViewboxSmall && $this->bViewboxBounded);
}
/**
* Set rectangular viewbox.
*
* The viewbox may be bounded which means that no search results
* must be outside the viewbox.
*
* @param float[4] $aViewBox Coordinates of the viewbox.
* @param bool $bBounded True if the viewbox is bounded.
*
* @return void
*/
public function setViewboxFromBox(&$aViewBox, $bBounded)
{
$this->bViewboxBounded = $bBounded;
$this->sqlViewboxCentre = '';
$this->sqlViewboxSmall = sprintf(
'ST_SetSRID(ST_MakeBox2D(ST_Point(%F,%F),ST_Point(%F,%F)),4326)',
$aViewBox[0],
$aViewBox[1],
$aViewBox[2],
$aViewBox[3]
);
$fHeight = abs($aViewBox[0] - $aViewBox[2]);
$fWidth = abs($aViewBox[1] - $aViewBox[3]);
$this->sqlViewboxLarge = sprintf(
'ST_SetSRID(ST_MakeBox2D(ST_Point(%F,%F),ST_Point(%F,%F)),4326)',
max($aViewBox[0], $aViewBox[2]) + $fHeight,
max($aViewBox[1], $aViewBox[3]) + $fWidth,
min($aViewBox[0], $aViewBox[2]) - $fHeight,
min($aViewBox[1], $aViewBox[3]) - $fWidth
);
}
/**
* Set viewbox along a route.
*
* The viewbox may be bounded which means that no search results
* must be outside the viewbox.
*
* @param object $oDB DB connection to use for computing the box.
* @param string[] $aRoutePoints List of x,y coordinates along a route.
* @param float $fRouteWidth Buffer around the route to use.
* @param bool $bBounded True if the viewbox bounded.
*
* @return void
*/
public function setViewboxFromRoute(&$oDB, $aRoutePoints, $fRouteWidth, $bBounded)
{
$this->bViewboxBounded = $bBounded;
$this->sqlViewboxCentre = "ST_SetSRID('LINESTRING(";
$sSep = '';
foreach ($aRoutePoints as $aPoint) {
$fPoint = (float)$aPoint;
$this->sqlViewboxCentre .= $sSep.$fPoint;
$sSep = ($sSep == ' ') ? ',' : ' ';
}
$this->sqlViewboxCentre .= ")'::geometry,4326)";
$sSQL = 'ST_BUFFER('.$this->sqlViewboxCentre.','.($fRouteWidth/69).')';
$sGeom = chksql($oDB->getOne('select '.$sSQL), 'Could not get small viewbox');
$this->sqlViewboxSmall = "'".$sGeom."'::geometry";
$sSQL = 'ST_BUFFER('.$this->sqlViewboxCentre.','.($fRouteWidth/30).')';
$sGeom = chksql($oDB->getOne('select '.$sSQL), 'Could not get large viewbox');
$this->sqlViewboxLarge = "'".$sGeom."'::geometry";
}
/**
* Set list of excluded place IDs.
*
* @param integer[] $aExcluded List of IDs.
*
* @return void
*/
public function setExcludeList($aExcluded)
{
$this->sqlExcludeList = ' not in ('.join(',', $aExcluded).')';
}
/**
* Set list of countries to restrict search to.
*
* @param string[] $aCountries List of two-letter lower-case country codes.
*
* @return void
*/
public function setCountryList($aCountries)
{
$this->sqlCountryList = '('.join(',', array_map('addQuotes', $aCountries)).')';
}
/**
* Extract a reference point from a query string.
*
* @param string $sQuery Query to scan.
*
* @return string The remaining query string.
*/
public function setNearPointFromQuery($sQuery)
{
$aResult = parseLatLon($sQuery);
if ($aResult !== false
&& $aResult[1] <= 90.1
&& $aResult[1] >= -90.1
&& $aResult[2] <= 180.1
&& $aResult[2] >= -180.1
) {
$this->setNearPoint($aResult[1], $aResult[2]);
$sQuery = trim(str_replace($aResult[0], ' ', $sQuery));
}
return $sQuery;
}
/**
* Get an SQL snipped for computing the distance from the reference point.
*
* @param string $sObj SQL variable name to compute the distance from.
*
* @return string An SQL string.
*/
public function distanceSQL($sObj)
{
return 'ST_Distance('.$this->sqlNear.", $sObj)";
}
/**
* Get an SQL snipped for checking if something is within range of the
* reference point.
*
* @param string $sObj SQL variable name to compute if it is within range.
*
* @return string An SQL string.
*/
public function withinSQL($sObj)
{
return sprintf('ST_DWithin(%s, %s, %F)', $sObj, $this->sqlNear, $this->fNearRadius);
}
/**
* Get an SQL snipped of the importance factor of the viewbox.
*
* The importance factor is computed by checking if an object is within
* the viewbox and/or the extended version of the viewbox.
*
* @param string $sObj SQL variable name of object to weight the importance
*
* @return string SQL snipped of the factor with a leading multiply sign.
*/
public function viewboxImportanceSQL($sObj)
{
$sSQL = '';
if ($this->sqlViewboxSmall) {
$sSQL = " * CASE WHEN ST_Contains($this->sqlViewboxSmall, $sObj) THEN 1 ELSE 0.5 END";
}
if ($this->sqlViewboxLarge) {
$sSQL = " * CASE WHEN ST_Contains($this->sqlViewboxLarge, $sObj) THEN 1 ELSE 0.5 END";
}
return $sSQL;
}
/**
* SQL snipped checking if a place ID should be excluded.
*
* @param string $sVariable SQL variable name of place ID to check,
* potentially prefixed with more SQL.
*
* @return string SQL snippet.
*/
public function excludeSQL($sVariable)
{
if ($this->sqlExcludeList) {
return $sVariable.$this->sqlExcludeList;
}
return '';
}
public function debugInfo()
{
return array(
'Near radius' => $this->fNearRadius,
'Near point (SQL)' => $this->sqlNear,
'Bounded viewbox' => $this->bViewboxBounded,
'Viewbox (SQL, small)' => $this->sqlViewboxSmall,
'Viewbox (SQL, large)' => $this->sqlViewboxLarge,
'Viewbox (SQL, centre)' => $this->sqlViewboxCentre,
'Countries (SQL)' => $this->sqlCountryList,
'Excluded IDs (SQL)' => $this->sqlExcludeList
);
}
}

1044
lib/SearchDescription.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,44 @@
<?php
namespace Nominatim;
/**
* Operators describing special searches.
*/
abstract class Operator
{
/// No operator selected.
const NONE = 0;
/// Search for POI of the given type.
const TYPE = 1;
/// Search for POIs near the given place.
const NEAR = 2;
/// Search for POIS in the given place.
const IN = 3;
/// Search for POIS named as given.
const NAME = 4;
/// Search for postcodes.
const POSTCODE = 5;
private static $aConstantNames = null;
public static function toString($iOperator)
{
if ($iOperator == Operator::NONE) {
return '';
}
if (Operator::$aConstantNames === null) {
$oReflector = new \ReflectionClass('Nominatim\Operator');
$aConstants = $oReflector->getConstants();
Operator::$aConstantNames = array();
foreach ($aConstants as $sName => $iValue) {
Operator::$aConstantNames[$iValue] = $sName;
}
}
return Operator::$aConstantNames[$iOperator];
}
}

54
lib/Status.php Normal file
View File

@@ -0,0 +1,54 @@
<?php
namespace Nominatim;
use Exception;
use PEAR;
class Status
{
protected $oDB;
public function __construct(&$oDB)
{
$this->oDB =& $oDB;
}
public function status()
{
if (!$this->oDB || PEAR::isError($this->oDB)) {
throw new Exception('No database', 700);
}
$sStandardWord = $this->oDB->getOne("SELECT make_standard_name('a')");
if (PEAR::isError($sStandardWord)) {
throw new Exception('Module failed', 701);
}
if ($sStandardWord != 'a') {
throw new Exception('Module call failed', 702);
}
$sSQL = 'SELECT word_id, word_token, word, class, type, country_code, ';
$sSQL .= "operator, search_name_count FROM word WHERE word_token IN (' a')";
$iWordID = $this->oDB->getOne($sSQL);
if (PEAR::isError($iWordID)) {
throw new Exception('Query failed', 703);
}
if (!$iWordID) {
throw new Exception('No value', 704);
}
}
public function dataDate()
{
$sSQL = 'SELECT EXTRACT(EPOCH FROM lastimportdate) FROM import_status LIMIT 1';
$iDataDateEpoch = $this->oDB->getOne($sSQL);
if (PEAR::isError($iDataDateEpoch)) {
throw Exception('Data date query failed '.$iDataDateEpoch->getMessage(), 705);
}
return $iDataDateEpoch;
}
}

29
lib/TokenCountry.php Normal file
View File

@@ -0,0 +1,29 @@
<?php
namespace Nominatim\Token;
/**
* A country token.
*/
class Country
{
/// Database word id, if available.
public $iId;
/// Two-letter country code (lower-cased).
public $sCountryCode;
public function __construct($iId, $sCountryCode)
{
$this->iId = $iId;
$this->sCountryCode = $sCountryCode;
}
public function debugInfo()
{
return array(
'ID' => $this->iId,
'Type' => 'country',
'Info' => $this->sCountryCode
);
}
}

29
lib/TokenHousenumber.php Normal file
View File

@@ -0,0 +1,29 @@
<?php
namespace Nominatim\Token;
/**
* A house number token.
*/
class HouseNumber
{
/// Database word id, if available.
public $iId;
/// Normalized house number.
public $sToken;
public function __construct($iId, $sToken)
{
$this->iId = $iId;
$this->sToken = $sToken;
}
public function debugInfo()
{
return array(
'ID' => $this->iId,
'Type' => 'house number',
'Info' => array('nr' => $this->sToken)
);
}
}

188
lib/TokenList.php Normal file
View File

@@ -0,0 +1,188 @@
<?php
namespace Nominatim;
require_once(CONST_BasePath.'/lib/TokenCountry.php');
require_once(CONST_BasePath.'/lib/TokenHousenumber.php');
require_once(CONST_BasePath.'/lib/TokenPostcode.php');
require_once(CONST_BasePath.'/lib/TokenSpecialTerm.php');
require_once(CONST_BasePath.'/lib/TokenWord.php');
require_once(CONST_BasePath.'/lib/SpecialSearchOperator.php');
/**
* Saves information about the tokens that appear in a search query.
*
* Tokens are sorted by their normalized form, the token word. There are different
* kinds of tokens, represented by different Token* classes. Note that
* tokens do not have a common base class. All tokens need to have a field
* with the word id that points to an entry in the `word` database table
* but otherwise the information saved about a token can be very different.
*
* There are two different kinds of token words: full words and partial terms.
*
* Full words start with a space. They represent a complete name of a place.
* All special tokens are normally full words.
*
* Partial terms have no space at the beginning. They may represent a part of
* a name of a place (e.g. in the name 'World Trade Center' a partial term
* would be 'Trade' or 'Trade Center'). They are only used in TokenWord.
*/
class TokenList
{
// List of list of tokens indexed by their word_token.
private $aTokens = array();
/**
* Return total number of tokens.
*
* @return Integer
*/
public function count()
{
return count($this->aTokens);
}
/**
* Check if there are tokens for the given token word.
*
* @param string $sWord Token word to look for.
*
* @return bool True if there is one or more token for the token word.
*/
public function contains($sWord)
{
return isset($this->aTokens[$sWord]);
}
/**
* Get the list of tokens for the given token word.
*
* @param string $sWord Token word to look for.
*
* @return object[] Array of tokens for the given token word or an
* empty array if no tokens could be found.
*/
public function get($sWord)
{
return isset($this->aTokens[$sWord]) ? $this->aTokens[$sWord] : array();
}
/**
* Add token information from the word table in the database.
*
* @param object $oDB Database connection.
* @param string[] $aTokens List of tokens to look up in the database.
* @param string[] $aCountryCodes List of country restrictions.
* @param string $sNormQuery Normalized query string.
* @param object $oNormalizer Normalizer function to use on tokens.
*
* @return void
*/
public function addTokensFromDB(&$oDB, &$aTokens, &$aCountryCodes, $sNormQuery, $oNormalizer)
{
// Check which tokens we have, get the ID numbers
$sSQL = 'SELECT word_id, word_token, word, class, type, country_code,';
$sSQL .= ' operator, coalesce(search_name_count, 0) as count';
$sSQL .= ' FROM word WHERE word_token in (';
$sSQL .= join(',', array_map('getDBQuoted', $aTokens)).')';
Debug::printSQL($sSQL);
$aDBWords = chksql($oDB->getAll($sSQL), 'Could not get word tokens.');
foreach ($aDBWords as $aWord) {
$oToken = null;
$iId = (int) $aWord['word_id'];
if ($aWord['class']) {
// Special terms need to appear in their normalized form.
if ($aWord['word']) {
$sNormWord = $aWord['word'];
if ($oNormalizer != null) {
$sNormWord = $oNormalizer->transliterate($aWord['word']);
}
if (strpos($sNormQuery, $sNormWord) === false) {
continue;
}
}
if ($aWord['class'] == 'place' && $aWord['type'] == 'house') {
$oToken = new Token\HouseNumber($iId, trim($aWord['word_token']));
} elseif ($aWord['class'] == 'place' && $aWord['type'] == 'postcode') {
if ($aWord['word']
&& pg_escape_string($aWord['word']) == $aWord['word']
) {
$oToken = new Token\Postcode(
$iId,
$aWord['word'],
$aWord['country_code']
);
}
} else {
// near and in operator the same at the moment
$oToken = new Token\SpecialTerm(
$iId,
$aWord['class'],
$aWord['type'],
$aWord['operator'] ? Operator::NEAR : Operator::NONE
);
}
} elseif ($aWord['country_code']) {
// Filter country tokens that do not match restricted countries.
if (!$aCountryCodes
|| in_array($aWord['country_code'], $aCountryCodes)
) {
$oToken = new Token\Country($iId, $aWord['country_code']);
}
} else {
$oToken = new Token\Word(
$iId,
$aWord['word_token'][0] != ' ',
(int) $aWord['count']
);
}
if ($oToken) {
$this->addToken($aWord['word_token'], $oToken);
}
}
}
/**
* Add a new token for the given word.
*
* @param string $sWord Word the token describes.
* @param object $oToken Token object to add.
*
* @return void
*/
public function addToken($sWord, $oToken)
{
if (isset($this->aTokens[$sWord])) {
$this->aTokens[$sWord][] = $oToken;
} else {
$this->aTokens[$sWord] = array($oToken);
}
}
public function debugTokenByWordIdList()
{
$aWordsIDs = array();
foreach ($this->aTokens as $sToken => $aWords) {
foreach ($aWords as $aToken) {
if ($aToken->iId !== null) {
$aWordsIDs[$aToken->iId] =
'#'.$sToken.'('.$aToken->iId.')#';
}
}
}
return $aWordsIDs;
}
public function debugInfo()
{
return $this->aTokens;
}
}

32
lib/TokenPostcode.php Normal file
View File

@@ -0,0 +1,32 @@
<?php
namespace Nominatim\Token;
/**
* A postcode token.
*/
class Postcode
{
/// Database word id, if available.
public $iId;
/// Full nomralized postcode (upper cased).
public $sPostcode;
// Optional country code the postcode belongs to (currently unused).
public $sCountryCode;
public function __construct($iId, $sPostcode, $sCountryCode = '')
{
$this->iId = $iId;
$this->sPostcode = $sPostcode;
$this->sCountryCode = empty($sCountryCode) ? '' : $sCountryCode;
}
public function debugInfo()
{
return array(
'ID' => $this->iId,
'Type' => 'postcode',
'Info' => $this->sPostcode.'('.$this->sCountryCode.')'
);
}
}

41
lib/TokenSpecialTerm.php Normal file
View File

@@ -0,0 +1,41 @@
<?php
namespace Nominatim\Token;
require_once(CONST_BasePath.'/lib/SpecialSearchOperator.php');
/**
* A word token describing a place type.
*/
class SpecialTerm
{
/// Database word id, if applicable.
public $iId;
/// Class (or OSM tag key) of the place to look for.
public $sClass;
/// Type (or OSM tag value) of the place to look for.
public $sType;
/// Relationship of the operator to the object (see Operator class).
public $iOperator;
public function __construct($iID, $sClass, $sType, $iOperator)
{
$this->iId = $iID;
$this->sClass = $sClass;
$this->sType = $sType;
$this->iOperator = $iOperator;
}
public function debugInfo()
{
return array(
'ID' => $this->iId,
'Type' => 'special term',
'Info' => array(
'class' => $this->sClass,
'type' => $this->sType,
'operator' => \Nominatim\Operator::toString($this->iOperator)
)
);
}
}

35
lib/TokenWord.php Normal file
View File

@@ -0,0 +1,35 @@
<?php
namespace Nominatim\Token;
/**
* A standard word token.
*/
class Word
{
/// Database word id, if applicable.
public $iId;
/// If true, the word may represent only part of a place name.
public $bPartial;
/// Number of appearances in the database.
public $iSearchNameCount;
public function __construct($iId, $bPartial, $iSearchNameCount)
{
$this->iId = $iId;
$this->bPartial = $bPartial;
$this->iSearchNameCount = $iSearchNameCount;
}
public function debugInfo()
{
return array(
'ID' => $this->iId,
'Type' => 'word',
'Info' => array(
'partial' => $this->bPartial,
'count' => $this->iSearchNameCount
)
);
}
}

View File

@@ -1,145 +1,222 @@
<?php
function getCmdOpt($aArg, $aSpec, &$aResult, $bExitOnError = false, $bExitOnUnknown = false)
{
$aQuick = array();
$aCounts = array();
foreach($aSpec as $aLine)
{
if (is_array($aLine))
{
if ($aLine[0]) $aQuick['--'.$aLine[0]] = $aLine;
if ($aLine[1]) $aQuick['-'.$aLine[1]] = $aLine;
$aCounts[$aLine[0]] = 0;
}
}
function getCmdOpt($aArg, $aSpec, &$aResult, $bExitOnError = false, $bExitOnUnknown = false)
{
$aQuick = array();
$aCounts = array();
$aResult = array();
$bUnknown = false;
$iSize = sizeof($aArg);
for ($i = 1; $i < $iSize; $i++)
{
if (isset($aQuick[$aArg[$i]]))
{
$aLine = $aQuick[$aArg[$i]];
$aCounts[$aLine[0]]++;
$xVal = null;
if ($aLine[4] == $aLine[5])
{
if ($aLine[4])
{
$xVal = array();
for($n = $aLine[4]; $i < $iSize && $n; $n--)
{
$i++;
if ($i >= $iSize || $aArg[$i][0] == '-') showUsage($aSpec, $bExitOnError, 'Parameter of \''.$aLine[0].'\' is missing');
foreach ($aSpec as $aLine) {
if (is_array($aLine)) {
if ($aLine[0]) $aQuick['--'.$aLine[0]] = $aLine;
if ($aLine[1]) $aQuick['-'.$aLine[1]] = $aLine;
$aCounts[$aLine[0]] = 0;
}
}
switch ($aLine[6])
{
case 'realpath':
$xVal[] = realpath($aArg[$i]);
break;
case 'realdir':
$sPath = realpath(dirname($aArg[$i]));
if ($sPath)
$xVal[] = $sPath . '/' . basename($aArg[$i]);
else
$xVal[] = $sPath;
break;
case 'bool':
$xVal[] = (bool)$aArg[$i];
break;
case 'int':
$xVal[] = (int)$aArg[$i];
break;
case 'float':
$xVal[] = (float)$aArg[$i];
break;
default:
$xVal[] = $aArg[$i];
break;
}
}
if ($aLine[4] == 1) $xVal = $xVal[0];
}
else
{
$xVal = true;
}
}
else
{
fail('Variable numbers of params not yet supported');
}
$aResult = array();
$bUnknown = false;
$iSize = count($aArg);
for ($i = 1; $i < $iSize; $i++) {
if (isset($aQuick[$aArg[$i]])) {
$aLine = $aQuick[$aArg[$i]];
$aCounts[$aLine[0]]++;
$xVal = null;
if ($aLine[4] == $aLine[5]) {
if ($aLine[4]) {
$xVal = array();
for ($n = $aLine[4]; $i < $iSize && $n; $n--) {
$i++;
if ($i >= $iSize || $aArg[$i][0] == '-') showUsage($aSpec, $bExitOnError, 'Parameter of \''.$aLine[0].'\' is missing');
if ($aLine[3] > 1)
{
if (!array_key_exists($aLine[0], $aResult)) $aResult[$aLine[0]] = array();
$aResult[$aLine[0]][] = $xVal;
}
else
{
$aResult[$aLine[0]] = $xVal;
}
}
else
{
$bUnknown = $aArg[$i];
}
}
switch ($aLine[6]) {
case 'realpath':
$xVal[] = realpath($aArg[$i]);
break;
case 'realdir':
$sPath = realpath(dirname($aArg[$i]));
if ($sPath) {
$xVal[] = $sPath . '/' . basename($aArg[$i]);
} else {
$xVal[] = $sPath;
}
break;
case 'bool':
$xVal[] = (bool)$aArg[$i];
break;
case 'int':
$xVal[] = (int)$aArg[$i];
break;
case 'float':
$xVal[] = (float)$aArg[$i];
break;
default:
$xVal[] = $aArg[$i];
break;
}
}
if ($aLine[4] == 1) $xVal = $xVal[0];
} else {
$xVal = true;
}
} else {
fail('Variable numbers of params not yet supported');
}
if (array_key_exists('help', $aResult)) showUsage($aSpec);
if ($bUnknown && $bExitOnUnknown) showUsage($aSpec, $bExitOnError, 'Unknown option \''.$bUnknown.'\'');
if ($aLine[3] > 1) {
if (!array_key_exists($aLine[0], $aResult)) $aResult[$aLine[0]] = array();
$aResult[$aLine[0]][] = $xVal;
} else {
$aResult[$aLine[0]] = $xVal;
}
} else {
$bUnknown = $aArg[$i];
}
}
foreach($aSpec as $aLine)
{
if (is_array($aLine))
{
if ($aCounts[$aLine[0]] < $aLine[2]) showUsage($aSpec, $bExitOnError, 'Option \''.$aLine[0].'\' is missing');
if ($aCounts[$aLine[0]] > $aLine[3]) showUsage($aSpec, $bExitOnError, 'Option \''.$aLine[0].'\' is pressent too many times');
switch ($aLine[6])
{
case 'bool':
if (!array_key_exists($aLine[0], $aResult))
$aResult[$aLine[0]] = false;
break;
}
}
}
return $bUnknown;
}
if (array_key_exists('help', $aResult)) showUsage($aSpec);
if ($bUnknown && $bExitOnUnknown) showUsage($aSpec, $bExitOnError, 'Unknown option \''.$bUnknown.'\'');
function showUsage($aSpec, $bExit = false, $sError = false)
{
if ($sError)
{
echo basename($_SERVER['argv'][0]).': '.$sError."\n";
echo 'Try `'.basename($_SERVER['argv'][0]).' --help` for more information.'."\n";
exit;
}
echo "Usage: ".basename($_SERVER['argv'][0])."\n";
$bFirst = true;
foreach($aSpec as $aLine)
{
if (is_array($aLine))
{
if ($bFirst)
{
$bFirst = false;
echo "\n";
}
$aNames = array();
if ($aLine[1]) $aNames[] = '-'.$aLine[1];
if ($aLine[0]) $aNames[] = '--'.$aLine[0];
$sName = join(', ',$aNames);
echo ' '.$sName.str_repeat(' ',30-strlen($sName)).$aLine[7]."\n";
}
else
{
echo $aLine."\n";
}
}
echo "\n";
exit;
}
foreach ($aSpec as $aLine) {
if (is_array($aLine)) {
if ($aCounts[$aLine[0]] < $aLine[2]) showUsage($aSpec, $bExitOnError, 'Option \''.$aLine[0].'\' is missing');
if ($aCounts[$aLine[0]] > $aLine[3]) showUsage($aSpec, $bExitOnError, 'Option \''.$aLine[0].'\' is pressent too many times');
switch ($aLine[6]) {
case 'bool':
if (!array_key_exists($aLine[0], $aResult))
$aResult[$aLine[0]] = false;
break;
}
}
}
return $bUnknown;
}
function showUsage($aSpec, $bExit = false, $sError = false)
{
if ($sError) {
echo basename($_SERVER['argv'][0]).': '.$sError."\n";
echo 'Try `'.basename($_SERVER['argv'][0]).' --help` for more information.'."\n";
exit;
}
echo 'Usage: '.basename($_SERVER['argv'][0])."\n";
$bFirst = true;
foreach ($aSpec as $aLine) {
if (is_array($aLine)) {
if ($bFirst) {
$bFirst = false;
echo "\n";
}
$aNames = array();
if ($aLine[1]) $aNames[] = '-'.$aLine[1];
if ($aLine[0]) $aNames[] = '--'.$aLine[0];
$sName = join(', ', $aNames);
echo ' '.$sName.str_repeat(' ', 30-strlen($sName)).$aLine[7]."\n";
} else {
echo $aLine."\n";
}
}
echo "\n";
exit;
}
function chksql($oSql, $sMsg = false)
{
if (PEAR::isError($oSql)) {
fail($sMsg || $oSql->getMessage(), $oSql->userinfo);
}
return $oSql;
}
function info($sMsg)
{
echo date('Y-m-d H:i:s == ').$sMsg."\n";
}
$aWarnings = array();
function warn($sMsg)
{
$GLOBALS['aWarnings'][] = $sMsg;
echo date('Y-m-d H:i:s == ').'WARNING: '.$sMsg."\n";
}
function repeatWarnings()
{
foreach ($GLOBALS['aWarnings'] as $sMsg) {
echo ' * ',$sMsg."\n";
}
}
function runSQLScript($sScript, $bfatal = true, $bVerbose = false, $bIgnoreErrors = false)
{
// Convert database DSN to psql parameters
$aDSNInfo = DB::parseDSN(CONST_Database_DSN);
if (!isset($aDSNInfo['port']) || !$aDSNInfo['port']) $aDSNInfo['port'] = 5432;
$sCMD = 'psql -p '.$aDSNInfo['port'].' -d '.$aDSNInfo['database'];
if (isset($aDSNInfo['hostspec']) && $aDSNInfo['hostspec']) {
$sCMD .= ' -h ' . $aDSNInfo['hostspec'];
}
if (isset($aDSNInfo['username']) && $aDSNInfo['username']) {
$sCMD .= ' -U ' . $aDSNInfo['username'];
}
$aProcEnv = null;
if (isset($aDSNInfo['password']) && $aDSNInfo['password']) {
$aProcEnv = array_merge(array('PGPASSWORD' => $aDSNInfo['password']), $_ENV);
}
if (!$bVerbose) {
$sCMD .= ' -q';
}
if ($bfatal && !$bIgnoreErrors) {
$sCMD .= ' -v ON_ERROR_STOP=1';
}
$aDescriptors = array(
0 => array('pipe', 'r'),
1 => STDOUT,
2 => STDERR
);
$ahPipes = null;
$hProcess = @proc_open($sCMD, $aDescriptors, $ahPipes, null, $aProcEnv);
if (!is_resource($hProcess)) {
fail('unable to start pgsql');
}
if (!$bVerbose) {
fwrite($ahPipes[0], 'set client_min_messages to WARNING;');
}
while (strlen($sScript)) {
$iWritten = fwrite($ahPipes[0], $sScript);
if ($iWritten <= 0) break;
$sScript = substr($sScript, $iWritten);
}
fclose($ahPipes[0]);
$iReturn = proc_close($hProcess);
if ($bfatal && $iReturn > 0) {
fail("pgsql returned with error code ($iReturn)");
}
}
function runWithEnv($sCmd, $aEnv)
{
$aFDs = array(
0 => array('pipe', 'r'),
1 => STDOUT,
2 => STDERR
);
$aPipes = null;
$hProc = @proc_open($sCmd, $aFDs, $aPipes, null, $aEnv);
if (!is_resource($hProc)) {
fail('unable to run command:' . $sCmd);
}
fclose($aPipes[0]); // no stdin
$iStat = proc_close($hProc);
return $iStat;
}

View File

@@ -1,26 +1,43 @@
<?php
require_once('DB.php');
function &getDB($bNew = false, $bPersistent = false)
{
// Get the database object
$oDB =& DB::connect(CONST_Database_DSN.($bNew?'?new_link=true':''), $bPersistent);
if (PEAR::IsError($oDB))
{
var_dump(CONST_Database_DSN);
var_Dump($oDB);
fail($oDB->getMessage());
}
$oDB->setFetchMode(DB_FETCHMODE_ASSOC);
$oDB->query("SET DateStyle TO 'sql,european'");
$oDB->query("SET client_encoding TO 'utf-8'");
$iMaxExecution = ini_get('max_execution_time') * 1000;
if ($iMaxExecution > 0) $oDB->query("SET statement_timeout TO $iMaxExecution");
return $oDB;
}
require_once('DB.php');
function getDBQuoted($s)
{
return "'".pg_escape_string($s)."'";
}
function &getDB($bNew = false, $bPersistent = false)
{
// Get the database object
$oDB = chksql(
DB::connect(CONST_Database_DSN.($bNew?'?new_link=true':''), $bPersistent),
'Failed to establish database connection'
);
$oDB->setFetchMode(DB_FETCHMODE_ASSOC);
$oDB->query("SET DateStyle TO 'sql,european'");
$oDB->query("SET client_encoding TO 'utf-8'");
$iMaxExecution = ini_get('max_execution_time') * 1000;
if ($iMaxExecution > 0) $oDB->query("SET statement_timeout TO $iMaxExecution");
return $oDB;
}
function getDBQuoted($s)
{
return "'".pg_escape_string($s)."'";
}
function getArraySQL($a)
{
return 'ARRAY['.join(',', $a).']';
}
function getPostgresVersion(&$oDB)
{
$sVersionString = $oDB->getOne('select version()');
preg_match('#PostgreSQL ([0-9]+)[.]([0-9]+)[^0-9]#', $sVersionString, $aMatches);
return (float) ($aMatches[1].'.'.$aMatches[2]);
}
function getPostgisVersion(&$oDB)
{
$sVersionString = $oDB->getOne('select postgis_full_version()');
preg_match('#POSTGIS="([0-9]+)[.]([0-9]+)[.]([0-9]+)( r([0-9]+))?"#', $sVersionString, $aMatches);
return (float) ($aMatches[1].'.'.$aMatches[2]);
}

View File

@@ -1,31 +1,28 @@
<?php
if (file_exists(getenv('NOMINATIM_SETTINGS')))
{
require_once(getenv('NOMINATIM_SETTINGS'));
}
require_once('init.php');
require_once('cmd.php');
require_once('init.php');
require_once('cmd.php');
require_once('DebugNone.php');
// handle http proxy when using file_get_contents
if (CONST_HTTP_Proxy) {
$proxy = 'tcp://' . CONST_HTTP_Proxy_Host . ':' . CONST_HTTP_Proxy_Port;
$aHeaders = array();
if(CONST_HTTP_Proxy_Login != null && CONST_HTTP_Proxy_Login != '' && CONST_HTTP_Proxy_Password != null && CONST_HTTP_Proxy_Password != '') {
$auth = base64_encode(CONST_HTTP_Proxy_Login . ':' . CONST_HTTP_Proxy_Password);
$aHeaders = array("Proxy-Authorization: Basic $auth");
}
$aContext = array(
'http' => array(
'proxy' => $proxy,
'request_fulluri' => true,
'header' => $aHeaders
),
'https' => array(
'proxy' => $proxy,
'request_fulluri' => true,
'header' => $aHeaders
)
);
stream_context_set_default($aContext);
}
// handle http proxy when using file_get_contents
if (CONST_HTTP_Proxy) {
$proxy = 'tcp://' . CONST_HTTP_Proxy_Host . ':' . CONST_HTTP_Proxy_Port;
$aHeaders = array();
if (CONST_HTTP_Proxy_Login != null && CONST_HTTP_Proxy_Login != '' && CONST_HTTP_Proxy_Password != null && CONST_HTTP_Proxy_Password != '') {
$auth = base64_encode(CONST_HTTP_Proxy_Login . ':' . CONST_HTTP_Proxy_Password);
$aHeaders = array("Proxy-Authorization: Basic $auth");
}
$aContext = array(
'http' => array(
'proxy' => $proxy,
'request_fulluri' => true,
'header' => $aHeaders
),
'https' => array(
'proxy' => $proxy,
'request_fulluri' => true,
'header' => $aHeaders
)
);
stream_context_set_default($aContext);
}

View File

@@ -1,64 +1,101 @@
<?php
require_once('init.php');
if (CONST_NoAccessControl)
{
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: OPTIONS,GET");
if (!empty($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
{
header("Access-Control-Allow-Headers: ".$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']);
}
}
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') exit;
require_once('init.php');
require_once('ParameterParser.php');
require_once(CONST_Debug ? 'DebugHtml.php' : 'DebugNone.php');
if (CONST_ClosedForIndexing && strpos(CONST_ClosedForIndexingExceptionIPs, ','.$_SERVER["REMOTE_ADDR"].',') === false)
{
echo "Closed for re-indexing...";
exit;
}
/***************************************************************************
*
* Error handling functions
*
*/
$aBucketKeys = array();
if (isset($_SERVER["HTTP_REFERER"])) $aBucketKeys[] = str_replace('www.','',strtolower(parse_url($_SERVER["HTTP_REFERER"], PHP_URL_HOST)));
if (isset($_SERVER["REMOTE_ADDR"])) $aBucketKeys[] = $_SERVER["REMOTE_ADDR"];
if (isset($_GET["email"])) $aBucketKeys[] = $_GET["email"];
function chksql($oSql, $sMsg = 'Database request failed')
{
if (!PEAR::isError($oSql)) return $oSql;
$fBucketVal = doBucket($aBucketKeys,
(defined('CONST_ConnectionBucket_PageType')?constant('CONST_ConnectionBucket_Cost_'.CONST_ConnectionBucket_PageType):1) + user_busy_cost(),
CONST_ConnectionBucket_LeakRate, CONST_ConnectionBucket_BlockLimit);
header('HTTP/1.0 500 Internal Server Error');
header('Content-type: text/html; charset=utf-8');
if ($fBucketVal > CONST_ConnectionBucket_WaitLimit && $fBucketVal < CONST_ConnectionBucket_BlockLimit)
{
$m = getBucketMemcache();
$iCurrentSleeping = $m->increment('sleepCounter');
if (false === $iCurrentSleeping)
{
$m->add('sleepCounter', 0);
$iCurrentSleeping = $m->increment('sleepCounter');
}
if ($iCurrentSleeping >= CONST_ConnectionBucket_MaxSleeping || isBucketSleeping($aBucketKeys))
{
// Too many threads sleeping already. This becomes a hard block.
$fBucketVal = doBucket($aBucketKeys, CONST_ConnectionBucket_BlockLimit, CONST_ConnectionBucket_LeakRate, CONST_ConnectionBucket_BlockLimit);
}
else
{
setBucketSleeping($aBucketKeys, true);
sleep(($fBucketVal - CONST_ConnectionBucket_WaitLimit)/CONST_ConnectionBucket_LeakRate);
$fBucketVal = doBucket($aBucketKeys, CONST_ConnectionBucket_LeakRate, CONST_ConnectionBucket_LeakRate, CONST_ConnectionBucket_BlockLimit);
setBucketSleeping($aBucketKeys, false);
}
$m->decrement('sleepCounter');
}
$sSqlError = $oSql->getMessage();
if (strpos(CONST_BlockedIPs, ','.$_SERVER["REMOTE_ADDR"].',') !== false || $fBucketVal >= CONST_ConnectionBucket_BlockLimit)
{
header("HTTP/1.0 429 Too Many Requests");
echo "Your IP has been blocked. \n";
echo CONST_BlockMessage;
exit;
}
echo <<<INTERNALFAIL
<html>
<head><title>Internal Server Error</title></head>
<body>
<h1>Internal Server Error</h1>
<p>Nominatim has encountered an internal error while accessing the database.
This may happen because the database is broken or because of a bug in
the software. If you think it is a bug, feel free to report
it over on <a href="https://github.com/openstreetmap/Nominatim/issues">
Github</a>. Please include the URL that caused the problem and the
complete error details below.</p>
<p><b>Message:</b> $sMsg</p>
<p><b>SQL Error:</b> $sSqlError</p>
<p><b>Details:</b> <pre>
INTERNALFAIL;
header('Content-type: text/html; charset=utf-8');
if (CONST_Debug) {
var_dump($oSql);
} else {
echo "<pre>\n".$oSql->getUserInfo().'</pre>';
}
echo '</pre></p></body></html>';
exit;
}
function failInternalError($sError, $sSQL = false, $vDumpVar = false)
{
header('HTTP/1.0 500 Internal Server Error');
header('Content-type: text/html; charset=utf-8');
echo '<html><body><h1>Internal Server Error</h1>';
echo '<p>Nominatim has encountered an internal error while processing your request. This is most likely because of a bug in the software.</p>';
echo '<p><b>Details:</b> '.$sError,'</p>';
echo '<p>Feel free to file an issue on <a href="https://github.com/openstreetmap/Nominatim/issues">Github</a>. ';
echo 'Please include the error message above and the URL you used.</p>';
if (CONST_Debug) {
echo '<hr><h2>Debugging Information</h2><br>';
if ($sSQL) {
echo '<h3>SQL query</h3><code>'.$sSQL.'</code>';
}
if ($vDumpVar) {
echo '<h3>Result</h3> <code>';
var_dump($vDumpVar);
echo '</code>';
}
}
echo "\n</body></html>\n";
exit;
}
function userError($sError)
{
header('HTTP/1.0 400 Bad Request');
header('Content-type: text/html; charset=utf-8');
echo '<html><body><h1>Bad Request</h1>';
echo '<p>Nominatim has encountered an error with your request.</p>';
echo '<p><b>Details:</b> '.$sError.'</p>';
echo '<p>If you feel this error is incorrect feel file an issue on <a href="https://github.com/openstreetmap/Nominatim/issues">Github</a>. ';
echo 'Please include the error message above and the URL you used.</p>';
echo "\n</body></html>\n";
exit;
}
/***************************************************************************
* HTTP Reply header setup
*/
if (CONST_NoAccessControl) {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: OPTIONS,GET');
if (!empty($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) {
header('Access-Control-Allow-Headers: '.$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']);
}
}
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') exit;
if (CONST_Debug) header('Content-type: text/html; charset=utf-8');

View File

@@ -1,14 +1,9 @@
<?php
@define('CONST_BasePath', dirname(dirname(__FILE__)));
require_once(CONST_BasePath.'/lib/lib.php');
require_once(CONST_BasePath.'/lib/db.php');
require_once(CONST_BasePath.'/settings/settings.php');
require_once(CONST_BasePath.'/lib/lib.php');
require_once(CONST_BasePath.'/lib/leakybucket.php');
require_once(CONST_BasePath.'/lib/db.php');
if (get_magic_quotes_gpc())
{
echo "Please disable magic quotes in your php.ini configuration\n";
exit;
}
if (get_magic_quotes_gpc()) {
echo "Please disable magic quotes in your php.ini configuration\n";
exit;
}

View File

@@ -1,168 +0,0 @@
<?php
function getBucketMemcache()
{
static $m;
if (!CONST_ConnectionBucket_MemcacheServerAddress) return null;
if (!isset($m))
{
$m = new Memcached();
$m->addServer(CONST_ConnectionBucket_MemcacheServerAddress, CONST_ConnectionBucket_MemcacheServerPort);
}
return $m;
}
function doBucket($asKey, $iRequestCost, $iLeakPerSecond, $iThreshold)
{
$m = getBucketMemcache();
if (!$m) return 0;
$iMaxVal = 0;
$t = time();
foreach($asKey as $sKey)
{
$aCurrentBlock = $m->get($sKey);
if (!$aCurrentBlock)
{
$aCurrentBlock = array($iRequestCost, $t, false);
}
else
{
// add RequestCost
// remove leak * the time since the last request
$aCurrentBlock[0] += $iRequestCost - ($t - $aCurrentBlock[1])*$iLeakPerSecond;
$aCurrentBlock[1] = $t;
}
if ($aCurrentBlock[0] <= 0)
{
$m->delete($sKey);
}
else
{
// If we have hit the threshold stop and record this to the block list
if ($aCurrentBlock[0] >= $iThreshold)
{
$aCurrentBlock[0] = $iThreshold;
// Make up to 10 attempts to record this to memcache (with locking to prevent conflicts)
$i = 10;
for($i = 0; $i < 10; $i++)
{
$aBlockedList = $m->get('blockedList', null, $hCasToken);
if (!$aBlockedList)
{
$aBlockedList = array();
$m->add('blockedList', $aBlockedList);
$aBlockedList = $m->get('blockedList', null, $hCasToken);
}
if (!isset($aBlockedList[$sKey]))
{
$aBlockedList[$sKey] = array(1, $t);
}
else
{
$aBlockedList[$sKey][0]++;
$aBlockedList[$sKey][1] = $t;
}
if (sizeof($aBlockedList) > CONST_ConnectionBucket_MaxBlockList)
{
uasort($aBlockedList, 'byValue1');
$aBlockedList = array_slice($aBlockedList, 0, CONST_ConnectionBucket_MaxBlockList);
}
$x = $m->cas($hCasToken, 'blockedList', $aBlockedList);
if ($x) break;
}
}
// Only keep in memcache until the time it would have expired (to avoid clutering memcache)
$m->set($sKey, $aCurrentBlock, $t + 1 + $aCurrentBlock[0]/$iLeakPerSecond);
}
// Bucket result in the largest bucket we find
$iMaxVal = max($iMaxVal, $aCurrentBlock[0]);
}
return $iMaxVal;
}
function isBucketSleeping($asKey)
{
$m = getBucketMemcache();
if (!$m) return false;
foreach($asKey as $sKey)
{
$aCurrentBlock = $m->get($sKey);
if ($aCurrentBlock[2]) return true;
}
return false;
}
function setBucketSleeping($asKey, $bVal)
{
$m = getBucketMemcache();
if (!$m) return false;
$iMaxVal = 0;
$t = time();
foreach($asKey as $sKey)
{
$aCurrentBlock = $m->get($sKey);
$aCurrentBlock[2] = $bVal;
$m->set($sKey, $aCurrentBlock, $t + 1 + $aCurrentBlock[0]/CONST_ConnectionBucket_LeakRate);
}
return true;
}
function byValue1($a, $b)
{
if ($a[1] == $b[1])
{
return 0;
}
return ($a[1] > $b[1]) ? -1 : 1;
}
function byLastBlockTime($a, $b)
{
if ($a['lastBlockTimestamp'] == $b['lastBlockTimestamp'])
{
return 0;
}
return ($a['lastBlockTimestamp'] > $b['lastBlockTimestamp']) ? -1 : 1;
}
function getBucketBlocks()
{
$m = getBucketMemcache();
if (!$m) return null;
$t = time();
$aBlockedList = $m->get('blockedList', null, $hCasToken);
if (!$aBlockedList) $aBlockedList = array();
foreach($aBlockedList as $sKey => $aDetails)
{
$aCurrentBlock = $m->get($sKey);
if (!$aCurrentBlock) $aCurrentBlock = array(0, $t);
$iCurrentBucketSize = max(0, $aCurrentBlock[0] - ($t - $aCurrentBlock[1])*CONST_ConnectionBucket_LeakRate);
$aBlockedList[$sKey] = array(
'totalBlocks' => $aDetails[0],
'lastBlockTimestamp' => $aDetails[1],
'isSleeping' => (isset($aCurrentBlock[2])?$aCurrentBlock[2]:false),
'currentBucketSize' => $iCurrentBucketSize,
'currentlyBlocked' => $iCurrentBucketSize + (CONST_ConnectionBucket_Cost_Reverse) >= CONST_ConnectionBucket_BlockLimit,
);
}
uasort($aBlockedList, 'byLastBlockTime');
return $aBlockedList;
}
function clearBucketBlocks()
{
$m = getBucketMemcache();
if (!$m) return false;
$m->delete('blockedList');
return true;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,90 +1,74 @@
<?php
function logStart(&$oDB, $sType = '', $sQuery = '', $aLanguageList = array())
{
$aStartTime = explode('.',microtime(true));
if (!isset($aStartTime[1])) $aStartTime[1] = '0';
$sOutputFormat = '';
if (isset($_GET['format'])) $sOutputFormat = $_GET['format'];
function logStart(&$oDB, $sType = '', $sQuery = '', $aLanguageList = array())
{
$fStartTime = microtime(true);
$aStartTime = explode('.', $fStartTime);
if (!isset($aStartTime[1])) $aStartTime[1] = '0';
$hLog = array(
date('Y-m-d H:i:s',$aStartTime[0]).'.'.$aStartTime[1],
$_SERVER["REMOTE_ADDR"],
$_SERVER['QUERY_STRING'],
$sQuery
);
$sOutputFormat = '';
if (isset($_GET['format'])) $sOutputFormat = $_GET['format'];
if (CONST_Log_DB)
{
// Log
if ($sType == 'search')
{
$oDB->query('insert into query_log values ('.getDBQuoted($hLog[0]).','.getDBQuoted($hLog[3]).','.getDBQuoted($hLog[1]).')');
}
if ($sType == 'reverse') {
$sOutQuery = (isset($_GET['lat'])?$_GET['lat']:'').'/';
if (isset($_GET['lon'])) $sOutQuery .= $_GET['lon'];
if (isset($_GET['zoom'])) $sOutQuery .= '/'.$_GET['zoom'];
} else {
$sOutQuery = $sQuery;
}
$sSQL = 'insert into new_query_log (type,starttime,query,ipaddress,useragent,language,format)';
$sSQL .= ' values ('.getDBQuoted($sType).','.getDBQuoted($hLog[0]).','.getDBQuoted($hLog[2]);
$sSQL .= ','.getDBQuoted($hLog[1]).','.getDBQuoted($_SERVER['HTTP_USER_AGENT']).','.getDBQuoted(join(',',$aLanguageList)).','.getDBQuoted($sOutputFormat).')';
$oDB->query($sSQL);
}
$hLog = array(
date('Y-m-d H:i:s', $aStartTime[0]).'.'.$aStartTime[1],
$_SERVER['REMOTE_ADDR'],
$_SERVER['QUERY_STRING'],
$sOutQuery,
$sType,
$fStartTime
);
if (CONST_Log_File && CONST_Log_File_ReverseLog != '')
{
if ($sType == 'reverse')
{
$aStartTime = explode('.',$hLog[0]);
file_put_contents(CONST_Log_File_ReverseLog,
$aStartTime[0].','.$aStartTime[1].','.
php_uname('n').','.
'"'.addslashes(isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:'').'",'.
'"'.addslashes($hLog[1]).'",'.
$_GET['lat'].','.
$_GET['lon'].','.
$_GET['zoom'].','.
'"'.addslashes($_SERVER['HTTP_USER_AGENT']).'",'.
'"'.addslashes($sOutputFormat).'"'."\n",
FILE_APPEND);
}
}
if (CONST_Log_DB) {
if (isset($_GET['email']))
$sUserAgent = $_GET['email'];
elseif (isset($_SERVER['HTTP_REFERER']))
$sUserAgent = $_SERVER['HTTP_REFERER'];
elseif (isset($_SERVER['HTTP_USER_AGENT']))
$sUserAgent = $_SERVER['HTTP_USER_AGENT'];
else $sUserAgent = '';
$sSQL = 'insert into new_query_log (type,starttime,query,ipaddress,useragent,language,format,searchterm)';
$sSQL .= ' values ('.getDBQuoted($sType).','.getDBQuoted($hLog[0]).','.getDBQuoted($hLog[2]);
$sSQL .= ','.getDBQuoted($hLog[1]).','.getDBQuoted($sUserAgent).','.getDBQuoted(join(',', $aLanguageList)).','.getDBQuoted($sOutputFormat).','.getDBQuoted($hLog[3]).')';
$oDB->query($sSQL);
}
return $hLog;
}
return $hLog;
}
function logEnd(&$oDB, $hLog, $iNumResults)
{
$aEndTime = explode('.',microtime(true));
if (!$aEndTime[1]) $aEndTime[1] = '0';
$sEndTime = date('Y-m-d H:i:s',$aEndTime[0]).'.'.$aEndTime[1];
function logEnd(&$oDB, $hLog, $iNumResults)
{
$fEndTime = microtime(true);
if (CONST_Log_DB)
{
$sSQL = 'update query_log set endtime = '.getDBQuoted($sEndTime).', results = '.$iNumResults;
$sSQL .= ' where starttime = '.getDBQuoted($hLog[0]);
$sSQL .= ' and ipaddress = '.getDBQuoted($hLog[1]);
$sSQL .= ' and query = '.getDBQuoted($hLog[3]);
$oDB->query($sSQL);
if (CONST_Log_DB) {
$aEndTime = explode('.', $fEndTime);
if (!$aEndTime[1]) $aEndTime[1] = '0';
$sEndTime = date('Y-m-d H:i:s', $aEndTime[0]).'.'.$aEndTime[1];
$sSQL = 'update new_query_log set endtime = '.getDBQuoted($sEndTime).', results = '.$iNumResults;
$sSQL .= ' where starttime = '.getDBQuoted($hLog[0]);
$sSQL .= ' and ipaddress = '.getDBQuoted($hLog[1]);
$sSQL .= ' and query = '.getDBQuoted($hLog[2]);
$oDB->query($sSQL);
}
$sSQL = 'update new_query_log set endtime = '.getDBQuoted($sEndTime).', results = '.$iNumResults;
$sSQL .= ' where starttime = '.getDBQuoted($hLog[0]);
$sSQL .= ' and ipaddress = '.getDBQuoted($hLog[1]);
$sSQL .= ' and query = '.getDBQuoted($hLog[2]);
$oDB->query($sSQL);
}
if (CONST_Log_File && CONST_Log_File_SearchLog != '')
{
$aStartTime = explode('.',$hLog[0]);
file_put_contents(CONST_Log_File_SearchLog,
$aStartTime[0].','.$aStartTime[1].','.
php_uname('n').','.
'"'.addslashes(isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:'').'",'.
'"'.addslashes($hLog[1]).'",'.
'"'.addslashes($hLog[3]).'",'.
'"'.addslashes($_SERVER['HTTP_USER_AGENT']).'",'.
'"'.addslashes((isset($_GET['format']))?$_GET['format']:'').'",'.
$iNumResults."\n",
FILE_APPEND);
}
}
if (CONST_Log_File) {
$aOutdata = sprintf(
"[%s] %.4f %d %s \"%s\"\n",
$hLog[0],
$fEndTime-$hLog[5],
$iNumResults,
$hLog[4],
$hLog[2]
);
file_put_contents(CONST_Log_File, $aOutdata, FILE_APPEND | LOCK_EX);
}
}

52
lib/output.php Normal file
View File

@@ -0,0 +1,52 @@
<?php
function formatOSMType($sType, $bIncludeExternal = true)
{
if ($sType == 'N') return 'node';
if ($sType == 'W') return 'way';
if ($sType == 'R') return 'relation';
if (!$bIncludeExternal) return '';
if ($sType == 'T') return 'way';
if ($sType == 'I') return 'way';
return '';
}
function osmLink($aFeature, $sRefText = false)
{
$sOSMType = formatOSMType($aFeature['osm_type'], false);
if ($sOSMType) {
return '<a href="//www.openstreetmap.org/'.$sOSMType.'/'.$aFeature['osm_id'].'">'.$sOSMType.' '.($sRefText?$sRefText:$aFeature['osm_id']).'</a>';
}
return '';
}
function wikipediaLink($aFeature)
{
if ($aFeature['wikipedia']) {
list($sLanguage, $sArticle) = explode(':', $aFeature['wikipedia']);
return '<a href="https://'.$sLanguage.'.wikipedia.org/wiki/'.urlencode($sArticle).'" target="_blank">'.$aFeature['wikipedia'].'</a>';
}
return '';
}
function detailsLink($aFeature, $sTitle = false)
{
if (!$aFeature['place_id']) return '';
return '<a href="details.php?place_id='.$aFeature['place_id'].'">'.($sTitle?$sTitle:$aFeature['place_id']).'</a>';
}
function detailsPermaLink($aFeature, $sRefText = false)
{
$sOSMType = formatOSMType($aFeature['osm_type'], false);
if ($sOSMType) {
$sLabel = $sRefText ? $sRefText : $sOSMType.' '.$aFeature['osm_id'];
return '<a href="details.php?osmtype='.$aFeature['osm_type'].'&osmid='.$aFeature['osm_id'].'&class='.$aFeature['class'].'">'.$sLabel.'</a>';
}
return '';
}

View File

@@ -0,0 +1,81 @@
<?php
// https://github.com/geocoders/geocodejson-spec/
$aFilteredPlaces = array();
if (empty($aPlace)) {
if (isset($sError))
$aFilteredPlaces['error'] = $sError;
else $aFilteredPlaces['error'] = 'Unable to geocode';
javascript_renderData($aFilteredPlaces);
} else {
$aFilteredPlaces = array(
'type' => 'Feature',
'properties' => array(
'geocoding' => array()
)
);
if (isset($aPlace['place_id'])) $aFilteredPlaces['properties']['geocoding']['place_id'] = $aPlace['place_id'];
$sOSMType = formatOSMType($aPlace['osm_type']);
if ($sOSMType) {
$aFilteredPlaces['properties']['geocoding']['osm_type'] = $sOSMType;
$aFilteredPlaces['properties']['geocoding']['osm_id'] = $aPlace['osm_id'];
}
$aFilteredPlaces['properties']['geocoding']['type'] = $aPlace['type'];
$aFilteredPlaces['properties']['geocoding']['accuracy'] = (int) $fDistance;
$aFilteredPlaces['properties']['geocoding']['label'] = $aPlace['langaddress'];
$aFilteredPlaces['properties']['geocoding']['name'] = $aPlace['placename'];
if (isset($aPlace['address'])) {
$aFieldMappings = array(
'house_number' => 'housenumber',
'road' => 'street',
'locality' => 'locality',
'postcode' => 'postcode',
'city' => 'city',
'district' => 'district',
'county' => 'county',
'state' => 'state',
'country' => 'country'
);
$aAddressNames = $aPlace['address']->getAddressNames();
foreach ($aFieldMappings as $sFrom => $sTo) {
if (isset($aAddressNames[$sFrom])) {
$aFilteredPlaces['properties']['geocoding'][$sTo] = $aAddressNames[$sFrom];
}
}
$aFilteredPlaces['properties']['geocoding']['admin']
= $aPlace['address']->getAdminLevels();
}
if (isset($aPlace['asgeojson'])) {
$aFilteredPlaces['geometry'] = json_decode($aPlace['asgeojson']);
} else {
$aFilteredPlaces['geometry'] = array(
'type' => 'Point',
'coordinates' => array(
(float) $aPlace['lon'],
(float) $aPlace['lat']
)
);
}
javascript_renderData(array(
'type' => 'FeatureCollection',
'geocoding' => array(
'version' => '0.1.0',
'attribution' => 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright',
'licence' => 'ODbL',
'query' => $sQuery
),
'features' => array($aFilteredPlaces)
));
}

View File

@@ -0,0 +1,69 @@
<?php
$aFilteredPlaces = array();
if (empty($aPlace)) {
if (isset($sError))
$aFilteredPlaces['error'] = $sError;
else $aFilteredPlaces['error'] = 'Unable to geocode';
javascript_renderData($aFilteredPlaces);
} else {
$aFilteredPlaces = array(
'type' => 'Feature',
'properties' => array()
);
if (isset($aPlace['place_id'])) $aFilteredPlaces['properties']['place_id'] = $aPlace['place_id'];
$sOSMType = formatOSMType($aPlace['osm_type']);
if ($sOSMType) {
$aFilteredPlaces['properties']['osm_type'] = $sOSMType;
$aFilteredPlaces['properties']['osm_id'] = $aPlace['osm_id'];
}
$aFilteredPlaces['properties']['place_rank'] = $aPlace['rank_search'];
$aFilteredPlaces['properties']['category'] = $aPlace['class'];
$aFilteredPlaces['properties']['type'] = $aPlace['type'];
$aFilteredPlaces['properties']['importance'] = $aPlace['importance'];
$aFilteredPlaces['properties']['addresstype'] = strtolower($aPlace['addresstype']);
$aFilteredPlaces['properties']['name'] = $aPlace['placename'];
$aFilteredPlaces['properties']['display_name'] = $aPlace['langaddress'];
if (isset($aPlace['address'])) {
$aFilteredPlaces['properties']['address'] = $aPlace['address']->getAddressNames();
}
if (isset($aPlace['sExtraTags'])) $aFilteredPlaces['properties']['extratags'] = $aPlace['sExtraTags'];
if (isset($aPlace['sNameDetails'])) $aFilteredPlaces['properties']['namedetails'] = $aPlace['sNameDetails'];
if (isset($aPlace['aBoundingBox'])) {
$aFilteredPlaces['bbox'] = array(
(float) $aPlace['aBoundingBox'][2], // minlon
(float) $aPlace['aBoundingBox'][0], // minlat
(float) $aPlace['aBoundingBox'][3], // maxlon
(float) $aPlace['aBoundingBox'][1] // maxlat
);
}
if (isset($aPlace['asgeojson'])) {
$aFilteredPlaces['geometry'] = json_decode($aPlace['asgeojson']);
} else {
$aFilteredPlaces['geometry'] = array(
'type' => 'Point',
'coordinates' => array(
(float) $aPlace['lon'],
(float) $aPlace['lat']
)
);
}
javascript_renderData(array(
'type' => 'FeatureCollection',
'licence' => 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright',
'features' => array($aFilteredPlaces)
));
}

View File

@@ -1,106 +1,112 @@
<?php
header("content-type: text/html; charset=UTF-8");
header("content-type: text/html; charset=UTF-8");
?>
<?php include(CONST_BasePath.'/lib/template/includes/html-header.php'); ?>
<link href="css/common.css" rel="stylesheet" type="text/css" />
<link href="css/search.css" rel="stylesheet" type="text/css" />
<link href="css/common.css" rel="stylesheet" type="text/css" />
<link href="css/search.css" rel="stylesheet" type="text/css" />
</head>
<body id="reverse-page">
<?php include(CONST_BasePath.'/lib/template/includes/html-top-navigation.php'); ?>
<?php include(CONST_BasePath.'/lib/template/includes/html-top-navigation.php'); ?>
<form class="form-inline" role="search" accept-charset="UTF-8" action="<?php echo CONST_Website_BaseURL; ?>reverse.php">
<div class="form-group">
<input name="format" type="hidden" value="html">
<input name="lat" type="text" class="form-control input-sm" placeholder="latitude" value="<?php echo htmlspecialchars($_GET['lat']); ?>" >
<input name="lon" type="text" class="form-control input-sm" placeholder="longitude" value="<?php echo htmlspecialchars($_GET['lon']); ?>" >
max zoom
<form class="form-inline" role="search" accept-charset="UTF-8" action="<?php echo CONST_Website_BaseURL; ?>reverse.php">
<div class="form-group">
<input name="format" type="hidden" value="html">
lat
<input name="lat" type="text" class="form-control input-sm" placeholder="latitude" value="<?php echo $fLat; ?>" >
<a href="#" class="btn btn-default btn-xs" id="switch-coords" title="switch lat and lon">&lt;&gt;</a>
lon
<input name="lon" type="text" class="form-control input-sm" placeholder="longitude" value="<?php echo $fLon; ?>" >
max zoom
<select name="zoom" class="form-control input-sm" value="<?php echo htmlspecialchars($_GET['zoom']); ?>">
<option value="" <?php echo $_GET['zoom']==''?'selected':'' ?> >--</option>
<select name="zoom" class="form-control input-sm">
<option value="" <?php if ($iZoom === false) echo 'selected="selected"' ?> >--</option>
<?php
$aZoomLevels = array(
0 => "Continent / Sea",
1 => "",
2 => "",
3 => "Country",
4 => "",
5 => "State",
6 => "Region",
7 => "",
8 => "County",
9 => "",
10 => "City",
11 => "",
12 => "Town / Village",
13 => "",
14 => "Suburb",
15 => "",
16 => "Street",
17 => "",
18 => "Building",
19 => "",
20 => "",
21 => "",
);
foreach($aZoomLevels as $iZoomLevel => $sLabel)
{
$bSel = $iZoom === $iZoomLevel;
echo '<option value="'.$iZoomLevel.'"'.($bSel?' selected="selected"':'').'>'.$iZoomLevel.' '.$sLabel.'</option>'."\n";
}
?>
</select>
</div>
<div class="form-group search-button-group">
<button type="submit" class="btn btn-primary btn-sm">Search</button>
</div>
<div class="search-type-link">
<a href="<?php echo CONST_Website_BaseURL; ?>search.php">forward search</a>
</div>
</form>
<div id="content">
<?php if (count($aPlace)>0) { ?>
<div id="searchresults" class="sidebar">
<?php
$aResult = $aPlace;
$aZoomLevels = array(
0 => "Continent / Sea",
1 => "",
2 => "",
3 => "Country",
4 => "",
5 => "State",
6 => "Region",
7 => "",
8 => "County",
9 => "",
10 => "City",
11 => "",
12 => "Town / Village",
13 => "",
14 => "Suburb",
15 => "",
16 => "Street",
17 => "",
18 => "Building",
19 => "",
20 => "",
21 => "",
);
echo '<div class="result" data-position="0">';
foreach($aZoomLevels as $iZoomLevel => $sLabel)
{
$bSel = isset($_GET['zoom']) && ($_GET['zoom'] == (string)$iZoomLevel);
echo '<option value="'.$iZoomLevel.'"'.($bSel?'selected':'').'>'.$iZoomLevel.' '.$sLabel.'</option>'."\n";
}
echo (isset($aResult['icon'])?'<img alt="icon" src="'.$aResult['icon'].'"/>':'');
echo ' <span class="name">'.htmlspecialchars($aResult['langaddress']).'</span>';
if (isset($aResult['label']))
echo ' <span class="type">('.$aResult['label'].')</span>';
else if ($aResult['type'] == 'yes')
echo ' <span class="type">('.ucwords(str_replace('_',' ',$aResult['class'])).')</span>';
else
echo ' <span class="type">('.ucwords(str_replace('_',' ',$aResult['type'])).')</span>';
echo '<p>'.$aResult['lat'].','.$aResult['lon'].'</p>';
echo ' <a class="btn btn-default btn-xs details" href="details.php?place_id='.$aResult['place_id'].'">details</a>';
echo '</div>';
?>
</select>
</div>
<div class="form-group search-button-group">
<button type="submit" class="btn btn-primary btn-sm">Search</button>
</div>
<div class="search-type-link">
<a href="<?php echo CONST_Website_BaseURL; ?>search.php">forward search</a>
</div>
</form>
<div id="content">
<?php if ($aPlace) { ?>
<div id="searchresults" class="sidebar">
<?php
$aResult = $aPlace;
echo '<div class="result" data-position="0">';
echo (isset($aResult['icon'])?'<img alt="icon" src="'.$aResult['icon'].'"/>':'');
echo ' <span class="name">'.htmlspecialchars($aResult['langaddress']).'</span>';
if (isset($aResult['label']))
echo ' <span class="type">('.$aResult['label'].')</span>';
else if ($aResult['type'] == 'yes')
echo ' <span class="type">('.ucwords(str_replace('_',' ',$aResult['class'])).')</span>';
else
echo ' <span class="type">('.ucwords(str_replace('_',' ',$aResult['type'])).')</span>';
echo '<p>'.$aResult['lat'].','.$aResult['lon'].'</p>';
echo ' <a class="btn btn-default btn-xs details" href="details.php?place_id='.$aResult['place_id'].'">details</a>';
echo '</div>';
?>
</div>
</div>
<?php } else { ?>
<div id="intro" class="sidebar">
Search for coordinates or click anywhere on the map.
</div>
<div id="intro" class="sidebar">
Search for coordinates or click anywhere on the map.
</div>
<?php } ?>
<div id="map-wrapper">
<div id="map-position"></div>
<div id="map"></div>
</div>
<div id="map-wrapper">
<div id="map-position">
<div id="map-position-inner"></div>
<div id="map-position-close"><a href="#">hide</a></div>
</div>
<div id="map"></div>
</div>
</div> <!-- /content -->
</div> <!-- /content -->
@@ -108,22 +114,22 @@
<script type="text/javascript">
<?php
<script type="text/javascript">
<?php
$aNominatimMapInit = [
'zoom' => isset($_GET['zoom']) ? htmlspecialchars($_GET['zoom']) : CONST_Default_Zoom,
'lat' => isset($_GET['lat'] ) ? htmlspecialchars($_GET['lat'] ) : CONST_Default_Lat,
'lon' => isset($_GET['lon'] ) ? htmlspecialchars($_GET['lon'] ) : CONST_Default_Lon,
'tile_url' => $sTileURL,
'tile_attribution' => $sTileAttribution
];
echo 'var nominatim_map_init = ' . json_encode($aNominatimMapInit, JSON_PRETTY_PRINT) . ';';
$aNominatimMapInit = array(
'zoom' => $iZoom !== false ? $iZoom : CONST_Default_Zoom,
'lat' => $fLat !== false ? $fLat : CONST_Default_Lat,
'lon' => $fLon !== false ? $fLon : CONST_Default_Lon,
'tile_url' => $sTileURL,
'tile_attribution' => $sTileAttribution
);
echo 'var nominatim_map_init = ' . json_encode($aNominatimMapInit, JSON_PRETTY_PRINT) . ';';
echo 'var nominatim_results = ' . json_encode([$aPlace], JSON_PRETTY_PRINT) . ';';
?>
</script>
<?php include(CONST_BasePath.'/lib/template/includes/html-footer.php'); ?>
echo 'var nominatim_results = ' . json_encode([$aPlace], JSON_PRETTY_PRINT) . ';';
?>
</script>
<?php include(CONST_BasePath.'/lib/template/includes/html-footer.php'); ?>
</body>
</html>

View File

@@ -1,30 +1,62 @@
<?php
$aFilteredPlaces = array();
if (!sizeof($aPlace))
{
if (isset($sError))
$aFilteredPlaces['error'] = $sError;
else
$aFilteredPlaces['error'] = 'Unable to geocode';
}
else
{
if (isset($aPlace['place_id'])) $aFilteredPlaces['place_id'] = $aPlace['place_id'];
$aFilteredPlaces['licence'] = "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright";
$sOSMType = ($aPlace['osm_type'] == 'N'?'node':($aPlace['osm_type'] == 'W'?'way':($aPlace['osm_type'] == 'R'?'relation':'')));
if ($sOSMType)
{
$aFilteredPlaces['osm_type'] = $sOSMType;
$aFilteredPlaces['osm_id'] = $aPlace['osm_id'];
}
if (isset($aPlace['lat'])) $aFilteredPlaces['lat'] = $aPlace['lat'];
if (isset($aPlace['lon'])) $aFilteredPlaces['lon'] = $aPlace['lon'];
$aFilteredPlaces['display_name'] = $aPlace['langaddress'];
if (isset($aPlace['aAddress'])) $aFilteredPlaces['address'] = $aPlace['aAddress'];
if (isset($aPlace['sExtraTags'])) $aFilteredPlaces['extratags'] = $aPlace['sExtraTags'];
if (isset($aPlace['sNameDetails'])) $aFilteredPlaces['namedetails'] = $aPlace['sNameDetails'];
}
$aFilteredPlaces = array();
javascript_renderData($aFilteredPlaces);
if (empty($aPlace)) {
if (isset($sError))
$aFilteredPlaces['error'] = $sError;
else $aFilteredPlaces['error'] = 'Unable to geocode';
} else {
if (isset($aPlace['place_id'])) $aFilteredPlaces['place_id'] = $aPlace['place_id'];
$aFilteredPlaces['licence'] = 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright';
$sOSMType = formatOSMType($aPlace['osm_type']);
if ($sOSMType) {
$aFilteredPlaces['osm_type'] = $sOSMType;
$aFilteredPlaces['osm_id'] = $aPlace['osm_id'];
}
if (isset($aPlace['lat'])) $aFilteredPlaces['lat'] = $aPlace['lat'];
if (isset($aPlace['lon'])) $aFilteredPlaces['lon'] = $aPlace['lon'];
if ($sOutputFormat == 'jsonv2' || $sOutputFormat == 'geojson') {
$aFilteredPlaces['place_rank'] = $aPlace['rank_search'];
$aFilteredPlaces['category'] = $aPlace['class'];
$aFilteredPlaces['type'] = $aPlace['type'];
$aFilteredPlaces['importance'] = $aPlace['importance'];
$aFilteredPlaces['addresstype'] = strtolower($aPlace['addresstype']);
$aFilteredPlaces['name'] = $aPlace['placename'];
}
$aFilteredPlaces['display_name'] = $aPlace['langaddress'];
if (isset($aPlace['address'])) {
$aFilteredPlaces['address'] = $aPlace['address']->getAddressNames();
}
if (isset($aPlace['sExtraTags'])) $aFilteredPlaces['extratags'] = $aPlace['sExtraTags'];
if (isset($aPlace['sNameDetails'])) $aFilteredPlaces['namedetails'] = $aPlace['sNameDetails'];
if (isset($aPlace['aBoundingBox'])) {
$aFilteredPlaces['boundingbox'] = $aPlace['aBoundingBox'];
}
if (isset($aPlace['asgeojson'])) {
$aFilteredPlaces['geojson'] = json_decode($aPlace['asgeojson']);
}
if (isset($aPlace['assvg'])) {
$aFilteredPlaces['svg'] = $aPlace['assvg'];
}
if (isset($aPlace['astext'])) {
$aFilteredPlaces['geotext'] = $aPlace['astext'];
}
if (isset($aPlace['askml'])) {
$aFilteredPlaces['geokml'] = $aPlace['askml'];
}
}
javascript_renderData($aFilteredPlaces);

View File

@@ -1,41 +0,0 @@
<?php
$aFilteredPlaces = array();
if (!sizeof($aPlace))
{
if (isset($sError))
$aFilteredPlaces['error'] = $sError;
else
$aFilteredPlaces['error'] = 'Unable to geocode';
}
else
{
if ($aPlace['place_id']) $aFilteredPlaces['place_id'] = $aPlace['place_id'];
$aFilteredPlaces['licence'] = "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright";
$sOSMType = ($aPlace['osm_type'] == 'N'?'node':($aPlace['osm_type'] == 'W'?'way':($aPlace['osm_type'] == 'R'?'relation':'')));
if ($sOSMType)
{
$aFilteredPlaces['osm_type'] = $sOSMType;
$aFilteredPlaces['osm_id'] = $aPlace['osm_id'];
}
if (isset($aPlace['lat'])) $aFilteredPlaces['lat'] = $aPlace['lat'];
if (isset($aPlace['lon'])) $aFilteredPlaces['lon'] = $aPlace['lon'];
$aFilteredPlaces['place_rank'] = $aPlace['rank_search'];
$aFilteredPlaces['category'] = $aPlace['class'];
$aFilteredPlaces['type'] = $aPlace['type'];
$aFilteredPlaces['importance'] = $aPlace['importance'];
$aFilteredPlaces['addresstype'] = strtolower($aPlace['addresstype']);
$aFilteredPlaces['display_name'] = $aPlace['langaddress'];
$aFilteredPlaces['name'] = $aPlace['placename'];
if (isset($aPlace['aAddress'])) $aFilteredPlaces['address'] = $aPlace['aAddress'];
if (isset($aPlace['sExtraTags'])) $aFilteredPlaces['extratags'] = $aPlace['sExtraTags'];
if (isset($aPlace['sNameDetails'])) $aFilteredPlaces['namedetails'] = $aPlace['sNameDetails'];
}
javascript_renderData($aFilteredPlaces);

View File

@@ -1,68 +1,87 @@
<?php
header("content-type: text/xml; charset=UTF-8");
header('content-type: text/xml; charset=UTF-8');
echo "<";
echo "?xml version=\"1.0\" encoding=\"UTF-8\" ?";
echo ">\n";
echo '<';
echo '?xml version="1.0" encoding="UTF-8" ?';
echo ">\n";
echo "<reversegeocode";
echo " timestamp='".date(DATE_RFC822)."'";
echo " attribution='Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright'";
echo " querystring='".htmlspecialchars($_SERVER['QUERY_STRING'], ENT_QUOTES)."'";
echo ">\n";
echo '<reversegeocode';
echo " timestamp='".date(DATE_RFC822)."'";
echo " attribution='Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright'";
echo " querystring='".htmlspecialchars($_SERVER['QUERY_STRING'], ENT_QUOTES)."'";
echo ">\n";
if (!sizeof($aPlace))
{
if (isset($sError))
echo "<error>$sError</error>";
else
echo "<error>Unable to geocode</error>";
}
else
{
echo "<result";
if ($aPlace['place_id']) echo ' place_id="'.$aPlace['place_id'].'"';
$sOSMType = ($aPlace['osm_type'] == 'N'?'node':($aPlace['osm_type'] == 'W'?'way':($aPlace['osm_type'] == 'R'?'relation':'')));
if ($sOSMType) echo ' osm_type="'.$sOSMType.'"'.' osm_id="'.$aPlace['osm_id'].'"';
if ($aPlace['ref']) echo ' ref="'.htmlspecialchars($aPlace['ref']).'"';
if (isset($aPlace['lat'])) echo ' lat="'.htmlspecialchars($aPlace['lat']).'"';
if (isset($aPlace['lon'])) echo ' lon="'.htmlspecialchars($aPlace['lon']).'"';
echo ">".htmlspecialchars($aPlace['langaddress'])."</result>";
if (empty($aPlace)) {
if (isset($sError))
echo "<error>$sError</error>";
else echo '<error>Unable to geocode</error>';
} else {
echo '<result';
if ($aPlace['place_id']) echo ' place_id="'.$aPlace['place_id'].'"';
$sOSMType = formatOSMType($aPlace['osm_type']);
if ($sOSMType) echo ' osm_type="'.$sOSMType.'"'.' osm_id="'.$aPlace['osm_id'].'"';
if ($aPlace['ref']) echo ' ref="'.htmlspecialchars($aPlace['ref']).'"';
if (isset($aPlace['lat'])) echo ' lat="'.htmlspecialchars($aPlace['lat']).'"';
if (isset($aPlace['lon'])) echo ' lon="'.htmlspecialchars($aPlace['lon']).'"';
if (isset($aPlace['aBoundingBox'])) {
echo ' boundingbox="';
echo join(',', $aPlace['aBoundingBox']);
echo '"';
}
if (isset($aPlace['aAddress']))
{
echo "<addressparts>";
foreach($aPlace['aAddress'] as $sKey => $sValue)
{
$sKey = str_replace(' ','_',$sKey);
echo "<$sKey>";
echo htmlspecialchars($sValue);
echo "</$sKey>";
}
echo "</addressparts>";
}
if (isset($aPlace['asgeojson'])) {
echo ' geojson=\'';
echo $aPlace['asgeojson'];
echo '\'';
}
if (isset($aPlace['sExtraTags']))
{
echo "<extratags>";
foreach ($aPlace['sExtraTags'] as $sKey => $sValue)
{
echo '<tag key="'.htmlspecialchars($sKey).'" value="'.htmlspecialchars($sValue).'"/>';
}
echo "</extratags>";
}
if (isset($aPlace['assvg'])) {
echo ' geosvg=\'';
echo $aPlace['assvg'];
echo '\'';
}
if (isset($aPlace['sNameDetails']))
{
echo "<namedetails>";
foreach ($aPlace['sNameDetails'] as $sKey => $sValue)
{
echo '<name desc="'.htmlspecialchars($sKey).'">';
echo htmlspecialchars($sValue);
echo "</name>";
}
echo "</namedetails>";
}
}
if (isset($aPlace['astext'])) {
echo ' geotext=\'';
echo $aPlace['astext'];
echo '\'';
}
echo '>'.htmlspecialchars($aPlace['langaddress']).'</result>';
echo "</reversegeocode>";
if (isset($aPlace['address'])) {
echo '<addressparts>';
foreach ($aPlace['address']->getAddressNames() as $sKey => $sValue) {
$sKey = str_replace(' ', '_', $sKey);
echo "<$sKey>";
echo htmlspecialchars($sValue);
echo "</$sKey>";
}
echo '</addressparts>';
}
if (isset($aPlace['sExtraTags'])) {
echo '<extratags>';
foreach ($aPlace['sExtraTags'] as $sKey => $sValue) {
echo '<tag key="'.htmlspecialchars($sKey).'" value="'.htmlspecialchars($sValue).'"/>';
}
echo '</extratags>';
}
if (isset($aPlace['sNameDetails'])) {
echo '<namedetails>';
foreach ($aPlace['sNameDetails'] as $sKey => $sValue) {
echo '<name desc="'.htmlspecialchars($sKey).'">';
echo htmlspecialchars($sValue);
echo '</name>';
}
echo '</namedetails>';
}
if (isset($aPlace['askml'])) {
echo "\n<geokml>";
echo $aPlace['askml'];
echo '</geokml>';
}
}
echo '</reversegeocode>';

View File

@@ -1,133 +1,122 @@
<?php
header("content-type: text/html; charset=UTF-8");
header("content-type: text/html; charset=UTF-8");
?>
<?php include(CONST_BasePath.'/lib/template/includes/html-header.php'); ?>
<link href="css/common.css" rel="stylesheet" type="text/css" />
<link href="css/details.css" rel="stylesheet" type="text/css" />
<link href="css/common.css" rel="stylesheet" type="text/css" />
<link href="css/details.css" rel="stylesheet" type="text/css" />
</head>
<?php
function osm_link($aFeature)
{
$sOSMType = ($aFeature['osm_type'] == 'N'?'node':($aFeature['osm_type'] == 'W'?'way':($aFeature['osm_type'] == 'R'?'relation':'')));
if ($sOSMType) {
return '<a href="http://www.openstreetmap.org/browse/'.$sOSMType.'/'.$aFeature['osm_id'].'">'.$sOSMType.' '.$aFeature['osm_id'].'</a>';
}
return '';
}
function osmMapUrl($aFeature)
{
if (isset($sFeature['error_x']) && isset($sFeature['error_y']))
{
$sBaseUrl = '//www.openstreetmap.org/';
$sOSMType = formatOSMType($aFeature['osm_type'], false);
if ($sOSMType)
{
$sBaseUrl += $sOSMType.'/'.$aFeature['osm_id'];
}
function osm_map_url($aFeature)
{
$sLon = $aFeature['error_x'];
$sLat = $aFeature['error_y'];
return '<a href="'.$sBaseUrl.'?mlat='.$aFeature['error_y'].'&mlon='.$aFeature['error_x'].'">view on osm.org</a>';
}
return '';
}
if (isset($sLat))
{
$sOSMType = ($aFeature['osm_type'] == 'N'?'node':($aFeature['osm_type'] == 'W'?'way':($aFeature['osm_type'] == 'R'?'relation':'')));
if ($sOSMType)
{
return "http://www.openstreetmap.org/?lat=".$sLat."&lon=".$sLon."&zoom=18&layers=M&".$sOSMType."=".$aFeature['osm_id'];
}
}
return '';
}
function josm_edit_url($aFeature)
{
$fWidth = 0.0002;
$sLon = $aFeature['error_x'];
$sLat = $aFeature['error_y'];
function josm_edit_url($aFeature)
{
$fWidth = 0.0002;
$sLon = $aFeature['error_x'];
$sLat = $aFeature['error_y'];
if (isset($sLat))
{
return "http://localhost:8111/load_and_zoom?left=".($sLon-$fWidth)."&right=".($sLon+$fWidth)."&top=".($sLat+$fWidth)."&bottom=".($sLat-$fWidth);
}
if (isset($sLat))
{
return "http://localhost:8111/load_and_zoom?left=".($sLon-$fWidth)."&right=".($sLon+$fWidth)."&top=".($sLat+$fWidth)."&bottom=".($sLat-$fWidth);
}
$sOSMType = formatOSMType($aFeature['osm_type'], false);
if ($sOSMType)
{
return 'http://localhost:8111/import?url=http://www.openstreetmap.org/api/0.6/'.$sOSMType.'/'.$aFeature['osm_id'].'/full';
// Should be better to load by object id - but this doesn't seem to zoom correctly
// return " <a href=\"http://localhost:8111/load_object?new_layer=true&objects=".strtolower($aFeature['osm_type']).$sOSMID."\" target=\"josm\">Remote Control (JOSM / Merkaartor)</a>";
}
return '';
}
$sOSMType = ($aFeature['osm_type'] == 'N'?'node':($aFeature['osm_type'] == 'W'?'way':($aFeature['osm_type'] == 'R'?'relation':'')));
if ($sOSMType)
{
return 'http://localhost:8111/import?url=http://www.openstreetmap.org/api/0.6/'.$sOSMType.'/'.$aFeature['osm_id'].'/full';
// Should be better to load by object id - but this doesn't seem to zoom correctly
// return " <a href=\"http://localhost:8111/load_object?new_layer=true&objects=".strtolower($aFeature['osm_type']).$sOSMID."\" target=\"josm\">Remote Control (JOSM / Merkaartor)</a>";
}
return '';
}
function potlach_edit_url($aFeature)
{
$fWidth = 0.0002;
$sLat = $aFeature['error_y'];
$sLon = $aFeature['error_x'];
function potlach_edit_url($aFeature)
{
$fWidth = 0.0002;
$sLat = $aFeature['error_y'];
$sLon = $aFeature['error_x'];
if (isset($sLat))
{
return "http://www.openstreetmap.org/edit?editor=potlatch2&bbox=".($sLon-$fWidth).",".($sLat-$fWidth).",".($sLon+$fWidth).",".($sLat+$fWidth);
}
return '';
}
if (isset($sLat))
{
return "//www.openstreetmap.org/edit?editor=potlatch2&bbox=".($sLon-$fWidth).",".($sLat-$fWidth).",".($sLon+$fWidth).",".($sLat+$fWidth);
}
return '';
}
?>
<body id="details-page">
<div class="container">
<div class="row">
<div class="col-md-6">
<div class="container">
<div class="row">
<div class="col-md-6">
<h1><?php echo $aPointDetails['localname'] ?></h1>
<div class="locationdetails">
<h2 class="bg-danger">This object has an invalid geometry.</h2>
<h1><?php echo $aPointDetails['localname'] ?></h1>
<div class="locationdetails">
<h2 class="bg-danger">This object has an invalid geometry.</h2>
<div>
Type: <span class="type"><?php echo $aPointDetails['class'].':'.$aPointDetails['type'];?></span>
</div>
<div>
Type: <span class="type"><?php echo $aPointDetails['class'].':'.$aPointDetails['type'];?></span>
</div>
<div>
OSM: <span class="label"><?php echo osm_link($aPointDetails); ?><span>
</div>
<div>
OSM: <span class="label"><?php echo osmLink($aPointDetails); ?><span>
</div>
<h4>Error</h4>
<p>
<?php echo $aPointDetails['errormessage']?$aPointDetails['errormessage']:'unknown'; ?>
</p>
<?php if (osm_map_url($aPointDetails)) { ?>
<a href="<?php echo osm_map_url($aPointDetails); ?>">view on osm.org</a>
<?php } ?>
<h4>Error</h4>
<p>
<?php echo $aPointDetails['errormessage']?$aPointDetails['errormessage']:'unknown'; ?>
</p>
<?php echo osmMapUrl($aPointDetails); ?>
<h4>Edit</h4>
<ul>
<?php if (josm_edit_url($aPointDetails)) { ?>
<li><a href="<?php echo josm_edit_url($aPointDetails); ?>" target="josm">Remote Control (JOSM / Merkaartor)</a></li>
<?php } ?>
<?php if (potlach_edit_url($aPointDetails)) { ?>
<li><a href="<?php echo potlach_edit_url($aPointDetails); ?>" target="potlatch2">Potlatch 2</a></li>
<?php } ?>
</ul>
</div>
</div>
<div class="col-md-6">
<div id="map"></div>
</div>
<h4>Edit</h4>
<ul>
<?php if (josm_edit_url($aPointDetails)) { ?>
<li><a href="<?php echo josm_edit_url($aPointDetails); ?>" target="josm">Remote Control (JOSM / Merkaartor)</a></li>
<?php } ?>
<?php if (potlach_edit_url($aPointDetails)) { ?>
<li><a href="<?php echo potlach_edit_url($aPointDetails); ?>" target="potlatch2">Potlatch 2</a></li>
<?php } ?>
</ul>
</div>
</div>
<div class="col-md-6">
<div id="map"></div>
</div>
</div>
</div>
<script type="text/javascript">
<script type="text/javascript">
var nominatim_result = {
outlinestring: '<?php echo $aPointDetails['outlinestring'];?>',
lon: <?php echo isset($aPointDetails['error_x']) ? $aPointDetails['error_x'] : 0; ?>,
lat: <?php echo isset($aPointDetails['error_y']) ? $aPointDetails['error_y'] : 0; ?>
};
var nominatim_result = {
outlinestring: '<?php echo $aPointDetails['outlinestring'];?>',
lon: <?php echo isset($aPointDetails['error_x']) ? $aPointDetails['error_x'] : 0; ?>,
lat: <?php echo isset($aPointDetails['error_y']) ? $aPointDetails['error_y'] : 0; ?>
};
</script>
</script>
<?php include(CONST_BasePath.'/lib/template/includes/html-footer.php'); ?>
</body>
</html>
<?php include(CONST_BasePath.'/lib/template/includes/html-footer.php'); ?>
</body>
</html>

View File

@@ -1,288 +1,254 @@
<?php
header("content-type: text/html; charset=UTF-8");
header("content-type: text/html; charset=UTF-8");
?>
<?php include(CONST_BasePath.'/lib/template/includes/html-header.php'); ?>
<link href="css/common.css" rel="stylesheet" type="text/css" />
<link href="css/details.css" rel="stylesheet" type="text/css" />
<link href="css/common.css" rel="stylesheet" type="text/css" />
<link href="css/details.css" rel="stylesheet" type="text/css" />
</head>
<?php
function headline($sTitle)
{
echo "<tr class='all-columns'><td colspan='6'><h2>".$sTitle."</h2></td></tr>\n";
}
function headline($sTitle)
{
echo "<tr class='all-columns'><td colspan='6'><h2>".$sTitle."</h2></td></tr>\n";
}
function headline3($sTitle)
{
echo "<tr class='all-columns'><td colspan='6'><h3>".$sTitle."</h3></td></tr>\n";
}
function osm_link($aFeature)
{
$sOSMType = ($aFeature['osm_type'] == 'N'?'node':($aFeature['osm_type'] == 'W'?'way':($aFeature['osm_type'] == 'R'?'relation':'')));
if ($sOSMType)
{
return '<a href="http://www.openstreetmap.org/browse/'.$sOSMType.'/'.$aFeature['osm_id'].'">'.$sOSMType.' '.$aFeature['osm_id'].'</a>';
}
return '';
}
function wikipedia_link($aFeature)
{
if ($aFeature['wikipedia'])
{
list($sWikipediaLanguage,$sWikipediaArticle) = explode(':',$aFeature['wikipedia']);
return '<a href="https://'.$sWikipediaLanguage.'.wikipedia.org/wiki/'.urlencode($sWikipediaArticle).'" target="_blank">'.$aFeature['wikipedia'].'</a>';
}
return '';
}
function nominatim_link($aFeature, $sTitle)
{
return '<a href="details.php?place_id='.$aFeature['place_id'].'">'.$sTitle.'</a>';
}
function format_distance($fDistance)
{
// $fDistance is in meters
if ($fDistance < 1)
{
return '0';
}
elseif ($fDistance < 1000)
{
return'<abbr class="distance" title="'.$fDistance.'">~'.(round($fDistance,0)).' m</abbr>';
}
else
{
return'<abbr class="distance" title="'.$fDistance.'">~'.(round($fDistance/1000,1)).' km</abbr>';
}
}
function kv($sKey,$sValue)
{
echo ' <tr><td>' . $sKey . '</td><td>'.$sValue.'</td></tr>'. "\n";
}
function headline3($sTitle)
{
echo "<tr class='all-columns'><td colspan='6'><h3>".$sTitle."</h3></td></tr>\n";
}
function hash_to_subtable($aAssociatedList)
{
$sHTML = '';
foreach($aAssociatedList as $sKey => $sValue)
{
$sHTML = $sHTML.' <div class="line"><span class="name">'.$sValue.'</span> ('.$sKey.')</div>'."\n";
}
return $sHTML;
}
function format_distance($fDistance)
{
// $fDistance is in meters
if ($fDistance < 1)
{
return '0';
}
elseif ($fDistance < 1000)
{
return'<abbr class="distance" title="'.$fDistance.'">~'.(round($fDistance,0)).' m</abbr>';
}
else
{
return'<abbr class="distance" title="'.$fDistance.'">~'.(round($fDistance/1000,1)).' km</abbr>';
}
}
// function hash_to_subtable($aAssociatedList)
// {
// $sHTML = '<table class="table">';
// foreach($aAssociatedList as $sKey => $sValue)
// {
// $sHTML = $sHTML . '<tr><td>'.$sKey.'</td><td class="name">'.$sValue.'</td></tr>'."\n";
// }
// $sHTML = $sHTML . '</table>';
// return $sHTML;
// }
function kv($sKey,$sValue)
{
echo ' <tr><td>' . $sKey . '</td><td>'.$sValue.'</td></tr>'. "\n";
}
function map_icon($sIcon)
{
if ($sIcon){
echo '<img id="mapicon" src="'.CONST_Website_BaseURL.'images/mapicons/'.$sIcon.'.n.32.png'.'" alt="'.$sIcon.'" />';
}
}
function hash_to_subtable($aAssociatedList)
{
$sHTML = '';
foreach ($aAssociatedList as $sKey => $sValue) {
$sHTML = $sHTML.' <div class="line"><span class="name">'.$sValue.'</span> ('.$sKey.')</div>'."\n";
}
return $sHTML;
}
function map_icon($sIcon)
{
if ($sIcon){
echo '<img id="mapicon" src="'.CONST_Website_BaseURL.'images/mapicons/'.$sIcon.'.n.32.png'.'" alt="'.$sIcon.'" />';
}
}
function _one_row($aAddressLine){
$bNotUsed = (isset($aAddressLine['isaddress']) && $aAddressLine['isaddress'] == 'f');
function _one_row($aAddressLine){
$bNotUsed = (isset($aAddressLine['isaddress']) && $aAddressLine['isaddress'] == 'f');
echo '<tr class="' . ($bNotUsed?'notused':'') . '">'."\n";
echo ' <td class="name">'.(trim($aAddressLine['localname'])?$aAddressLine['localname']:'<span class="noname">No Name</span>')."</td>\n";
echo ' <td>' . $aAddressLine['class'].':'.$aAddressLine['type'] . "</td>\n";
echo ' <td>' . osm_link($aAddressLine) . "</td>\n";
echo ' <td>' . (isset($aAddressLine['admin_level']) ? $aAddressLine['admin_level'] : '') . "</td>\n";
// echo '<td>' . (isset($aAddressLine['rank_search_label']) ? $aAddressLine['rank_search_label'] : '') ."</td>\n";
// echo ', <span class="area">'.($aAddressLine['fromarea']=='t'?'Polygon':'Point').'</span>';
echo ' <td>' . format_distance($aAddressLine['distance'])."</td>\n";
echo ' <td>' . nominatim_link($aAddressLine,'details &gt;') . "</td>\n";
echo "</tr>\n";
}
echo '<tr class="' . ($bNotUsed?'notused':'') . '">'."\n";
echo ' <td class="name">'.(trim($aAddressLine['localname'])?$aAddressLine['localname']:'<span class="noname">No Name</span>')."</td>\n";
echo ' <td>' . $aAddressLine['class'].':'.$aAddressLine['type'] . "</td>\n";
echo ' <td>' . osmLink($aAddressLine) . "</td>\n";
echo ' <td>' . (isset($aAddressLine['rank_address']) ? $aAddressLine['rank_address'] : '') . "</td>\n";
echo ' <td>' . ($aAddressLine['admin_level'] < 15 ? $aAddressLine['admin_level'] : '') . "</td>\n";
echo ' <td>' . format_distance($aAddressLine['distance'])."</td>\n";
echo ' <td>' . detailsLink($aAddressLine,'details &gt;') . "</td>\n";
echo "</tr>\n";
}
function _one_keyword_row($keyword_token,$word_id){
echo "<tr>\n";
echo '<td>';
// mark partial tokens (those starting with a space) with a star for readability
echo ($keyword_token[0]==' '?'*':'');
echo $keyword_token;
if (isset($word_id))
{
echo '</td><td>word id: '.$word_id;
}
echo "</td></tr>\n";
}
?>
<body id="details-page">
<?php include(CONST_BasePath.'/lib/template/includes/html-top-navigation.php'); ?>
<div class="container">
<div class="row">
<div class="col-sm-10">
<h1><?php echo $aPointDetails['localname'] ?></h1>
</div>
<div class="col-sm-2 text-right">
<?php map_icon($aPointDetails['icon']) ?>
</div>
</div>
<div class="row">
<div class="col-md-6">
<table id="locationdetails" class="table table-striped">
<?php include(CONST_BasePath.'/lib/template/includes/html-top-navigation.php'); ?>
<div class="container">
<div class="row">
<div class="col-sm-10">
<h1>
<?php echo $aPointDetails['localname'] ?>
<small><?php echo detailsPermaLink($aPointDetails, 'link to this page') ?></small>
</h1>
</div>
<div class="col-sm-2 text-right">
<?php map_icon($aPointDetails['icon']) ?>
</div>
</div>
<div class="row">
<div class="col-md-6">
<table id="locationdetails" class="table table-striped">
<?php
<?php
kv('Name' , hash_to_subtable($aPointDetails['aNames']) );
kv('Type' , $aPointDetails['class'].':'.$aPointDetails['type'] );
kv('Last Updated' , $aPointDetails['indexed_date'] );
kv('Admin Level' , $aPointDetails['admin_level'] );
kv('Rank' , $aPointDetails['rank_search_label'] );
if ($aPointDetails['calculated_importance']) {
kv('Importance' , $aPointDetails['calculated_importance'].($aPointDetails['importance']?'':' (estimated)') );
}
kv('Coverage' , ($aPointDetails['isarea']=='t'?'Polygon':'Point') );
kv('Centre Point' , $aPointDetails['lat'].','.$aPointDetails['lon'] );
kv('OSM' , osm_link($aPointDetails) );
if ($aPointDetails['wikipedia'])
{
kv('Wikipedia Calculated' , wikipedia_link($aPointDetails) );
}
kv('Name' , hash_to_subtable($aPointDetails['aNames']) );
kv('Type' , $aPointDetails['class'].':'.$aPointDetails['type'] );
kv('Last Updated' , (new DateTime('@'.$aPointDetails['indexed_epoch']))->format(DateTime::RFC822) );
kv('Admin Level' , $aPointDetails['admin_level'] );
kv('Rank' , $aPointDetails['rank_search_label'] );
if ($aPointDetails['calculated_importance']) {
kv('Importance' , $aPointDetails['calculated_importance'].($aPointDetails['importance']?'':' (estimated)') );
}
kv('Coverage' , ($aPointDetails['isarea']=='t'?'Polygon':'Point') );
kv('Centre Point' , $aPointDetails['lat'].','.$aPointDetails['lon'] );
kv('OSM' , osmLink($aPointDetails) );
if ($aPointDetails['wikipedia'])
{
kv('Wikipedia Calculated' , wikipediaLink($aPointDetails) );
}
kv('Extra Tags' , hash_to_subtable($aPointDetails['aExtraTags']) );
kv('Computed Postcode', $aPointDetails['postcode']);
kv('Address Tags' , hash_to_subtable($aPointDetails['aAddressTags']) );
kv('Extra Tags' , hash_to_subtable($aPointDetails['aExtraTags']) );
?>
?>
</table>
</div>
</table>
</div>
<div class="col-md-6">
<div id="map"></div>
</div>
<div class="col-md-6">
<div id="map"></div>
</div>
</div>
<div class="row">
<div class="col-md-12">
</div>
<div class="row">
<div class="col-md-12">
<h2>Address</h2>
<h2>Address</h2>
<table id="address" class="table table-striped table-responsive">
<thead>
<tr>
<td>Local name</td>
<td>Type</td>
<td>OSM</td>
<td>Admin level</td>
<!-- <td>Search rank</td> -->
<td>Distance</td>
<td></td>
</tr>
</thead>
<tbody>
<table id="address" class="table table-striped table-responsive">
<thead>
<tr>
<td>Local name</td>
<td>Type</td>
<td>OSM</td>
<td>Address rank</td>
<td>Admin level</td>
<td>Distance</td>
<td></td>
</tr>
</thead>
<tbody>
<?php
foreach($aAddressLines as $aAddressLine)
{
_one_row($aAddressLine);
}
?>
<?php
foreach ($aAddressLines as $aAddressLine) {
_one_row($aAddressLine);
}
?>
<?php
if ($aLinkedLines)
{
headline('Linked Places');
foreach($aLinkedLines as $aAddressLine)
{
_one_row($aAddressLine);
}
}
if ($aLinkedLines)
{
headline('Linked Places');
foreach ($aLinkedLines as $aAddressLine) {
_one_row($aAddressLine);
}
}
if ($bIncludeKeywords)
{
headline('Name Keywords');
if ($aPlaceSearchNameKeywords) {
foreach ($aPlaceSearchNameKeywords as $aRow) {
_one_keyword_row($aRow['word_token'], $aRow['word_id']);
}
}
headline('Address Keywords');
if ($aPlaceSearchAddressKeywords) {
foreach ($aPlaceSearchAddressKeywords as $aRow) {
_one_keyword_row($aRow['word_token'], $aRow['word_id']);
}
}
}
if ($aPlaceSearchNameKeywords)
{
headline('Name Keywords');
foreach($aPlaceSearchNameKeywords as $aRow)
{
echo '<div>'.$aRow['word_token']."</div>\n";
}
}
if (!empty($aHierarchyLines))
{
headline('Parent Of');
if ($aPlaceSearchAddressKeywords)
{
headline('Address Keywords');
foreach($aPlaceSearchAddressKeywords as $aRow)
{
echo '<div>'.($aRow['word_token'][0]==' '?'*':'').$aRow['word_token'].'('.$aRow['word_id'].')'."</div>\n";
}
}
if (sizeof($aParentOfLines))
{
headline('Parent Of');
$aGroupedAddressLines = array();
foreach ($aHierarchyLines as $aAddressLine) {
if ($aAddressLine['type'] == 'yes') $sType = $aAddressLine['class'];
else $sType = $aAddressLine['type'];
$aGroupedAddressLines = array();
foreach($aParentOfLines as $aAddressLine)
{
if ($aAddressLine['type'] == 'yes') $sType = $aAddressLine['class'];
else $sType = $aAddressLine['type'];
if (!isset($aGroupedAddressLines[$sType]))
$aGroupedAddressLines[$sType] = array();
$aGroupedAddressLines[$sType][] = $aAddressLine;
}
foreach ($aGroupedAddressLines as $sGroupHeading => $aHierarchyLines) {
$sGroupHeading = ucwords($sGroupHeading);
headline3($sGroupHeading);
if (!isset($aGroupedAddressLines[$sType]))
$aGroupedAddressLines[$sType] = array();
$aGroupedAddressLines[$sType][] = $aAddressLine;
}
foreach($aGroupedAddressLines as $sGroupHeading => $aParentOfLines)
{
$sGroupHeading = ucwords($sGroupHeading);
headline3($sGroupHeading);
foreach ($aHierarchyLines as $aAddressLine) {
_one_row($aAddressLine);
}
}
if (count($aHierarchyLines) >= 500) {
echo '<p>There are more child objects which are not shown.</p>';
}
}
foreach($aParentOfLines as $aAddressLine)
{
_one_row($aAddressLine);
}
}
if (sizeof($aParentOfLines) >= 500) {
echo '<p>There are more child objects which are not shown.</p>';
}
}
// headline('Other Parts');
// headline('Linked To');
echo "</table>\n";
echo "</table>\n";
?>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
<?php
<script type="text/javascript">
<?php
$aNominatimMapInit = [
'tile_url' => $sTileURL,
'tile_attribution' => $sTileAttribution
];
echo 'var nominatim_map_init = ' . json_encode($aNominatimMapInit, JSON_PRETTY_PRINT) . ';';
$aNominatimMapInit = array(
'tile_url' => $sTileURL,
'tile_attribution' => $sTileAttribution
);
echo 'var nominatim_map_init = ' . json_encode($aNominatimMapInit, JSON_PRETTY_PRINT) . ';';
$aPlace = [
'outlinestring' => $aPointDetails['outlinestring'],
'lon' => $aPointDetails['lon'],
'lat' => $aPointDetails['lat'],
];
echo 'var nominatim_result = ' . json_encode($aPlace, JSON_PRETTY_PRINT) . ';';
$aPlace = array(
'asgeojson' => $aPointDetails['asgeojson'],
'lon' => $aPointDetails['lon'],
'lat' => $aPointDetails['lat'],
);
echo 'var nominatim_result = ' . json_encode($aPlace, JSON_PRETTY_PRINT) . ';';
?>
</script>
?>
</script>
<?php include(CONST_BasePath.'/lib/template/includes/html-footer.php'); ?>
<?php include(CONST_BasePath.'/lib/template/includes/html-footer.php'); ?>
</body>
</html>

View File

@@ -0,0 +1,104 @@
<?php
$aPlaceDetails = array();
$aPlaceDetails['place_id'] = (int) $aPointDetails['place_id'];
$aPlaceDetails['parent_place_id'] = (int) $aPointDetails['parent_place_id'];
$aPlaceDetails['osm_type'] = $aPointDetails['osm_type'];
$aPlaceDetails['osm_id'] = (int) $aPointDetails['osm_id'];
$aPlaceDetails['category'] = $aPointDetails['class'];
$aPlaceDetails['type'] = $aPointDetails['type'];
$aPlaceDetails['admin_level'] = $aPointDetails['admin_level'];
$aPlaceDetails['localname'] = $aPointDetails['localname'];
$aPlaceDetails['names'] = $aPointDetails['aNames'];
$aPlaceDetails['addresstags'] = $aPointDetails['aAddressTags'];
$aPlaceDetails['housenumber'] = $aPointDetails['housenumber'];
$aPlaceDetails['calculated_postcode'] = $aPointDetails['postcode'];
$aPlaceDetails['country_code'] = $aPointDetails['country_code'];
$aPlaceDetails['indexed_date'] = (new DateTime('@'.$aPointDetails['indexed_epoch']))->format(DateTime::RFC3339);
$aPlaceDetails['importance'] = (float) $aPointDetails['importance'];
$aPlaceDetails['calculated_importance'] = (float) $aPointDetails['calculated_importance'];
$aPlaceDetails['extratags'] = $aPointDetails['aExtraTags'];
$aPlaceDetails['calculated_wikipedia'] = $aPointDetails['wikipedia'];
if ($aPointDetails['icon']) {
$aPlaceDetails['icon'] = CONST_Website_BaseURL.'images/mapicons/'.$aPointDetails['icon'].'.n.32.png';
}
$aPlaceDetails['rank_address'] = (int) $aPointDetails['rank_address'];
$aPlaceDetails['rank_search'] = (int) $aPointDetails['rank_search'];
$aPlaceDetails['isarea'] = ($aPointDetails['isarea'] == 't');
$aPlaceDetails['centroid'] = array(
'type' => 'Point',
'coordinates' => array( (float) $aPointDetails['lon'], (float) $aPointDetails['lat'] )
);
$aPlaceDetails['geometry'] = json_decode($aPointDetails['asgeojson']);
$funcMapAddressLine = function ($aFull) {
$aMapped = array(
'localname' => $aFull['localname'],
'place_id' => isset($aFull['place_id']) ? (int) $aFull['place_id'] : null,
'osm_id' => isset($aFull['osm_id']) ? (int) $aFull['osm_id'] : null,
'osm_type' => isset($aFull['osm_type']) ? $aFull['osm_type'] : null,
'class' => $aFull['class'],
'type' => $aFull['type'],
'admin_level' => isset($aFull['admin_level']) ? (int) $aFull['admin_level'] : null,
'rank_address' => $aFull['rank_address'] ? (int) $aFull['rank_address'] : null,
'distance' => (float) $aFull['distance']
);
return $aMapped;
};
$funcMapKeyword = function ($aFull) {
$aMapped = array(
'id' => (int) $aFull['word_id'],
'token' => $aFull['word_token']
);
return $aMapped;
};
if ($aAddressLines) {
$aPlaceDetails['address'] = array_map($funcMapAddressLine, $aAddressLines);
}
if ($aLinkedLines) {
$aPlaceDetails['linked_places'] = array_map($funcMapAddressLine, $aLinkedLines);
}
if ($bIncludeKeywords) {
$aPlaceDetails['keywords'] = array();
if ($aPlaceSearchNameKeywords) {
$aPlaceDetails['keywords']['name'] = array_map($funcMapKeyword, $aPlaceSearchNameKeywords);
}
if ($aPlaceSearchAddressKeywords) {
$aPlaceDetails['keywords']['address'] = array_map($funcMapKeyword, $aPlaceSearchAddressKeywords);
}
}
if ($bIncludeHierarchy) {
if ($bGroupHierarchy) {
$aPlaceDetails['hierarchy'] = array();
foreach ($aHierarchyLines as $aAddressLine) {
if ($aAddressLine['type'] == 'yes') $sType = $aAddressLine['class'];
else $sType = $aAddressLine['type'];
if (!isset($aPlaceDetails['hierarchy'][$sType]))
$aPlaceDetails['hierarchy'][$sType] = array();
$aPlaceDetails['hierarchy'][$sType][] = $funcMapAddressLine($aAddressLine);
}
} else {
$aPlaceDetails['hierarchy'] = array_map($funcMapAddressLine, $aHierarchyLines);
}
}
javascript_renderData($aPlaceDetails);

View File

@@ -1,14 +1,15 @@
<footer>
<p class="disclaimer">
Addresses and postcodes are approximate
</p>
<p class="copyright">
&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors
</p>
<p class="disclaimer">
Addresses and postcodes are approximate
</p>
<p class="copyright">
&copy; <a href="https://osm.org/copyright">OpenStreetMap</a> contributors
</p>
</footer>
<script src="js/jquery.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/leaflet.min.js"></script>
<script src="js/leaflet-omnivore.min.js"></script>
<script src="js/Control.Minimap.min.js"></script>
<script src="js/url-search-params.js"></script>
<script src="js/nominatim-ui.js"></script>

View File

@@ -1,11 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>OpenStreetMap Nominatim: Search</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>OpenStreetMap Nominatim: Search</title>
<meta content="IE=edge" http-equiv="x-ua-compatible" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<base href="<?php echo CONST_Website_BaseURL;?>" />
<link href="nominatim.xml" rel="search" title="Nominatim Search" type="application/opensearchdescription+xml" />
<link href="css/leaflet.css" rel="stylesheet" />
<link href="css/bootstrap-theme.min.css" rel="stylesheet" />
<link href="css/bootstrap.min.css" rel="stylesheet" />
<base href="<?php echo CONST_Website_BaseURL;?>" />
<link href="nominatim.xml" rel="search" title="Nominatim Search" type="application/opensearchdescription+xml" />
<link href="css/leaflet.css" rel="stylesheet" />
<link href="css/Control.Minimap.min.css" rel="stylesheet" />
<link href="css/bootstrap-theme.min.css" rel="stylesheet" />
<link href="css/bootstrap.min.css" rel="stylesheet" />

View File

@@ -1,49 +1,49 @@
<header class="container-fluid">
<header class="container-fluid">
<div class="row">
<div class="col-xs-4">
<div class="brand">
<a href="<?php echo CONST_Website_BaseURL;?>">
<img alt="logo" src="images/osm_logo.120px.png" width="30" height="30"/>
<h1>Nominatim</h1>
</a>
<div class="col-xs-4">
<div class="brand">
<a href="<?php echo CONST_Website_BaseURL;?>">
<img alt="logo" src="images/osm_logo.120px.png" width="30" height="30"/>
<h1>Nominatim</h1>
</a>
</div>
</div>
</div>
<div id="last-updated" class="col-xs-4 text-center">
<?php if ($sDataDate){ ?>
Data last updated:
<br>
<?php echo $sDataDate; ?>
<?php } ?>
</div>
<div class="col-xs-4 text-right">
<div class="btn-group">
<button class="dropdown-toggle btn btn-sm btn-default" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
About &amp; Help <span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right">
<li><a href="http://wiki.openstreetmap.org/wiki/Nominatim" target="_blank">Documentation</a></li>
<li><a href="http://wiki.openstreetmap.org/wiki/Nominatim/FAQ" target="_blank">FAQ</a></li>
<li role="separator" class="divider"></li>
<li><a href="#" class="" data-toggle="modal" data-target="#report-modal">Report problem with results</a></li>
</ul>
<div id="last-updated" class="col-xs-4 text-center">
<?php if (isset($sDataDate)){ ?>
Data last updated:
<br>
<?php echo $sDataDate; ?>
<?php } ?>
</div>
<div class="col-xs-4 text-right">
<div class="btn-group">
<button class="dropdown-toggle btn btn-sm btn-default" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
About &amp; Help <span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right">
<li><a href="https://wiki.openstreetmap.org/wiki/Nominatim" target="_blank">Documentation</a></li>
<li><a href="https://wiki.openstreetmap.org/wiki/Nominatim/FAQ" target="_blank">FAQ</a></li>
<li role="separator" class="divider"></li>
<li><a href="#" class="" data-toggle="modal" data-target="#report-modal">Report problem with results</a></li>
</ul>
</div>
</div>
</div>
</div>
</header>
</header>
<div class="modal fade" id="report-modal">
<div class="modal fade" id="report-modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">Report a problem</h4>
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">Report a problem</h4>
</div>
<div class="modal-body">
<?php include(CONST_BasePath.'/lib/template/includes/report-errors.php'); ?>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">OK</button>
</div>
</div>
<div class="modal-body">
<?php include(CONST_BasePath.'/lib/template/includes/report-errors.php'); ?>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">OK</button>
</div>
</div>
</div>
</div>
</div>

View File

@@ -1,9 +1,9 @@
<h2>Welcome to Nominatim</h2>
<p>Nominatim is a search engine for <a href="http://www.openstreetmap.org">OpenStreetMap</a>
data. This is the debugging interface. You may search for a name or address(forward search) or
look up data by its geographic coordinate(reverse search). Each result comes with a
<p>Nominatim is a search engine for <a href="https://www.openstreetmap.org">OpenStreetMap</a>
data. This is the debugging interface. You may search for a name or address (forward search) or
look up data by its geographic coordinate (reverse search). Each result comes with a
link to a details page where you can inspect what data about the object is saved in
the database and investigate how the address of the object has been computed.</p>
For more information visit the <a href="http://wiki.openstreetmap.org/wiki/Nominatim">Nominatim wiki page</a>.
For more information visit the <a href="https://wiki.openstreetmap.org/wiki/Nominatim">Nominatim wiki page</a>.

View File

@@ -1,24 +1,24 @@
<p>
Before reporting problems please read the <a target="_blank" href="http://wiki.openstreetmap.org/wiki/Nominatim">user documentation</a>
and
<a target="_blank" href="http://wiki.openstreetmap.org/wiki/Nominatim/FAQ">FAQ</a>.
Before reporting problems please read the <a target="_blank" href="https://wiki.openstreetmap.org/wiki/Nominatim">user documentation</a>
and
<a target="_blank" href="https://wiki.openstreetmap.org/wiki/Nominatim/FAQ">FAQ</a>.
If your problem relates to the address of a particular search result please use the 'details' link
to check how the address was generated before reporting a problem.
If your problem relates to the address of a particular search result please use the 'details' link
to check how the address was generated before reporting a problem.
</p>
<p>
Use <a target="_blank" href="https://github.com/twain47/nominatim/issues">Nominatim issues on github</a>
to report problems.
<!-- You can search for existing bug reports
<a href="http://trac.openstreetmap.org/query?status=new&amp;status=assigned&amp;status=reopened&amp;component=nominatim&amp;order=priority">here</a>.</p>
Use <a target="_blank" href="https://github.com/openstreetmap/nominatim/issues">Nominatim issues on github</a>
to report problems.
<!-- You can search for existing bug reports
<a href="https://trac.openstreetmap.org/query?status=new&amp;status=assigned&amp;status=reopened&amp;component=nominatim&amp;order=priority">here</a>.</p>
-->
</p>
<p>
Please ensure that you include a full description of the problem, including the search
query that you used, the problem with the result and, if the problem relates to missing data,
the osm type (node, way, relation) and id of the item that is missing.
Please ensure that you include a full description of the problem, including the search
query that you used, the problem with the result and, if the problem relates to missing data,
the osm type (node, way, relation) and id of the item that is missing.
</p>
<p>
Problems that contain enough detail are likely to get looked at before ones that require
significant research.
Problems that contain enough detail are likely to get looked at before ones that require
significant research.
</p>

View File

@@ -1,88 +1,77 @@
<?php
$aOutput = array();
$aOutput['licence'] = "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright";
$aOutput['batch'] = array();
$aOutput = array();
$aOutput['licence'] = 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright';
$aOutput['batch'] = array();
foreach($aBatchResults as $aSearchResults)
{
if (!$aSearchResults) $aSearchResults = array();
$aFilteredPlaces = array();
foreach($aSearchResults as $iResNum => $aPointDetails)
{
$aPlace = array(
'place_id'=>$aPointDetails['place_id'],
);
foreach ($aBatchResults as $aSearchResults) {
if (!$aSearchResults) $aSearchResults = array();
$aFilteredPlaces = array();
foreach ($aSearchResults as $iResNum => $aPointDetails) {
$aPlace = array(
'place_id'=>$aPointDetails['place_id'],
);
$sOSMType = ($aPointDetails['osm_type'] == 'N'?'node':($aPointDetails['osm_type'] == 'W'?'way':($aPointDetails['osm_type'] == 'R'?'relation':'')));
if ($sOSMType)
{
$aPlace['osm_type'] = $sOSMType;
$aPlace['osm_id'] = $aPointDetails['osm_id'];
}
$sOSMType = formatOSMType($aPointDetails['osm_type']);
if ($sOSMType) {
$aPlace['osm_type'] = $sOSMType;
$aPlace['osm_id'] = $aPointDetails['osm_id'];
}
if (isset($aPointDetails['aBoundingBox']))
{
$aPlace['boundingbox'] = array(
$aPointDetails['aBoundingBox'][0],
$aPointDetails['aBoundingBox'][1],
$aPointDetails['aBoundingBox'][2],
$aPointDetails['aBoundingBox'][3]);
if (isset($aPointDetails['aBoundingBox'])) {
$aPlace['boundingbox'] = array(
$aPointDetails['aBoundingBox'][0],
$aPointDetails['aBoundingBox'][1],
$aPointDetails['aBoundingBox'][2],
$aPointDetails['aBoundingBox'][3]
);
if (isset($aPointDetails['aPolyPoints']) && $bShowPolygons)
{
$aPlace['polygonpoints'] = $aPointDetails['aPolyPoints'];
}
}
if (isset($aPointDetails['aPolyPoints']) && $bShowPolygons) {
$aPlace['polygonpoints'] = $aPointDetails['aPolyPoints'];
}
}
if (isset($aPointDetails['zoom']))
{
$aPlace['zoom'] = $aPointDetails['zoom'];
}
if (isset($aPointDetails['zoom'])) {
$aPlace['zoom'] = $aPointDetails['zoom'];
}
$aPlace['lat'] = $aPointDetails['lat'];
$aPlace['lon'] = $aPointDetails['lon'];
$aPlace['display_name'] = $aPointDetails['name'];
$aPlace['place_rank'] = $aPointDetails['rank_search'];
$aPlace['lat'] = $aPointDetails['lat'];
$aPlace['lon'] = $aPointDetails['lon'];
$aPlace['display_name'] = $aPointDetails['name'];
$aPlace['place_rank'] = $aPointDetails['rank_search'];
$aPlace['category'] = $aPointDetails['class'];
$aPlace['type'] = $aPointDetails['type'];
$aPlace['category'] = $aPointDetails['class'];
$aPlace['type'] = $aPointDetails['type'];
$aPlace['importance'] = $aPointDetails['importance'];
$aPlace['importance'] = $aPointDetails['importance'];
if (isset($aPointDetails['icon']))
{
$aPlace['icon'] = $aPointDetails['icon'];
}
if (isset($aPointDetails['icon'])) {
$aPlace['icon'] = $aPointDetails['icon'];
}
if (isset($aPointDetails['address']) && sizeof($aPointDetails['address'])>0)
{
$aPlace['address'] = $aPointDetails['address'];
}
if (isset($aPointDetails['address'])) {
$aPlace['address'] = $aPointDetails['address']->getAddressNames();
}
if (isset($aPointDetails['asgeojson']))
{
$aPlace['geojson'] = json_decode($aPointDetails['asgeojson']);
}
if (isset($aPointDetails['asgeojson'])) {
$aPlace['geojson'] = json_decode($aPointDetails['asgeojson']);
}
if (isset($aPointDetails['assvg']))
{
$aPlace['svg'] = $aPointDetails['assvg'];
}
if (isset($aPointDetails['assvg'])) {
$aPlace['svg'] = $aPointDetails['assvg'];
}
if (isset($aPointDetails['astext']))
{
$aPlace['geotext'] = $aPointDetails['astext'];
}
if (isset($aPointDetails['astext'])) {
$aPlace['geotext'] = $aPointDetails['astext'];
}
if (isset($aPointDetails['askml']))
{
$aPlace['geokml'] = $aPointDetails['askml'];
}
if (isset($aPointDetails['askml'])) {
$aPlace['geokml'] = $aPointDetails['askml'];
}
$aFilteredPlaces[] = $aPlace;
}
$aOutput['batch'][] = $aFilteredPlaces;
}
$aFilteredPlaces[] = $aPlace;
}
$aOutput['batch'][] = $aFilteredPlaces;
}
javascript_renderData($aOutput, array('geojson'));
javascript_renderData($aOutput, array('geojson'));

View File

@@ -0,0 +1,73 @@
<?php
$aFilteredPlaces = array();
foreach ($aSearchResults as $iResNum => $aPointDetails) {
$aPlace = array(
'type' => 'Feature',
'properties' => array(
'geocoding' => array()
)
);
if (isset($aPointDetails['place_id'])) $aPlace['properties']['geocoding']['place_id'] = $aPointDetails['place_id'];
$sOSMType = formatOSMType($aPointDetails['osm_type']);
if ($sOSMType) {
$aPlace['properties']['geocoding']['osm_type'] = $sOSMType;
$aPlace['properties']['geocoding']['osm_id'] = $aPointDetails['osm_id'];
}
$aPlace['properties']['geocoding']['type'] = $aPointDetails['type'];
$aPlace['properties']['geocoding']['label'] = $aPointDetails['langaddress'];
$aPlace['properties']['geocoding']['name'] = $aPointDetails['placename'];
if (isset($aPointDetails['address'])) {
$aFieldMappings = array(
'house_number' => 'housenumber',
'road' => 'street',
'locality' => 'locality',
'postcode' => 'postcode',
'city' => 'city',
'district' => 'district',
'county' => 'county',
'state' => 'state',
'country' => 'country'
);
$aAddrNames = $aPointDetails['address']->getAddressNames();
foreach ($aFieldMappings as $sFrom => $sTo) {
if (isset($aAddrNames[$sFrom])) {
$aPlace['properties']['geocoding'][$sTo] = $aAddrNames[$sFrom];
}
}
$aPlace['properties']['geocoding']['admin']
= $aPointDetails['address']->getAdminLevels();
}
if (isset($aPointDetails['asgeojson'])) {
$aPlace['geometry'] = json_decode($aPointDetails['asgeojson']);
} else {
$aPlace['geometry'] = array(
'type' => 'Point',
'coordinates' => array(
(float) $aPointDetails['lon'],
(float) $aPointDetails['lat']
)
);
}
$aFilteredPlaces[] = $aPlace;
}
javascript_renderData(array(
'type' => 'FeatureCollection',
'geocoding' => array(
'version' => '0.1.0',
'attribution' => 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright',
'licence' => 'ODbL',
'query' => $sQuery
),
'features' => $aFilteredPlaces
));

View File

@@ -0,0 +1,71 @@
<?php
$aFilteredPlaces = array();
foreach ($aSearchResults as $iResNum => $aPointDetails) {
$aPlace = array(
'type' => 'Feature',
'properties' => array(
'place_id'=>$aPointDetails['place_id'],
)
);
$sOSMType = formatOSMType($aPointDetails['osm_type']);
if ($sOSMType) {
$aPlace['properties']['osm_type'] = $sOSMType;
$aPlace['properties']['osm_id'] = $aPointDetails['osm_id'];
}
if (isset($aPointDetails['aBoundingBox'])) {
$aPlace['bbox'] = array(
(float) $aPointDetails['aBoundingBox'][2], // minlon
(float) $aPointDetails['aBoundingBox'][0], // minlat
(float) $aPointDetails['aBoundingBox'][3], // maxlon
(float) $aPointDetails['aBoundingBox'][1] // maxlat
);
}
if (isset($aPointDetails['zoom'])) {
$aPlace['properties']['zoom'] = $aPointDetails['zoom'];
}
$aPlace['properties']['display_name'] = $aPointDetails['name'];
$aPlace['properties']['place_rank'] = $aPointDetails['rank_search'];
$aPlace['properties']['category'] = $aPointDetails['class'];
$aPlace['properties']['type'] = $aPointDetails['type'];
$aPlace['properties']['importance'] = $aPointDetails['importance'];
if (isset($aPointDetails['icon']) && $aPointDetails['icon']) {
$aPlace['properties']['icon'] = $aPointDetails['icon'];
}
if (isset($aPointDetails['address'])) {
$aPlace['properties']['address'] = $aPointDetails['address']->getAddressNames();
}
if (isset($aPointDetails['asgeojson'])) {
$aPlace['geometry'] = json_decode($aPointDetails['asgeojson']);
} else {
$aPlace['geometry'] = array(
'type' => 'Point',
'coordinates' => array(
(float) $aPointDetails['lon'],
(float) $aPointDetails['lat']
)
);
}
if (isset($aPointDetails['sExtraTags'])) $aPlace['properties']['extratags'] = $aPointDetails['sExtraTags'];
if (isset($aPointDetails['sNameDetails'])) $aPlace['properties']['namedetails'] = $aPointDetails['sNameDetails'];
$aFilteredPlaces[] = $aPlace;
}
javascript_renderData(array(
'type' => 'FeatureCollection',
'licence' => 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright',
'features' => $aFilteredPlaces
));

View File

@@ -1,91 +1,91 @@
<?php
header("content-type: text/html; charset=UTF-8");
header("content-type: text/html; charset=UTF-8");
?>
<?php include(CONST_BasePath.'/lib/template/includes/html-header.php'); ?>
<link href="css/common.css" rel="stylesheet" type="text/css" />
<link href="css/search.css" rel="stylesheet" type="text/css" />
<link href="css/common.css" rel="stylesheet" type="text/css" />
<link href="css/search.css" rel="stylesheet" type="text/css" />
</head>
<body id="search-page">
<?php include(CONST_BasePath.'/lib/template/includes/html-top-navigation.php'); ?>
<?php include(CONST_BasePath.'/lib/template/includes/html-top-navigation.php'); ?>
<form class="form-inline" role="search" accept-charset="UTF-8" action="<?php echo CONST_Website_BaseURL; ?>search.php">
<div class="form-group">
<input id="q" name="q" type="text" class="form-control input-sm" placeholder="Search" value="<?php echo htmlspecialchars($sQuery); ?>" >
</div>
<div class="form-group search-button-group">
<button type="submit" class="btn btn-primary btn-sm">Search</button>
<?php if (CONST_Search_AreaPolygons) { ?>
<!-- <input type="checkbox" value="1" name="polygon" <?php if ($bAsText) echo "checked='checked'"; ?>/> Highlight -->
<input type="hidden" value="1" name="polygon" />
<?php } ?>
<input type="hidden" name="viewbox" value="<?php echo $sViewBox; ?>" />
<div class="checkbox-inline">
<label>
<input type="checkbox" id="use_viewbox" <?php if ($sViewBox) echo "checked='checked'"; ?>>
apply viewbox
</label>
</div>
</div>
<div class="search-type-link">
<a href="<?php echo CONST_Website_BaseURL; ?>reverse.php?format=html">reverse search</a>
</div>
</form>
<form class="form-inline" role="search" accept-charset="UTF-8" action="<?php echo CONST_Website_BaseURL; ?>search.php">
<div class="form-group">
<input id="q" name="q" type="text" class="form-control input-sm" placeholder="Search" value="<?php echo htmlspecialchars($sQuery); ?>" >
</div>
<div class="form-group search-button-group">
<button type="submit" class="btn btn-primary btn-sm">Search</button>
<?php if (CONST_Search_AreaPolygons) { ?>
<input type="hidden" value="1" name="polygon_geojson" />
<?php } ?>
<input type="hidden" name="viewbox" value="<?php if (isset($aMoreParams['viewbox'])) echo ($aMoreParams['viewbox']); ?>" />
<div class="checkbox-inline">
<input type="checkbox" id="use_viewbox" <?php if (isset($aMoreParams['viewbox'])) echo "checked='checked'"; ?>>
<label for="use_viewbox">apply viewbox</label>
</div>
</div>
<div class="search-type-link">
<a id="switch-to-reverse" href="<?php echo CONST_Website_BaseURL; ?>reverse.php?format=html">reverse search</a>
</div>
</form>
<div id="content">
<div id="content">
<?php if ($sQuery) { ?>
<div id="searchresults" class="sidebar">
<?php
$i = 0;
foreach($aSearchResults as $iResNum => $aResult)
{
<div id="searchresults" class="sidebar">
<?php
$i = 0;
foreach($aSearchResults as $iResNum => $aResult)
{
echo '<div class="result" data-position=' . $i . '>';
echo '<div class="result" data-position=' . $i . '>';
echo (isset($aResult['icon'])?'<img alt="icon" src="'.$aResult['icon'].'"/>':'');
echo ' <span class="name">'.htmlspecialchars($aResult['name']).'</span>';
// echo ' <span class="latlon">'.round($aResult['lat'],3).','.round($aResult['lon'],3).'</span>';
// echo ' <span class="place_id">'.$aResult['place_id'].'</span>';
if (isset($aResult['label']))
echo ' <span class="type">('.$aResult['label'].')</span>';
else if ($aResult['type'] == 'yes')
echo ' <span class="type">('.ucwords(str_replace('_',' ',$aResult['class'])).')</span>';
else
echo ' <span class="type">('.ucwords(str_replace('_',' ',$aResult['type'])).')</span>';
echo ' <a class="btn btn-default btn-xs details" href="details.php?place_id='.$aResult['place_id'].'">details</a>';
echo '</div>';
$i = $i+1;
}
if (sizeof($aSearchResults) && $sMoreURL)
{
echo '<div class="more"><a class="btn btn-primary" href="'.htmlentities($sMoreURL).'">Search for more results</a></div>';
}
else
{
echo '<div class="noresults">No search results found</div>';
}
echo (isset($aResult['icon'])?'<img alt="icon" src="'.$aResult['icon'].'"/>':'');
echo ' <span class="name">'.htmlspecialchars($aResult['name']).'</span>';
// echo ' <span class="latlon">'.round($aResult['lat'],3).','.round($aResult['lon'],3).'</span>';
// echo ' <span class="place_id">'.$aResult['place_id'].'</span>';
if (isset($aResult['label']))
echo ' <span class="type">('.$aResult['label'].')</span>';
else if ($aResult['type'] == 'yes')
echo ' <span class="type">('.ucwords(str_replace('_',' ',$aResult['class'])).')</span>';
else
echo ' <span class="type">('.ucwords(str_replace('_',' ',$aResult['type'])).')</span>';
echo ' <a class="btn btn-default btn-xs details" href="details.php?place_id='.$aResult['place_id'].'">details</a>';
echo '</div>';
$i = $i+1;
}
if (!empty($aSearchResults) && $sMoreURL)
{
echo '<div class="more"><a class="btn btn-primary" href="'.htmlentities($sMoreURL).'">Search for more results</a></div>';
}
else
{
echo '<div class="noresults">No search results found</div>';
}
?>
</div>
?>
</div>
<?php } else { ?>
<div id="intro" class="sidebar">
<?php include(CONST_BasePath.'/lib/template/includes/introduction.php'); ?>
</div>
<div id="intro" class="sidebar">
<?php include(CONST_BasePath.'/lib/template/includes/introduction.php'); ?>
</div>
<?php } ?>
<div id="map-wrapper">
<div id="map-position"></div>
<div id="map"></div>
</div>
<div id="map-wrapper">
<div id="map-position">
<div id="map-position-inner"></div>
<div id="map-position-close"><a href="#">hide</a></div>
</div>
<div id="map"></div>
</div>
</div> <!-- /content -->
</div> <!-- /content -->
@@ -93,22 +93,22 @@
<script type="text/javascript">
<?php
<script type="text/javascript">
<?php
$aNominatimMapInit = [
'zoom' => $iZoom,
'lat' => $fLat,
'lon' => $fLon,
'tile_url' => $sTileURL,
'tile_attribution' => $sTileAttribution
];
echo 'var nominatim_map_init = ' . json_encode($aNominatimMapInit, JSON_PRETTY_PRINT) . ';';
$aNominatimMapInit = array(
'zoom' => CONST_Default_Zoom,
'lat' => CONST_Default_Lat,
'lon' => CONST_Default_Lon,
'tile_url' => CONST_Map_Tile_URL,
'tile_attribution' => CONST_Map_Tile_Attribution
);
echo 'var nominatim_map_init = ' . json_encode($aNominatimMapInit, JSON_PRETTY_PRINT) . ';';
echo 'var nominatim_results = ' . json_encode($aSearchResults, JSON_PRETTY_PRINT) . ';';
?>
</script>
<?php include(CONST_BasePath.'/lib/template/includes/html-footer.php'); ?>
echo 'var nominatim_results = ' . json_encode($aSearchResults, JSON_PRETTY_PRINT) . ';';
?>
</script>
<?php include(CONST_BasePath.'/lib/template/includes/html-footer.php'); ?>
</body>
</html>

View File

@@ -1,83 +1,73 @@
<?php
header("content-type: application/json; charset=UTF-8");
$aFilteredPlaces = array();
foreach($aSearchResults as $iResNum => $aPointDetails)
{
$aPlace = array(
'place_id'=>$aPointDetails['place_id'],
'licence'=>"Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright",
);
$aFilteredPlaces = array();
foreach ($aSearchResults as $iResNum => $aPointDetails) {
$aPlace = array(
'place_id'=>$aPointDetails['place_id'],
'licence'=>'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright',
);
$sOSMType = formatOSMType($aPointDetails['osm_type']);
if ($sOSMType) {
$aPlace['osm_type'] = $sOSMType;
$aPlace['osm_id'] = $aPointDetails['osm_id'];
}
$sOSMType = ($aPointDetails['osm_type'] == 'N'?'node':($aPointDetails['osm_type'] == 'W'?'way':($aPointDetails['osm_type'] == 'R'?'relation':'')));
if ($sOSMType)
{
$aPlace['osm_type'] = $sOSMType;
$aPlace['osm_id'] = $aPointDetails['osm_id'];
}
if (isset($aPointDetails['aBoundingBox'])) {
$aPlace['boundingbox'] = $aPointDetails['aBoundingBox'];
if (isset($aPointDetails['aBoundingBox']))
{
$aPlace['boundingbox'] = array(
$aPointDetails['aBoundingBox'][0],
$aPointDetails['aBoundingBox'][1],
$aPointDetails['aBoundingBox'][2],
$aPointDetails['aBoundingBox'][3]);
if (isset($aPointDetails['aPolyPoints'])) {
$aPlace['polygonpoints'] = $aPointDetails['aPolyPoints'];
}
}
if (isset($aPointDetails['aPolyPoints']) && $bShowPolygons)
{
$aPlace['polygonpoints'] = $aPointDetails['aPolyPoints'];
}
}
if (isset($aPointDetails['zoom'])) {
$aPlace['zoom'] = $aPointDetails['zoom'];
}
if (isset($aPointDetails['zoom']))
{
$aPlace['zoom'] = $aPointDetails['zoom'];
}
$aPlace['lat'] = $aPointDetails['lat'];
$aPlace['lon'] = $aPointDetails['lon'];
$aPlace['lat'] = $aPointDetails['lat'];
$aPlace['lon'] = $aPointDetails['lon'];
$aPlace['display_name'] = $aPointDetails['name'];
$aPlace['display_name'] = $aPointDetails['name'];
$aPlace['class'] = $aPointDetails['class'];
$aPlace['type'] = $aPointDetails['type'];
if ($sOutputFormat == 'jsonv2' || $sOutputFormat == 'geojson') {
$aPlace['place_rank'] = $aPointDetails['rank_search'];
$aPlace['category'] = $aPointDetails['class'];
} else {
$aPlace['class'] = $aPointDetails['class'];
}
$aPlace['type'] = $aPointDetails['type'];
$aPlace['importance'] = $aPointDetails['importance'];
$aPlace['importance'] = $aPointDetails['importance'];
if (isset($aPointDetails['icon']) && $aPointDetails['icon'])
{
$aPlace['icon'] = $aPointDetails['icon'];
}
if (isset($aPointDetails['icon']) && $aPointDetails['icon']) {
$aPlace['icon'] = $aPointDetails['icon'];
}
if (isset($aPointDetails['address']))
{
$aPlace['address'] = $aPointDetails['address'];
}
if (isset($aPointDetails['address'])) {
$aPlace['address'] = $aPointDetails['address']->getAddressNames();
}
if (isset($aPointDetails['asgeojson']))
{
$aPlace['geojson'] = json_decode($aPointDetails['asgeojson']);
}
if (isset($aPointDetails['asgeojson'])) {
$aPlace['geojson'] = json_decode($aPointDetails['asgeojson']);
}
if (isset($aPointDetails['assvg']))
{
$aPlace['svg'] = $aPointDetails['assvg'];
}
if (isset($aPointDetails['assvg'])) {
$aPlace['svg'] = $aPointDetails['assvg'];
}
if (isset($aPointDetails['astext']))
{
$aPlace['geotext'] = $aPointDetails['astext'];
}
if (isset($aPointDetails['astext'])) {
$aPlace['geotext'] = $aPointDetails['astext'];
}
if (isset($aPointDetails['askml']))
{
$aPlace['geokml'] = $aPointDetails['askml'];
}
if (isset($aPointDetails['askml'])) {
$aPlace['geokml'] = $aPointDetails['askml'];
}
if (isset($aPointDetails['sExtraTags'])) $aPlace['extratags'] = $aPointDetails['sExtraTags'];
if (isset($aPointDetails['sNameDetails'])) $aPlace['namedetails'] = $aPointDetails['sNameDetails'];
if (isset($aPointDetails['sExtraTags'])) $aPlace['extratags'] = $aPointDetails['sExtraTags'];
if (isset($aPointDetails['sNameDetails'])) $aPlace['namedetails'] = $aPointDetails['sNameDetails'];
$aFilteredPlaces[] = $aPlace;
}
$aFilteredPlaces[] = $aPlace;
}
javascript_renderData($aFilteredPlaces);
javascript_renderData($aFilteredPlaces);

View File

@@ -1,82 +0,0 @@
<?php
$aFilteredPlaces = array();
foreach($aSearchResults as $iResNum => $aPointDetails)
{
$aPlace = array(
'place_id'=>$aPointDetails['place_id'],
'licence'=>"Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright",
);
$sOSMType = ($aPointDetails['osm_type'] == 'N'?'node':($aPointDetails['osm_type'] == 'W'?'way':($aPointDetails['osm_type'] == 'R'?'relation':'')));
if ($sOSMType)
{
$aPlace['osm_type'] = $sOSMType;
$aPlace['osm_id'] = $aPointDetails['osm_id'];
}
if (isset($aPointDetails['aBoundingBox']))
{
$aPlace['boundingbox'] = array(
$aPointDetails['aBoundingBox'][0],
$aPointDetails['aBoundingBox'][1],
$aPointDetails['aBoundingBox'][2],
$aPointDetails['aBoundingBox'][3]);
if (isset($aPointDetails['aPolyPoints']) && $bShowPolygons)
{
$aPlace['polygonpoints'] = $aPointDetails['aPolyPoints'];
}
}
if (isset($aPointDetails['zoom']))
{
$aPlace['zoom'] = $aPointDetails['zoom'];
}
$aPlace['lat'] = $aPointDetails['lat'];
$aPlace['lon'] = $aPointDetails['lon'];
$aPlace['display_name'] = $aPointDetails['name'];
$aPlace['place_rank'] = $aPointDetails['rank_search'];
$aPlace['category'] = $aPointDetails['class'];
$aPlace['type'] = $aPointDetails['type'];
$aPlace['importance'] = $aPointDetails['importance'];
if (isset($aPointDetails['icon']))
{
$aPlace['icon'] = $aPointDetails['icon'];
}
if (isset($aPointDetails['address']) && sizeof($aPointDetails['address'])>0)
{
$aPlace['address'] = $aPointDetails['address'];
}
if (isset($aPointDetails['asgeojson']))
{
$aPlace['geojson'] = json_decode($aPointDetails['asgeojson']);
}
if (isset($aPointDetails['assvg']))
{
$aPlace['svg'] = $aPointDetails['assvg'];
}
if (isset($aPointDetails['astext']))
{
$aPlace['geotext'] = $aPointDetails['astext'];
}
if (isset($aPointDetails['askml']))
{
$aPlace['geokml'] = $aPointDetails['askml'];
}
if (isset($aPointDetails['sExtraTags'])) $aPlace['extratags'] = $aPointDetails['sExtraTags'];
if (isset($aPointDetails['sNameDetails'])) $aPlace['namedetails'] = $aPointDetails['sNameDetails'];
$aFilteredPlaces[] = $aPlace;
}
javascript_renderData($aFilteredPlaces);

View File

@@ -1,164 +1,134 @@
<?php
header("content-type: text/xml; charset=UTF-8");
header('content-type: text/xml; charset=UTF-8');
echo "<";
echo "?xml version=\"1.0\" encoding=\"UTF-8\" ?";
echo ">\n";
echo '<';
echo '?xml version="1.0" encoding="UTF-8" ?';
echo ">\n";
echo "<";
echo (isset($sXmlRootTag)?$sXmlRootTag:'searchresults');
echo " timestamp='".date(DATE_RFC822)."'";
echo " attribution='Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright'";
echo " querystring='".htmlspecialchars($sQuery, ENT_QUOTES)."'";
if ($sViewBox) echo " viewbox='".htmlspecialchars($sViewBox, ENT_QUOTES)."'";
echo " polygon='".($bShowPolygons?'true':'false')."'";
if (sizeof($aExcludePlaceIDs))
{
echo " exclude_place_ids='".htmlspecialchars(join(',',$aExcludePlaceIDs))."'";
}
if ($sMoreURL)
{
echo " more_url='".htmlspecialchars($sMoreURL)."'";
}
echo ">\n";
echo '<';
echo (isset($sXmlRootTag)?$sXmlRootTag:'searchresults');
echo " timestamp='".date(DATE_RFC822)."'";
echo " attribution='Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright'";
echo " querystring='".htmlspecialchars($sQuery, ENT_QUOTES)."'";
if (isset($aMoreParams['viewbox'])) echo " viewbox='".htmlspecialchars($aMoreParams['viewbox'], ENT_QUOTES)."'";
echo " polygon='".(isset($aMoreParams['polygon'])?'true':'false')."'";
if (isset($aMoreParams['exclude_place_ids'])) {
echo " exclude_place_ids='".htmlspecialchars($aMoreParams['exclude_place_ids'])."'";
}
echo " more_url='".htmlspecialchars($sMoreURL)."'";
echo ">\n";
foreach($aSearchResults as $iResNum => $aResult)
{
echo "<place place_id='".$aResult['place_id']."'";
$sOSMType = ($aResult['osm_type'] == 'N'?'node':($aResult['osm_type'] == 'W'?'way':($aResult['osm_type'] == 'R'?'relation':'')));
if ($sOSMType)
{
echo " osm_type='$sOSMType'";
echo " osm_id='".$aResult['osm_id']."'";
}
echo " place_rank='".$aResult['rank_search']."'";
foreach ($aSearchResults as $iResNum => $aResult) {
echo "<place place_id='".$aResult['place_id']."'";
$sOSMType = formatOSMType($aResult['osm_type']);
if ($sOSMType) {
echo " osm_type='$sOSMType'";
echo " osm_id='".$aResult['osm_id']."'";
}
echo " place_rank='".$aResult['rank_search']."'";
if (isset($aResult['aBoundingBox']))
{
echo ' boundingbox="';
echo $aResult['aBoundingBox'][0];
echo ','.$aResult['aBoundingBox'][1];
echo ','.$aResult['aBoundingBox'][2];
echo ','.$aResult['aBoundingBox'][3];
echo '"';
if (isset($aResult['aBoundingBox'])) {
echo ' boundingbox="';
echo join(',', $aResult['aBoundingBox']);
echo '"';
if ($bShowPolygons && isset($aResult['aPolyPoints']))
{
echo ' polygonpoints=\'';
echo json_encode($aResult['aPolyPoints']);
echo '\'';
}
}
if (isset($aResult['aPolyPoints'])) {
echo ' polygonpoints=\'';
echo json_encode($aResult['aPolyPoints']);
echo '\'';
}
}
if (isset($aResult['asgeojson']))
{
echo ' geojson=\'';
echo $aResult['asgeojson'];
echo '\'';
}
if (isset($aResult['asgeojson'])) {
echo ' geojson=\'';
echo $aResult['asgeojson'];
echo '\'';
}
if (isset($aResult['assvg']))
{
echo ' geosvg=\'';
echo $aResult['assvg'];
echo '\'';
}
if (isset($aResult['assvg'])) {
echo ' geosvg=\'';
echo $aResult['assvg'];
echo '\'';
}
if (isset($aResult['astext']))
{
echo ' geotext=\'';
echo $aResult['astext'];
echo '\'';
}
if (isset($aResult['astext'])) {
echo ' geotext=\'';
echo $aResult['astext'];
echo '\'';
}
if (isset($aResult['zoom']))
{
echo " zoom='".$aResult['zoom']."'";
}
if (isset($aResult['zoom'])) {
echo " zoom='".$aResult['zoom']."'";
}
echo " lat='".$aResult['lat']."'";
echo " lon='".$aResult['lon']."'";
echo " display_name='".htmlspecialchars($aResult['name'], ENT_QUOTES)."'";
echo " lat='".$aResult['lat']."'";
echo " lon='".$aResult['lon']."'";
echo " display_name='".htmlspecialchars($aResult['name'], ENT_QUOTES)."'";
echo " class='".htmlspecialchars($aResult['class'])."'";
echo " type='".htmlspecialchars($aResult['type'], ENT_QUOTES)."'";
echo " importance='".htmlspecialchars($aResult['importance'])."'";
if (isset($aResult['icon']) && $aResult['icon'])
{
echo " icon='".htmlspecialchars($aResult['icon'], ENT_QUOTES)."'";
}
echo " class='".htmlspecialchars($aResult['class'])."'";
echo " type='".htmlspecialchars($aResult['type'], ENT_QUOTES)."'";
echo " importance='".htmlspecialchars($aResult['importance'])."'";
if (isset($aResult['icon']) && $aResult['icon']) {
echo " icon='".htmlspecialchars($aResult['icon'], ENT_QUOTES)."'";
}
$bHasDelim = false;
$bHasDelim = false;
if (isset($aResult['askml']))
{
if (!$bHasDelim)
{
$bHasDelim = true;
echo ">";
}
echo "\n<geokml>";
echo $aResult['askml'];
echo "</geokml>";
}
if (isset($aResult['askml'])) {
if (!$bHasDelim) {
$bHasDelim = true;
echo '>';
}
echo "\n<geokml>";
echo $aResult['askml'];
echo '</geokml>';
}
if (isset($aResult['sExtraTags']))
{
if (!$bHasDelim)
{
$bHasDelim = true;
echo ">";
}
echo "\n<extratags>";
foreach ($aResult['sExtraTags'] as $sKey => $sValue)
{
echo '<tag key="'.htmlspecialchars($sKey).'" value="'.htmlspecialchars($sValue).'"/>';
}
echo "</extratags>";
}
if (isset($aResult['sExtraTags'])) {
if (!$bHasDelim) {
$bHasDelim = true;
echo '>';
}
echo "\n<extratags>";
foreach ($aResult['sExtraTags'] as $sKey => $sValue) {
echo '<tag key="'.htmlspecialchars($sKey).'" value="'.htmlspecialchars($sValue).'"/>';
}
echo '</extratags>';
}
if (isset($aResult['sNameDetails']))
{
if (!$bHasDelim)
{
$bHasDelim = true;
echo ">";
}
echo "\n<namedetails>";
foreach ($aResult['sNameDetails'] as $sKey => $sValue)
{
echo '<name desc="'.htmlspecialchars($sKey).'">';
echo htmlspecialchars($sValue);
echo "</name>";
}
echo "</namedetails>";
}
if (isset($aResult['sNameDetails'])) {
if (!$bHasDelim) {
$bHasDelim = true;
echo '>';
}
echo "\n<namedetails>";
foreach ($aResult['sNameDetails'] as $sKey => $sValue) {
echo '<name desc="'.htmlspecialchars($sKey).'">';
echo htmlspecialchars($sValue);
echo '</name>';
}
echo '</namedetails>';
}
if (isset($aResult['address']))
{
if (!$bHasDelim)
{
$bHasDelim = true;
echo ">";
}
echo "\n";
foreach($aResult['address'] as $sKey => $sValue)
{
$sKey = str_replace(' ','_',$sKey);
echo "<$sKey>";
echo htmlspecialchars($sValue);
echo "</$sKey>";
}
}
if (isset($aResult['address'])) {
if (!$bHasDelim) {
$bHasDelim = true;
echo '>';
}
echo "\n";
foreach ($aResult['address']->getAddressNames() as $sKey => $sValue) {
$sKey = str_replace(' ', '_', $sKey);
echo "<$sKey>";
echo htmlspecialchars($sValue);
echo "</$sKey>";
}
}
if ($bHasDelim)
{
echo "</place>";
}
else
{
echo "/>";
}
}
echo "</" . (isset($sXmlRootTag)?$sXmlRootTag:'searchresults') . ">";
if ($bHasDelim) {
echo '</place>';
} else {
echo '/>';
}
}
echo '</' . (isset($sXmlRootTag)?$sXmlRootTag:'searchresults') . '>';

View File

@@ -1,125 +0,0 @@
# SYNOPSIS
#
# AX_LIB_POSTGRESQL_SVR([MINIMUM-VERSION])
#
# DESCRIPTION
#
# This macro provides tests of availability of PostgreSQL server library
#
# This macro calls:
#
# AC_SUBST(POSTGRESQL_PGXS)
# AC_SUBST(POSTGRESQL_SERVER_CFLAGS)
#
# LICENSE
#
# Copyright (c) 2008 Mateusz Loskot <mateusz@loskot.net>
# Copyright (c) 2015 Sarah Hoffmann <lonia@denofr.de>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved.
AC_DEFUN([AX_LIB_POSTGRESQL_SVR],
[
AC_ARG_WITH([postgresql],
AC_HELP_STRING([--with-postgresql-svr=@<:@ARG@:>@],
[use PostgreSQL server library @<:@default=yes@:>@, optionally specify path to pg_config]
),
[
if test "$withval" = "no"; then
want_postgresql="no"
elif test "$withval" = "yes"; then
want_postgresql="yes"
else
want_postgresql="yes"
PG_CONFIG="$withval"
fi
],
[want_postgresql="yes"]
)
dnl
dnl Check PostgreSQL server libraries
dnl
if test "$want_postgresql" = "yes"; then
if test -z "$PG_CONFIG" -o test; then
AC_PATH_PROG([PG_CONFIG], [pg_config], [])
fi
if test ! -x "$PG_CONFIG"; then
AC_MSG_ERROR([$PG_CONFIG does not exist or it is not an exectuable file])
PG_CONFIG="no"
found_postgresql="no"
fi
if test "$PG_CONFIG" != "no"; then
AC_MSG_CHECKING([for PostgreSQL server libraries])
POSTGRESQL_SERVER_CFLAGS="-I`$PG_CONFIG --includedir-server`"
POSTGRESQL_VERSION=`$PG_CONFIG --version | sed -e 's#PostgreSQL ##'`
POSTGRESQL_PGXS=`$PG_CONFIG --pgxs`
if test -f "$POSTGRESQL_PGXS"
then
found_postgresql="yes"
AC_MSG_RESULT([yes])
fi
else
found_postgresql="no"
AC_MSG_RESULT([no])
fi
fi
dnl
dnl Check if required version of PostgreSQL is available
dnl
postgresql_version_req=ifelse([$1], [], [], [$1])
if test "$found_postgresql" = "yes" -a -n "$postgresql_version_req"; then
AC_MSG_CHECKING([if PostgreSQL version is >= $postgresql_version_req])
dnl Decompose required version string of PostgreSQL
dnl and calculate its number representation
postgresql_version_req_major=`expr $postgresql_version_req : '\([[0-9]]*\)'`
postgresql_version_req_minor=`expr $postgresql_version_req : '[[0-9]]*\.\([[0-9]]*\)'`
postgresql_version_req_micro=`expr $postgresql_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
if test "x$postgresql_version_req_micro" = "x"; then
postgresql_version_req_micro="0"
fi
postgresql_version_req_number=`expr $postgresql_version_req_major \* 1000000 \
\+ $postgresql_version_req_minor \* 1000 \
\+ $postgresql_version_req_micro`
dnl Decompose version string of installed PostgreSQL
dnl and calculate its number representation
postgresql_version_major=`expr $POSTGRESQL_VERSION : '\([[0-9]]*\)'`
postgresql_version_minor=`expr $POSTGRESQL_VERSION : '[[0-9]]*\.\([[0-9]]*\)'`
postgresql_version_micro=`expr $POSTGRESQL_VERSION : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
if test "x$postgresql_version_micro" = "x"; then
postgresql_version_micro="0"
fi
postgresql_version_number=`expr $postgresql_version_major \* 1000000 \
\+ $postgresql_version_minor \* 1000 \
\+ $postgresql_version_micro`
postgresql_version_check=`expr $postgresql_version_number \>\= $postgresql_version_req_number`
if test "$postgresql_version_check" = "1"; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi
fi
AC_SUBST([POSTGRESQL_PGXS])
AC_SUBST([POSTGRESQL_SERVER_CFLAGS])
])

View File

@@ -1,150 +0,0 @@
# SYNOPSIS
#
# AX_LIB_XML2([MINIMUM-VERSION])
#
# DESCRIPTION
#
# This macro provides tests of availability of xml2 'libxml2' library
# of particular version or newer.
#
# AX_LIB_LIBXML2 macro takes only one argument which is optional. If
# there is no required version passed, then macro does not run version
# test.
#
# The --with-libxml2 option takes one of three possible values:
#
# no - do not check for xml2 library
#
# yes - do check for xml2 library in standard locations (xml2-config
# should be in the PATH)
#
# path - complete path to xml2-config utility, use this option if xml2-config
# can't be found in the PATH
#
# This macro calls:
#
# AC_SUBST(XML2_CFLAGS)
# AC_SUBST(XML2_LDFLAGS)
# AC_SUBST(XML2_VERSION)
#
# And sets:
#
# HAVE_XML2
#
# LICENSE
#
# Copyright (c) 2009 Hartmut Holzgraefe <hartmut@php.net>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved.
AC_DEFUN([AX_LIB_XML2],
[
AC_ARG_WITH([libxml2],
AC_HELP_STRING([--with-libxml2=@<:@ARG@:>@],
[use libxml2 library @<:@default=yes@:>@, optionally specify path to xml2-config]
),
[
if test "$withval" = "no"; then
want_libxml2="no"
elif test "$withval" = "yes"; then
want_libxml2="yes"
else
want_libxml2="yes"
XML2_CONFIG="$withval"
fi
],
[want_libxml2="yes"]
)
XML2_CFLAGS=""
XML2_LDFLAGS=""
XML2_VERSION=""
dnl
dnl Check xml2 libraries (libxml2)
dnl
if test "$want_libxml2" = "yes"; then
if test -z "$XML2_CONFIG" -o test; then
AC_PATH_PROG([XML2_CONFIG], [xml2-config], [])
fi
if test ! -x "$XML2_CONFIG"; then
AC_MSG_ERROR([$XML2_CONFIG does not exist or it is not an exectuable file])
XML2_CONFIG="no"
found_libxml2="no"
fi
if test "$XML2_CONFIG" != "no"; then
AC_MSG_CHECKING([for xml2 libraries])
XML2_CFLAGS="`$XML2_CONFIG --cflags`"
XML2_LDFLAGS="`$XML2_CONFIG --libs`"
XML2_VERSION=`$XML2_CONFIG --version`
AC_DEFINE([HAVE_XML2], [1],
[Define to 1 if xml2 libraries are available])
found_libxml2="yes"
AC_MSG_RESULT([yes])
else
found_libxml2="no"
AC_MSG_RESULT([no])
fi
fi
dnl
dnl Check if required version of xml2 is available
dnl
libxml2_version_req=ifelse([$1], [], [], [$1])
if test "$found_libxml2" = "yes" -a -n "$libxml2_version_req"; then
AC_MSG_CHECKING([if libxml2 version is >= $libxml2_version_req])
dnl Decompose required version string of libxml2
dnl and calculate its number representation
libxml2_version_req_major=`expr $libxml2_version_req : '\([[0-9]]*\)'`
libxml2_version_req_minor=`expr $libxml2_version_req : '[[0-9]]*\.\([[0-9]]*\)'`
libxml2_version_req_micro=`expr $libxml2_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
if test "x$libxml2_version_req_micro" = "x"; then
libxml2_version_req_micro="0"
fi
libxml2_version_req_number=`expr $libxml2_version_req_major \* 1000000 \
\+ $libxml2_version_req_minor \* 1000 \
\+ $libxml2_version_req_micro`
dnl Decompose version string of installed PostgreSQL
dnl and calculate its number representation
libxml2_version_major=`expr $XML2_VERSION : '\([[0-9]]*\)'`
libxml2_version_minor=`expr $XML2_VERSION : '[[0-9]]*\.\([[0-9]]*\)'`
libxml2_version_micro=`expr $XML2_VERSION : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
if test "x$libxml2_version_micro" = "x"; then
libxml2_version_micro="0"
fi
libxml2_version_number=`expr $libxml2_version_major \* 1000000 \
\+ $libxml2_version_minor \* 1000 \
\+ $libxml2_version_micro`
libxml2_version_check=`expr $libxml2_version_number \>\= $libxml2_version_req_number`
if test "$libxml2_version_check" = "1"; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi
fi
AC_SUBST([XML2_VERSION])
AC_SUBST([XML2_CFLAGS])
AC_SUBST([XML2_LDFLAGS])
])

10
module/CMakeLists.txt Normal file
View File

@@ -0,0 +1,10 @@
# just use the pgxs makefile
ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/dummy
COMMAND PGXS=${PGXS} PG_CONFIG=${PG_CONFIG} MODSRCDIR=${CMAKE_CURRENT_SOURCE_DIR} $(MAKE) -f ${CMAKE_CURRENT_SOURCE_DIR}/Makefile
COMMENT "Running external makefile ${PGXS}"
)
ADD_CUSTOM_TARGET( nominatim_lib ALL
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/dummy
)

View File

@@ -1,8 +1,9 @@
MODULES = nominatim
PGXS := @POSTGRESQL_PGXS@
PG_CONFIG := @PG_CONFIG@
PG_CPPFLAGS = -I$(MODSRCDIR)
include $(PGXS)
VPATH = $(MODSRCDIR)
all:
chmod 755 nominatim.so

View File

@@ -157,17 +157,18 @@ transliteration( PG_FUNCTION_ARGS )
PG_RETURN_TEXT_P(result);
}
// Set isspace=1 if the replacement _only_ adds a space before the search string. I.e. to == " " + from
void str_replace(char* buffer, int* len, int* changes, char* from, int fromlen, char* to, int tolen, int isspace)
{
char *p;
// Search string is too long to be pressent
// Search string is too long to be present
if (fromlen > *len) return;
p = strstr(buffer, from);
while(p)
{
if (!isspace || *(p-1) != ' ')
if (!isspace || (p > buffer && *(p-1) != ' '))
{
(*changes)++;
if (tolen != fromlen) memmove(p+tolen, p+fromlen, *len-(p-buffer)+1);
@@ -230,7 +231,7 @@ gettokenstring( PG_FUNCTION_ARGS )
sourcedata = (unsigned char *)VARDATA(source);
sourcedatalength = VARSIZE(source) - VARHDRSZ;
// Buffer for doing the replace in - string could get slightly longer (double is mastive overkill)
// Buffer for doing the replace in - string could get slightly longer (double is massive overkill)
buffer = (char *)palloc((sourcedatalength*2)*sizeof(char));
memcpy(buffer+1, sourcedata, sourcedatalength);
buffer[0] = 32;

File diff suppressed because one or more lines are too long

12
nominatim/CMakeLists.txt Normal file
View File

@@ -0,0 +1,12 @@
add_executable(nominatim export.c geometry.cpp import.c index.c input.c nominatim.c postgresql.c sprompt.c)
CHECK_SYMBOL_EXISTS(bswap_32 "byteswap.h" HAVE_BYTESWAP)
CHECK_SYMBOL_EXISTS(bswap32 "sys/endian.h" HAVE_SYS_ENDIAN)
target_compile_definitions(nominatim
PRIVATE HAVE_BYTESWAP=$<BOOL:${HAVE_BYTESWAP}>
PRIVATE HAVE_SYS_ENDIAN=$<BOOL:${HAVE_SYS_ENDIAN}>
)
target_link_libraries(nominatim ${LIBXML2_LIBRARIES} ${ZLIB_LIBRARIES} ${BZIP2_LIBRARIES} ${PostgreSQL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})

View File

@@ -1,9 +0,0 @@
bin_PROGRAMS = nominatim
nominatim_SOURCES = export.c geometry.cpp import.c index.c input.c nominatim.c postgresql.c sprompt.c
AM_CFLAGS = @PTHREAD_CFLAGS@ @POSTGRESQL_CPPFLAGS@ @XML_CPPFLAGS@ @BZIP2_CFLAGS@ @GEOS_CFLAGS@ @PROJ_CFLAGS@ -DVERSION='"@PACKAGE_VERSION@"'
AM_CPPFLAGS = @PTHREAD_CFLAGS@ @POSTGRESQL_CPPFLAGS@ @XML_CPPFLAGS@ @BZIP2_CFLAGS@ @GEOS_CFLAGS@ @PROJ_CFLAGS@
nominatim_LDADD = @PTHREAD_CFLAGS@ @POSTGRESQL_LDFLAGS@ @POSTGRESQL_LIBS@ @XML_LIBS@ @BZIP2_LDFLAGS@ @BZIP2_LIBS@ @GEOS_LDFLAGS@ @GEOS_LIBS@ @PROJ_LDFLAGS@ @PROJ_LIBS@ -lz

View File

@@ -152,7 +152,7 @@ void nominatim_exportCreatePreparedQueries(PGconn * conn)
pg_prepare_params[0] = PG_OID_INT8;
res = PQprepare(conn, "placex_details",
"select placex.osm_type, placex.osm_id, placex.class, placex.type, placex.name, placex.housenumber, placex.country_code, ST_AsText(placex.geometry), placex.admin_level, placex.rank_address, placex.rank_search, placex.parent_place_id, parent.osm_type, parent.osm_id, placex.indexed_status from placex left outer join placex as parent on (placex.parent_place_id = parent.place_id) where placex.place_id = $1",
"select placex.osm_type, placex.osm_id, placex.class, placex.type, placex.name, placex.housenumber, placex.country_code, ST_AsText(placex.geometry), placex.admin_level, placex.rank_address, placex.rank_search, placex.parent_place_id, parent.osm_type, parent.osm_id, placex.indexed_status, placex.linked_place_id from placex left outer join placex as parent on (placex.parent_place_id = parent.place_id) where placex.place_id = $1",
1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
@@ -355,7 +355,7 @@ void nominatim_exportFreeQueries(struct export_data * querySet)
/*
* Requirements: the prepared queries must exist
*/
void nominatim_exportPlace(uint64_t place_id, PGconn * conn,
void nominatim_exportPlace(uint64_t place_id, PGconn * conn,
xmlTextWriterPtr writer, pthread_mutex_t * writer_mutex, struct export_data * prevQuerySet)
{
struct export_data querySet;
@@ -387,7 +387,7 @@ void nominatim_exportPlace(uint64_t place_id, PGconn * conn,
{
// Add
if (writer_mutex) pthread_mutex_lock( writer_mutex );
nominatim_exportStartMode(writer, 1);
nominatim_exportStartMode(writer, 1);
}
else
{
@@ -396,14 +396,14 @@ void nominatim_exportPlace(uint64_t place_id, PGconn * conn,
// TODO: detect changes
if (writer_mutex) pthread_mutex_lock( writer_mutex );
nominatim_exportStartMode(writer, 2);
nominatim_exportStartMode(writer, 2);
}
}
else
{
// Add
if (writer_mutex) pthread_mutex_lock( writer_mutex );
nominatim_exportStartMode(writer, 1);
nominatim_exportStartMode(writer, 1);
}
xmlTextWriterStartElement(writer, BAD_CAST "feature");
@@ -417,6 +417,7 @@ void nominatim_exportPlace(uint64_t place_id, PGconn * conn,
xmlTextWriterWriteAttribute(writer, BAD_CAST "parent_place_id", BAD_CAST PQgetvalue(querySet.res, 0, 11));
xmlTextWriterWriteAttribute(writer, BAD_CAST "parent_type", BAD_CAST PQgetvalue(querySet.res, 0, 12));
xmlTextWriterWriteAttribute(writer, BAD_CAST "parent_id", BAD_CAST PQgetvalue(querySet.res, 0, 13));
xmlTextWriterWriteAttribute(writer, BAD_CAST "linked_place_id", BAD_CAST PQgetvalue(querySet.res, 0, 15));
if (PQntuples(querySet.resNames))
{

View File

@@ -486,7 +486,7 @@ void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
}
paramValues[7] = (const char *)featureExtraTagString;
if (strlen(feature.parentPlaceID) == 0)
if (xmlStrlen(feature.parentPlaceID) == 0)
paramValues[8] = "0";
else
paramValues[8] = (const char *)feature.parentPlaceID;
@@ -541,10 +541,10 @@ void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
if (featureNameLines)
{
if (strlen(feature.parentPlaceID) > 0 && featureAddressLines == 0)
if (xmlStrlen(feature.parentPlaceID) > 0 && featureAddressLines == 0)
{
paramValues[0] = (const char *)place_id;
paramValues[1] = feature.parentPlaceID;
paramValues[1] = (const char *)feature.parentPlaceID;
if (verbose) fprintf(stderr, "search_name_from_parent_insert: INSERT %s %s\n", paramValues[0], paramValues[1]);
res = PQexecPrepared(conn, "search_name_from_parent_insert", 2, paramValues, NULL, NULL, 0);
if (PQresultStatus(res) != PGRES_COMMAND_OK)

View File

@@ -1,4 +1,6 @@
/*
* triggers indexing (reparenting etc.) through setting resetting indexed_status: update placex/osmline set indexed_status = 0 where indexed_status > 0
* triggers placex_update and osmline_update
*/
#include <stdio.h>
@@ -19,34 +21,258 @@
extern int verbose;
void nominatim_index(int rank_min, int rank_max, int num_threads, const char *conninfo, const char *structuredoutputfile)
void run_indexing(int rank, int interpolation, PGconn *conn, int num_threads,
struct index_thread_data * thread_data, const char *structuredoutputfile)
{
struct index_thread_data * thread_data;
pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
int tuples, count, sleepcount;
pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
time_t rankStartTime;
int rankTotalTuples;
int rankCountTuples;
float rankPerSecond;
PGconn *conn;
PGresult * res;
PGresult * resSectors;
PGresult * resPlaces;
PGresult * resNULL;
int rank;
int i;
int iSector;
int iResult;
const char *paramValues[2];
int paramLengths[2];
int paramFormats[2];
uint32_t paramRank;
uint32_t paramSector;
uint32_t sector;
xmlTextWriterPtr writer;
pthread_mutex_t writer_mutex = PTHREAD_MUTEX_INITIALIZER;
// Create the output file
writer = NULL;
if (structuredoutputfile)
{
writer = nominatim_exportXMLStart(structuredoutputfile);
}
if (interpolation)
{
fprintf(stderr, "Starting interpolation lines (location_property_osmline)\n");
}
else
{
fprintf(stderr, "Starting rank %d\n", rank);
}
rankCountTuples = 0;
rankPerSecond = 0;
paramRank = PGint32(rank);
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
if (interpolation)
{
resSectors = PQexecPrepared(conn, "index_sectors_osmline", 0, NULL, 0, NULL, 1);
}
else
{
resSectors = PQexecPrepared(conn, "index_sectors", 1, paramValues, paramLengths, paramFormats, 1);
}
if (PQresultStatus(resSectors) != PGRES_TUPLES_OK)
{
fprintf(stderr, "index_sectors: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resSectors);
exit(EXIT_FAILURE);
}
if (PQftype(resSectors, 0) != PG_OID_INT4)
{
fprintf(stderr, "Sector value has unexpected type\n");
PQclear(resSectors);
exit(EXIT_FAILURE);
}
if (PQftype(resSectors, 1) != PG_OID_INT8)
{
fprintf(stderr, "Sector value has unexpected type\n");
PQclear(resSectors);
exit(EXIT_FAILURE);
}
rankTotalTuples = 0;
for (iSector = 0; iSector < PQntuples(resSectors); iSector++)
{
rankTotalTuples += PGint64(*((uint64_t *)PQgetvalue(resSectors, iSector, 1)));
}
rankStartTime = time(0);
for (iSector = 0; iSector <= PQntuples(resSectors); iSector++)
{
if (iSector > 0)
{
resPlaces = PQgetResult(conn);
if (PQresultStatus(resPlaces) != PGRES_TUPLES_OK)
{
fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
if (PQftype(resPlaces, 0) != PG_OID_INT8)
{
fprintf(stderr, "Place_id value has unexpected type\n");
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
resNULL = PQgetResult(conn);
if (resNULL != NULL)
{
fprintf(stderr, "Unexpected non-null response\n");
exit(EXIT_FAILURE);
}
}
if (iSector < PQntuples(resSectors))
{
sector = PGint32(*((uint32_t *)PQgetvalue(resSectors, iSector, 0)));
// fprintf(stderr, "\n Starting sector %d size %ld\n", sector, PGint64(*((uint64_t *)PQgetvalue(resSectors, iSector, 1))));
// Get all the place_id's for this sector
paramRank = PGint32(rank);
paramSector = PGint32(sector);
if (rankTotalTuples-rankCountTuples < num_threads*1000)
{
// no sectors
if (interpolation)
{
iResult = PQsendQueryPrepared(conn, "index_nosector_places_osmline", 0, NULL, 0, NULL, 1);
}
else
{
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
iResult = PQsendQueryPrepared(conn, "index_nosector_places", 1, paramValues, paramLengths, paramFormats, 1);
}
}
else
{
if (interpolation)
{
iResult = PQsendQueryPrepared(conn, "index_sector_places_osmline", 1, paramValues, paramLengths, paramFormats, 1);
paramValues[0] = (char *)&paramSector;
paramLengths[0] = sizeof(paramSector);
paramFormats[0] = 1;
}
else
{
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
paramValues[1] = (char *)&paramSector;
paramLengths[1] = sizeof(paramSector);
paramFormats[1] = 1;
iResult = PQsendQueryPrepared(conn, "index_sector_places", 2, paramValues, paramLengths, paramFormats, 1);
}
}
if (!iResult)
{
fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
}
if (iSector > 0)
{
count = 0;
rankPerSecond = 0;
tuples = PQntuples(resPlaces);
if (tuples > 0)
{
// Spawn threads
for (i = 0; i < num_threads; i++)
{
thread_data[i].res = resPlaces;
thread_data[i].tuples = tuples;
thread_data[i].count = &count;
thread_data[i].count_mutex = &count_mutex;
thread_data[i].writer = writer;
thread_data[i].writer_mutex = &writer_mutex;
if (interpolation)
{
thread_data[i].table = 0; // use interpolations table
}
else
{
thread_data[i].table = 1; // use placex table
}
pthread_create(&thread_data[i].thread, NULL, &nominatim_indexThread, (void *)&thread_data[i]);
}
// Monitor threads to give user feedback
sleepcount = 0;
while (count < tuples)
{
usleep(1000);
// Aim for one update per second
if (sleepcount++ > 1000)
{
rankPerSecond = ((float)rankCountTuples + (float)count) / MAX(difftime(time(0), rankStartTime),1);
if(interpolation)
{
fprintf(stderr, " Done %i in %i @ %f per second - Interpolation lines ETA (seconds): %f\n", (rankCountTuples + count), (int)(difftime(time(0), rankStartTime)), rankPerSecond, ((float)(rankTotalTuples - (rankCountTuples + count)))/rankPerSecond);
}
else
{
fprintf(stderr, " Done %i in %i @ %f per second - Rank %i ETA (seconds): %f\n", (rankCountTuples + count), (int)(difftime(time(0), rankStartTime)), rankPerSecond, rank, ((float)(rankTotalTuples - (rankCountTuples + count)))/rankPerSecond);
}
sleepcount = 0;
}
}
// Wait for everything to finish
for (i = 0; i < num_threads; i++)
{
pthread_join(thread_data[i].thread, NULL);
}
rankCountTuples += tuples;
}
// Finished sector
rankPerSecond = (float)rankCountTuples / MAX(difftime(time(0), rankStartTime),1);
fprintf(stderr, " Done %i in %i @ %f per second - ETA (seconds): %f\n", rankCountTuples, (int)(difftime(time(0), rankStartTime)), rankPerSecond, ((float)(rankTotalTuples - rankCountTuples))/rankPerSecond);
PQclear(resPlaces);
}
if (rankTotalTuples-rankCountTuples < num_threads*20 && iSector < PQntuples(resSectors))
{
iSector = PQntuples(resSectors) - 1;
}
}
// Finished rank
fprintf(stderr, "\r Done %i in %i @ %f per second - FINISHED\n\n", rankCountTuples, (int)(difftime(time(0), rankStartTime)), rankPerSecond);
PQclear(resSectors);
}
void nominatim_index(int rank_min, int rank_max, int num_threads, const char *conninfo, const char *structuredoutputfile)
{
struct index_thread_data *thread_data;
PGconn *conn;
PGresult *res;
int num_rows = 0, status_code = 0;
int db_has_locale = 0;
char *result_string = NULL;
int rank;
int i;
xmlTextWriterPtr writer;
pthread_mutex_t writer_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -60,6 +286,23 @@ void nominatim_index(int rank_min, int rank_max, int num_threads, const char *co
exit(EXIT_FAILURE);
}
res = PQexec(conn, "SHOW lc_messages");
status_code = PQresultStatus(res);
if (status_code != PGRES_TUPLES_OK && status_code != PGRES_SINGLE_TUPLE) {
fprintf(stderr, "Failed determining database locale: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
num_rows = PQntuples(res);
if (num_rows > 0)
{
result_string = PQgetvalue(res, 0, 0);
if (result_string && (strlen(result_string) > 0) && (strcasecmp(result_string, "C") != 0))
{
// non-default locale if the result exists, is non-empty, and is not "C"
db_has_locale = 1;
}
}
pg_prepare_params[0] = PG_OID_INT4;
res = PQprepare(conn, "index_sectors",
"select geometry_sector,count(*) from placex where rank_search = $1 and indexed_status > 0 group by geometry_sector order by geometry_sector",
@@ -70,6 +313,16 @@ void nominatim_index(int rank_min, int rank_max, int num_threads, const char *co
exit(EXIT_FAILURE);
}
PQclear(res);
res = PQprepare(conn, "index_sectors_osmline",
"select geometry_sector,count(*) from location_property_osmline where indexed_status > 0 group by geometry_sector order by geometry_sector",
0, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed preparing index_sectors: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
PQclear(res);
pg_prepare_params[0] = PG_OID_INT4;
res = PQprepare(conn, "index_nosectors",
@@ -104,7 +357,28 @@ void nominatim_index(int rank_min, int rank_max, int num_threads, const char *co
exit(EXIT_FAILURE);
}
PQclear(res);
pg_prepare_params[0] = PG_OID_INT4;
res = PQprepare(conn, "index_sector_places_osmline",
"select place_id from location_property_osmline where geometry_sector = $1 and indexed_status > 0",
1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed preparing index_sector_places: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
PQclear(res);
res = PQprepare(conn, "index_nosector_places_osmline",
"select place_id from location_property_osmline where indexed_status > 0 order by geometry_sector",
0, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed preparing index_nosector_places: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
PQclear(res);
// Build the data for each thread
thread_data = (struct index_thread_data *)malloc(sizeof(struct index_thread_data)*num_threads);
for (i = 0; i < num_threads; i++)
@@ -122,199 +396,54 @@ void nominatim_index(int rank_min, int rank_max, int num_threads, const char *co
1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed preparing index_placex: %s\n", PQerrorMessage(conn));
fprintf(stderr, "Failed preparing index_placex: %s\n", PQerrorMessage(thread_data[i].conn));
exit(EXIT_FAILURE);
}
PQclear(res);
pg_prepare_params[0] = PG_OID_INT8;
res = PQprepare(thread_data[i].conn, "index_osmline",
"update location_property_osmline set indexed_status = 0 where place_id = $1",
1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed preparing index_osmline: %s\n", PQerrorMessage(thread_data[i].conn));
exit(EXIT_FAILURE);
}
PQclear(res);
/*res = PQexec(thread_data[i].conn, "set enable_seqscan = false");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
if (db_has_locale)
{
fprintf(stderr, "Failed disabling sequential scan: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
// Make sure the error message is not localized as we parse it later.
res = PQexec(thread_data[i].conn, "SET lc_messages TO 'C'");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed to set langauge: %s\n", PQerrorMessage(thread_data[i].conn));
exit(EXIT_FAILURE);
}
PQclear(res);
}
PQclear(res);*/
nominatim_exportCreatePreparedQueries(thread_data[i].conn);
}
// Create the output file
writer = NULL;
if (structuredoutputfile)
{
writer = nominatim_exportXMLStart(structuredoutputfile);
}
fprintf(stderr, "Starting indexing rank (%i to %i) using %i threads\n", rank_min, rank_max, num_threads);
for (rank = rank_min; rank <= rank_max; rank++)
{
fprintf(stderr, "Starting rank %d\n", rank);
rankCountTuples = 0;
rankPerSecond = 0;
paramRank = PGint32(rank);
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
// if (rank < 16)
// resSectors = PQexecPrepared(conn, "index_nosectors", 1, paramValues, paramLengths, paramFormats, 1);
// else
resSectors = PQexecPrepared(conn, "index_sectors", 1, paramValues, paramLengths, paramFormats, 1);
if (PQresultStatus(resSectors) != PGRES_TUPLES_OK)
// OSMLINE: do reindexing (=> reparenting) for interpolation lines at rank 30, but before all other objects of rank 30
// reason: houses (rank 30) depend on the updated interpolation line, when reparenting (see placex_update in functions.sql)
if (rank == 30)
{
fprintf(stderr, "index_sectors: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resSectors);
exit(EXIT_FAILURE);
run_indexing(rank, 1, conn, num_threads, thread_data, structuredoutputfile);
}
if (PQftype(resSectors, 0) != PG_OID_INT4)
{
fprintf(stderr, "Sector value has unexpected type\n");
PQclear(resSectors);
exit(EXIT_FAILURE);
}
if (PQftype(resSectors, 1) != PG_OID_INT8)
{
fprintf(stderr, "Sector value has unexpected type\n");
PQclear(resSectors);
exit(EXIT_FAILURE);
}
rankTotalTuples = 0;
for (iSector = 0; iSector < PQntuples(resSectors); iSector++)
{
rankTotalTuples += PGint64(*((uint64_t *)PQgetvalue(resSectors, iSector, 1)));
}
rankStartTime = time(0);
for (iSector = 0; iSector <= PQntuples(resSectors); iSector++)
{
if (iSector > 0)
{
resPlaces = PQgetResult(conn);
if (PQresultStatus(resPlaces) != PGRES_TUPLES_OK)
{
fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
if (PQftype(resPlaces, 0) != PG_OID_INT8)
{
fprintf(stderr, "Place_id value has unexpected type\n");
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
resNULL = PQgetResult(conn);
if (resNULL != NULL)
{
fprintf(stderr, "Unexpected non-null response\n");
exit(EXIT_FAILURE);
}
}
if (iSector < PQntuples(resSectors))
{
sector = PGint32(*((uint32_t *)PQgetvalue(resSectors, iSector, 0)));
// fprintf(stderr, "\n Starting sector %d size %ld\n", sector, PGint64(*((uint64_t *)PQgetvalue(resSectors, iSector, 1))));
// Get all the place_id's for this sector
paramRank = PGint32(rank);
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
paramSector = PGint32(sector);
paramValues[1] = (char *)&paramSector;
paramLengths[1] = sizeof(paramSector);
paramFormats[1] = 1;
if (rankTotalTuples-rankCountTuples < num_threads*1000)
{
iResult = PQsendQueryPrepared(conn, "index_nosector_places", 1, paramValues, paramLengths, paramFormats, 1);
}
else
{
iResult = PQsendQueryPrepared(conn, "index_sector_places", 2, paramValues, paramLengths, paramFormats, 1);
}
if (!iResult)
{
fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
}
if (iSector > 0)
{
count = 0;
rankPerSecond = 0;
tuples = PQntuples(resPlaces);
if (tuples > 0)
{
// Spawn threads
for (i = 0; i < num_threads; i++)
{
thread_data[i].res = resPlaces;
thread_data[i].tuples = tuples;
thread_data[i].count = &count;
thread_data[i].count_mutex = &count_mutex;
thread_data[i].writer = writer;
thread_data[i].writer_mutex = &writer_mutex;
pthread_create(&thread_data[i].thread, NULL, &nominatim_indexThread, (void *)&thread_data[i]);
}
// Monitor threads to give user feedback
sleepcount = 0;
while (count < tuples)
{
usleep(1000);
// Aim for one update per second
if (sleepcount++ > 500)
{
rankPerSecond = ((float)rankCountTuples + (float)count) / MAX(difftime(time(0), rankStartTime),1);
fprintf(stderr, " Done %i in %i @ %f per second - Rank %i ETA (seconds): %f\n", (rankCountTuples + count), (int)(difftime(time(0), rankStartTime)), rankPerSecond, rank, ((float)(rankTotalTuples - (rankCountTuples + count)))/rankPerSecond);
sleepcount = 0;
}
}
// Wait for everything to finish
for (i = 0; i < num_threads; i++)
{
pthread_join(thread_data[i].thread, NULL);
}
rankCountTuples += tuples;
}
// Finished sector
rankPerSecond = (float)rankCountTuples / MAX(difftime(time(0), rankStartTime),1);
fprintf(stderr, " Done %i in %i @ %f per second - ETA (seconds): %f\n", rankCountTuples, (int)(difftime(time(0), rankStartTime)), rankPerSecond, ((float)(rankTotalTuples - rankCountTuples))/rankPerSecond);
PQclear(resPlaces);
}
if (rankTotalTuples-rankCountTuples < num_threads*20 && iSector < PQntuples(resSectors))
{
iSector = PQntuples(resSectors) - 1;
}
}
// Finished rank
fprintf(stderr, "\r Done %i in %i @ %f per second - FINISHED \n\n", rankCountTuples, (int)(difftime(time(0), rankStartTime)), rankPerSecond);
PQclear(resSectors);
run_indexing(rank, 0, conn, num_threads, thread_data, structuredoutputfile);
}
if (writer)
{
nominatim_exportXMLEnd(writer);
}
// Close all connections
for (i = 0; i < num_threads; i++)
{
PQfinish(thread_data[i].conn);
}
PQfinish(conn);
// Close all connections
for (i = 0; i < num_threads; i++)
{
PQfinish(thread_data[i].conn);
}
PQfinish(conn);
}
void *nominatim_indexThread(void * thread_data_in)
@@ -324,12 +453,15 @@ void *nominatim_indexThread(void * thread_data_in)
PGresult *res;
const char *paramValues[1];
const char *paramValues[1];
int paramLengths[1];
int paramFormats[1];
uint64_t paramPlaceID;
uint64_t place_id;
time_t updateStartTime;
uint64_t place_id;
time_t updateStartTime;
unsigned table;
table = thread_data->table;
while (1)
{
@@ -348,37 +480,58 @@ void *nominatim_indexThread(void * thread_data_in)
if (verbose) fprintf(stderr, " Processing place_id %ld\n", place_id);
updateStartTime = time(0);
int done = 0;
int done = 0;
if (thread_data->writer)
{
nominatim_exportPlaceQueries(place_id, thread_data->conn, &querySet);
}
while(!done)
{
paramPlaceID = PGint64(place_id);
paramValues[0] = (char *)&paramPlaceID;
paramLengths[0] = sizeof(paramPlaceID);
paramFormats[0] = 1;
res = PQexecPrepared(thread_data->conn, "index_placex", 1, paramValues, paramLengths, paramFormats, 1);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
done = 1;
else
{
if (!strncmp(PQerrorMessage(thread_data->conn), "ERROR: deadlock detected", 25))
{
fprintf(stderr, "index_placex: UPDATE failed - deadlock, retrying (%ld)\n", place_id);
PQclear(res);
sleep(rand() % 10);
}
else
{
fprintf(stderr, "index_placex: UPDATE failed: %s", PQerrorMessage(thread_data->conn));
PQclear(res);
exit(EXIT_FAILURE);
}
}
while(!done)
{
paramPlaceID = PGint64(place_id);
paramValues[0] = (char *)&paramPlaceID;
paramLengths[0] = sizeof(paramPlaceID);
paramFormats[0] = 1;
if (table == 1) // table=1 for placex
{
res = PQexecPrepared(thread_data->conn, "index_placex", 1, paramValues, paramLengths, paramFormats, 1);
}
else // table=0 for osmline
{
res = PQexecPrepared(thread_data->conn, "index_osmline", 1, paramValues, paramLengths, paramFormats, 1);
}
if (PQresultStatus(res) == PGRES_COMMAND_OK)
done = 1;
else
{
if (!strncmp(PQerrorMessage(thread_data->conn), "ERROR: deadlock detected", 25))
{
if (table == 1)
{
fprintf(stderr, "index_placex: UPDATE failed - deadlock, retrying (%ld)\n", place_id);
}
else
{
fprintf(stderr, "index_osmline: UPDATE failed - deadlock, retrying (%ld)\n", place_id);
}
PQclear(res);
sleep(rand() % 10);
}
else
{
if (table == 1)
{
fprintf(stderr, "index_placex: UPDATE failed: %s", PQerrorMessage(thread_data->conn));
}
else
{
fprintf(stderr, "index_osmline: UPDATE failed: %s", PQerrorMessage(thread_data->conn));
}
PQclear(res);
exit(EXIT_FAILURE);
}
}
}
PQclear(res);
if (difftime(time(0), updateStartTime) > 1) fprintf(stderr, " Slow place_id %ld\n", place_id);

Some files were not shown because too many files have changed in this diff Show More