Compare commits
3119 Commits
v0.3.9
...
v5.3.0-rc.2
| Author | SHA1 | Date | |
|---|---|---|---|
| 247a7488b8 | |||
| 1806198971 | |||
| 375331b80c | |||
| 8fdbe965cc | |||
| dc77d02e8a | |||
| 6265b8fa77 | |||
| 311b348d09 | |||
| ec02cdc4cc | |||
| 5905708111 | |||
| 5d91b759d1 | |||
| ec0a1a4ab1 | |||
| efa29edf09 | |||
| 2a05b70dfc | |||
| 8693e68271 | |||
| d21a9a514d | |||
| e03d132823 | |||
| 61ba985bc9 | |||
| 4629a20fe4 | |||
| a28125ee9a | |||
| df877aca1b | |||
| 05dc415aba | |||
| 6dedd9cb72 | |||
| 256d39b572 | |||
| d186ae1863 | |||
| fddc19e98d | |||
| 2592cd2e58 | |||
| 93b6438cea | |||
| f6746d88b7 | |||
| 34ace4dd4b | |||
| 41d0f42ddf | |||
| 2868f702a5 | |||
| ec4dcee8bd | |||
| 8c378191df | |||
| b98431e8e6 | |||
| 3c8781855e | |||
| 27a94f3ca6 | |||
| 04e334e3e2 | |||
| 12d4832037 | |||
| 6e4f6fec91 | |||
| 57c9525e5c | |||
| 543e4fb57d | |||
| 3881ead8e5 | |||
| 911d1e81b6 | |||
| ae06300c17 | |||
| 26879ca91a | |||
| 306744e5cb | |||
| 3ca32898a1 | |||
| 532fda267f | |||
| 494845b160 | |||
| 0fc823041e | |||
| 71eae4137d | |||
| 47b19f209b | |||
| 2b5355edca | |||
| e9a0beb4e8 | |||
| 6bdfe68897 | |||
| cf2d2b6763 | |||
| 95cd44f34f | |||
| d330e60d40 | |||
| 99004bbec8 | |||
| bbcc728a07 | |||
| 033dc0a72d | |||
| 1c140a112a | |||
| 312e86eb58 | |||
| 1dfdb38d4a | |||
| dfafe7dc5f | |||
| 6ecc123d15 | |||
| 6f322d2140 | |||
| dfa762bccc | |||
| 87f00d2c4c | |||
| 6f94e0dfb8 | |||
| ad70759f91 | |||
| 27c4e8ddd0 | |||
| 805d74b6ae | |||
| 4ad78309e2 | |||
| b78207ddd8 | |||
| b6834da9a4 | |||
| 801cc72691 | |||
| e198709643 | |||
| ed8d5e0b0a | |||
| e8fb312703 | |||
| 058b8c3b31 | |||
| ae3ccb009e | |||
| 0c60a2aef8 | |||
| 44fdf86702 | |||
| 1659bbf7b1 | |||
| 46b58fba83 | |||
| 84da86ba4a | |||
| 6777127497 | |||
| a4ac07866a | |||
| 448f8377fb | |||
| c490752ca7 | |||
| 6edc565c01 | |||
| bb0c2754d3 | |||
| 58d6e8f4d0 | |||
| bdc66049a5 | |||
| 0a53775fb3 | |||
| 9cdc9008aa | |||
| bd707b0cfc | |||
| a85f39c140 | |||
| ef7b36da32 | |||
| 14fdf861ca | |||
| 7641b12b08 | |||
| e7159adf59 | |||
| 51f08f2994 | |||
| a03eac8e48 | |||
| 503137221d | |||
| fb9205bf81 | |||
| bfbb313088 | |||
| 25d3c4b843 | |||
| 371c06d66d | |||
| 3e5c978719 | |||
| 843f1a6356 | |||
| a5c5faa21d | |||
| 6a1e17c6fa | |||
| cd30f370b8 | |||
| 4ae8abe6a3 | |||
| 82bfd4ee40 | |||
| e08c4cff13 | |||
| 6e16eab6ec | |||
| 21c47514da | |||
| d6de2ca71c | |||
| 451a0d9090 | |||
| 262354f733 | |||
| 498370330d | |||
| 6865853776 | |||
| 1418c0dbbc | |||
| bbc79dd49f | |||
| 8036320d94 | |||
| c30f69d6e9 | |||
| 2e2f34f241 | |||
| cbbeef5c46 | |||
| 823ee54f22 | |||
| 3d03797e53 | |||
| 089e60fa1e | |||
| baf8e4784b | |||
| d53350b263 | |||
| 824afdceca | |||
| a8230e976f | |||
| 6af7e6866c | |||
| aaa27333ba | |||
| 797f2a196b | |||
| 51066ff18f | |||
| 4de64a92cb | |||
| a21fd2ea18 | |||
| 0df0b4305d | |||
| a5ed53e7aa | |||
| 0587c5f5c4 | |||
| 57dbb18c4c | |||
| 4d92f08424 | |||
| 254ee07942 | |||
| 0bf8bd2230 | |||
| b5225f07cb | |||
| abed7690d0 | |||
| f96174ddbe | |||
| e5b713841a | |||
| 3b1b12069f | |||
| 1635f7351d | |||
| ce5ae411c1 | |||
| d1bc32fb31 | |||
| f9f87f25d4 | |||
| 89aa6b7881 | |||
| edf9e0c1ed | |||
| c2e520ad9d | |||
| 7649187095 | |||
| fe39d0fd10 | |||
| 98b83b7208 | |||
| 57321979ae | |||
| e3ce0c5887 | |||
| 95af72c70c | |||
| 3b37769624 | |||
| d150df1c5c | |||
| a322e27e05 | |||
| 98fe0badbe | |||
| 44b841a25d | |||
| 9c8bf820de | |||
| 4d9aa65e78 | |||
| 0f3942558f | |||
| ba074b0116 | |||
| 6aa97048df | |||
| d9a5c79ea6 | |||
| 9d7714c714 | |||
| 8291be375a | |||
| 0a73737f69 | |||
| 2fd1b6c913 | |||
| ea38a1d880 | |||
| f576e13c51 | |||
| ee7bb8731a | |||
| da0c3ff394 | |||
| 6ae559b42b | |||
| 95ca6ebdaa | |||
| 0d6964d9c8 | |||
| ba386d4b2c | |||
| b5ffb51e18 | |||
| a9f674497a | |||
| 1e8a92ccb4 | |||
| b9178bb8c7 | |||
| 520b29d0d5 | |||
| fe397e6953 | |||
| dcb741d827 | |||
| 508c205d35 | |||
| d5294bb5d0 | |||
| 6ed9be31ca | |||
| 3bbd3a8a65 | |||
| 73a608895a | |||
| 96c73baeb3 | |||
| 73113f5eb8 | |||
| 7b74b86891 | |||
| 0903b8227f | |||
| fa525ad610 | |||
| 0f2bb5dde5 | |||
| 84dc1b6845 | |||
| 4ce1a37772 | |||
| 8dd4cc5c40 | |||
| 6aed145dae | |||
| d15cc77b0b | |||
| 24a75d37fb | |||
| 7e80dae59b | |||
| 7316c48e9f | |||
| c520c7a24a | |||
| 7564633045 | |||
| 7174c5d036 | |||
| ddd128ce0e | |||
| f5aa5c0769 | |||
| 2acde49f0f | |||
| 8849015bbf | |||
| 70cd7a94ec | |||
| 3984dea34b | |||
| b11b471aa4 | |||
| 63754df4d4 | |||
| e644424508 | |||
| 4f6eef3d16 | |||
| e2e8104864 | |||
| 96127c289c | |||
| cfed65f7ea | |||
| c2263fec9b | |||
| 497720d060 | |||
| 238366e71f | |||
| 2c8cf26e74 | |||
| c87ae5612a | |||
| a2d83753bc | |||
| eedf75d951 | |||
| 3f51a1ae2e | |||
| a000f80705 | |||
| 7030bff7f7 | |||
| bb0b7fd2d1 | |||
| 71e1f3679e | |||
| b33517b099 | |||
| f3d5336892 | |||
| d81f25d54e | |||
| 44ebdfeb2d | |||
| a5a7a03fa0 | |||
| 363d2145bd | |||
| c7e19396a4 | |||
| 445e5bed49 | |||
| 4cf94319df | |||
| 1bb88b374e | |||
| 35fac07581 | |||
| 9287475b2a | |||
| b4976f89f2 | |||
| 93c8674a40 | |||
| d5f21fd13a | |||
| 04eef0463a | |||
| 82c3bc7b0e | |||
| 1d33cb96f5 | |||
| 648646068c | |||
| f251f93a11 | |||
| aab1aad8f4 | |||
| 65a6dc704e | |||
| 6018fcf490 | |||
| 1e6888c0d3 | |||
| c7303be33b | |||
| d8acf76f2d | |||
| 08248e3853 | |||
| 78acc6f215 | |||
| a4f1dc536d | |||
| 57a30dd375 | |||
| 5517ee334f | |||
| 30af544919 | |||
| f0069d3dcc | |||
| 206bdff9e7 | |||
| c32270b2b8 | |||
| cc03402570 | |||
| 21a76f1867 | |||
| 212ad94c90 | |||
| 378d9f4112 | |||
| e341d367d8 | |||
| 98937b187f | |||
| 59168e21b4 | |||
| d12a95b4ef | |||
| 83482afa02 | |||
| e470d1ae1c | |||
| e504128587 | |||
| 1ab6c07bad | |||
| 5ce465ce23 | |||
| a8b730576f | |||
| b796033473 | |||
| d078ed67ca | |||
| 346146d834 | |||
| 64307ea882 | |||
| 578eda7d28 | |||
| 505f4cb4a2 | |||
| bac6b729bf | |||
| d3a5cadb6c | |||
| 65351faf83 | |||
| 3aa1c5f13c | |||
| 8f3fe410b8 | |||
| ff3bf32b11 | |||
| 38cb01a30e | |||
| b8f7569e93 | |||
| cf17bd38eb | |||
| 930f6df2cb | |||
| e88106e990 | |||
| 21f64c75eb | |||
| 5186b9490d | |||
| e9e935303c | |||
| a154d71841 | |||
| fddb035539 | |||
| 1544a08ea2 | |||
| 8d68d4c050 | |||
| 62a1290043 | |||
| c5e1742150 | |||
| 754bc2d274 | |||
| 3ac061c546 | |||
| e59a7926a2 | |||
| be5b49e391 | |||
| 7b32d3184c | |||
| d770c35245 | |||
| e04baef3bb | |||
| 9d3ad22bc7 | |||
| cc35d15b2d | |||
| 15e3928906 | |||
| 4363fd64c4 | |||
| dac2f93383 | |||
| 82372bb2ab | |||
| b0c67c9019 | |||
| d83a34f72b | |||
| a16f156203 | |||
| 807aa71a7c | |||
| 14d9b67b58 | |||
| 82df0ca766 | |||
| a6c7529a4e | |||
| 202bb6d3e2 | |||
| bc514926bf | |||
| 9fc16b6a83 | |||
| 2125e0175d | |||
| 6b5982d389 | |||
| a4a8aa63d4 | |||
| bedf451952 | |||
| 93b8f1993c | |||
| c693f4806b | |||
| b07275694a | |||
| 82177c101b | |||
| da6dbd2159 | |||
| b3957d87b4 | |||
| 5f9ccadd6c | |||
| 6e04da9f8f | |||
| 58c13d2c07 | |||
| bca8593eef | |||
| 3e2e10a4c3 | |||
| 6979763292 | |||
| 324f1739e4 | |||
| 1489662f57 | |||
| 1c1f407f67 | |||
| 8fb631417b | |||
| ae45ad1ad2 | |||
| 6b89803534 | |||
| d01b34f501 | |||
| fcad2fa471 | |||
| 589767fe6d | |||
| d6407e5095 | |||
| 8ff8dc7200 | |||
| 2f7b02c96f | |||
| 669e2a767a | |||
| 2b4f9feeab | |||
| 1554916639 | |||
| 32a3651231 | |||
| dbd4ecf89b | |||
| 7416653874 | |||
| 621ed970da | |||
| 457ba9ac62 | |||
| f9da5f2c80 | |||
| b6a793a1e2 | |||
| bf2ab3d8af | |||
| 02f75236cb | |||
| 5dff83c6e9 | |||
| 43725bae89 | |||
| 59c12506cf | |||
| be15a3b739 | |||
| 9f515dad09 | |||
| 5052c4ae3a | |||
| 9a617f5d41 | |||
| 4886d46d91 | |||
| 67834def5f | |||
| c51ffeb65a | |||
| 68ee4eab61 | |||
| fa6d4ac0bc | |||
| 3fa533d91e | |||
| c0db144906 | |||
| ea2ec168b0 | |||
| cb18c1a54d | |||
| 45bcb22270 | |||
| 2539fd53dc | |||
| 8a2bd09fd0 | |||
| def89ac079 | |||
| fe08726387 | |||
| 9bb4a68599 | |||
| 996a27dbd1 | |||
| 58ebadd7b3 | |||
| cae06ba2c1 | |||
| 0274afa0f7 | |||
| 221f70ac7b | |||
| d3dbca374d | |||
| 6f0b6a8158 | |||
| b25cd6aaf2 | |||
| d27025003a | |||
| 66eb90d9d0 | |||
| 6a81a9d191 | |||
| 64cb134113 | |||
| 891ff7dd80 | |||
| 6643e7f499 | |||
| fcbf527ba5 | |||
| dfd180a292 | |||
| fa0a5040e5 | |||
| 56ba2cb251 | |||
| dea12779cf | |||
| 6033c05ff0 | |||
| 407da8bd15 | |||
| 43413ff980 | |||
| 4d864b8267 | |||
| a516245c94 | |||
| b1ed268d0e | |||
| 83b86bf092 | |||
| 954caa6804 | |||
| 8b6da4d2fe | |||
| f2d70d972d | |||
| b20de76037 | |||
| a33bd9dfe6 | |||
| f2443c64db | |||
| 278ec04f5e | |||
| 95787255a1 | |||
| eaf9993dd9 | |||
| 470d7600b8 | |||
| 849baea544 | |||
| 4f1ca20dda | |||
| 97401ad99a | |||
| 59f5e364c1 | |||
| 29c2a117c0 | |||
| c209e31ce1 | |||
| 12608889e2 | |||
| 3343882876 | |||
| 6e50b5fc60 | |||
| c540c85cf8 | |||
| b17491ebe5 | |||
| 76b410b2ca | |||
| 069388eae0 | |||
| c6c25e609b | |||
| 9b52dd8bf7 | |||
| 2cf19010e3 | |||
| 89d56e1cd1 | |||
| ef1fb08723 | |||
| e60ebee3f2 | |||
| 4c88fe0fb1 | |||
| 13338414db | |||
| 96f49f3b53 | |||
| 75979d7e1c | |||
| 29a2447906 | |||
| 2f702f61a4 | |||
| 5a71acbe3c | |||
| ca3e8ef09e | |||
| 8c44084af1 | |||
| d829a390fd | |||
| 6b6597e453 | |||
| 97c550d5f6 | |||
| acfd6ab141 | |||
| 7e790c1aa6 | |||
| d1e2aa57a8 | |||
| 2e6e3bf0b0 | |||
| e5025665fc | |||
| 1a8097f810 | |||
| f45daad6ca | |||
| e4e85e6f7e | |||
| 5beaf695ed | |||
| d09827b501 | |||
| 97722adbfa | |||
| 006a8833d3 | |||
| 8111baa8f9 | |||
| d6e4dc0aa2 | |||
| 497da1d29b | |||
| cbc8b64854 | |||
| c06f2a50f1 | |||
| 825a422721 | |||
| 2c4ba90abb | |||
| 6dda899a60 | |||
| 8725e2f40d | |||
| 35c501c203 | |||
| 30a9bc3179 | |||
| f9350a276c | |||
| cd9addf0e2 | |||
| 2219b6507c | |||
| 09931d7ad8 | |||
| 7ce0c0ef9a | |||
| 49e2cb6c36 | |||
| 4b60fc4747 | |||
| 164fb09f2c | |||
| 5647e6c199 | |||
| a4d6544764 | |||
| e942f6e420 | |||
| 7174baa91e | |||
| 5c8b7542d0 | |||
| e8035ced5a | |||
| 70a086a9e1 | |||
| 08cb6d1f63 | |||
| c7f3645fe2 | |||
| 4b6a85aae0 | |||
| c8a8859d2f | |||
| 8c0f47f06c | |||
| 926290dd9c | |||
| 6ae3315bb9 | |||
| 8621b1890e | |||
| c726001a0e | |||
| eba5f7d275 | |||
| 2f793473cc | |||
| 91567cad9e | |||
| d48ee84ae7 | |||
| fd000cad86 | |||
| 6244063073 | |||
| f34de8422e | |||
| a33edd15b4 | |||
| 6a65261765 | |||
| 07f3e2d457 | |||
| 958199ffef | |||
| e5ebf74d76 | |||
| 126d2f85ac | |||
| 908e3a2af6 | |||
| 25e40d723a | |||
| 7a764ce78b | |||
| 8947c789a9 | |||
| 8ac403abb9 | |||
| 9752cb8e4d | |||
| e9be9dd8d0 | |||
| 5e6d638c6f | |||
| c47f6e2ca5 | |||
| cc09df1961 | |||
| db26d2b2d7 | |||
| 5b33efeecc | |||
| fda4656630 | |||
| 5829bbe22d | |||
| f4cfde719d | |||
| 1fd66f55c1 | |||
| a964bec0f8 | |||
| b65ba5c394 | |||
| d51eefa1c4 | |||
| 4025cbd555 | |||
| 3da27c06c3 | |||
| bc7824812b | |||
| baf7822340 | |||
| 82ee08fcaf | |||
| 51d153a5f7 | |||
| df608e8b43 | |||
| 8e477437a6 | |||
| e70f0eea02 | |||
| 8be93a0202 | |||
| d4f7f19a22 | |||
| 4441381042 | |||
| 61c9c69718 | |||
| 5beaab97da | |||
| 843a4b8eae | |||
| 9ec46222e3 | |||
| 210da11fbb | |||
| ee61ae360d | |||
| 890e0f4995 | |||
| 224c66e0dc | |||
| 88052cd194 | |||
| c22453f24a | |||
| 099a805260 | |||
| 7ed474af8d | |||
| 9d893d6d4d | |||
| e55af0c274 | |||
| 803fbf2541 | |||
| 061b2b63e9 | |||
| 1486098065 | |||
| 0f0db4c823 | |||
| c3e7e96dce | |||
| 3c5f6bd8ac | |||
| b6b59e5c08 | |||
| a7aa27c87c | |||
| 735b325d74 | |||
| f948380fa2 | |||
| 79cf1880fc | |||
| ca130e1dc4 | |||
| d67ce81438 | |||
| ec1a84c57a | |||
| 59163cb2fc | |||
| 419cf9e2b0 | |||
| 95c78eac9c | |||
| 51a4cf5e46 | |||
| 2472c5d6a1 | |||
| 59fbb289b9 | |||
| e82bc20422 | |||
| 1e753e98ce | |||
| 39b3cab1da | |||
| 87fbfc6475 | |||
| cb8bfa027e | |||
| 1b1274fd56 | |||
| 38db495879 | |||
| a781c36876 | |||
| 71c336d9dd | |||
| e10e8910f3 | |||
| 253496c7ee | |||
| 30a3ab68c0 | |||
| 663a7c52c7 | |||
| 4e8ccd6f7d | |||
| 879ccfc8c2 | |||
| a77574b3d7 | |||
| 50738f8ce0 | |||
| 5c01878542 | |||
| ea93f6f560 | |||
| 7bab34eeda | |||
| 0cc23dec6f | |||
| 71c0d5253d | |||
| a674028c37 | |||
| 29fff4f51b | |||
| 4309ccfa02 | |||
| 4e8fe89faa | |||
| 8218d5a47e | |||
| 4bbb587280 | |||
| 0f04fe75bd | |||
| 11b356e55f | |||
| 80f008684d | |||
| c9c2d8133c | |||
| ac9a4d1e0d | |||
| d7dd6acd9d | |||
| b5739cb3d8 | |||
| ea93d56ca8 | |||
| 10097a946f | |||
| c439594403 | |||
| 29cf9e05db | |||
| 298f68c966 | |||
| 0b3289ea37 | |||
| 5f457bff12 | |||
| 6c00ccca9a | |||
| 7e679ab252 | |||
| 0ca21dbc91 | |||
| d2590f1078 | |||
| eb3f550e26 | |||
| 06aa6dedab | |||
| f769478abe | |||
| ba5f0af5a4 | |||
| 5e5f72ae57 | |||
| f36037ebf2 | |||
| 0c276ac71e | |||
| 9e95d1f1fd | |||
| e00bda37a5 | |||
| e7ea5f500d | |||
| a8fc95d4e4 | |||
| 3f598a5121 | |||
| 81c5ec0777 | |||
| 32bb58b272 | |||
| aa4b786ab3 | |||
| 3f5968b60c | |||
| 251eeb534a | |||
| 90add9f840 | |||
| 770624d492 | |||
| c59758ef65 | |||
| 15752335f4 | |||
| 3e4b48e206 | |||
| 25c685527a | |||
| fbabd137c2 | |||
| 6e7cf68164 | |||
| b47a532eb4 | |||
| 7c30ea32bf | |||
| bb06e044f5 | |||
| 01318a08b4 | |||
| 119487f1aa | |||
| 911427a361 | |||
| 58628a4bfc | |||
| b08b360f38 | |||
| adb8d0e845 | |||
| e0f009b3b9 | |||
| f1aa03c360 | |||
| 2ba417cf9f | |||
| d8af074ff6 | |||
| daf2bbf991 | |||
| 6605f293b4 | |||
| 482e18ccdb | |||
| ef1e0e14ec | |||
| 33f083b213 | |||
| bcfbc0cf6c | |||
| 00d75ece64 | |||
| dc1b5d3424 | |||
| 58fb633df3 | |||
| 36f9366f3f | |||
| 712f1ca02a | |||
| 285b238f26 | |||
| 70fb12b10e | |||
| 6380a6be05 | |||
| 548fd92c15 | |||
| 86de53eb9a | |||
| e1616953db | |||
| c1dbab50fe | |||
| b6bb6a92a9 | |||
| 0ab80ad0a7 | |||
| 61744764da | |||
| 8eb98982f3 | |||
| 1090339331 | |||
| 804816f014 | |||
| 51e8318224 | |||
| 0d38a50dba | |||
| 72094acf74 | |||
| 1bd67943bb | |||
| 30101e129f | |||
| 9bb31678a6 | |||
| 5e5c52ff0a | |||
| d9d4742130 | |||
| 0fab6b7cab | |||
| f10286de8c | |||
| a0e0465704 | |||
| c8457a2619 | |||
| 14c36bc405 | |||
| 81319228bd | |||
| fcd7b05900 | |||
| 8378d95588 | |||
| b34f9b1795 | |||
| 35b098e656 | |||
| e05a45b080 | |||
| 715ee66b03 | |||
| 3d6e9da115 | |||
| 54410988eb | |||
| dded2c2463 | |||
| fcf5838019 | |||
| beafa18708 | |||
| bd371a11ad | |||
| 1895fee1c9 | |||
| 2200d0b678 | |||
| f3c4a7dd16 | |||
| 25834b89dd | |||
| 4d20dea271 | |||
| c59647ad2f | |||
| e466cbe0ce | |||
| a24de2d22a | |||
| f452a3025d | |||
| 3c58eaf49f | |||
| c75b497b2e | |||
| d572d77b48 | |||
| a4074332cc | |||
| c31ceb6a5b | |||
| b0863d8628 | |||
| c38a6d74dd | |||
| 7bec75b709 | |||
| 56ea24b03b | |||
| 277829c280 | |||
| c127aaae6b | |||
| c895848061 | |||
| 64e5ebb55f | |||
| 83addd6bba | |||
| d87a19b2f9 | |||
| b58edc980c | |||
| f3e72623e9 | |||
| 54ee76bcef | |||
| efe6faabfd | |||
| 3ee8b655ea | |||
| c70d138eb9 | |||
| af2a327310 | |||
| b27e0e2807 | |||
| 8267ed53f0 | |||
| aa90d7b4b7 | |||
| 6b69946b9e | |||
| a1b87b5236 | |||
| 3044c5ea52 | |||
| d0636a9f6d | |||
| 0d291cb68e | |||
| c8bb50497b | |||
| ea027a7cc1 | |||
| 62e8601919 | |||
| be2cc7aed9 | |||
| 17babb22e2 | |||
| 21245273b4 | |||
| 8d7821c84e | |||
| c78dff9a15 | |||
| 25fea558ba | |||
| b1c84b598f | |||
| a6aa0a4cb0 | |||
| 8640129835 | |||
| 655dd2277c | |||
| 40f95191a0 | |||
| a013da860e | |||
| 4150c804df | |||
| 0446847278 | |||
| 2cf8309987 | |||
| 5b30f92677 | |||
| 88fac0ad2b | |||
| 45a9a6c4df | |||
| af554e7ed0 | |||
| 8912928581 | |||
| c2e49bd152 | |||
| ac0279aa83 | |||
| ae4161b780 | |||
| adc3bacea9 | |||
| e125f3a897 | |||
| f86b5a44bc | |||
| 0c5899b2a2 | |||
| a7d83b701f | |||
| d0b591307a | |||
| 13378a4b55 | |||
| ac6218eef2 | |||
| a98cc51ac2 | |||
| 92a06c9a28 | |||
| e595bdb20a | |||
| 9bd2446901 | |||
| 27babfec3d | |||
| 017ff53702 | |||
| 49441fe204 | |||
| 03d360b7bf | |||
| 53542abbb7 | |||
| fc908d4687 | |||
| e90b1bbead | |||
| ce1ca1b625 | |||
| 0eaa393065 | |||
| 6d749777fc | |||
| 6c20a4a874 | |||
| 79e8d1aac3 | |||
| becae46296 | |||
| 2ce553d661 | |||
| 66cadac6b6 | |||
| c237c5353b | |||
| c27a7e087f | |||
| 0894590a96 | |||
| 2efef91f1c | |||
| 3feba9a581 | |||
| afae896d05 | |||
| bcbaa21739 | |||
| d60bc61d13 | |||
| aeee565115 | |||
| 8126793b18 | |||
| 6a2592421c | |||
| 36adeec220 | |||
| 22bf0ead18 | |||
| b9dd6369d4 | |||
| 3d6c0ac512 | |||
| 95bf81f528 | |||
| 56e35e8ef2 | |||
| ae802a8a83 | |||
| ee71d2fe5f | |||
| 8dd2447cc5 | |||
| 3869ab6345 | |||
| 26453af1b9 | |||
| 5dc7b79bb6 | |||
| 33403efc8e | |||
| a0b4fcc05a | |||
| 82f7ab2ba5 | |||
| 505833a534 | |||
| 2557fb4f4d | |||
| 8511256779 | |||
| ae85d86d8f | |||
| 042740877c | |||
| b787b993b6 | |||
| 51ae14ec23 | |||
| 152f739527 | |||
| da88cb6a43 | |||
| 52a8bb414c | |||
| a27902205b | |||
| 7fb5b9886e | |||
| 8feb300d15 | |||
| 085bab749f | |||
| 96a5e594b3 | |||
| 04765d82ba | |||
| 47a9981571 | |||
| 0b45678ccc | |||
| 19ac465fa4 | |||
| 69bc8a8b22 | |||
| d0644bace9 | |||
| aae02cd1be | |||
| 47d56676f1 | |||
| efbaaf2f84 | |||
| d38575a011 | |||
| 908a9e9fa1 | |||
| 0ebabfad73 | |||
| 6ac3d902c9 | |||
| 3beb8c825b | |||
| b80e96547e | |||
| 2679c1cf0a | |||
| 65183e94c6 | |||
| 6b0fe683c9 | |||
| f14352f494 | |||
| ab9426e260 | |||
| 27fe85ac8b | |||
| eb6f01e65a | |||
| a6d406d2c3 | |||
| 4b8c0ac143 | |||
| c9f0158fdb | |||
| aac21f932b | |||
| ec01c2a119 | |||
| fbef77a942 | |||
| f207d988f4 | |||
| 60fc486cea | |||
| 978b70c998 | |||
| ef171f3acd | |||
| 64b36807d3 | |||
| 5de8f1803c | |||
| d1c4a26791 | |||
| a647cb9836 | |||
| 7398bed974 | |||
| 6077708831 | |||
| 6eebb1c089 | |||
| 6cd55e535c | |||
| 7d0955c0f4 | |||
| 8c9d24bd9f | |||
| c40375a424 | |||
| 2949a52a11 | |||
| 2e762d05f9 | |||
| bb06bfbbd7 | |||
| b8d20dfe99 | |||
| fa8529949b | |||
| 7b37c847bd | |||
| 3075f6cea7 | |||
| ff966490bb | |||
| 46993b43fe | |||
| 5e15bceaae | |||
| fefe5e241a | |||
| 8804330d83 | |||
| f5c12ec433 | |||
| 262cdd7bc0 | |||
| efee07e20b | |||
| 603b83e1c3 | |||
| a48f02e0da | |||
| d189339495 | |||
| 0802804677 | |||
| d9c281cd7c | |||
| 46185fe9e8 | |||
| 38e8a90f4e | |||
| 7a115e93c0 | |||
| d391df52ba | |||
| 46fc6f8da4 | |||
| 0fcca04150 | |||
| 54a9173107 | |||
| bf455c8d20 | |||
| c05d23a586 | |||
| 2a882aa58d | |||
| 04e26ba6b8 | |||
| 2211731c80 | |||
| 0fbdd57835 | |||
| 312b414d8f | |||
| a6e7954128 | |||
| 1417d43430 | |||
| 60ef6070b0 | |||
| 2f42196fca | |||
| f8b5e7e2c9 | |||
| 2c0547bb0e | |||
| 0f9eec887f | |||
| 234cf2d847 | |||
| 9304ad125c | |||
| 752c15c230 | |||
| 4f792c40b7 | |||
| 0245184c18 | |||
| 7ddf0226c6 | |||
| 17c3c1d66a | |||
| 40a3008318 | |||
| b48022be22 | |||
| 502aedb33e | |||
| 17f8e65808 | |||
| 439eb9da3d | |||
| f6116db957 | |||
| b36145e3c4 | |||
| 1c1bfd7541 | |||
| c824429458 | |||
| 238e77d959 | |||
| 23b2154d98 | |||
| 25c8711aad | |||
| cf30628d4e | |||
| e21eaa4b9e | |||
| 80b897d8cf | |||
| 1ed7bcfb2c | |||
| e20f92bbbb | |||
| 6e717bfd30 | |||
| 5d743bb0a3 | |||
| 7675c730b6 | |||
| 42942bb1e0 | |||
| 9d12de9bce | |||
| 790520e335 | |||
| 4b0e1a4b19 | |||
| a877f8abf0 | |||
| 491b1d9c96 | |||
| 2ce74c05e1 | |||
| 88e6558da3 | |||
| f1140ec903 | |||
| 8a745ecdfd | |||
| b8e29f5ae3 | |||
| 22e83013e3 | |||
| cc4713d878 | |||
| 490e838c60 | |||
| 6b15f29d7c | |||
| e7d9e42a16 | |||
| bd91727f49 | |||
| 328faf3744 | |||
| 1157cb9b95 | |||
| 7c8626d144 | |||
| 03faf2665b | |||
| 9959fd26bb | |||
| 43dcdb21ec | |||
| 3727637145 | |||
| 466251287f | |||
| f46706843b | |||
| c93ca02fb8 | |||
| 4813488f84 | |||
| fc292cc2d8 | |||
| f875e26fbf | |||
| 05658aeb3b | |||
| a14cb1fc06 | |||
| f68247673a | |||
| f65dd63210 | |||
| 03f64a6c20 | |||
| 0627c3443d | |||
| c65dd16460 | |||
| c590596dbe | |||
| 23cd4d5ed2 | |||
| 4dc6ff9fb8 | |||
| 8638cbf8b2 | |||
| a2555983e6 | |||
| 21804aecdb | |||
| 6991a38703 | |||
| 6b18e4f7e9 | |||
| efc9007cbf | |||
| efd33b295a | |||
| fa4ba42f15 | |||
| d3ef520915 | |||
| 811e29ff1b | |||
| 95d1efb7f8 | |||
| 5341cb5ff9 | |||
| cb37c0d135 | |||
| 73d40ce02a | |||
| c1709da6bf | |||
| dcfa81f983 | |||
| 42b1eaa240 | |||
| 1da1fa5a31 | |||
| 707931125e | |||
| f4e82a879b | |||
| 4f7369ed02 | |||
| 4312013552 | |||
| e8bc69aa01 | |||
| befb667759 | |||
| b35254ec78 | |||
| 9956988938 | |||
| 5b0e2e487a | |||
| ccd3872bf1 | |||
| b209952ce0 | |||
| 3568de2c6c | |||
| a8957d75b9 | |||
| 028ca5c9d9 | |||
| d516e1c736 | |||
| afdf8e7b21 | |||
| 9852b147f8 | |||
| 552cdbfe20 | |||
| 4ca29dd18e | |||
| 0d971a70cc | |||
| 0dda98384b | |||
| 685d330ee2 | |||
| 2d455018ae | |||
| fce486735b | |||
| 45073ce9eb | |||
| 4ba732c886 | |||
| a6cb786718 | |||
| 93a2e66704 | |||
| facbe2c012 | |||
| 02a49c8a68 | |||
| 97585bb26a | |||
| b618a1241f | |||
| d936009ea1 | |||
| 078f71c144 | |||
| bfc6c9b89d | |||
| 758d402305 | |||
| e6789fab6c | |||
| a2e114e852 | |||
| 0baf90a218 | |||
| f9f3d43152 | |||
| 326f2d2743 | |||
| 57f257dce5 | |||
| c27fc4e4d8 | |||
| a37192c102 | |||
| 68bd6a29b6 | |||
| da11113bf1 | |||
| 70f4cdd0ca | |||
| 78ac3cffde | |||
| 7eb2af6cd3 | |||
| 0b1c9d33a5 | |||
| 648a62112e | |||
| ff7cb91d9c | |||
| fd5881670d | |||
| fc8768b79b | |||
| 914570b053 | |||
| 1a8783cfa0 | |||
| 28bfefcac6 | |||
| bec56522e3 | |||
| 0ddd473477 | |||
| 2defc8e826 | |||
| c3756f6b58 | |||
| 66af3d260c | |||
| 5c3398c280 | |||
| 63a59325f5 | |||
| f1091f97fc | |||
| fe9bdfef79 | |||
| a8f11981e3 | |||
| 94651744af | |||
| 24e7d00af5 | |||
| f85a35b5fc | |||
| a27aad0061 | |||
| 9a332d2f86 | |||
| 1264983688 | |||
| 4d4a3d02ed | |||
| 53cee90933 | |||
| 6daa3290d4 | |||
| 5a9bee0527 | |||
| 6914d26187 | |||
| 68c01d09bb | |||
| 4bf1ad2566 | |||
| 00ed526fb0 | |||
| 9bdc58069b | |||
| 4ddbd2efb6 | |||
| f3f153cb38 | |||
| 9414a8085d | |||
| 33b18df1a0 | |||
| da91d342f7 | |||
| 4950e044ba | |||
| b41af5f580 | |||
| 24090d4642 | |||
| cdb1918973 | |||
| a8e8f04fa3 | |||
| 4ec3102df2 | |||
| 7e722db3ee | |||
| 20c45be3b3 | |||
| f2ee0aad20 | |||
| 478d4a571a | |||
| 4253ebf243 | |||
| 5b782a783a | |||
| c38183423f | |||
| 019e26dd8e | |||
| 6d2a65b4ea | |||
| 4206d98b55 | |||
| 9005fe2f61 | |||
| f87f18a291 | |||
| c0fdcb381a | |||
| aeaf0e7ba8 | |||
| 6dada4e347 | |||
| 61f015eef6 | |||
| d843521839 | |||
| 420369fe13 | |||
| 71bf1edc5e | |||
| d06ac519ab | |||
| 50512b52e1 | |||
| 543e77b9be | |||
| 783d455bd7 | |||
| 6c35272fe2 | |||
| 6955978a62 | |||
| 27d87dff79 | |||
| d8ca58a04e | |||
| ce34798685 | |||
| 16fd5249dd | |||
| b9a4c322a7 | |||
| 673bf356e4 | |||
| 6228412e61 | |||
| 578d947e2d | |||
| 72629d0081 | |||
| d7989f19cf | |||
| 8b11cdbf61 | |||
| 5c1f76e3cf | |||
| 63ba6018f3 | |||
| 8f3482561b | |||
| 13ceeb191c | |||
| 1536d1c044 | |||
| 16b6c26d6e | |||
| c7e30e2266 | |||
| d5e4495f89 | |||
| 963960a44c | |||
| a62c10321c | |||
| bb49e03435 | |||
| 38e7b1a262 | |||
| a00d3dfc00 | |||
| cd458e7a44 | |||
| 3f82570469 | |||
| a8642bd208 | |||
| b404c79ca4 | |||
| 29c75337f2 | |||
| fca4aeb50b | |||
| 1dfa2d6e91 | |||
| 79650ca3fd | |||
| fd84827e51 | |||
| 78283a0e0e | |||
| 993321e971 | |||
| f7a1e2f652 | |||
| e75be68466 | |||
| 74ac283c52 | |||
| 9ef1f8cba3 | |||
| e45656e5bf | |||
| cdc4fb45f2 | |||
| 5379a555db | |||
| d07c0bde80 | |||
| 7015ed203a | |||
| 1ead4cbb14 | |||
| 84ebca0dd2 | |||
| cf45b2cddb | |||
| 8f8bd05f83 | |||
| b1155a202c | |||
| d4aaaf16f8 | |||
| 119fb63576 | |||
| 3f7afd47d2 | |||
| ca0f8ed653 | |||
| 809bdb7c1f | |||
| 0424ff0818 | |||
| 9b952ff48c | |||
| c5064710a8 | |||
| 57e522065a | |||
| 7143daf500 | |||
| 71a00fc01b | |||
| 941483c14d | |||
| 17d8e65c64 | |||
| 72c0feb048 | |||
| 9e20dbe226 | |||
| 06f2738c03 | |||
| 5a257416ca | |||
| f9f0ffb64d | |||
| 31cf8a8813 | |||
| 98b7e0a407 | |||
| 7ed63d2ab5 | |||
| 6e6b38e8e9 | |||
| 829b9d96e4 | |||
| 85cef7e37c | |||
| c526bec798 | |||
| 9231335eef | |||
| dfac34beac | |||
| 82dd5d8ccf | |||
| be506f7121 | |||
| 2470494009 | |||
| f95a4b9b46 | |||
| 6b444a0877 | |||
| 5c4a845b55 | |||
| 468c01056f | |||
| 397078758e | |||
| c9af06c9e0 | |||
| 5a7e663b1d | |||
| e0550cd20b | |||
| 5844231a37 | |||
| 8d435638e1 | |||
| 55cad1b3ac | |||
| 9deadc1371 | |||
| 998abf05ba | |||
| aab5092da3 | |||
| 65ee5c4bbb | |||
| 42ab938a19 | |||
| 2891de2fcd | |||
| ed3758874d | |||
| 895d8179a2 | |||
| 8f6fc0146b | |||
| e1ac1c4fdc | |||
| a6b44a1470 | |||
| e8834a68f3 | |||
| 6ad1cd3fb5 | |||
| 3279cbac24 | |||
| 5094bad838 | |||
| 94af9b7f13 | |||
| 8e02263084 | |||
| fe0fe1873a | |||
| de29574314 | |||
| 5ac024788e | |||
| a1e273e983 | |||
| a95bf64ccf | |||
| 4fa9022932 | |||
| f10fb77a81 | |||
| db092c828e | |||
| bed0598530 | |||
| b734d4bbc1 | |||
| d2080808db | |||
| 345d5e8d9e | |||
| bcc41bf3d1 | |||
| b2d444d782 | |||
| bac6703f8e | |||
| 6cbbd1e5a1 | |||
| b6ef558c86 | |||
| 70bb082973 | |||
| 8b8a19c75d | |||
| 0b53242564 | |||
| f11bd509b0 | |||
| 57608628a4 | |||
| f167c3e12e | |||
| 262b380280 | |||
| ee0c20ae44 | |||
| c30c144120 | |||
| a5ee82b0d1 | |||
| a4f558181d | |||
| 120303e6e3 | |||
| b3822d5802 | |||
| 980e4ee89a | |||
| bb1428eeb1 | |||
| f6a90e9b42 | |||
| a71159667d | |||
| 74e00cf652 | |||
| e773a80b06 | |||
| e6eea67eeb | |||
| 8429a1e792 | |||
| 47fbd2a2b5 | |||
| 93835b9b94 | |||
| 2de3fc9f6f | |||
| 78a8cf6982 | |||
| 99cf3219d4 | |||
| 7587e97d46 | |||
| 3061c8b854 | |||
| 77e9e95067 | |||
| 6191b6bee2 | |||
| b15f8f68e4 | |||
| 84c12793e8 | |||
| 6eeadddd4d | |||
| a40b3a98dc | |||
| f0d66ff0fb | |||
| d3ebd360b2 | |||
| ebbe1692c8 | |||
| ca7d406787 | |||
| a2dc8378f5 | |||
| b570e89dbd | |||
| 108f87678a | |||
| 00146ae87c | |||
| e3757fbbfa | |||
| ac64e8b15e | |||
| c39ca7189b | |||
| 03c8fdd30a | |||
| 788bc67faa | |||
| 048be2da2c | |||
| 8e1f70865e | |||
| 6143f1ff5b | |||
| db30836b53 | |||
| 3e8ef5e462 | |||
| 0a53dccd4c | |||
| 2b5aa142fb | |||
| 40443d1e25 | |||
| cb4e7614ee | |||
| 3d84dbc73f | |||
| beb2ab9ad5 | |||
| 9a0877379c | |||
| bbd0239ece | |||
| 92956f2b45 | |||
| 48d1a5ec5d | |||
| 2ff2ce460c | |||
| 7cc875b8db | |||
| 9387f583fa | |||
| 707dd700b0 | |||
| ddff9b612f | |||
| 338ac5d4a3 | |||
| ca7abd727a | |||
| 62b20769ee | |||
| 4ec323c5cc | |||
| 84e72ede72 | |||
| bd37c48596 | |||
| e30f0e8e11 | |||
| c43a2513a8 | |||
| 4b4bc0dde2 | |||
| 49adf2192a | |||
| a7eabeb73f | |||
| f838f3427b | |||
| 1cc75ca636 | |||
| d4356b0453 | |||
| 35542e5823 | |||
| c80c2233c5 | |||
| c2f0e4f683 | |||
| 2621f4a2fa | |||
| 3c055642d5 | |||
| 43b881d0cd | |||
| 8b7b32e225 | |||
| 00b0ff50f3 | |||
| 1acde593b5 | |||
| c43c043521 | |||
| b526cadebd | |||
| 94f44e1d5d | |||
| 0352d9c99e | |||
| 0cd3f37e1b | |||
| 486d7b6d62 | |||
| 8f4e332409 | |||
| f0389c0b2f | |||
| 922e8a4912 | |||
| 021a1c7a39 | |||
| 4a7451682b | |||
| faa880d60a | |||
| fd30e82836 | |||
| 3ef34fbb56 | |||
| 7345dc6861 | |||
| 9958937fd1 | |||
| f19c57200d | |||
| 8a2652f53d | |||
| dddde4ddab | |||
| 300d901618 | |||
| 1cb72acd27 | |||
| a17776cb5f | |||
| 94b749ab00 | |||
| 5fc0d284cb | |||
| bbe1211451 | |||
| ce152b205f | |||
| a5fd7cf4e9 | |||
| da38a1367a | |||
| 1445f11c19 | |||
| 86df55f5cc | |||
| cf294c938e | |||
| ebff45f803 | |||
| 7b8021a36e | |||
| 5c77bb7c67 | |||
| 8ade26b4a4 | |||
| bdbc60b4f7 | |||
| 373fa7a7d9 | |||
| eec4f173a7 | |||
| d726ce6340 | |||
| b406844c96 | |||
| 153d38f10c | |||
| dce917eb74 | |||
| eb711787ae | |||
| 9967dbbaa9 | |||
| 71dc10ebea | |||
| 782fba2ce7 | |||
| 4d73f98050 | |||
| 79d2083a00 | |||
| ee3b296a99 | |||
| 8b62d04453 | |||
| 9b0d3dfaeb | |||
| b1ef4cfee9 | |||
| f12f6a56ba | |||
| 2777d53a12 | |||
| aba3ec692f | |||
| b7c8fcd062 | |||
| 3065de63dd | |||
| a57fb4f1ab | |||
| c493a22765 | |||
| d85e5def5d | |||
| 0aba499c8e | |||
| 4146695f34 | |||
| 4e57e10ba8 | |||
| daa6d02887 | |||
| a87d89302f | |||
| 2a9b1311d3 | |||
| 7d73501b87 | |||
| 039d6acd3e | |||
| 405fcdc483 | |||
| f52abc1a62 | |||
| e763953562 | |||
| 4cab617c25 | |||
| 0190b5e5af | |||
| abc0952247 | |||
| 6ce2726a87 | |||
| 17a4463f59 | |||
| e76d8df246 | |||
| a46bcf45d5 | |||
| 1f985d04a2 | |||
| d64e6e6c1f | |||
| 1164a65df8 | |||
| d57f07d57e | |||
| 5c0a964321 | |||
| cf3b8d09d9 | |||
| 1c7397fb21 | |||
| 6a08d93e2c | |||
| 4c03ace9eb | |||
| 2cd616dd30 | |||
| eab87c0827 | |||
| 8b8188710e | |||
| fd9bb3ac43 | |||
| 6d9c3bca33 | |||
| dd33a45644 | |||
| 074c7a9c40 | |||
| de2f06970d | |||
| 6166d946f7 | |||
| c778ab9622 | |||
| aad846b968 | |||
| f04a3e3d2e | |||
| 7ad52de2b1 | |||
| 0706ba9bec | |||
| ed53888fce | |||
| fd76fba235 | |||
| 95088a785a | |||
| f46b600ec0 | |||
| 566ab993df | |||
| 407036e215 | |||
| 7b1a5566fb | |||
| 1b0d8739c1 | |||
| 266feea397 | |||
| c4c6ab2494 | |||
| 079eea3f2b | |||
| a457d69034 | |||
| d0175798bf | |||
| 80e07943ee | |||
| e2954211ec | |||
| 337bed8176 | |||
| 71197e1c89 | |||
| e1a13f5ce8 | |||
| 1ed2c16a51 | |||
| 12e1bd80b3 | |||
| fd6daa580a | |||
| d2a19ec8ec | |||
| 8f3feac916 | |||
| c0e066440c | |||
| fbb4e9078a | |||
| d96e90c6f4 | |||
| 3b435d8956 | |||
| 345dd2481b | |||
| 006bcc0fc8 | |||
| c25d14e454 | |||
| 5ff95dc32d | |||
| 34031aab1b | |||
| 3035219212 | |||
| 8a608eb930 | |||
| c2fc47df34 | |||
| d4065774ce | |||
| 6d43d9f2b6 | |||
| 94d7fd9112 | |||
| 04b5833e98 | |||
| 52592b84fd | |||
| f2cd68e3ec | |||
| aff590a44d | |||
| 0d432f6377 | |||
| 59bceee258 | |||
| 4a0a0bac1d | |||
| c7bd96ea8b | |||
| 0eb2106067 | |||
| c03aec364c | |||
| f2cdb97867 | |||
| 727e284ed0 | |||
| 3248977e02 | |||
| 7ee8776165 | |||
| f89f4bd20b | |||
| a372ade7ce | |||
| 61dca4a35e | |||
| c0402345f7 | |||
| 9cc68b26e2 | |||
| 27c9230a82 | |||
| e985c9714b | |||
| 6c5015811e | |||
| 86e7de4d62 | |||
| 147d35e40d | |||
| b76fc724fd | |||
| 1bfab4e279 | |||
| 11bdfba37e | |||
| 405f08b807 | |||
| 592211cecd | |||
| a4f31001e8 | |||
| c2deedac8b | |||
| 9a61f8b894 | |||
| 3a291f5c8e | |||
| 559a2dcec7 | |||
| b7f003c4aa | |||
| d11c0bbd5c | |||
| c2f775fcaa | |||
| 19ac831c2e | |||
| 23b413a398 | |||
| 098de196e2 | |||
| 27d2c31f28 | |||
| c9c9edeb23 | |||
| 5adf792fad | |||
| 81af7d73a6 | |||
| 23e4e0786d | |||
| 0640ce9632 | |||
| 3e49bf4f42 | |||
| 66b038a010 | |||
| 9bbbebf31d | |||
| 19765cfa14 | |||
| d6badca610 | |||
| 6933804aa4 | |||
| 5bed7f292f | |||
| f553896e2d | |||
| 60663b5433 | |||
| 1851a31e66 | |||
| d853310bee | |||
| 11c671354b | |||
| b15599f01e | |||
| 4b957abc0c | |||
| 8ee82d1e03 | |||
| 5565662d87 | |||
| 78735fae6b | |||
| d3b9911445 | |||
| 7813dafc96 | |||
| 02b561edd2 | |||
| 272a1fda54 | |||
| bc8666df83 | |||
| 028fad94af | |||
| 0c735953c9 | |||
| 736bc87480 | |||
| dd94a64048 | |||
| cf9f88f8ce | |||
| 5694aeda5f | |||
| 7829e3c132 | |||
| 2ce0d60db1 | |||
| 68e66dad06 | |||
| 80db907857 | |||
| 76674a3594 | |||
| 98dba11c5e | |||
| de261d28ef | |||
| d43716612b | |||
| cfaacf7cb2 | |||
| b9922bc90b | |||
| 31cae8f05f | |||
| 133e382aae | |||
| e02c721c2b | |||
| 5af0ceb2d2 | |||
| 6460fdc62b | |||
| 402ca780bf | |||
| 643ab92cd2 | |||
| a9c3b343fc | |||
| 592bebaf29 | |||
| 4df215e674 | |||
| 91792f45ea | |||
| 20091e94c8 | |||
| 76aa494be4 | |||
| 6fb8fdc2bd | |||
| 0d879ed290 | |||
| d8d46e0f3e | |||
| e5830b0116 | |||
| d89b171f49 | |||
| a760aec791 | |||
| 34d5d353af | |||
| e8e637c4f2 | |||
| adbca39fef | |||
| a2c88b607f | |||
| 2115a67d24 | |||
| dec73b02e9 | |||
| 0e6ed53cee | |||
| fd6c70afe1 | |||
| c4f193b13e | |||
| 70703c39f3 | |||
| d429485f0c | |||
| 89460dd39c | |||
| f46b259384 | |||
| fb0ce48f2f | |||
| cb4a81008c | |||
| d620da365e | |||
| 0c3102721c | |||
| b3fa03043d | |||
| 38d7db49c8 | |||
| 1a8c832039 | |||
| 6e54f8cfa6 | |||
| 4838ffb82d | |||
| 1bcf41d382 | |||
| e381566494 | |||
| 66d7a073d3 | |||
| 0637215b85 | |||
| dc1405ffa8 | |||
| 0fce20c503 | |||
| 1b16dd126b | |||
| fe07f9208c | |||
| f092fc3fc6 | |||
| b5228dcda0 | |||
| a5db3ea25b | |||
| 173fad2362 | |||
| 496338d84d | |||
| 59727a6967 | |||
| 3a5e41ed91 | |||
| 2259bce05f | |||
| 7e00a86bb4 | |||
| 73a2a938b4 | |||
| c2098938f5 | |||
| 773ff182ee | |||
| 878c49e4e1 | |||
| 023dd3e880 | |||
| 6b88856c16 | |||
| dd5f926077 | |||
| 845020b0e2 | |||
| 7cf363eb06 | |||
| f67e670621 | |||
| 645e3ccbb3 | |||
| ab385f2bf5 | |||
| 5080b9a82b | |||
| 51e42ded44 | |||
| 37fb89c691 | |||
| 440eda3807 | |||
| bad2576397 | |||
| fdf2e5934d | |||
| 3da1e8598b | |||
| 0296c767bf | |||
| c215c42289 | |||
| 8adab95973 | |||
| b89c7580e6 | |||
| a85fe2cb08 | |||
| 4c4c126361 | |||
| e9e12b88f8 | |||
| dc08c516bf | |||
| 9b1f108051 | |||
| b0f9a0feb4 | |||
| 3bd27ae8c5 | |||
| 79b9bdf7ce | |||
| 9e09168597 | |||
| e5f12347bd | |||
| 86d3556c6d | |||
| 45838b33b7 | |||
| a1d4798ded | |||
| 25c52b7482 | |||
| fcf9f266ad | |||
| fa638ae3a0 | |||
| 6d9cd504a0 | |||
| f9e9bb8870 | |||
| 85ab2425a8 | |||
| 9931155c68 | |||
| 56b6d928b6 | |||
| b865bea482 | |||
| b6314e0c73 | |||
| 2c773750c7 | |||
| 539b9be1d3 | |||
| 00e8caa0e3 | |||
| 1ff8b62bf5 | |||
| 25fb985af8 | |||
| 858245db7d | |||
| 09bea2ad5b | |||
| adb520ec2a | |||
| 5a1ff4b50d | |||
| e0f8acf733 | |||
| a81542eeee | |||
| f67eeb66aa | |||
| 884c998622 | |||
| 88c8d73a94 | |||
| 86576768d1 | |||
| 3327c32b20 | |||
| 97ed6a3a4e | |||
| 85d8e0ac2c | |||
| 2a68f9f532 | |||
| b55d35c7bb | |||
| 98f85d7728 | |||
| 328a7caf61 | |||
| 275ea9b0bb | |||
| bb78bc8fe3 | |||
| 10224a692b | |||
| 3eb83d0737 | |||
| f35fa0049c | |||
| d77a88c21e | |||
| 3d55622237 | |||
| bf76465029 | |||
| 129a6ed99e | |||
| 9f5fc4ab0c | |||
| 97f6468663 | |||
| a883b73981 | |||
| 36aadc21a7 | |||
| da469911d3 | |||
| 4195b0d0e6 | |||
| d241aef502 | |||
| 8b2ca6b13d | |||
| ade94c87b5 | |||
| 46f3426c35 | |||
| 3503cd9b71 | |||
| 73cc040792 | |||
| 6c6029618a | |||
| 2a8084b6c6 | |||
| 86ca9bd0f9 | |||
| b192678abf | |||
| 9a998d7b41 | |||
| 64a6859753 | |||
| b20b7e65bf | |||
| 203e3ef077 | |||
| 7be5502a12 | |||
| 0de6e4ccbb | |||
| c8041bacd6 | |||
| 1187f83ffd | |||
| dd3b8469dd | |||
| 34bbd7dcaa | |||
| 8318b3ba83 | |||
| 6768ecc3fc | |||
| 9672f00ec3 | |||
| 0c1101739d | |||
| 872cb2d9c8 | |||
| 3e47fe54fa | |||
| f0d3d23b5f | |||
| 69e59b0ced | |||
| ad4fb5afe3 | |||
| dd6dd63798 | |||
| 7a3748b8f6 | |||
| 06a08a874f | |||
| 37a9813482 | |||
| fe7b436a8c | |||
| 601eff1af6 | |||
| 29949eae1b | |||
| 9dfe6d1e85 | |||
| fb3bc22c64 | |||
| b89304a24b | |||
| 69b3457e83 | |||
| cf21074f10 | |||
| dc7f21513a | |||
| a15450af91 | |||
| efbcce0ffe | |||
| 1c2c87e03d | |||
| 93b33c0518 | |||
| 53e01952be | |||
| 1c12b468a8 | |||
| ccd803416e | |||
| 62f2a42f28 | |||
| d6e76fd1c0 | |||
| 9135c56ac6 | |||
| 0e7eff3963 | |||
| bd1928e445 | |||
| 8e105af232 | |||
| 796cbafde4 | |||
| 29354a1586 | |||
| bcd73e604c | |||
| e80ca6553d | |||
| 90f17c2140 | |||
| 2e5cc1e6ae | |||
| 0ea7fd9c3d | |||
| 814d9aa01b | |||
| 3fa12445a5 | |||
| 547a2aec09 | |||
| 9175fb7da8 | |||
| 887032881a | |||
| e67f82283f | |||
| cfa83658dc | |||
| c881aa7b32 | |||
| a8db29399f | |||
| baacd0e50c | |||
| 0f8c3b1960 | |||
| cd523cc934 | |||
| 044271a55c | |||
| f662b9a081 | |||
| ba10f97420 | |||
| 50c460ebd5 | |||
| 501863a0eb | |||
| ec9b2dbe42 | |||
| db2ba22bd6 | |||
| 087f08dad2 | |||
| bf7b146dfc | |||
| 01f3237416 | |||
| 8f813fbc67 | |||
| f4ff695080 | |||
| 08cc2bbd70 | |||
| 46a7e46068 | |||
| 472a567f42 | |||
| f3bc1ed3a9 | |||
| 7ba9b97afc | |||
| 061d281d2a | |||
| 2835508292 | |||
| 959d9a3ad9 | |||
| 7cf34a6d6f | |||
| 8d6d7d1f20 | |||
| b115764d9c | |||
| 1b5d332e93 | |||
| 356dfc806d | |||
| f2b556adfd | |||
| 1bbfced61a | |||
| 800cb8c6dd | |||
| 6b1d672dc1 | |||
| 6e138bbf54 | |||
| 6dabf4507a | |||
| 527e6cbc72 | |||
| 39edbcbabd | |||
| 0077856d2f | |||
| b65f1d7df0 | |||
| 201afbbeec | |||
| f5caf96d2e | |||
| 73efcc6b0c | |||
| d69510f997 | |||
| d6946a8aae | |||
| ebbc168f3f | |||
| 347cbd37ca | |||
| d190e0b771 | |||
| 5f28a7db0d | |||
| d0c99f1999 | |||
| bf71781ee9 | |||
| fbce104f3b | |||
| ef9074f8e4 | |||
| 67f3111cc0 | |||
| 56d2101b1a | |||
| a28395b116 | |||
| eebf3a54e2 | |||
| 7e70fa63d7 | |||
| bea4b520c0 | |||
| 64c17c4ecd | |||
| 26f7ac9ca1 | |||
| b1a12768e1 | |||
| 0e5a448d04 | |||
| 91a89399f8 | |||
| c6bb7c5993 | |||
| 48b131eb5c | |||
| 1328be2b61 | |||
| 88c1e622dd | |||
| 10672786a1 | |||
| d896a9efec | |||
| 0ccdd4b6ad | |||
| 66fc676858 | |||
| 12f2acc9ff | |||
| b53e8bf501 | |||
| e296264ea6 | |||
| 598f5519d1 | |||
| ced64d7a09 | |||
| 7075a8a8ef | |||
| e2605c2838 | |||
| be63939441 | |||
| dea9c37d99 | |||
| 4d27366ead | |||
| a11a8429bb | |||
| 6da33cafe5 | |||
| 06f82d5e8a | |||
| 89dd0c4a40 | |||
| 1b10f53eff | |||
| 8bd7d57dd8 | |||
| 4a6325696e | |||
| b50a907ca3 | |||
| 59e9a67abd | |||
| 1d2f06df6d | |||
| 725b93a961 | |||
| a21e4c5a0b | |||
| 433db17083 | |||
| f8753fb9f1 | |||
| 25d5653f66 | |||
| 703a88a639 | |||
| 25326b571b | |||
| 5e2f4c9d2d | |||
| f43d380fe2 | |||
| 2240d3d0d1 | |||
| b6eea9a880 | |||
| 6bbd7c0c0b | |||
| 2caeb4008c | |||
| a4919ffb45 | |||
| b384340cbb | |||
| 061f46306f | |||
| fe1f11b071 | |||
| d3f5db576a | |||
| 0ca586e1c8 | |||
| a0b55f9df3 | |||
| 24943ccee6 | |||
| bcaaf34fa7 | |||
| ea17d1f6c7 | |||
| 3be734010c | |||
| e79787cc77 | |||
| 7de428233e | |||
| 9722f56be8 | |||
| e766d206f1 | |||
| 1fa9091239 | |||
| 04e1e5e3a2 | |||
| fa5c0560fa | |||
| 55d47b3e31 | |||
| 5bb96fd477 | |||
| 22b404a1b4 | |||
| 03dcf82602 | |||
| 95d1e8a4f1 | |||
| 67f68b47db | |||
| 593808f24d | |||
| 0a884cc64a | |||
| a54d4b98b1 | |||
| 23132e5292 | |||
| d741b624be | |||
| 00bc394bdb | |||
| d7215ad185 | |||
| 2b63eb8243 | |||
| 1bb3da0332 | |||
| c7d3d635f6 | |||
| f4c8db6105 | |||
| b2637b9a43 | |||
| 09d0ac3838 | |||
| f42cc848d5 | |||
| 4b1224f874 | |||
| 10bb2cce8e | |||
| 8174b3b85a | |||
| 71e2f2ed61 | |||
| 8d8724b3e1 | |||
| 47f65ccba6 | |||
| df0c1106ce | |||
| 47a2271e27 | |||
| ea367a7f37 | |||
| f4b192e33c | |||
| a5c824f694 | |||
| ccc4607d6d | |||
| 4ec41392f7 | |||
| 5f2b2cd0f7 | |||
| 361e3ca356 | |||
| 13bf4fab32 | |||
| 4b583e8ce9 | |||
| d31c6fe286 | |||
| 79de97d814 | |||
| 1c5d093b59 | |||
| ecff2beafa | |||
| 7e0b19c43d | |||
| 2ebe2faa74 | |||
| aec1451168 | |||
| 38251aa513 | |||
| d92e8ca8d2 | |||
| 2e5876d488 | |||
| 3dddd16ec7 | |||
| 40ff7ad999 | |||
| cb79f769c9 | |||
| e95feff016 | |||
| f65b32c1af | |||
| 46dd9b9887 | |||
| 4445f21e8a | |||
| 00d3676a20 | |||
| 0f7cb12e97 | |||
| 8485e02c00 | |||
| ae7300f9b4 | |||
| fc796539e8 | |||
| 1d8c43b445 | |||
| 58de37e822 | |||
| 7b3a0c5105 | |||
| 592034653c | |||
| 8d9f830c53 | |||
| d8eea0ce0e | |||
| c28c441e77 | |||
| 1391420699 | |||
| c0be751ef4 | |||
| 5e2462e061 | |||
| 5c0eb4772d | |||
| ef8706b4e1 | |||
| acd1919e8d | |||
| 459e2a322b | |||
| e62caf33aa | |||
| 72fd0f3d41 | |||
| 032c21c545 | |||
| b391daac6d | |||
| 8cb6959e3f | |||
| 49c817a60e | |||
| 6859b53155 | |||
| c581563230 | |||
| fc1db35f27 | |||
| 2734a4aee4 | |||
| 172f65969c | |||
| f0dbe0deb9 | |||
| 8f8d81f90c | |||
| 665523bc7e | |||
| 99e8fa70ba | |||
| 4c1d7c9d73 | |||
| d1cc8e7ad7 | |||
| 7629e44e4c | |||
| b62f6a6141 | |||
| 10d7a2396c | |||
| 007eced326 | |||
| 1128270d4b | |||
| c7d889bf9e | |||
| 7cb585c1a1 | |||
| 75157221b2 | |||
| 9807520ef0 | |||
| c658ee5c78 | |||
| cbfbcdcff5 | |||
| 9a0581ea7f | |||
| 60c268ddd6 | |||
| 0361e0204a | |||
| 2da427134b | |||
| 4fce0dadcf | |||
| 288c241fb4 | |||
| f3e3eda69e | |||
| 0f4dd8103d | |||
| 86ee05ee5e | |||
| 3b9c6a6465 | |||
| 8e73a4a19d | |||
| 428bb36ec6 | |||
| 0a24df6bd0 | |||
| d3ca080729 | |||
| 7658031784 | |||
| 710e74219a | |||
| 0249bed53a | |||
| 9d14f81b79 | |||
| a7c683a83c | |||
| 16631bf454 | |||
| 3c563f7073 | |||
| 344bdbb707 | |||
| a0256dfc60 | |||
| b131f27eb9 | |||
| 0d9b70552e | |||
| ea1a89290a | |||
| 59f1679d37 | |||
| 5121983218 | |||
| 0d7141ce5b | |||
| b4b753ce2e | |||
| 4f666e4d53 | |||
| 874a988527 | |||
| 51c79f9784 | |||
| 4d19811026 | |||
| d1454075ab | |||
| becb6cf5bf | |||
| a6f34d2044 | |||
| 7300024e13 | |||
| 282800e6b1 | |||
| e938bd3481 | |||
| 9b501276fb | |||
| 90d191f5f8 | |||
| f452e7f9d2 | |||
| 1d25f41122 | |||
| 5556785804 | |||
| 22ce4c24fb | |||
| d4d2d127d1 | |||
| 3c28932862 | |||
| 7e9177cb3c | |||
| f692103c81 | |||
| 5a1dfe9b89 | |||
| 7175180dc9 | |||
| f95d1fa8ba | |||
| 7b57068f6f | |||
| d79eac3e26 | |||
| 27c255c874 | |||
| bdc611b23a | |||
| 4cddf0bf5d | |||
| 462d4c99cc | |||
| 94a2188090 | |||
| ebcdcb5f00 | |||
| f9e780ed67 | |||
| 18f8ce69cd | |||
| dce665f14e | |||
| 80046b646b | |||
| 06ddceeac0 | |||
| b7ea1dfcd0 | |||
| 6d9598cd4c | |||
| 60c9701c3f | |||
| 2a8644b72c | |||
| b6e469abd1 | |||
| 004c237085 | |||
| 398e3bdf82 | |||
| 958350af82 | |||
| 2d677a8af9 | |||
| 05a79f5b55 | |||
| ac9566d3d7 | |||
| 8b7bf94aae | |||
| c4e785e523 | |||
| 2f6f883f7f | |||
| d071e92a1c | |||
| b18b4072e1 | |||
| 0a2898da17 | |||
| 73fb596973 | |||
| c3f9dc7400 | |||
| c75ce210ea | |||
| ffca6d8ba5 | |||
| 1ec35befc8 | |||
| 6080eaebbd | |||
| 41ea339053 | |||
| 75f9c08445 | |||
| cec3d1488a | |||
| ebec082da2 | |||
| bec585e382 | |||
| 2cc8ae875a | |||
| db8252e650 | |||
| e3cb26a1c4 | |||
| 44036ae26d | |||
| 5b5f871a6e | |||
| 9a8f9cae6d | |||
| 8f804581c0 | |||
| e26ef17545 | |||
| 800bb223b5 | |||
| 75606f2100 | |||
| a28928e6ca | |||
| 8700007025 | |||
| 520f7fa2de | |||
| 096208a154 | |||
| 27caab69ec | |||
| 3fe2b587cb | |||
| c791188811 | |||
| b227c90c18 | |||
| 8a5538356b | |||
| b257c881b5 | |||
| 0f5dffb1c3 | |||
| d2bd238274 | |||
| fed700440d | |||
| 32a9d42412 | |||
| efc938d870 | |||
| 369f669227 | |||
| 1c56671f01 | |||
| 4dbc1e0e96 | |||
| 94288843f1 | |||
| b12decc865 | |||
| 0fc944abf3 | |||
| 9f96c98f02 | |||
| 9805b05738 | |||
| 13ed186469 | |||
| 00a43221ac | |||
| edc39112e2 | |||
| 3b727dea99 | |||
| f16b2adec7 | |||
| 7d425aa76f | |||
| 651c07c724 | |||
| 4d27b75897 | |||
| 6f75d68d07 | |||
| ae269e12bb | |||
| 3a48929fe6 | |||
| be970326b6 | |||
| 463511871f | |||
| 002da1e02d | |||
| b095aae5ce | |||
| 511c21029e | |||
| 81b0447024 | |||
| d42772a261 | |||
| c1136099a9 | |||
| 06f8a975c0 | |||
| c8cd8775f6 | |||
| f9900c91bd | |||
| accaf6e77e | |||
| 8490e297a9 | |||
| 6d3a4b5f6c | |||
| 1f36206f45 | |||
| 952e10936c | |||
| 2b3093a687 | |||
| d7e25772b0 | |||
| c66c9b0353 | |||
| bbde0d75da | |||
| c3aec4f627 | |||
| 113852eed4 | |||
| 6b9b2c1468 | |||
| 2c87b295ff | |||
| 93767d68f8 | |||
| cc3646ca16 | |||
| 48333f73d5 | |||
| 1f4241a63d | |||
| 8eccfaa034 | |||
| 438d1af12a | |||
| 5be6ef380f | |||
| 76419ed2fc | |||
| 4684921e51 | |||
| edd8caa2bf | |||
| cb5575ae89 | |||
| 42e726dec5 | |||
| e3d33aa171 | |||
| f2ceeb35da | |||
| 577cf5ddc4 | |||
| 91ced39233 | |||
| 4b6cb0b8b8 | |||
| fb81302382 | |||
| dfc81f65ee | |||
| 909db4c861 | |||
| 4277eed1b6 | |||
| 6f5703a5fe | |||
| f7469f298d | |||
| b29d5df7a2 | |||
| 549ba65861 | |||
| a9d99cbe54 | |||
| 8438024370 | |||
| e6a00ddcfd | |||
| 71b967d243 | |||
| 1fc1e9590a | |||
| 0a0099fb41 | |||
| b890d394ad | |||
| a7fd37ae76 | |||
| 41fafae21d | |||
| a38c007f51 | |||
| c7ee402b0e | |||
| 1c19796e3e | |||
| 76fb0cb965 | |||
| 23c79f5cc9 | |||
| 14eac50261 | |||
| cf3eae1c91 | |||
| db06cdb4ce | |||
| 7ba8e51fa9 | |||
| bc6466cc36 | |||
| 4fbefaef9a | |||
| be11d3325d | |||
| 274140d309 | |||
| ed960ccc8d | |||
| f2b72113c1 | |||
| 67a8d30e87 | |||
| dafd0e5db7 | |||
| d6d10cbf06 | |||
| 3d3ba86be4 | |||
| 52ed8a7ed0 | |||
| 9449c99e25 | |||
| 4c0846734e | |||
| 4c64f5fe62 | |||
| 9455ea0547 | |||
| c3b54a63c3 | |||
| b9e1d3116c | |||
| 5bb7e62a7c | |||
| a443f3a0bb | |||
| 440244eed8 | |||
| 2b9e25300f | |||
| de264dbf94 | |||
| 848b773e24 | |||
| d92f022041 | |||
| 57fab61789 | |||
| ec8f977ebe | |||
| 8dc85e7641 | |||
| 4e00ebcd74 | |||
| 335e719b5d | |||
| 415f8ef2d8 | |||
| 17615d1d4a | |||
| 5072252c72 | |||
| 46e93770c9 | |||
| fe43734811 | |||
| 0df81c49d5 | |||
| 5653516b32 | |||
| 22da5be08e | |||
| 862656aecc | |||
| ec119a6d52 | |||
| 6b98b5f4c7 | |||
| 5effe95f2c | |||
| f22e3fd3ff | |||
| 0047040af9 | |||
| 60987e6b9b | |||
| 27d5e2b219 | |||
| 53fd0c3a55 | |||
| 63456a6d4f | |||
| d4cd3c2f7b | |||
| dbf7137a1a | |||
| 785891c315 | |||
| b7417ec954 | |||
| 61b861f0e5 | |||
| 0fea0738bf | |||
| 4f25d29815 | |||
| 28302a5040 | |||
| 9cc5ca5c58 | |||
| 4c4e60b3c9 | |||
| 5689a96602 | |||
| 8b57db467a | |||
| 50339e53e2 | |||
| bc9f5189a5 | |||
| fee83fee40 | |||
| cd5112ab0e | |||
| a43b88f9a2 | |||
| c20fd5dcaa | |||
| f12e296c09 | |||
| 9c3a572646 | |||
| 6175faa9a4 | |||
| af02fc6bbe | |||
| cc0bbc42a2 | |||
| fd747c7340 | |||
| bd33202972 | |||
| f6f0de0e38 | |||
| 881041800b | |||
| 11f3ac16f6 | |||
| 969bf95230 | |||
| abc6b4180c | |||
| f74d762a92 | |||
| f00892ed66 | |||
| f14c6e6845 | |||
| b1bbf2ef84 | |||
| 201062cade | |||
| 8cb9198bcf | |||
| f5e53c0452 | |||
| 41d9c00f70 | |||
| b52f392c92 | |||
| efaa3b5ab2 | |||
| 36f3d8d6ac | |||
| e469afa4a9 | |||
| 9d4b0caa5b | |||
| 392c07951e | |||
| 8e72c3d81e | |||
| 02428f1e06 | |||
| b3aa513563 | |||
| b8b08cb114 | |||
| ebbbf1059d | |||
| 37297076f8 | |||
| a75b2df6fe | |||
| 9ccd0f0282 | |||
| e57d9f2e2e | |||
| cf593ba9f9 | |||
| 9eb862a6a4 | |||
| bc84e08da5 | |||
| 24dae2f096 | |||
| ab24d6bd96 | |||
| 7782c80c4f | |||
| 994bd0a910 | |||
| bc9dcba4d4 | |||
| 85c244ed08 | |||
| 495196193c | |||
| def1e5e1d8 | |||
| 2727091e47 | |||
| d7fbd416ba | |||
| 6a09ce1613 | |||
| 774e6346e7 | |||
| 05b939760c | |||
| d6c6fbfe03 | |||
| bb3cbf2dda | |||
| 39d96a45aa | |||
| 6a8c5c8869 | |||
| 96318bbe11 | |||
| 00dd2463fd | |||
| bcd55626ef | |||
| 8f8cb6a52f | |||
| 2e3d33dfcd | |||
| 1e40cd6f0b | |||
| 6e2608b2f2 | |||
| 60d80cf261 | |||
| 9c23fd4a31 | |||
| fccb1aad32 | |||
| 2780ff31b5 | |||
| c37c8dc21d | |||
| 6ee7a81f10 | |||
| 3d94638d86 | |||
| 418ff95543 | |||
| 221113cbb7 | |||
| 13ea12cf6e | |||
| 1945aae4dc | |||
| 30362cfc0c | |||
| 6cdc590db5 | |||
| eb122a2b8c | |||
| feaf8711d3 | |||
| 6e364ff0ba | |||
| 6f6aff7493 | |||
| 207cddd50b | |||
| 35988d8f09 | |||
| bea63028c7 | |||
| 0244060806 | |||
| bfdc296f43 | |||
| 8e625a5d07 | |||
| 3460bd0ba9 | |||
| 4dd0377eb8 | |||
| 6e1ab9fe3a | |||
| 7a2d214cc4 | |||
| 62495a6de4 | |||
| 8ea88468f3 | |||
| 687892890b | |||
| ff0dfacc48 | |||
| 235a52032a | |||
| a5ee7e78f6 | |||
| 181dbe8493 | |||
| dae9c9a7ed | |||
| 6d6d299ea4 | |||
| 6fd615b9cd | |||
| d09394ed52 | |||
| 3e6f27d173 | |||
| 82c2ae5441 | |||
| 7edf2bb2c2 | |||
| c9607b99a3 | |||
| 2fe1a84dd4 | |||
| c63218a889 | |||
| 5efa9664db | |||
| dc75469e78 | |||
| 9d1e21b5ad | |||
| 27a367c733 | |||
| ffa0ace2a7 | |||
| 074e1e992c | |||
| cdd72c7e56 | |||
| a5e99a95a3 | |||
| 1de736019d | |||
| d6b2712070 | |||
| eda8f4ccec | |||
| 7e3f476407 | |||
| e10f36d5f0 | |||
| 1bfd9abda3 | |||
| 4a1a10fde8 | |||
| 4c3cb76ced | |||
| e2794e9f06 | |||
| 7d2c627ad2 | |||
| b310e0f718 | |||
| 18915ae2bd | |||
| 5dbda8f519 | |||
| 82ce9dfc04 | |||
| ad5cd564ab | |||
| 6f01f580ca | |||
| d5130d9fe4 | |||
| 0341a0d5e7 | |||
| 32191fb05a | |||
| 1592fe377a | |||
| 5add28410f | |||
| d54a55c12b | |||
| aab5e8430f | |||
| 2e20fdb462 | |||
| 2ac3da7a90 | |||
| 399b79bab2 | |||
| b9eb936cac | |||
| 38117df11b | |||
| 27d729baf0 | |||
| d408a64c8c | |||
| 9aeb28066d | |||
| 6fb7c8687e | |||
| d9666008e3 | |||
| e132230651 | |||
| c2877a0c22 | |||
| 251fc3ec68 | |||
| 287f0a3b68 | |||
| b03d9fe987 | |||
| 98372ef33f | |||
| d00f4afb84 | |||
| d4bf02c882 | |||
| 284e671163 | |||
| 0f112e5c9d | |||
| 759449b4be | |||
| 9c03f919a3 | |||
| c9afd9a281 | |||
| a999cb9db9 | |||
| fdc5bd6195 | |||
| e1d94eee21 | |||
| 885f237217 | |||
| 5860a4e28e | |||
| 2bebed44ff | |||
| 4990e544cf | |||
| 8010506d4e | |||
| f2f7abb9a8 | |||
| 85f6ab869e | |||
| fc87b0a11e | |||
| 79bc071754 | |||
| 797243fc9c | |||
| cc7c6b9ece | |||
| 279071e5bb | |||
| 426374ff8a | |||
| 1508874ebc | |||
| bbe440cacd | |||
| e647e73af9 | |||
| 696ddfde0e | |||
| 37d6257524 | |||
| faee894052 | |||
| 61f16b8c5e | |||
| 85eb38e755 | |||
| a87cf60dfc | |||
| 3b135447f3 | |||
| 0c3713f7e5 | |||
| 4d0571fd73 | |||
| 4722988bf0 | |||
| 61151535e6 | |||
| bcff6c192c | |||
| 020d0cfb49 | |||
| d38e3bd729 | |||
| 84a604f70b | |||
| 782baf54a3 | |||
| d754e4eeca | |||
| db98f6191e | |||
| b453a42f77 | |||
| 2a6585e664 | |||
| bc013925b8 | |||
| 8108ecc4d3 | |||
| 1c80584206 | |||
| a3dd9c3e57 | |||
| 8f05fc0a84 | |||
| 3c4feecda0 | |||
| e776a51c73 | |||
| 129e8ef98a | |||
| 69134f6d6a | |||
| b32062f875 | |||
| 8d46ee85f1 | |||
| 9f9fde1f2b | |||
| 2b041e09ac | |||
| 73b32bb45e | |||
| 11e6e74f09 | |||
| bf3e3f0c3d | |||
| 2656acc321 | |||
| e46c9be79f | |||
| 507167d5c1 | |||
| fc90162f69 | |||
| 1e8fb7a38c | |||
| afb6c5a09d | |||
| 2255ab0a37 | |||
| a6ab042078 | |||
| 480f70c049 | |||
| 0592897859 | |||
| d5a9f8e177 | |||
| 5840829cdc | |||
| fd0946b770 | |||
| 293b462fd2 | |||
| 3db50fdd54 | |||
| 1540e6518c | |||
| 8b30c13cd9 | |||
| a7eb89b2f0 | |||
| 53c102e1e9 | |||
| 7d90737921 | |||
| e281f88f2e | |||
| 16c5c7bbb4 | |||
| 7d4dfd87f1 | |||
| 6156bf0f9d | |||
| ee1fdca52e | |||
| 95b5bcbd49 | |||
| 0c529361a3 | |||
| 7110acc94f | |||
| 1188002bcb | |||
| b47a3f15ce | |||
| 695a2a2b6e | |||
| c8b4ef3eed | |||
| 6091248493 | |||
| 32fd507ad9 | |||
| 0ee77a37d1 | |||
| 05241544c5 | |||
| 495c872489 | |||
| 8c09edfdbd | |||
| 67722cf788 | |||
| 8e3484b873 | |||
| 4622aebabb | |||
| 96f29c27cd | |||
| 3de98f7a9d | |||
| 2b33fcd92d | |||
| b1ffcd4350 | |||
| fd500001fb | |||
| 54a757a917 | |||
| 98dfc218d9 | |||
| f6f0f1fb72 | |||
| 218c810860 | |||
| c836b6df3b | |||
| 637bab29c6 | |||
| 0061b3fcbf | |||
| 2a19ded9d5 | |||
| bda9de0775 | |||
| 7047610a45 | |||
| 903d6f9e12 | |||
| 7d61bb2868 | |||
| def7164cad | |||
| fc399e01fe | |||
| ffdc3eee2d | |||
| 1f6f44ab01 | |||
| 19740758c9 | |||
| f618660d24 | |||
| f50dbe298a | |||
| c324fbace4 | |||
| d05152af71 | |||
| bf228b4ae4 | |||
| ba0c17e287 | |||
| 6cfbd4cefe | |||
| e17a2e79a0 | |||
| 72d709ae6c | |||
| 08ca450c40 | |||
| a2951659ac | |||
| 3a6af3810f | |||
| 3973554f07 | |||
| 718cba2e36 | |||
| d2a70d1504 | |||
| 4bc847ac42 | |||
| c3621edf9c | |||
| a64f2de9e1 | |||
| ce684cf9d4 | |||
| 1d1be10f16 | |||
| a09f97c9d5 | |||
| 48da2d2dfb | |||
| 36c0edea2a | |||
| 3568dc2083 | |||
| 51ad72a432 | |||
| 9ce970df8f | |||
| cfa4d80dd7 | |||
| 885cd05f1a | |||
| 21188725d5 | |||
| 70f257b62f | |||
| e8fb8e13df | |||
| 7b7b93e9ba | |||
| 4014da3cc5 | |||
| 410120adee | |||
| a98e65aa1e | |||
| dba9998118 | |||
| 1c75ce5911 | |||
| 33b30aeb95 | |||
| abd8d3459a | |||
| 471698c59f | |||
| e67cf578ae | |||
| 186ad5d444 | |||
| 7eb810c34a | |||
| 7817384e3c | |||
| 34256ba358 | |||
| 08eb5aa7d1 | |||
| 1d3932e8c5 | |||
| 3f85b30d4a | |||
| e4c398aa23 | |||
| f9417555d0 | |||
| 5d3123b97f | |||
| 25080aaf1d | |||
| 05ac4b5ab6 | |||
| 07e13e2499 | |||
| 2d9645b9b0 | |||
| 65ccbedab2 | |||
| 631567864b | |||
| 39d479128c | |||
| 4c0b315c07 | |||
| 264e83a1f3 | |||
| 2b2ed50721 | |||
| 31fbf99109 | |||
| 63381ad221 | |||
| 6ee2d1103e | |||
| bee18dba54 | |||
| 481e445e8a | |||
| 129f7b7441 | |||
| d6bc3c5175 | |||
| de7c56c6bc | |||
| 0c59ecfa14 | |||
| f67241a3cb | |||
| 3b2893944c | |||
| dd7d6df4c6 | |||
| efbda436f3 | |||
| 2064934939 | |||
| b36cf7c450 | |||
| a24dd3dee2 | |||
| 7b22f08869 | |||
| 840929754a | |||
| 51fd332806 | |||
| 4d7e0f6b79 | |||
| b74a573ec5 | |||
| 5faf88afdb | |||
| 5e1110930e | |||
| f11adf5f80 | |||
| 40a71e09a6 | |||
| 1231847a3c | |||
| b06a73e893 | |||
| f99f194927 | |||
| eac7d07ef6 | |||
| 60d70a9f4c | |||
| c944783590 | |||
| 8104a8aea1 | |||
| a4db678895 | |||
| da33d02461 | |||
| 9b4071006e | |||
| b3cdd5b3bf | |||
| 93e53ec612 | |||
| ea8319e2b9 | |||
| 2fae253c62 | |||
| e204b257ad | |||
| dd83d8ed61 | |||
| 61f3d85af1 | |||
| 804e515847 | |||
| 35977b6c7f | |||
| 23f1d3d83b | |||
| b8ea935424 | |||
| 7c0866f626 | |||
| 0f2062b739 | |||
| e91454eeee | |||
| 58134200df | |||
| f6bab21928 | |||
| 011910811b | |||
| bbc0ba147a | |||
| 922a4331db | |||
| 8f7f1e2683 | |||
| 1980cc007f | |||
| 39611f7477 | |||
| e3d659576f | |||
| 46d4670b74 | |||
| 15ca6d5ca9 | |||
| 58f23cda4a | |||
| a58d8420a2 | |||
| 96f834fb81 | |||
| 86617eccb1 | |||
| f2936d1c2d | |||
| 0fc8e04ab5 | |||
| a65e2d3115 | |||
| ca6e25b11c | |||
| 3ec6a6f5bc | |||
| c12fae47e7 | |||
| 604d2c698b | |||
| 5d14016366 | |||
| b112becbba | |||
| e68a09fb3c | |||
| 30e9b4513a | |||
| 671b14dac0 | |||
| 82e99988e8 | |||
| 313a7ed7fa | |||
| cf3365574e | |||
| 0e1f6f50ea | |||
| 5b6518d4a9 | |||
| c009dce591 | |||
| 40e2d7932b | |||
| e29b7a6eae | |||
| a3e9cbc000 | |||
| aedcc2ff40 | |||
| 4c17aeb180 | |||
| ef60ae652c | |||
| 1d62ed028e | |||
| 50bf7694c2 | |||
| 807f1d7c1c | |||
| 7a7d0c09d9 | |||
| f90ce77da4 | |||
| d27ac27bc7 | |||
| 44c6a64bf4 | |||
| 2d6eae9391 | |||
| ba440550a6 | |||
| 8e24fee9da | |||
| 1148652101 | |||
| ed01eeaeb3 | |||
| 096f187d6f | |||
| fa35eb1959 | |||
| 8d89d30c74 | |||
| f1bde40939 | |||
| 4e7ccaa298 | |||
| d0284991ed | |||
| c4998990e5 | |||
| 42d3ee9b94 | |||
| be5c3e41e1 | |||
| 3282d410c4 | |||
| 75303c95f8 | |||
| 0209272831 | |||
| 0e16c4ed97 | |||
| e49720f34a | |||
| 8aee371d81 | |||
| 71c4f81b59 | |||
| 3127fafc88 | |||
| 4e6bdf28cc | |||
| 621a5a86a0 | |||
| d80c8cbd2f | |||
| 686f1aeeb2 | |||
| e27a69bab7 | |||
| 4ee2e1d049 | |||
| 2102648102 | |||
| 8611e40172 | |||
| 7d5b88fff8 | |||
| cfd9aa31a9 | |||
| 62aea4c321 | |||
| f75fcb3041 | |||
| 971c557d85 | |||
| ea05aa225e | |||
| 56cdabff6a | |||
| 15f62e680a | |||
| 0af4e16c21 | |||
| c7b90bac1a | |||
| 4b81331d53 | |||
| 47ab0cbf62 | |||
| f5b079b8e7 | |||
| 21c4691d40 | |||
| 3726706608 | |||
| 28a53aa147 | |||
| 2ad572490c | |||
| 0ed9caf969 | |||
| 63ee376f71 | |||
| 67bcb98a84 | |||
| 9cd91ae99c | |||
| d111a0e5e6 | |||
| 11d4c04cea | |||
| 01773c2a00 | |||
| 1079bf7843 | |||
| 05bcfd2c1c | |||
| 5357a6a4fd | |||
| b6787b0014 | |||
| a32116d24c | |||
| a03b698e5a | |||
| fa0c5db18c | |||
| bc063ded7a | |||
| 846505cbc8 | |||
| 964118d1d6 | |||
| c43b67ea2e | |||
| f68af08931 | |||
| cdd5a41965 | |||
| e13ee59af3 | |||
| 9eb183e01d | |||
| 1163417722 | |||
| 3edc48cda5 | |||
| 2c01425ee5 | |||
| ed9c72814f | |||
| adbbe2b097 | |||
| 7335e0809a | |||
| 75dabb75e2 | |||
| 15adcd24be | |||
| e98ba99331 | |||
| 11459d38d0 | |||
| baf4ea2e8c | |||
| 6a29168c14 | |||
| a4689c7a27 | |||
| 8fda5a187b | |||
| 7b78270f4b | |||
| afd3599a9c | |||
| 4bc8562cd0 | |||
| 11fed4c06c | |||
| 9416a983c6 | |||
| 8108c6320d | |||
| b40b931568 | |||
| 282f70ea91 | |||
| a671f63a3e | |||
| f3ad14cb7f | |||
| 21eb5b661d | |||
| 87fe073118 | |||
| 507dadebf4 | |||
| 7dac8c621c | |||
| 19f4ebf3c5 | |||
| c21b40bebc | |||
| 0766c3c62d | |||
| cc40eb709c | |||
| 3625308585 | |||
| df3a7676eb | |||
| 8f6077e973 | |||
| e6689144c4 | |||
| a67de410bf | |||
| 54ec1a89de | |||
| 4b5f744c6f | |||
| df978345d7 | |||
| facc07c60d | |||
| 2f203ac22c | |||
| cc864191b8 | |||
| 547455245e | |||
| b0d7449bb4 | |||
| aed04c7d55 | |||
| bb5973f2fd | |||
| f801fd1f0d | |||
| 44ca12ead6 | |||
| 9c48389f74 | |||
| acefb5a5f3 | |||
| 3d691a3aec | |||
| 38ebdbb563 | |||
| 1090325c31 | |||
| f8ba4b9312 | |||
| 49a1dfff60 | |||
| 5f4d342d45 | |||
| e1c1f79068 | |||
| a716fa252f | |||
| 0b12e4d8be | |||
| 6ad6c94355 | |||
| 78270c8155 | |||
| 4573ae21e6 | |||
| 0ab6220635 | |||
| 3b51976b96 | |||
| c35211b2f6 | |||
| f62515e13b | |||
| 7f2daf8926 | |||
| 0325861ef3 | |||
| 37f8285a6e | |||
| d3906cffdc | |||
| bee1c77efe | |||
| 7250a82286 | |||
| 984457f9c6 | |||
| 5db23f7e46 | |||
| f4f49b2b46 | |||
| 58b35f6e2d | |||
| b51ad16756 | |||
| d790bda7d2 | |||
| 15ce232f61 | |||
| d999a47600 | |||
| 644286111f | |||
| 917b1cbd6c | |||
| 6d1b585212 | |||
| 6ca35a6264 | |||
| 0290b1b4e0 | |||
| 1d86bf3e56 | |||
| 3fd8ab8d3a | |||
| d240ae3b03 | |||
| b875765c52 | |||
| 2bdec31219 | |||
| a9eebdb1fa | |||
| b25f3a9e91 | |||
| 06f3375a97 | |||
| 5057ae920c | |||
| 6a03f13d55 | |||
| 20cbfd95d6 | |||
| 885dbe1e65 | |||
| 7d7cce5c72 | |||
| 0c66f84555 | |||
| 044e41c079 | |||
| 8dc631e13c | |||
| d93b4feb99 | |||
| 0b873f590c | |||
| f52d637f58 | |||
| e2daf5c2fc | |||
| bef113001a | |||
| f0b403bc2e | |||
| a21fb5fc89 | |||
| bbc0424563 | |||
| f487845e9d | |||
| 77641a9fce | |||
| 56d93eb18b | |||
| da1fd96d4e | |||
| d1fdc7061f | |||
| 2822382797 | |||
| 35c9021bdf | |||
| 493b13364f | |||
| a8ff3231a8 | |||
| c2a750a690 | |||
| 6a9541833a | |||
| 9117b45899 | |||
| 812cf36d52 | |||
| 4aa7420d6a | |||
| 1802839a22 | |||
| 9a2d701e2e | |||
| 69ad3f3365 | |||
| d53eb881c2 | |||
| e28e45f38e | |||
| bf6ca22b00 | |||
| b8acbae3e8 | |||
| 4ec9f2c00f | |||
| 4fc329a1eb | |||
| 0574a60bc2 | |||
| e490c4afed | |||
| d028a30f87 | |||
| 75a2d4d00a | |||
| a122a1e8c7 | |||
| 8fe09c85b6 | |||
| bc951de2a5 | |||
| c970cd13cc | |||
| 8983c0f927 | |||
| a47467f29b | |||
| ef206eb4d9 | |||
| da5eec1c5f | |||
| a69b3535a5 | |||
| f4c23f3259 | |||
| e36e9fd629 | |||
| d2f19353ed | |||
| 2d498cb88b | |||
| a80815d57a | |||
| acab77f4f8 | |||
| bddad0c57c | |||
| 3968349480 | |||
| 3ae17761b3 | |||
| 9a28bdbf76 | |||
| e769821e0f | |||
| 9b68821f05 | |||
| b2adb22b2d | |||
| 981941edf4 | |||
| 111dea89a9 | |||
| 2720f4de9c | |||
| 21645643b0 | |||
| c6a07acd90 | |||
| 1816e6607e | |||
| 37dd05a9b5 | |||
| 529997de9b | |||
| 4f37270300 | |||
| faf9c96442 | |||
| f7e09686e5 | |||
| 8eef8204e7 | |||
| 8b8e08f0f5 | |||
| a6bfec22b5 | |||
| d05c4fa9ed | |||
| 07231d3706 | |||
| 584ba10726 | |||
| 24a61dc650 | |||
| 7e7aa6aaee | |||
| 35c5be6475 | |||
| fcf3eb6193 | |||
| 5226b200e7 | |||
| 5f57152156 | |||
| 633ef26054 | |||
| 285bd4f542 | |||
| e706fb973f | |||
| 8dc7afed4e | |||
| 0c7f996de6 | |||
| 985a8e9f97 | |||
| 5e26e4c22d | |||
| 00e27e4b5c | |||
| b3ec9c9323 | |||
| 84ffedd95d | |||
| 455dc26a5d | |||
| 0fccd0f0d2 | |||
| 7e639d6bc1 | |||
| 694ce9d04f | |||
| aebe8572f9 | |||
| c98eed612a | |||
| 5f0ee417b1 | |||
| a6b4658138 | |||
| 1a57aff0f4 | |||
| afc0bac232 | |||
| ac1c59b724 | |||
| 1f9806386e | |||
| 1b67120704 | |||
| 5579388896 | |||
| 49c972983d | |||
| 3cb34f8036 | |||
| 3c5b2286a3 | |||
| 845972daa5 | |||
| e00ef38305 | |||
| 22d0861f6d | |||
| 5265f38c35 | |||
| d13cd4d4b3 | |||
| 79d33d669c | |||
| 439f6e62bc | |||
| 3ef054bbac | |||
| 5a13c6cc3f | |||
| b7750ff742 | |||
| 2c0fa2a9f6 | |||
| 881a57bf8d | |||
| c924b2067c | |||
| fdd0c8470f | |||
| 1960c38468 | |||
| 3074a0146e | |||
| f060dfda40 | |||
| b0ead129ca | |||
| abe9c4d53c | |||
| 15a95ff425 | |||
| 37b8f97d60 | |||
| 88a4bb4d12 | |||
| 50594febc7 | |||
| 9587923e55 | |||
| 2850a074ea | |||
| bed5c8002f | |||
| cc982a578d | |||
| e12ad48822 | |||
| 6abbb06ff6 | |||
| 3d68769503 | |||
| bd316e7e98 | |||
| 3f4c4d675b | |||
| 4b7e5b7445 | |||
| 996dbdde00 | |||
| db67f2ddf1 | |||
| 7b9b2fd23a | |||
| 700747801c | |||
| cb30f4668e | |||
| 9710f39cad | |||
| e3244dd649 | |||
| abd20776a2 | |||
| 5d8b4cb261 | |||
| 9ee615020f | |||
| acef734643 | |||
| 0ff7ac6aad | |||
| 859502c504 | |||
| 9c2926ef8a | |||
| 3188bc5aba | |||
| bf9d9512a0 | |||
| ba03f99e09 | |||
| 8e89f80588 | |||
| 07e245eb02 | |||
| ea12c6fde6 | |||
| 38c7d07e50 | |||
| a0a835bbe6 | |||
| c09e897dab | |||
| c5a3937c80 | |||
| 8e6cc09d2f | |||
| dee3529f14 | |||
| bf5d83d228 | |||
| c2b7336817 | |||
| fc6017c0dd | |||
| 821cc3a177 | |||
| 8939cef020 | |||
| fb17653651 | |||
| f8a07c7a03 | |||
| eb89436df3 | |||
| c1e7ba7118 | |||
| ffddea75a4 | |||
| 380111a604 | |||
| dd4461d473 | |||
| 2706a0bec1 | |||
| 46b207e08e | |||
| d3eda80969 | |||
| 66fb5fc9c8 | |||
| 2d3fb858ad | |||
| 7bf74c0917 | |||
| 5b22dffa6f | |||
| 3ca9420801 | |||
| 3c948a82c0 | |||
| c33c6188a8 | |||
| 0d8f2e1b18 | |||
| 17ed4f908c | |||
| 946bfb9a26 | |||
| 6c2c48a611 | |||
| 1f36cf9242 | |||
| 3ddac9ac5d | |||
| 1b22b348b0 | |||
| f68721af07 | |||
| d53b7de5ec | |||
| b25f3891c8 | |||
| ca58c9ce09 | |||
| 7a2a535f87 | |||
| 17d220187a | |||
| d3a4857826 | |||
| e64fec15b0 | |||
| 3d5f566d86 | |||
| c87b63cb24 | |||
| cd95f9310b | |||
| 297128c19c | |||
| 25a385c940 | |||
| 181e814139 | |||
| 52e5483dfb | |||
| 56f6c795ed | |||
| 5d8cfa465b | |||
| b6ca4a7a46 | |||
| a45508a96b | |||
| a45d274847 | |||
| e3cc896a42 | |||
| 99a47ae87b | |||
| b1388b6f30 | |||
| 2cddf90e49 | |||
| 85148d1283 | |||
| 7b0b378abc |
+59
-23
@@ -2,53 +2,89 @@
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -2
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlinesLeft: false
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: true
|
||||
AlwaysBreakTemplateDeclarations: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: false
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterControlStatement: true
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterObjCDeclaration: true
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
IndentBraces: true
|
||||
BreakBeforeBinaryOperators: false
|
||||
BreakBeforeBraces: Allman
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BinPackParameters: false
|
||||
ColumnLimit: 100
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
DerivePointerBinding: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
||||
IncludeCategories:
|
||||
- Regex: '^<'
|
||||
Priority: 3
|
||||
- Regex: '^"(osrm|util|engine|extract|contract)/'
|
||||
Priority: 2
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
IndentCaseLabels: false
|
||||
MaxEmptyLinesToKeep: 1
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyExcessCharacter: 1000
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerBindsToType: false
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
Cpp11BracedListStyle: true
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
IndentWidth: 4
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
BreakBeforeBraces: Allman
|
||||
IndentFunctionDeclarationAfterType: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInAngles: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
ContinuationIndentWidth: 4
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
||||
SpaceBeforeParens: ControlStatements
|
||||
...
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
Checks: '-clang-analyzer-*,google-*,llvm-*,misc-*,readability-*,-google-build-explicit-make-pair,-google-explicit-constructor,-google-readability-braces-around-statements,-google-readability-casting,-google-readability-namespace-comments,-google-readability-function,-google-readability-todo,-google-runtime-int,-llvm-namespace-comment,-llvm-header-guard,-llvm-twine-local,-misc-argument-comment,-readability-braces-around-statements,-readability-identifier-naming'
|
||||
...
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
# Kind-specific patterns to check AST nodes against. Both python-clang and
|
||||
# libclang docs explain CursorKind, with differences in detail. See also:
|
||||
# - https://github.com/llvm-mirror/clang/blob/aca4fe314a55cacae29e1548cb7bfd2119c6df4c/bindings/python/clang/cindex.py#L599
|
||||
# - http://clang.llvm.org/doxygen/group__CINDEX.html#gaaccc432245b4cd9f2d470913f9ef0013
|
||||
# - https://docs.python.org/2/library/re.html#regular-expression-syntax
|
||||
|
||||
class_decl: '^([A-Z]+[a-z]+)+$'
|
||||
struct_decl: '^([A-Z]+[a-z]+)+$'
|
||||
field_decl: '^[a-z_]+$'
|
||||
var_decl: '^[a-z]+[a-z0-9_]*$'
|
||||
parm_decl: '^[a-z]*[a-z0-9_]*$'
|
||||
namespace: '^[a-z_]*$'
|
||||
cxx_method: '^([A-Z]+[a-z]+)+$'
|
||||
function_decl: '^[a-z]+([A-Z]+[a-z]+)*$'
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"rules": {
|
||||
"indent": [
|
||||
2,
|
||||
4
|
||||
],
|
||||
"quotes": [
|
||||
1,
|
||||
"single"
|
||||
],
|
||||
"linebreak-style": [
|
||||
2,
|
||||
"unix"
|
||||
],
|
||||
"semi": [
|
||||
2,
|
||||
"always"
|
||||
],
|
||||
"no-console": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"env": {
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": "eslint:recommended"
|
||||
}
|
||||
+19
-20
@@ -1,3 +1,7 @@
|
||||
# pre compiled dependencies #
|
||||
#############################
|
||||
osrm-deps
|
||||
|
||||
# Compiled source #
|
||||
###################
|
||||
*.com
|
||||
@@ -36,8 +40,9 @@ Thumbs.db
|
||||
# build related files #
|
||||
#######################
|
||||
/build/
|
||||
/Util/UUID.cpp
|
||||
/Util/GitDescription.cpp
|
||||
/example/build/
|
||||
/test/data/monaco*
|
||||
/cmake/postinst
|
||||
|
||||
# Eclipse related files #
|
||||
#########################
|
||||
@@ -52,25 +57,8 @@ Thumbs.db
|
||||
stxxl.log
|
||||
stxxl.errlog
|
||||
|
||||
# compiled protobuffers #
|
||||
#########################
|
||||
/DataStructures/pbf-proto/*.pb.h
|
||||
/DataStructures/pbf-proto/*.pb.cc
|
||||
|
||||
# External Libs #
|
||||
#################
|
||||
/lib/
|
||||
/win/lib
|
||||
|
||||
# Visual Studio Temp + build Files #
|
||||
# Compiled Binary Files #
|
||||
####################################
|
||||
/win/*.user
|
||||
/win/*.ncb
|
||||
/win/*.suo
|
||||
/win/Debug/
|
||||
/win/Release/
|
||||
/win/bin/
|
||||
/win/bin-debug/
|
||||
/osrm-extract
|
||||
/osrm-io-benchmark
|
||||
/osrm-components
|
||||
@@ -79,14 +67,25 @@ stxxl.errlog
|
||||
/osrm-prepare
|
||||
/osrm-unlock-all
|
||||
/osrm-cli
|
||||
/osrm-check-hsgr
|
||||
/osrm-springclean
|
||||
/nohup.out
|
||||
|
||||
# Sandbox folder #
|
||||
###################
|
||||
/sandbox/
|
||||
|
||||
# Test related files #
|
||||
######################
|
||||
/test/profile.lua
|
||||
/test/cache
|
||||
/test/speeds.csv
|
||||
/test/penalties.csv
|
||||
/test/data/monaco.*
|
||||
node_modules
|
||||
|
||||
# Deprecated config file #
|
||||
##########################
|
||||
/server.ini
|
||||
|
||||
*.swp
|
||||
|
||||
+191
-42
@@ -1,47 +1,196 @@
|
||||
language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
# - clang
|
||||
# Make sure CMake is installed
|
||||
install:
|
||||
- sudo apt-get update >/dev/null
|
||||
- sudo apt-get -q install libprotoc-dev libprotobuf7 libprotobuf-dev libosmpbf-dev libbz2-dev libstxxl-dev libstxxl1 libxml2-dev libzip-dev libboost1.46-all-dev lua5.1 liblua5.1-0-dev libluabind-dev rubygems
|
||||
- curl -s https://gist.githubusercontent.com/DennisOSRM/803a64a9178ec375069f/raw/ | sudo bash
|
||||
before_script:
|
||||
- rvm use 1.9.3
|
||||
- gem install bundler
|
||||
- bundle install
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake .. $CMAKEOPTIONS
|
||||
script:
|
||||
- make -j 2
|
||||
- cd ..
|
||||
- cucumber -p verify
|
||||
after_script:
|
||||
# - cd ..
|
||||
# - cucumber -p verify
|
||||
|
||||
git:
|
||||
depth: 10
|
||||
|
||||
# sudo:required is needed for trusty images
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- develop
|
||||
cache:
|
||||
- bundler
|
||||
- apt
|
||||
env:
|
||||
- CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Release" OSRM_PORT=5000 OSRM_TIMEOUT=60
|
||||
- CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Debug" OSRM_PORT=5010 OSRM_TIMEOUT=60
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- irc.oftc.net#osrm
|
||||
on_success: change
|
||||
on_failure: always
|
||||
use_notice: true
|
||||
skip_join: false
|
||||
|
||||
recipients:
|
||||
- dennis@mapbox.com
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: always
|
||||
cache:
|
||||
ccache: true
|
||||
apt: true
|
||||
directories:
|
||||
- test/cache
|
||||
|
||||
env:
|
||||
global:
|
||||
- CCACHE_TEMPDIR=/tmp/.ccache-temp
|
||||
- CCACHE_COMPRESS=1
|
||||
- JOBS=4
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
# We override the compiler names here to yield better ccache behavior, which uses this as key
|
||||
include:
|
||||
|
||||
# Debug Builds
|
||||
- os: linux
|
||||
compiler: "gcc-5-debug"
|
||||
addons: &gcc5
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-5', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
|
||||
env: CCOMPILER='gcc-5' CXXCOMPILER='g++-5' BUILD_TYPE='Debug' COVERAGE=ON
|
||||
|
||||
- os: linux
|
||||
compiler: "gcc-4.8-debug"
|
||||
addons: &gcc48
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-4.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
|
||||
env: CCOMPILER='gcc-4.8' CXXCOMPILER='g++-4.8' BUILD_TYPE='Debug'
|
||||
|
||||
- os: linux
|
||||
compiler: "clang-3.8-debug"
|
||||
addons: &clang38
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['libstdc++-5-dev', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
|
||||
env: CLANG_VERSION='3.8.0' BUILD_TYPE='Debug' RUN_CLANG_FORMAT=ON
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode7.3
|
||||
compiler: clang
|
||||
env: CCOMPILER='clang' CXXCOMPILER='clang++' BUILD_TYPE='Debug' JOBS=1 CUCUMBER_TIMEOUT=60000
|
||||
|
||||
# Release Builds
|
||||
- os: linux
|
||||
compiler: "gcc-5-release"
|
||||
addons: &gcc5
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-5', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
|
||||
env: CCOMPILER='gcc-5' CXXCOMPILER='g++-5' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: "gcc-5-release-i686"
|
||||
env: TARGET_ARCH='i686' CCOMPILER='gcc-5' CXXCOMPILER='g++-5' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: "gcc-4.8-release-armhf"
|
||||
env: TARGET_ARCH='armhf' CCOMPILER='arm-linux-gnueabihf-gcc-4.8' CXXCOMPILER='arm-linux-gnueabihf-g++-4.8' BUILD_TYPE='Release'
|
||||
|
||||
# Disabled because of CI slowness
|
||||
#- os: linux
|
||||
#- compiler: gcc
|
||||
#- addons: &gcc48
|
||||
#- apt:
|
||||
#- sources: ['ubuntu-toolchain-r-test']
|
||||
#- packages: ['g++-4.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
|
||||
#- env: CCOMPILER='gcc-4.8' CXXCOMPILER='g++-4.8' BUILD_TYPE='Release'
|
||||
|
||||
# Disabled because of CI slowness
|
||||
#- os: linux
|
||||
#- compiler: clang
|
||||
#- addons: &clang38
|
||||
#- apt:
|
||||
#- sources: ['llvm-toolchain-precise-3.8', 'ubuntu-toolchain-r-test']
|
||||
#- packages: ['clang-3.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
|
||||
#- env: CCOMPILER='clang-3.8' CXXCOMPILER='clang++-3.8' BUILD_TYPE='Release'
|
||||
|
||||
# Disabled because of CI slowness
|
||||
#- os: osx
|
||||
#- osx_image: xcode7.3
|
||||
#- compiler: clang
|
||||
#- env: CCOMPILER='clang' CXXCOMPILER='clang++' BUILD_TYPE='Release'
|
||||
|
||||
# Shared Library
|
||||
- os: linux
|
||||
compiler: "gcc-5-release-shared"
|
||||
addons: &gcc5
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-5', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
|
||||
env: CCOMPILER='gcc-5' CXXCOMPILER='g++-5' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
|
||||
|
||||
# Disabled because CI slowness
|
||||
#- os: linux
|
||||
#- compiler: clang
|
||||
#- addons: &clang38
|
||||
#- apt:
|
||||
#- sources: ['llvm-toolchain-precise-3.8', 'ubuntu-toolchain-r-test']
|
||||
#- packages: ['clang-3.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
|
||||
#- env: CCOMPILER='clang-3.8' CXXCOMPILER='clang++-3.8' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
|
||||
|
||||
before_install:
|
||||
- if [[ ! -z $TARGET_ARCH ]] ; then source ./scripts/travis/before_install.$TARGET_ARCH.sh ; fi
|
||||
- if [[ $(uname -s) == 'Darwin' ]]; then sudo mdutil -i off /; fi;
|
||||
- source ./scripts/install_node.sh 4
|
||||
- npm install
|
||||
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
|
||||
- export PATH=${DEPS_DIR}/bin:${PATH} && mkdir -p ${DEPS_DIR}
|
||||
- CMAKE_URL="https://mason-binaries.s3.amazonaws.com/${TRAVIS_OS_NAME}-x86_64/cmake/3.5.2.tar.gz"
|
||||
- travis_retry wget --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C ${DEPS_DIR} || exit 1
|
||||
- |
|
||||
if [[ ${CLANG_VERSION:-false} != false ]]; then
|
||||
export CCOMPILER='clang'
|
||||
export CXXCOMPILER='clang++'
|
||||
CLANG_URL="https://mason-binaries.s3.amazonaws.com/${TRAVIS_OS_NAME}-x86_64/clang/${CLANG_VERSION}.tar.gz"
|
||||
travis_retry wget --quiet -O - ${CLANG_URL} | tar --strip-components=1 -xz -C ${DEPS_DIR} || exit 1
|
||||
fi
|
||||
- |
|
||||
if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
||||
# implicit deps, but seem to be installed by default with recent images: libxml2 GDAL boost
|
||||
brew install libzip libstxxl lua51 luabind tbb md5sha1sum ccache
|
||||
fi
|
||||
|
||||
install:
|
||||
- |
|
||||
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
|
||||
./scripts/check_taginfo.py taginfo.json profiles/car.lua
|
||||
fi
|
||||
- mkdir build && pushd build
|
||||
- export CC=${CCOMPILER} CXX=${CXXCOMPILER}
|
||||
- cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS:-OFF} -DCOVERAGE=${COVERAGE:-OFF} -DBUILD_TOOLS=1 -DENABLE_CCACHE=ON
|
||||
- echo "travis_fold:start:MAKE"
|
||||
- make osrm-extract --jobs=3
|
||||
- make --jobs=${JOBS}
|
||||
- make tests --jobs=${JOBS}
|
||||
- make benchmarks --jobs=${JOBS}
|
||||
- echo "travis_fold:end:MAKE"
|
||||
- ccache -s
|
||||
- sudo make install
|
||||
- |
|
||||
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
|
||||
sudo ldconfig
|
||||
fi
|
||||
- popd
|
||||
- mkdir example/build && pushd example/build
|
||||
- cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE}
|
||||
- make
|
||||
- popd
|
||||
|
||||
script:
|
||||
- if [[ $TARGET_ARCH == armhf ]] ; then echo "Skip tests for $TARGET_ARCH" && exit 0 ; fi
|
||||
- echo "travis_fold:start:BENCHMARK"
|
||||
- make -C test/data benchmark
|
||||
- echo "travis_fold:end:BENCHMARK"
|
||||
- ./example/build/osrm-example test/data/monaco.osrm
|
||||
# All tests assume to be run from the build directory
|
||||
- pushd build
|
||||
- ./unit_tests/library-tests ../test/data/monaco.osrm
|
||||
- ./unit_tests/extractor-tests
|
||||
- ./unit_tests/engine-tests
|
||||
- ./unit_tests/util-tests
|
||||
- ./unit_tests/server-tests
|
||||
- popd
|
||||
- npm test
|
||||
|
||||
after_success:
|
||||
- |
|
||||
if [ -n "${RUN_CLANG_FORMAT}" ]; then
|
||||
./scripts/format.sh # we don't want to fail just yet
|
||||
fi
|
||||
- |
|
||||
if [ -n "${COVERAGE}" ]; then
|
||||
bash <(curl -s https://codecov.io/bash)
|
||||
fi
|
||||
|
||||
@@ -1,198 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "DouglasPeucker.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../Util/MercatorUtil.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
//These thresholds are more or less heuristically chosen.
|
||||
static double DouglasPeuckerThresholds[19] = {
|
||||
262144., //z0
|
||||
131072., //z1
|
||||
65536., //z2
|
||||
32768., //z3
|
||||
16384., //z4
|
||||
8192., //z5
|
||||
4096., //z6
|
||||
2048., //z7
|
||||
960., //z8
|
||||
480., //z9
|
||||
240., //z10
|
||||
90., //z11
|
||||
50., //z12
|
||||
25., //z13
|
||||
15., //z14
|
||||
5., //z15
|
||||
.65, //z16
|
||||
.5, //z17
|
||||
.35 //z18
|
||||
};
|
||||
|
||||
/**
|
||||
* Yuck! Code duplication. This function is also in EgdeBasedNode.h
|
||||
*/
|
||||
double DouglasPeucker::ComputeDistance(
|
||||
const FixedPointCoordinate& point,
|
||||
const FixedPointCoordinate& segA,
|
||||
const FixedPointCoordinate& segB
|
||||
) const {
|
||||
const double x = lat2y(point.lat/COORDINATE_PRECISION);
|
||||
const double y = point.lon/COORDINATE_PRECISION;
|
||||
const double a = lat2y(segA.lat/COORDINATE_PRECISION);
|
||||
const double b = segA.lon/COORDINATE_PRECISION;
|
||||
const double c = lat2y(segB.lat/COORDINATE_PRECISION);
|
||||
const double d = segB.lon/COORDINATE_PRECISION;
|
||||
double p,q,nY;
|
||||
if( std::abs(a-c) > std::numeric_limits<double>::epsilon() ){
|
||||
const double m = (d-b)/(c-a); // slope
|
||||
// Projection of (x,y) on line joining (a,b) and (c,d)
|
||||
p = ((x + (m*y)) + (m*m*a - m*b))/(1. + m*m);
|
||||
q = b + m*(p - a);
|
||||
} else {
|
||||
p = c;
|
||||
q = y;
|
||||
}
|
||||
nY = (d*p - c*q)/(a*d - b*c);
|
||||
|
||||
//discretize the result to coordinate precision. it's a hack!
|
||||
if( std::abs(nY) < (1./COORDINATE_PRECISION) ) {
|
||||
nY = 0.;
|
||||
}
|
||||
|
||||
double r = (p - nY*a)/c;
|
||||
if( std::isnan(r) ) {
|
||||
r = ((segB.lat == point.lat) && (segB.lon == point.lon)) ? 1. : 0.;
|
||||
} else if( std::abs(r) <= std::numeric_limits<double>::epsilon() ) {
|
||||
r = 0.;
|
||||
} else if( std::abs(r-1.) <= std::numeric_limits<double>::epsilon() ) {
|
||||
r = 1.;
|
||||
}
|
||||
FixedPointCoordinate nearest_location;
|
||||
BOOST_ASSERT( !std::isnan(r) );
|
||||
if( r <= 0. ){
|
||||
nearest_location.lat = segA.lat;
|
||||
nearest_location.lon = segA.lon;
|
||||
} else if( r >= 1. ){
|
||||
nearest_location.lat = segB.lat;
|
||||
nearest_location.lon = segB.lon;
|
||||
} else { // point lies in between
|
||||
nearest_location.lat = y2lat(p)*COORDINATE_PRECISION;
|
||||
nearest_location.lon = q*COORDINATE_PRECISION;
|
||||
}
|
||||
BOOST_ASSERT( nearest_location.isValid() );
|
||||
const double approximated_distance = FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
point,
|
||||
nearest_location
|
||||
);
|
||||
BOOST_ASSERT( 0. <= approximated_distance );
|
||||
return approximated_distance;
|
||||
}
|
||||
|
||||
void DouglasPeucker::Run(
|
||||
std::vector<SegmentInformation> & input_geometry,
|
||||
const unsigned zoom_level
|
||||
) {
|
||||
{
|
||||
BOOST_ASSERT_MSG(zoom_level < 19, "unsupported zoom level");
|
||||
BOOST_ASSERT_MSG(1 < input_geometry.size(), "geometry invalid");
|
||||
std::size_t left_border = 0;
|
||||
std::size_t right_border = 1;
|
||||
//Sweep over array and identify those ranges that need to be checked
|
||||
do {
|
||||
BOOST_ASSERT_MSG(
|
||||
input_geometry[left_border].necessary,
|
||||
"left border must be necessary"
|
||||
);
|
||||
BOOST_ASSERT_MSG(
|
||||
input_geometry.back().necessary,
|
||||
"right border must be necessary"
|
||||
);
|
||||
|
||||
if(input_geometry[right_border].necessary) {
|
||||
recursion_stack.push(std::make_pair(left_border, right_border));
|
||||
left_border = right_border;
|
||||
}
|
||||
++right_border;
|
||||
} while( right_border < input_geometry.size());
|
||||
}
|
||||
while( !recursion_stack.empty() ) {
|
||||
//pop next element
|
||||
const PairOfPoints pair = recursion_stack.top();
|
||||
recursion_stack.pop();
|
||||
BOOST_ASSERT_MSG(
|
||||
input_geometry[pair.first].necessary,
|
||||
"left border mus be necessary"
|
||||
);
|
||||
BOOST_ASSERT_MSG(
|
||||
input_geometry[pair.second].necessary,
|
||||
"right border must be necessary"
|
||||
);
|
||||
BOOST_ASSERT_MSG(
|
||||
pair.second < input_geometry.size(),
|
||||
"right border outside of geometry"
|
||||
);
|
||||
BOOST_ASSERT_MSG(
|
||||
pair.first < pair.second,
|
||||
"left border on the wrong side"
|
||||
);
|
||||
double max_distance = std::numeric_limits<double>::min();
|
||||
|
||||
std::size_t farthest_element_index = pair.second;
|
||||
//find index idx of element with max_distance
|
||||
for(std::size_t i = pair.first+1; i < pair.second; ++i){
|
||||
const int temp_dist = ComputeDistance(
|
||||
input_geometry[i].location,
|
||||
input_geometry[pair.first].location,
|
||||
input_geometry[pair.second].location
|
||||
);
|
||||
const double distance = std::abs(temp_dist);
|
||||
if(
|
||||
distance > DouglasPeuckerThresholds[zoom_level] &&
|
||||
distance > max_distance
|
||||
) {
|
||||
farthest_element_index = i;
|
||||
max_distance = distance;
|
||||
}
|
||||
}
|
||||
if (max_distance > DouglasPeuckerThresholds[zoom_level]) {
|
||||
// mark idx as necessary
|
||||
input_geometry[farthest_element_index].necessary = true;
|
||||
if (1 < (farthest_element_index - pair.first) ) {
|
||||
recursion_stack.push(
|
||||
std::make_pair(pair.first, farthest_element_index)
|
||||
);
|
||||
}
|
||||
if (1 < (pair.second - farthest_element_index) ) {
|
||||
recursion_stack.push(
|
||||
std::make_pair(farthest_element_index, pair.second)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DOUGLASPEUCKER_H_
|
||||
#define DOUGLASPEUCKER_H_
|
||||
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <limits>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
/* This class object computes the bitvector of indicating generalized input
|
||||
* points according to the (Ramer-)Douglas-Peucker algorithm.
|
||||
*
|
||||
* Input is vector of pairs. Each pair consists of the point information and a
|
||||
* bit indicating if the points is present in the generalization.
|
||||
* Note: points may also be pre-selected*/
|
||||
|
||||
struct SegmentInformation;
|
||||
|
||||
class DouglasPeucker {
|
||||
private:
|
||||
typedef std::pair<std::size_t, std::size_t> PairOfPoints;
|
||||
//Stack to simulate the recursion
|
||||
std::stack<PairOfPoints> recursion_stack;
|
||||
|
||||
double ComputeDistance(
|
||||
const FixedPointCoordinate& point,
|
||||
const FixedPointCoordinate& segA,
|
||||
const FixedPointCoordinate& segB
|
||||
) const;
|
||||
public:
|
||||
void Run(
|
||||
std::vector<SegmentInformation> & input_geometry,
|
||||
const unsigned zoom_level
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
#endif /* DOUGLASPEUCKER_H_ */
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ITERATOR_BASED_CRC32_H
|
||||
#define ITERATOR_BASED_CRC32_H
|
||||
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#include <cpuid.h>
|
||||
#else
|
||||
#include <boost/crc.hpp> // for boost::crc_32_type
|
||||
|
||||
inline void __get_cpuid(
|
||||
int param,
|
||||
unsigned *eax,
|
||||
unsigned *ebx,
|
||||
unsigned *ecx,
|
||||
unsigned *edx
|
||||
) { *ecx = 0; }
|
||||
#endif
|
||||
|
||||
template<class ContainerT>
|
||||
class IteratorbasedCRC32 {
|
||||
private:
|
||||
typedef typename ContainerT::iterator IteratorType;
|
||||
unsigned crc;
|
||||
|
||||
bool use_SSE42_CRC_function;
|
||||
|
||||
#if !defined(__x86_64__)
|
||||
boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> CRC32_processor;
|
||||
#endif
|
||||
unsigned SoftwareBasedCRC32( char *str, unsigned len )
|
||||
{
|
||||
#if !defined(__x86_64__)
|
||||
CRC32_processor.process_bytes( str, len);
|
||||
return CRC32_processor.checksum();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// adapted from http://byteworm.com/2010/10/13/crc32/
|
||||
unsigned SSE42BasedCRC32( char *str, unsigned len )
|
||||
{
|
||||
#if defined(__x86_64__)
|
||||
unsigned q = len/sizeof(unsigned);
|
||||
unsigned r = len%sizeof(unsigned);
|
||||
unsigned *p = (unsigned*)str;
|
||||
|
||||
//crc=0;
|
||||
while (q--) {
|
||||
__asm__ __volatile__(
|
||||
".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
|
||||
:"=S"(crc)
|
||||
:"0"(crc), "c"(*p)
|
||||
);
|
||||
++p;
|
||||
}
|
||||
|
||||
str=(char*)p;
|
||||
while (r--) {
|
||||
__asm__ __volatile__(
|
||||
".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
|
||||
:"=S"(crc)
|
||||
:"0"(crc), "c"(*str)
|
||||
);
|
||||
++str;
|
||||
}
|
||||
#endif
|
||||
return crc;
|
||||
}
|
||||
|
||||
inline unsigned cpuid() const
|
||||
{
|
||||
unsigned eax = 0, ebx = 0, ecx = 0, edx = 0;
|
||||
// on X64 this calls hardware cpuid(.) instr. otherwise a dummy impl.
|
||||
__get_cpuid( 1, &eax, &ebx, &ecx, &edx );
|
||||
return ecx;
|
||||
}
|
||||
|
||||
bool DetectNativeCRC32Support()
|
||||
{
|
||||
static const int SSE42_BIT = 0x00100000;
|
||||
const unsigned ecx = cpuid();
|
||||
const bool has_SSE42 = ecx & SSE42_BIT;
|
||||
if (has_SSE42) {
|
||||
SimpleLogger().Write() << "using hardware based CRC32 computation";
|
||||
} else {
|
||||
SimpleLogger().Write() << "using software based CRC32 computation";
|
||||
}
|
||||
return has_SSE42;
|
||||
}
|
||||
|
||||
public:
|
||||
IteratorbasedCRC32() : crc(0)
|
||||
{
|
||||
use_SSE42_CRC_function = DetectNativeCRC32Support();
|
||||
}
|
||||
|
||||
unsigned operator()( IteratorType iter, const IteratorType end )
|
||||
{
|
||||
unsigned crc = 0;
|
||||
while(iter != end) {
|
||||
char * data = reinterpret_cast<char*>(&(*iter) );
|
||||
|
||||
if (use_SSE42_CRC_function)
|
||||
{
|
||||
crc = SSE42BasedCRC32( data, sizeof(typename ContainerT::value_type) );
|
||||
}
|
||||
else
|
||||
{
|
||||
crc = SoftwareBasedCRC32( data, sizeof(typename ContainerT::value_type) );
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* ITERATOR_BASED_CRC32_H */
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OBJECTTOBASE64_H_
|
||||
#define OBJECTTOBASE64_H_
|
||||
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/archive/iterators/base64_from_binary.hpp>
|
||||
#include <boost/archive/iterators/binary_from_base64.hpp>
|
||||
#include <boost/archive/iterators/transform_width.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
typedef
|
||||
boost::archive::iterators::base64_from_binary<
|
||||
boost::archive::iterators::transform_width<const char *, 6, 8>
|
||||
> base64_t;
|
||||
|
||||
typedef
|
||||
boost::archive::iterators::transform_width<
|
||||
boost::archive::iterators::binary_from_base64<
|
||||
std::string::const_iterator>, 8, 6
|
||||
> binary_t;
|
||||
|
||||
template<class ObjectT>
|
||||
static void EncodeObjectToBase64(const ObjectT & object, std::string& encoded) {
|
||||
const char * char_ptr_to_object = (const char *)&object;
|
||||
std::vector<unsigned char> data(sizeof(object));
|
||||
std::copy(
|
||||
char_ptr_to_object,
|
||||
char_ptr_to_object + sizeof(ObjectT),
|
||||
data.begin()
|
||||
);
|
||||
|
||||
unsigned char number_of_padded_chars = 0; // is in {0,1,2};
|
||||
while(data.size() % 3 != 0) {
|
||||
++number_of_padded_chars;
|
||||
data.push_back(0x00);
|
||||
}
|
||||
|
||||
BOOST_ASSERT_MSG(
|
||||
0 == data.size() % 3,
|
||||
"base64 input data size is not a multiple of 3!"
|
||||
);
|
||||
encoded.resize(sizeof(ObjectT));
|
||||
encoded.assign(
|
||||
base64_t( &data[0] ),
|
||||
base64_t( &data[0] + (data.size() - number_of_padded_chars) )
|
||||
);
|
||||
replaceAll(encoded, "+", "-");
|
||||
replaceAll(encoded, "/", "_");
|
||||
}
|
||||
|
||||
template<class ObjectT>
|
||||
static void DecodeObjectFromBase64(const std::string& input, ObjectT & object) {
|
||||
try {
|
||||
std::string encoded(input);
|
||||
//replace "-" with "+" and "_" with "/"
|
||||
replaceAll(encoded, "-", "+");
|
||||
replaceAll(encoded, "_", "/");
|
||||
|
||||
std::copy (
|
||||
binary_t( encoded.begin() ),
|
||||
binary_t( encoded.begin() + encoded.length() - 1),
|
||||
(char *)&object
|
||||
);
|
||||
|
||||
} catch(...) { }
|
||||
}
|
||||
|
||||
#endif /* OBJECTTOBASE64_H_ */
|
||||
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "PolylineCompressor.h"
|
||||
|
||||
void PolylineCompressor::encodeVectorSignedNumber(
|
||||
std::vector<int> & numbers,
|
||||
std::string & output
|
||||
) const {
|
||||
for(unsigned i = 0; i < numbers.size(); ++i) {
|
||||
numbers[i] <<= 1;
|
||||
if (numbers[i] < 0) {
|
||||
numbers[i] = ~(numbers[i]);
|
||||
}
|
||||
}
|
||||
for(unsigned i = 0; i < numbers.size(); ++i) {
|
||||
encodeNumber(numbers[i], output);
|
||||
}
|
||||
}
|
||||
|
||||
void PolylineCompressor::encodeNumber(int number_to_encode, std::string & output) const {
|
||||
while (number_to_encode >= 0x20) {
|
||||
int nextValue = (0x20 | (number_to_encode & 0x1f)) + 63;
|
||||
output += static_cast<char>(nextValue);
|
||||
if(92 == nextValue) {
|
||||
output += static_cast<char>(nextValue);
|
||||
}
|
||||
number_to_encode >>= 5;
|
||||
}
|
||||
|
||||
number_to_encode += 63;
|
||||
output += static_cast<char>(number_to_encode);
|
||||
if(92 == number_to_encode) {
|
||||
output += static_cast<char>(number_to_encode);
|
||||
}
|
||||
}
|
||||
|
||||
void PolylineCompressor::printEncodedString(
|
||||
const std::vector<SegmentInformation> & polyline,
|
||||
std::string & output
|
||||
) const {
|
||||
std::vector<int> deltaNumbers;
|
||||
output += "\"";
|
||||
if(!polyline.empty()) {
|
||||
FixedPointCoordinate lastCoordinate = polyline[0].location;
|
||||
deltaNumbers.push_back( lastCoordinate.lat );
|
||||
deltaNumbers.push_back( lastCoordinate.lon );
|
||||
for(unsigned i = 1; i < polyline.size(); ++i) {
|
||||
if(!polyline[i].necessary) {
|
||||
continue;
|
||||
}
|
||||
deltaNumbers.push_back(polyline[i].location.lat - lastCoordinate.lat);
|
||||
deltaNumbers.push_back(polyline[i].location.lon - lastCoordinate.lon);
|
||||
lastCoordinate = polyline[i].location;
|
||||
}
|
||||
encodeVectorSignedNumber(deltaNumbers, output);
|
||||
}
|
||||
output += "\"";
|
||||
|
||||
}
|
||||
|
||||
void PolylineCompressor::printEncodedString(
|
||||
const std::vector<FixedPointCoordinate>& polyline,
|
||||
std::string &output
|
||||
) const {
|
||||
std::vector<int> deltaNumbers(2*polyline.size());
|
||||
output += "\"";
|
||||
if(!polyline.empty()) {
|
||||
deltaNumbers[0] = polyline[0].lat;
|
||||
deltaNumbers[1] = polyline[0].lon;
|
||||
for(unsigned i = 1; i < polyline.size(); ++i) {
|
||||
deltaNumbers[(2*i)] = (polyline[i].lat - polyline[i-1].lat);
|
||||
deltaNumbers[(2*i)+1] = (polyline[i].lon - polyline[i-1].lon);
|
||||
}
|
||||
encodeVectorSignedNumber(deltaNumbers, output);
|
||||
}
|
||||
output += "\"";
|
||||
}
|
||||
|
||||
void PolylineCompressor::printUnencodedString(
|
||||
const std::vector<FixedPointCoordinate> & polyline,
|
||||
std::string & output
|
||||
) const {
|
||||
output += "[";
|
||||
std::string tmp;
|
||||
for(unsigned i = 0; i < polyline.size(); i++) {
|
||||
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].lat, tmp);
|
||||
output += "[";
|
||||
output += tmp;
|
||||
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].lon, tmp);
|
||||
output += ", ";
|
||||
output += tmp;
|
||||
output += "]";
|
||||
if( i < polyline.size()-1 ) {
|
||||
output += ",";
|
||||
}
|
||||
}
|
||||
output += "]";
|
||||
}
|
||||
|
||||
void PolylineCompressor::printUnencodedString(
|
||||
const std::vector<SegmentInformation> & polyline,
|
||||
std::string & output
|
||||
) const {
|
||||
output += "[";
|
||||
std::string tmp;
|
||||
for(unsigned i = 0; i < polyline.size(); i++) {
|
||||
if(!polyline[i].necessary) {
|
||||
continue;
|
||||
}
|
||||
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].location.lat, tmp);
|
||||
output += "[";
|
||||
output += tmp;
|
||||
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].location.lon, tmp);
|
||||
output += ", ";
|
||||
output += tmp;
|
||||
output += "]";
|
||||
if( i < polyline.size()-1 ) {
|
||||
output += ",";
|
||||
}
|
||||
}
|
||||
output += "]";
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef POLYLINECOMPRESSOR_H_
|
||||
#define POLYLINECOMPRESSOR_H_
|
||||
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class PolylineCompressor {
|
||||
private:
|
||||
void encodeVectorSignedNumber(
|
||||
std::vector<int> & numbers,
|
||||
std::string & output
|
||||
) const;
|
||||
|
||||
void encodeNumber(int number_to_encode, std::string & output) const;
|
||||
|
||||
public:
|
||||
void printEncodedString(
|
||||
const std::vector<SegmentInformation> & polyline,
|
||||
std::string & output
|
||||
) const;
|
||||
|
||||
void printEncodedString(
|
||||
const std::vector<FixedPointCoordinate>& polyline,
|
||||
std::string &output
|
||||
) const;
|
||||
|
||||
void printUnencodedString(
|
||||
const std::vector<FixedPointCoordinate> & polyline,
|
||||
std::string & output
|
||||
) const;
|
||||
|
||||
void printUnencodedString(
|
||||
const std::vector<SegmentInformation> & polyline,
|
||||
std::string & output
|
||||
) const;
|
||||
|
||||
};
|
||||
|
||||
#endif /* POLYLINECOMPRESSOR_H_ */
|
||||
@@ -1,502 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef STRONGLYCONNECTEDCOMPONENTS_H_
|
||||
#define STRONGLYCONNECTEDCOMPONENTS_H_
|
||||
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
#include "../DataStructures/DynamicGraph.h"
|
||||
#include "../DataStructures/ImportEdge.h"
|
||||
#include "../DataStructures/QueryNode.h"
|
||||
#include "../DataStructures/Percent.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/integer.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <gdal.h>
|
||||
#include <ogrsf_frmts.h>
|
||||
#else
|
||||
#include <gdal/gdal.h>
|
||||
#include <gdal/ogrsf_frmts.h>
|
||||
#endif
|
||||
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
class TarjanSCC {
|
||||
private:
|
||||
|
||||
struct TarjanNode {
|
||||
TarjanNode() : index(UINT_MAX), lowlink(UINT_MAX), onStack(false) {}
|
||||
unsigned index;
|
||||
unsigned lowlink;
|
||||
bool onStack;
|
||||
};
|
||||
|
||||
struct TarjanEdgeData {
|
||||
int distance;
|
||||
unsigned nameID:31;
|
||||
bool shortcut:1;
|
||||
short type;
|
||||
bool isAccessRestricted:1;
|
||||
bool forward:1;
|
||||
bool backward:1;
|
||||
bool roundabout:1;
|
||||
bool ignoreInGrid:1;
|
||||
bool reversedEdge:1;
|
||||
};
|
||||
|
||||
struct TarjanStackFrame {
|
||||
explicit TarjanStackFrame(
|
||||
NodeID v,
|
||||
NodeID parent
|
||||
) : v(v), parent(parent) { }
|
||||
NodeID v;
|
||||
NodeID parent;
|
||||
};
|
||||
|
||||
typedef DynamicGraph<TarjanEdgeData> TarjanDynamicGraph;
|
||||
typedef TarjanDynamicGraph::InputEdge TarjanEdge;
|
||||
typedef std::pair<NodeID, NodeID> RestrictionSource;
|
||||
typedef std::pair<NodeID, bool> restriction_target;
|
||||
typedef std::vector<restriction_target> EmanatingRestrictionsVector;
|
||||
typedef boost::unordered_map<RestrictionSource, unsigned> RestrictionMap;
|
||||
|
||||
std::vector<NodeInfo> m_coordinate_list;
|
||||
std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list;
|
||||
boost::shared_ptr<TarjanDynamicGraph> m_node_based_graph;
|
||||
boost::unordered_set<NodeID> m_barrier_node_list;
|
||||
boost::unordered_set<NodeID> m_traffic_light_list;
|
||||
unsigned m_restriction_counter;
|
||||
RestrictionMap m_restriction_map;
|
||||
|
||||
struct EdgeBasedNode {
|
||||
bool operator<(const EdgeBasedNode & other) const {
|
||||
return other.id < id;
|
||||
}
|
||||
bool operator==(const EdgeBasedNode & other) const {
|
||||
return id == other.id;
|
||||
}
|
||||
NodeID id;
|
||||
int lat1;
|
||||
int lat2;
|
||||
int lon1;
|
||||
int lon2:31;
|
||||
bool belongsToTinyComponent:1;
|
||||
NodeID nameID;
|
||||
unsigned weight:31;
|
||||
bool ignoreInGrid:1;
|
||||
};
|
||||
|
||||
public:
|
||||
TarjanSCC(
|
||||
int number_of_nodes,
|
||||
std::vector<NodeBasedEdge> & input_edges,
|
||||
std::vector<NodeID> & bn,
|
||||
std::vector<NodeID> & tl,
|
||||
std::vector<TurnRestriction> & irs,
|
||||
std::vector<NodeInfo> & nI
|
||||
) :
|
||||
m_coordinate_list(nI),
|
||||
m_restriction_counter(irs.size())
|
||||
{
|
||||
BOOST_FOREACH(const TurnRestriction & restriction, irs) {
|
||||
std::pair<NodeID, NodeID> restrictionSource = std::make_pair(
|
||||
restriction.fromNode, restriction.viaNode
|
||||
);
|
||||
unsigned index;
|
||||
RestrictionMap::iterator restriction_iterator = m_restriction_map.find(restrictionSource);
|
||||
if(restriction_iterator == m_restriction_map.end()) {
|
||||
index = m_restriction_bucket_list.size();
|
||||
m_restriction_bucket_list.resize(index+1);
|
||||
m_restriction_map.insert(std::make_pair(restrictionSource, index));
|
||||
} else {
|
||||
index = restriction_iterator->second;
|
||||
//Map already contains an is_only_*-restriction
|
||||
if(m_restriction_bucket_list.at(index).begin()->second) {
|
||||
continue;
|
||||
} else if(restriction.flags.isOnly) {
|
||||
//We are going to insert an is_only_*-restriction. There can be only one.
|
||||
m_restriction_bucket_list.at(index).clear();
|
||||
}
|
||||
}
|
||||
|
||||
m_restriction_bucket_list.at(index).push_back(
|
||||
std::make_pair(restriction.toNode, restriction.flags.isOnly)
|
||||
);
|
||||
}
|
||||
|
||||
m_barrier_node_list.insert(bn.begin(), bn.end());
|
||||
m_traffic_light_list.insert(tl.begin(), tl.end());
|
||||
|
||||
DeallocatingVector< TarjanEdge > edge_list;
|
||||
BOOST_FOREACH(const NodeBasedEdge & input_edge, input_edges) {
|
||||
TarjanEdge edge;
|
||||
if(!input_edge.isForward()) {
|
||||
edge.source = input_edge.target();
|
||||
edge.target = input_edge.source();
|
||||
edge.data.backward = input_edge.isForward();
|
||||
edge.data.forward = input_edge.isBackward();
|
||||
} else {
|
||||
edge.source = input_edge.source();
|
||||
edge.target = input_edge.target();
|
||||
edge.data.forward = input_edge.isForward();
|
||||
edge.data.backward = input_edge.isBackward();
|
||||
}
|
||||
if(edge.source == edge.target) {
|
||||
continue;
|
||||
}
|
||||
|
||||
edge.data.distance = (std::max)((int)input_edge.weight(), 1 );
|
||||
BOOST_ASSERT( edge.data.distance > 0 );
|
||||
edge.data.shortcut = false;
|
||||
edge.data.roundabout = input_edge.isRoundabout();
|
||||
edge.data.ignoreInGrid = input_edge.ignoreInGrid();
|
||||
edge.data.nameID = input_edge.name();
|
||||
edge.data.type = input_edge.type();
|
||||
edge.data.isAccessRestricted = input_edge.isAccessRestricted();
|
||||
edge.data.reversedEdge = false;
|
||||
edge_list.push_back( edge );
|
||||
if( edge.data.backward ) {
|
||||
std::swap( edge.source, edge.target );
|
||||
edge.data.forward = input_edge.isBackward();
|
||||
edge.data.backward = input_edge.isForward();
|
||||
edge.data.reversedEdge = true;
|
||||
edge_list.push_back( edge );
|
||||
}
|
||||
}
|
||||
std::vector<NodeBasedEdge>().swap(input_edges);
|
||||
BOOST_ASSERT_MSG(
|
||||
0 == input_edges.size() && 0 == input_edges.capacity(),
|
||||
"input edge vector not properly deallocated"
|
||||
);
|
||||
|
||||
std::sort( edge_list.begin(), edge_list.end() );
|
||||
|
||||
m_node_based_graph = boost::make_shared<TarjanDynamicGraph>(
|
||||
number_of_nodes,
|
||||
edge_list
|
||||
);
|
||||
}
|
||||
|
||||
~TarjanSCC() {
|
||||
m_node_based_graph.reset();
|
||||
}
|
||||
|
||||
void Run() {
|
||||
//remove files from previous run if exist
|
||||
DeleteFileIfExists("component.dbf");
|
||||
DeleteFileIfExists("component.shx");
|
||||
DeleteFileIfExists("component.shp");
|
||||
|
||||
Percent p(m_node_based_graph->GetNumberOfNodes());
|
||||
|
||||
OGRRegisterAll();
|
||||
|
||||
const char *pszDriverName = "ESRI Shapefile";
|
||||
OGRSFDriver * poDriver = OGRSFDriverRegistrar::GetRegistrar()->
|
||||
GetDriverByName( pszDriverName );
|
||||
if( NULL == poDriver ) {
|
||||
throw OSRMException("ESRI Shapefile driver not available");
|
||||
}
|
||||
OGRDataSource * poDS = poDriver->CreateDataSource(
|
||||
"component.shp",
|
||||
NULL
|
||||
);
|
||||
|
||||
if( NULL == poDS ) {
|
||||
throw OSRMException("Creation of output file failed");
|
||||
}
|
||||
|
||||
OGRLayer * poLayer = poDS->CreateLayer(
|
||||
"component",
|
||||
NULL,
|
||||
wkbLineString,
|
||||
NULL
|
||||
);
|
||||
|
||||
if( NULL == poLayer ) {
|
||||
throw OSRMException("Layer creation failed.");
|
||||
}
|
||||
|
||||
//The following is a hack to distinguish between stuff that happens
|
||||
//before the recursive call and stuff that happens after
|
||||
std::stack<std::pair<bool, TarjanStackFrame> > recursion_stack;
|
||||
//true = stuff before, false = stuff after call
|
||||
std::stack<NodeID> tarjan_stack;
|
||||
std::vector<unsigned> components_index(
|
||||
m_node_based_graph->GetNumberOfNodes(),
|
||||
UINT_MAX
|
||||
);
|
||||
std::vector<NodeID> component_size_vector;
|
||||
std::vector<TarjanNode> tarjan_node_list(
|
||||
m_node_based_graph->GetNumberOfNodes()
|
||||
);
|
||||
unsigned component_index = 0, size_of_current_component = 0;
|
||||
int index = 0;
|
||||
for(
|
||||
NodeID node = 0, last_node = m_node_based_graph->GetNumberOfNodes();
|
||||
node < last_node;
|
||||
++node
|
||||
) {
|
||||
if(UINT_MAX == components_index[node]) {
|
||||
recursion_stack.push(
|
||||
std::make_pair(true, TarjanStackFrame(node,node))
|
||||
);
|
||||
}
|
||||
|
||||
while(!recursion_stack.empty()) {
|
||||
bool before_recursion = recursion_stack.top().first;
|
||||
TarjanStackFrame currentFrame = recursion_stack.top().second;
|
||||
NodeID v = currentFrame.v;
|
||||
recursion_stack.pop();
|
||||
|
||||
if(before_recursion) {
|
||||
//Mark frame to handle tail of recursion
|
||||
recursion_stack.push(std::make_pair(false, currentFrame));
|
||||
|
||||
//Mark essential information for SCC
|
||||
tarjan_node_list[v].index = index;
|
||||
tarjan_node_list[v].lowlink = index;
|
||||
tarjan_stack.push(v);
|
||||
tarjan_node_list[v].onStack = true;
|
||||
++index;
|
||||
|
||||
//Traverse outgoing edges
|
||||
for(
|
||||
TarjanDynamicGraph::EdgeIterator e2 = m_node_based_graph->BeginEdges(v);
|
||||
e2 < m_node_based_graph->EndEdges(v);
|
||||
++e2
|
||||
) {
|
||||
const TarjanDynamicGraph::NodeIterator vprime =
|
||||
m_node_based_graph->GetTarget(e2);
|
||||
if(UINT_MAX == tarjan_node_list[vprime].index) {
|
||||
recursion_stack.push(
|
||||
std::make_pair(
|
||||
true,
|
||||
TarjanStackFrame(vprime, v)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
if(
|
||||
tarjan_node_list[vprime].onStack &&
|
||||
tarjan_node_list[vprime].index < tarjan_node_list[v].lowlink
|
||||
) {
|
||||
tarjan_node_list[v].lowlink = tarjan_node_list[vprime].index;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tarjan_node_list[currentFrame.parent].lowlink =
|
||||
std::min(
|
||||
tarjan_node_list[currentFrame.parent].lowlink,
|
||||
tarjan_node_list[v].lowlink
|
||||
);
|
||||
//after recursion, lets do cycle checking
|
||||
//Check if we found a cycle. This is the bottom part of the recursion
|
||||
if(tarjan_node_list[v].lowlink == tarjan_node_list[v].index) {
|
||||
NodeID vprime;
|
||||
do {
|
||||
vprime = tarjan_stack.top(); tarjan_stack.pop();
|
||||
tarjan_node_list[vprime].onStack = false;
|
||||
components_index[vprime] = component_index;
|
||||
++size_of_current_component;
|
||||
} while( v != vprime);
|
||||
|
||||
component_size_vector.push_back(size_of_current_component);
|
||||
|
||||
if(size_of_current_component > 1000) {
|
||||
SimpleLogger().Write() <<
|
||||
"large component [" << component_index << "]=" <<
|
||||
size_of_current_component;
|
||||
}
|
||||
|
||||
++component_index;
|
||||
size_of_current_component = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SimpleLogger().Write() <<
|
||||
"identified: " << component_size_vector.size() <<
|
||||
" many components, marking small components";
|
||||
|
||||
// TODO/C++11: prime candidate for lambda function
|
||||
unsigned size_one_counter = 0;
|
||||
for(unsigned i = 0, end = component_size_vector.size(); i < end; ++i){
|
||||
if(1 == component_size_vector[i]) {
|
||||
++size_one_counter;
|
||||
}
|
||||
}
|
||||
|
||||
SimpleLogger().Write() <<
|
||||
"identified " << size_one_counter << " SCCs of size 1";
|
||||
|
||||
uint64_t total_network_distance = 0;
|
||||
p.reinit(m_node_based_graph->GetNumberOfNodes());
|
||||
for(
|
||||
TarjanDynamicGraph::NodeIterator u = 0, last_u_node = m_node_based_graph->GetNumberOfNodes();
|
||||
u < last_u_node;
|
||||
++u
|
||||
) {
|
||||
p.printIncrement();
|
||||
for(
|
||||
TarjanDynamicGraph::EdgeIterator e1 = m_node_based_graph->BeginEdges(u), last_edge = m_node_based_graph->EndEdges(u);
|
||||
e1 < last_edge;
|
||||
++e1
|
||||
) {
|
||||
if(!m_node_based_graph->GetEdgeData(e1).reversedEdge) {
|
||||
continue;
|
||||
}
|
||||
const TarjanDynamicGraph::NodeIterator v = m_node_based_graph->GetTarget(e1);
|
||||
|
||||
total_network_distance += 100*FixedPointCoordinate::ApproximateDistance(
|
||||
m_coordinate_list[u].lat,
|
||||
m_coordinate_list[u].lon,
|
||||
m_coordinate_list[v].lat,
|
||||
m_coordinate_list[v].lon
|
||||
);
|
||||
|
||||
if( SHRT_MAX != m_node_based_graph->GetEdgeData(e1).type ) {
|
||||
BOOST_ASSERT(e1 != UINT_MAX);
|
||||
BOOST_ASSERT(u != UINT_MAX);
|
||||
BOOST_ASSERT(v != UINT_MAX);
|
||||
|
||||
const unsigned size_of_containing_component =
|
||||
std::min(
|
||||
component_size_vector[components_index[u]],
|
||||
component_size_vector[components_index[v]]
|
||||
);
|
||||
|
||||
//edges that end on bollard nodes may actually be in two distinct components
|
||||
if(size_of_containing_component < 10) {
|
||||
OGRLineString lineString;
|
||||
lineString.addPoint(
|
||||
m_coordinate_list[u].lon/COORDINATE_PRECISION,
|
||||
m_coordinate_list[u].lat/COORDINATE_PRECISION
|
||||
);
|
||||
lineString.addPoint(
|
||||
m_coordinate_list[v].lon/COORDINATE_PRECISION,
|
||||
m_coordinate_list[v].lat/COORDINATE_PRECISION
|
||||
);
|
||||
|
||||
OGRFeature * poFeature = OGRFeature::CreateFeature(
|
||||
poLayer->GetLayerDefn()
|
||||
);
|
||||
|
||||
poFeature->SetGeometry( &lineString );
|
||||
if( OGRERR_NONE != poLayer->CreateFeature(poFeature) ) {
|
||||
throw OSRMException(
|
||||
"Failed to create feature in shapefile."
|
||||
);
|
||||
}
|
||||
OGRFeature::DestroyFeature( poFeature );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
OGRDataSource::DestroyDataSource( poDS );
|
||||
std::vector<NodeID>().swap(component_size_vector);
|
||||
BOOST_ASSERT_MSG(
|
||||
0 == component_size_vector.size() &&
|
||||
0 == component_size_vector.capacity(),
|
||||
"component_size_vector not properly deallocated"
|
||||
);
|
||||
|
||||
std::vector<NodeID>().swap(components_index);
|
||||
BOOST_ASSERT_MSG(
|
||||
0 == components_index.size() && 0 == components_index.capacity(),
|
||||
"icomponents_index not properly deallocated"
|
||||
);
|
||||
|
||||
SimpleLogger().Write()
|
||||
<< "total network distance: " <<
|
||||
(uint64_t)total_network_distance/100/1000. <<
|
||||
" km";
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const {
|
||||
std::pair < NodeID, NodeID > restriction_source = std::make_pair(u, v);
|
||||
RestrictionMap::const_iterator restriction_iterator = m_restriction_map.find(restriction_source);
|
||||
if (restriction_iterator != m_restriction_map.end()) {
|
||||
const unsigned index = restriction_iterator->second;
|
||||
BOOST_FOREACH(
|
||||
const RestrictionSource & restriction_target,
|
||||
m_restriction_bucket_list.at(index)
|
||||
) {
|
||||
if(restriction_target.second) {
|
||||
return restriction_target.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
bool CheckIfTurnIsRestricted(
|
||||
const NodeID u,
|
||||
const NodeID v,
|
||||
const NodeID w
|
||||
) const {
|
||||
//only add an edge if turn is not a U-turn except it is the end of dead-end street.
|
||||
std::pair < NodeID, NodeID > restriction_source = std::make_pair(u, v);
|
||||
RestrictionMap::const_iterator restriction_iterator = m_restriction_map.find(restriction_source);
|
||||
if (restriction_iterator != m_restriction_map.end()) {
|
||||
const unsigned index = restriction_iterator->second;
|
||||
BOOST_FOREACH(
|
||||
const restriction_target & restriction_target,
|
||||
m_restriction_bucket_list.at(index)
|
||||
) {
|
||||
if(w == restriction_target.first) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeleteFileIfExists(const std::string & file_name) const {
|
||||
if (boost::filesystem::exists(file_name) ) {
|
||||
boost::filesystem::remove(file_name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* STRONGLYCONNECTEDCOMPONENTS_H_ */
|
||||
+250
@@ -0,0 +1,250 @@
|
||||
# 5.3.0 RC2
|
||||
Changes from 5.3.0-rc.1
|
||||
- Bugfixes
|
||||
- Fixes invalid checks in the lane-extraction part of the car profile
|
||||
|
||||
# 5.3.0 RC1
|
||||
- API
|
||||
- Introduces new `TurnType` in the form of `use lane`. The type indicates that you have to stick to a lane without turning
|
||||
- Introduces lanes to the route response. The lane data contains both the markings at the intersection and a flag indicating their involvement in the turn
|
||||
|
||||
- Infrastructure
|
||||
- BREAKING: The new turn type changes the turn-type order. This breaks the **data format**.
|
||||
- BREAKING: Turn lane data introduces a new file (osrm.tld). This breaks the fileformat for older versions.
|
||||
|
||||
# 5.2.5
|
||||
- Bugfixes
|
||||
- Fixes a segfault caused by incorrect trimming logic for very short steps.
|
||||
|
||||
# 5.2.4
|
||||
- Bugfixes:
|
||||
- Fixed in issue that arised on roundabouts in combination with intermediate intersections and sliproads
|
||||
|
||||
# 5.2.3
|
||||
- Bugfixes:
|
||||
- Fixed an issue with name changes in roundabouts that could result in crashes
|
||||
|
||||
# 5.2.2
|
||||
Changes from 5.2.1
|
||||
- Bugfixes:
|
||||
- Buffer overrun in tile plugin response handling
|
||||
|
||||
# 5.2.1
|
||||
Changes from 5.2.0
|
||||
- Bugfixes:
|
||||
- Removed debug statement that was spamming the console
|
||||
|
||||
# 5.2.0
|
||||
Changes from 5.2.0 RC2
|
||||
- Bugfixes:
|
||||
- Fixed crash when loading shared memory caused by invalid OSM IDs segment size.
|
||||
- Various small instructions handling fixes
|
||||
|
||||
Changes from 5.1.0
|
||||
- API:
|
||||
- new parameter `annotations` for `route`, `trip` and `match` requests. Returns additional data about each
|
||||
coordinate along the selected/matched route line per `RouteLeg`:
|
||||
- duration of each segment
|
||||
- distance of each segment
|
||||
- OSM node ids of all segment endpoints
|
||||
- Introducing Intersections for Route Steps. This changes the API format in multiple ways.
|
||||
- `bearing_before`/`bearing_after` of `StepManeuver` are now deprecated and will be removed in the next major release
|
||||
- `location` of `StepManeuvers` is now deprecated and will be removed in the next major release
|
||||
- every `RouteStep` now has property `intersections` containing a list of `Intersection` objects.
|
||||
- Support for destination signs. New member `destinations` in `RouteStep`, based on `destination` and `destination:ref`
|
||||
- Support for name pronunciations. New member `pronunciation` in `RouteStep`, based on `name:pronunciation`
|
||||
|
||||
- Profile changes:
|
||||
- duration parser now accepts P[n]DT[n]H[n]M[n]S, P[n]W, PTHHMMSS and PTHH:MM:SS ISO8601 formats.
|
||||
- `result.destinations` allows you to set a way's destinations
|
||||
- `result.pronunciation` allows you to set way name pronunciations
|
||||
- `highway=motorway_link` no longer implies `oneway` as per the OSM Wiki
|
||||
|
||||
- Infrastructure:
|
||||
- BREAKING: Changed the on-disk encoding of the StaticRTree to reduce ramIndex file size. This breaks the **data format**
|
||||
- BREAKING: Intersection Classification adds a new file to the mix (osrm.icd). This breaks the fileformat for older versions.
|
||||
- Better support for osrm-routed binary upgrade on the fly [UNIX specific]:
|
||||
- Open sockets with SO_REUSEPORT to allow multiple osrm-routed processes serving requests from the same port.
|
||||
- Add SIGNAL_PARENT_WHEN_READY environment variable to enable osrm-routed signal its parent with USR1 when it's running and waiting for requests.
|
||||
- Disable http access logging via DISABLE_ACCESS_LOGGING environment variable.
|
||||
|
||||
- Guidance:
|
||||
- BREAKING: modifies the file format with new internal identifiers
|
||||
- improved detection of turning streets, not reporting new-name in wrong situations
|
||||
- improved handling of sliproads (emit turns instead of 'take the ramp')
|
||||
- improved collapsing of instructions. Some 'new name' instructions will be suppressed if they are without alternative and the segment is short
|
||||
|
||||
- Bugfixes
|
||||
- fixed broken summaries for very short routes
|
||||
|
||||
# 5.2.0 RC2
|
||||
Changes from 5.2.0 RC1
|
||||
|
||||
- Guidance:
|
||||
- improved handling of sliproads (emit turns instead of 'take the ramp')
|
||||
- improved collapsing of instructions. Some 'new name' instructions will be suppressed if they are without alternative and the segment is short
|
||||
- BREAKING: modifies the file format with new internal identifiers
|
||||
|
||||
- API:
|
||||
- paramater `annotate` was renamed to `annotations`.
|
||||
- `annotation` as accidentally placed in `Route` instead of `RouteLeg`
|
||||
- Support for destination signs. New member `destinations` in `RouteStep`, based on `destination` and `destination:ref`
|
||||
- Support for name pronunciations. New member `pronunciation` in `RouteStep`, based on `name:pronunciation`
|
||||
- Add `nodes` property to `annotation` in `RouteLeg` containing the ids of nodes covered by the route
|
||||
|
||||
- Profile changes:
|
||||
- `result.destinations` allows you to set a way's destinations
|
||||
- `result.pronunciation` allows you to set way name pronunciations
|
||||
- `highway=motorway_link` no longer implies `oneway` as per the OSM Wiki
|
||||
|
||||
- Infrastructure
|
||||
- BREAKING: Changed the on-disk encoding of the StaticRTree to reduce ramIndex file size. This breaks the **data format**
|
||||
|
||||
- Bugfixes
|
||||
- fixed broken summaries for very short routes
|
||||
|
||||
# 5.2.0 RC1
|
||||
Changes from 5.1.0
|
||||
|
||||
- API:
|
||||
- new parameter `annotate` for `route` and `match` requests. Returns additional data about each
|
||||
coordinate along the selected/matched route line.
|
||||
- Introducing Intersections for Route Steps. This changes the API format in multiple ways.
|
||||
- `bearing_before`/`bearing_after` of `StepManeuver` are now deprecated and will be removed in the next major release
|
||||
- `location` of `StepManeuvers` is now deprecated and will be removed in the next major release
|
||||
- every `RouteStep` now has property `intersections` containing a list of `Intersection` objects.
|
||||
|
||||
- Profile changes:
|
||||
- duration parser now accepts P[n]DT[n]H[n]M[n]S, P[n]W, PTHHMMSS and PTHH:MM:SS ISO8601 formats.
|
||||
|
||||
- Infrastructure:
|
||||
- Better support for osrm-routed binary upgrade on the fly [UNIX specific]:
|
||||
- Open sockets with SO_REUSEPORT to allow multiple osrm-routed processes serving requests from the same port.
|
||||
- Add SIGNAL_PARENT_WHEN_READY environment variable to enable osrm-routed signal its parent with USR1 when it's running and waiting for requests.
|
||||
- BREAKING: Intersection Classification adds a new file to the mix (osrm.icd). This breaks the fileformat for older versions.
|
||||
- Disable http access logging via DISABLE_ACCESS_LOGGING environment
|
||||
variable.
|
||||
|
||||
- Guidance:
|
||||
- improved detection of turning streets, not reporting new-name in wrong situations
|
||||
|
||||
# 5.1.0
|
||||
Changes with regard to 5.0.0
|
||||
|
||||
- API:
|
||||
- added StepManeuver type `roundabout turn`. The type indicates a small roundabout that is treated as an intersection
|
||||
(turn right at the roundabout for first exit, go straight at the roundabout...)
|
||||
- added StepManeuver type `on ramp` and `off ramp` to distinguish between ramps that enter and exit a highway.
|
||||
- reduced new name instructions for trivial changes
|
||||
- combined multiple turns into a single instruction at segregated roads`
|
||||
|
||||
- Profile Changes:
|
||||
- introduced a suffix_list / get_name_suffix_list to specify name suffices to be suppressed in name change announcements
|
||||
- street names are now consistently assembled for the car, bike and walk profile as: "Name (Ref)" as in "Berlin (A5)"
|
||||
- new `car.lua` dependency `lib/destination.lua`
|
||||
- register a way's .nodes() function for use in the profile's way_function.
|
||||
|
||||
- Infrastructure
|
||||
- BREAKING: reordered internal instruction types. This breaks the **data format**
|
||||
- BREAKING: Changed the on-disk encoding of the StaticRTree for better performance. This breaks the **data format**
|
||||
|
||||
- Fixes:
|
||||
- Issue #2310: post-processing for local paths, fixes #2310
|
||||
- Issue #2309: local path looping, fixes #2309
|
||||
- Issue #2356: Make hint values optional
|
||||
- Issue #2349: Segmentation fault in some requests
|
||||
- Issue #2335: map matching was using shortest path with uturns disabled
|
||||
- Issue #2193: Fix syntax error position indicators in parameters queries
|
||||
- Fix search with u-turn
|
||||
- PhantomNode packing in MSVC now the same on other platforms
|
||||
- Summary is now not malformed when including unnamed roads
|
||||
- Emit new-name on when changing fron unanmed road to named road
|
||||
|
||||
# 5.0.0
|
||||
Changes with regard 5.0.0 RC2:
|
||||
- API:
|
||||
- if `geometry=geojson` is passed the resulting geometry can be a LineString or Point
|
||||
depending on how many coordinates are present.
|
||||
- the removal of the summary field was revered. for `steps=flase` the field will always be an empty string.
|
||||
|
||||
Changes with regard to 4.9.1:
|
||||
- API:
|
||||
- BREAKING: Complete rewrite of the HTTP and library API. See detailed documentation in the wiki.
|
||||
- BREAKING: The default coordinate order is now `longitude, latidue`. Exception: Polyline geometry
|
||||
which follow the original Google specification of `latitdue, longitude`.
|
||||
- BREAKING: Polyline geometries now use precision 5, instead of previously 6
|
||||
- BREAKING: Removed GPX support
|
||||
- New service `tile` which serves debug vector tiles of the road network
|
||||
- Completely new engine for guidance generation:
|
||||
- Support for highway ramps
|
||||
- Support for different intersection types (end of street, forks, merges)
|
||||
- Instruction post-processing to merge unimportant instructions
|
||||
- Improved handling of roundabouts
|
||||
|
||||
- Tools:
|
||||
- BREAKING: Renamed osrm-prepare to osrm-contract
|
||||
- BREAKING: Removes profiles from osrm-contract, only needed in osrm-extract.
|
||||
- Abort processing in osrm-extract if there are no snappable edges remaining.
|
||||
- Added .properties file to osrm-extract ouput.
|
||||
- Enables the use of multiple segment-speed-files on the osrm-contract command line
|
||||
|
||||
- Profile changes:
|
||||
- Remove movable bridge mode
|
||||
- Add `maxspeed=none` tag to car profile.
|
||||
- A `side_road` tag support for the OSRM car profile.
|
||||
|
||||
- Fixes:
|
||||
- Issue #2150: Prevents routing over delivery ways and nodes
|
||||
- Issue #1972: Provide uninstall target
|
||||
- Issue #2072: Disable alternatives by default and if core factor < 1.0
|
||||
- Issue #1999: Fix unpacking for self-loop nodes not in core.
|
||||
|
||||
- Infrastructure:
|
||||
- Cucumber test suit is now based on cucumber-js, removes Ruby as dependency
|
||||
- Updated to mapbox/variant v1.1
|
||||
- Updated to libosmium v2.6.1
|
||||
- Remove GeoJSON based debugging output, replaced by debug tiles
|
||||
|
||||
|
||||
# 5.0.0 RC2
|
||||
- Profiles:
|
||||
- `properties.allow_uturns_at_via` -> `properties.continue_straight_at_waypoint` (value is inverted!)
|
||||
- API:
|
||||
- Removed summary from legs property
|
||||
- Disable steps and alternatives by default
|
||||
- Fix `code` field: 'ok' -> 'Ok'
|
||||
- Allow 4.json and 4.3.json format
|
||||
- Conform to v5 spec and support "unlimited" as radiuses value.
|
||||
- `uturns` parameter was replaced by `continue_straight` (value is inverted!)
|
||||
- Features:
|
||||
- Report progress for gennerating edge expanded edges in the edge based graph factory
|
||||
- Add maxspeed=none tag to car profile.
|
||||
- Optimize StaticRTree code: speedup 2x (to RC1)
|
||||
- Optimize DouglasPeucker code: speedup 10x (to RC1)
|
||||
- Optimize WebMercator projection: speedup 2x (to RC1)
|
||||
- Bugs:
|
||||
- #2195: Resolves issues with multiple includedirs in pkg-config file
|
||||
- #2219: Internal server error when using the match plugin
|
||||
- #2027: basename -> filename
|
||||
- #2168: Report correct position where parsing failed
|
||||
- #2036: Add license to storage and storage config exposed in public API
|
||||
- Fix uturn detection in match plugin
|
||||
- Add missing -lz to fix linking of server-tests
|
||||
|
||||
# 5.0.0 RC1
|
||||
- Renamed osrm-prepare into osrm-contract
|
||||
- osrm-contract does not need a profile parameter anymore
|
||||
- New public HTTP API, find documentation [here](https://github.com/Project-OSRM/osrm-backend/wiki/New-Server-api)
|
||||
- POST support is discontinued, please use library bindings for more complex requests
|
||||
- Removed timestamp plugin
|
||||
- Coordinate order is now Longitude,Latitude
|
||||
- Cucumber tests now based on Javascript (run with `npm test`)
|
||||
- Profile API changed:
|
||||
- `forward_mode` and `backward_mode` now need to be selected from a pre-defined list
|
||||
- Global profile properties are now stored in a global `properties` element. This includes:
|
||||
- `properties.traffic_signal_penalty`
|
||||
- `properties.use_turn_restrictions`
|
||||
- `properties.u_turn_penalty`
|
||||
- `properties.allow_u_turn_at_via`
|
||||
|
||||
|
||||
+410
-179
@@ -1,77 +1,102 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
project(OSRM)
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
# we depend on 2.8.11 introducing target_include_directories
|
||||
|
||||
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR AND NOT MSVC_IDE)
|
||||
message(FATAL_ERROR "In-source builds are not allowed.
|
||||
Please create a directory and run cmake from there, passing the path to this source directory as the last argument.
|
||||
This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. Please delete them.")
|
||||
endif()
|
||||
|
||||
project(OSRM C CXX)
|
||||
set(OSRM_VERSION_MAJOR 5)
|
||||
set(OSRM_VERSION_MINOR 3)
|
||||
set(OSRM_VERSION_PATCH 0)
|
||||
|
||||
# these two functions build up custom variables:
|
||||
# OSRM_INCLUDE_PATHS and OSRM_DEFINES
|
||||
# These variables we want to pass to
|
||||
# include_directories and add_definitions for both
|
||||
# this build and for sharing externally via pkg-config
|
||||
|
||||
function(add_dependency_includes includes)
|
||||
list(APPEND OSRM_INCLUDE_PATHS "${includes}")
|
||||
set(OSRM_INCLUDE_PATHS "${OSRM_INCLUDE_PATHS}" PARENT_SCOPE)
|
||||
endfunction(add_dependency_includes)
|
||||
|
||||
function(add_dependency_defines defines)
|
||||
list(APPEND OSRM_DEFINES "${defines}")
|
||||
set(OSRM_DEFINES "${OSRM_DEFINES}" PARENT_SCOPE)
|
||||
endfunction(add_dependency_defines)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||
include(GetGitRevisionDescription)
|
||||
git_describe(GIT_DESCRIPTION)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
set(bitness 32)
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(bitness 64)
|
||||
message(STATUS "Building on a 64 bit system")
|
||||
else()
|
||||
message(WARNING "Building on a 32 bit system is unsupported")
|
||||
message(STATUS "Building on a 32 bit system")
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/Include/)
|
||||
if(WIN32 AND MSVC_VERSION LESS 1900)
|
||||
message(FATAL_ERROR "Building with Microsoft compiler needs Latest Visual Studio 2015 (Community or better)")
|
||||
endif()
|
||||
|
||||
add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/Util/UUID.cpp UUID.cpp.alwaysbuild
|
||||
COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR}
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/UUID-Config.cmake
|
||||
DEPENDS
|
||||
${CMAKE_SOURCE_DIR}/Util/UUID.cpp.in
|
||||
${CMAKE_SOURCE_DIR}/cmake/UUID-Config.cmake
|
||||
COMMENT "Configuring UUID.cpp"
|
||||
option(ENABLE_CCACHE "Speed up incremental rebuilds via ccache" ON)
|
||||
option(ENABLE_JSON_LOGGING "Adds additional JSON debug logging to the response" OFF)
|
||||
option(BUILD_TOOLS "Build OSRM tools" OFF)
|
||||
option(BUILD_COMPONENTS "Build osrm-components" OFF)
|
||||
option(ENABLE_ASSERTIONS OFF)
|
||||
option(COVERAGE OFF)
|
||||
option(SANITIZER OFF)
|
||||
option(ENABLE_LTO "Use LTO if available" ON)
|
||||
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include/)
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include/)
|
||||
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/)
|
||||
|
||||
add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND}
|
||||
"-DOUTPUT_DIR=${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"-DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
-P "${CMAKE_CURRENT_SOURCE_DIR}/cmake/FingerPrint-Config.cmake"
|
||||
COMMENT "Configuring revision fingerprint"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target(UUIDConfigure DEPENDS ${CMAKE_SOURCE_DIR}/Util/UUID.cpp)
|
||||
|
||||
set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread)
|
||||
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/Util/GitDescription.cpp.in
|
||||
${CMAKE_SOURCE_DIR}/Util/GitDescription.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/util/version.hpp.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/util/version.hpp
|
||||
)
|
||||
file(GLOB ExtractorGlob Extractor/*.cpp)
|
||||
set(ExtractorSources extractor.cpp ${ExtractorGlob})
|
||||
add_executable(osrm-extract ${ExtractorSources})
|
||||
file(GLOB UtilGlob src/util/*.cpp src/util/*/*.cpp)
|
||||
file(GLOB ExtractorGlob src/extractor/*.cpp src/extractor/*/*.cpp)
|
||||
file(GLOB ContractorGlob src/contractor/*.cpp)
|
||||
file(GLOB StorageGlob src/storage/*.cpp)
|
||||
file(GLOB ServerGlob src/server/*.cpp src/server/**/*.cpp)
|
||||
file(GLOB EngineGlob src/engine/*.cpp src/engine/**/*.cpp)
|
||||
|
||||
file(GLOB PrepareGlob Contractor/*.cpp DataStructures/HilbertValue.cpp)
|
||||
set(PrepareSources prepare.cpp ${PrepareGlob})
|
||||
add_executable(osrm-prepare ${PrepareSources})
|
||||
add_library(UTIL OBJECT ${UtilGlob})
|
||||
add_library(EXTRACTOR OBJECT ${ExtractorGlob})
|
||||
add_library(CONTRACTOR OBJECT ${ContractorGlob})
|
||||
add_library(STORAGE OBJECT ${StorageGlob})
|
||||
add_library(ENGINE OBJECT ${EngineGlob})
|
||||
add_library(SERVER OBJECT ${ServerGlob})
|
||||
|
||||
file(GLOB ServerGlob Server/*.cpp)
|
||||
file(GLOB DescriptorGlob Descriptors/*.cpp)
|
||||
file(GLOB DatastructureGlob DataStructures/SearchEngineData.cpp)
|
||||
file(GLOB CoordinateGlob DataStructures/Coordinate.cpp)
|
||||
file(GLOB AlgorithmGlob Algorithms/*.cpp)
|
||||
file(GLOB HttpGlob Server/Http/*.cpp)
|
||||
file(GLOB LibOSRMGlob Library/*.cpp)
|
||||
add_dependencies(UTIL FingerPrintConfigure)
|
||||
set_target_properties(UTIL PROPERTIES LINKER_LANGUAGE CXX)
|
||||
|
||||
set(
|
||||
OSRMSources
|
||||
${LibOSRMGlob}
|
||||
${DescriptorGlob}
|
||||
${DatastructureGlob}
|
||||
${CoordinateGlob}
|
||||
${AlgorithmGlob}
|
||||
${HttpGlob}
|
||||
)
|
||||
add_library(COORDLIB STATIC ${CoordinateGlob})
|
||||
add_library(OSRM ${OSRMSources} Util/GitDescription.cpp Util/UUID.cpp)
|
||||
add_library(UUID STATIC Util/UUID.cpp)
|
||||
add_library(GITDESCRIPTION STATIC Util/GitDescription.cpp)
|
||||
add_dependencies(UUID UUIDConfigure)
|
||||
add_dependencies(GITDESCRIPTION GIT_DESCRIPTION)
|
||||
|
||||
add_executable(osrm-routed routed.cpp ${ServerGlob})
|
||||
set_target_properties(osrm-routed PROPERTIES COMPILE_FLAGS -DROUTED)
|
||||
add_executable(osrm-datastore datastore.cpp)
|
||||
add_executable(osrm-extract src/tools/extract.cpp)
|
||||
add_executable(osrm-contract src/tools/contract.cpp)
|
||||
add_executable(osrm-routed src/tools/routed.cpp $<TARGET_OBJECTS:SERVER> $<TARGET_OBJECTS:UTIL>)
|
||||
add_executable(osrm-datastore src/tools/store.cpp $<TARGET_OBJECTS:UTIL>)
|
||||
add_library(osrm src/osrm/osrm.cpp $<TARGET_OBJECTS:ENGINE> $<TARGET_OBJECTS:UTIL> $<TARGET_OBJECTS:STORAGE>)
|
||||
add_library(osrm_extract $<TARGET_OBJECTS:EXTRACTOR> $<TARGET_OBJECTS:UTIL>)
|
||||
add_library(osrm_contract $<TARGET_OBJECTS:CONTRACTOR> $<TARGET_OBJECTS:UTIL>)
|
||||
add_library(osrm_store $<TARGET_OBJECTS:STORAGE> $<TARGET_OBJECTS:UTIL>)
|
||||
|
||||
# Check the release mode
|
||||
if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
@@ -79,49 +104,126 @@ if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
endif()
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
message(STATUS "Configuring OSRM in debug mode")
|
||||
if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
message(STATUS "adding profiling flags")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline")
|
||||
set(CMAKE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline")
|
||||
set(ENABLE_ASSERTIONS ON)
|
||||
if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-inline -fno-omit-frame-pointer")
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Og -ggdb")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
endif()
|
||||
if(CMAKE_BUILD_TYPE MATCHES Release)
|
||||
message(STATUS "Configuring OSRM in release mode")
|
||||
message(STATUS "Configuring OSRM in release mode")
|
||||
# Check if LTO is available
|
||||
check_cxx_compiler_flag("-flto" LTO_AVAILABLE)
|
||||
if(ENABLE_LTO AND LTO_AVAILABLE)
|
||||
set(OLD_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
# GCC in addition allows parallelizing LTO
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
include(ProcessorCount)
|
||||
ProcessorCount(NPROC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto=${NPROC}")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto")
|
||||
endif()
|
||||
set(CHECK_LTO_SRC "int main(){return 0;}")
|
||||
check_cxx_source_compiles("${CHECK_LTO_SRC}" LTO_WORKS)
|
||||
if(LTO_WORKS)
|
||||
message(STATUS "LTO working")
|
||||
else()
|
||||
message(STATUS "LTO broken")
|
||||
set(CMAKE_CXX_FLAGS "${OLD_CXX_FLAGS}")
|
||||
endif()
|
||||
|
||||
# Since gcc 4.9 the LTO format is non-standart ('slim'), so we need to use the build-in tools
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND
|
||||
NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0" AND NOT MINGW)
|
||||
message(STATUS "Using gcc specific binutils for LTO.")
|
||||
set(CMAKE_AR "/usr/bin/gcc-ar")
|
||||
set(CMAKE_RANLIB "/usr/bin/gcc-ranlib")
|
||||
endif()
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0")
|
||||
message(STATUS "Disabling LTO on GCC < 4.9.0 since it is broken, see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57038")
|
||||
set(CMAKE_CXX_FLAGS "${OLD_CXX_FLAGS}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(MAYBE_COVERAGE_LIBRARIES "")
|
||||
if (COVERAGE)
|
||||
if (NOT CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||
message(ERROR "COVERAGE=ON only make sense with a Debug build")
|
||||
endif()
|
||||
message(INFO "Enabling coverage")
|
||||
set(MAYBE_COVERAGE_LIBRARIES "gcov")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftest-coverage -fprofile-arcs")
|
||||
endif()
|
||||
if (SANITIZER)
|
||||
if (NOT CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||
message(ERROR "SANITIZER=ON only make sense with a Debug build")
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
|
||||
endif()
|
||||
|
||||
# Configuring compilers
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
# using Clang
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wunreachable-code -Wno-unknown-pragmas -Wno-unneeded-internal-declaration -pedantic -fPIC")
|
||||
message(STATUS "OpenMP parallelization not available using clang++")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wuninitialized -Wunreachable-code -Wstrict-overflow=2 -D_FORTIFY_SOURCE=2 -fPIC -fcolor-diagnostics")
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
|
||||
set(COLOR_FLAG "-fdiagnostics-color=auto")
|
||||
check_cxx_compiler_flag("-fdiagnostics-color=auto" HAS_COLOR_FLAG)
|
||||
if(NOT HAS_COLOR_FLAG)
|
||||
set(COLOR_FLAG "")
|
||||
endif()
|
||||
# using GCC
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fopenmp -pedantic -fPIC")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wuninitialized -Wunreachable-code -Wstrict-overflow=1 -D_FORTIFY_SOURCE=2 ${COLOR_FLAG} -fPIC")
|
||||
if(WIN32) # using mingw
|
||||
add_dependency_defines(-DWIN32)
|
||||
set(OPTIONAL_SOCKET_LIBS ws2_32 wsock32)
|
||||
endif()
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel")
|
||||
# using Intel C++
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-intel -wd10237 -Wall -openmp -ipo -fPIC")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-intel -wd10237 -Wall -ipo -fPIC")
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
|
||||
# using Visual Studio C++
|
||||
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} date_time chrono zlib)
|
||||
add_dependency_defines(-DBOOST_LIB_DIAGNOSTIC)
|
||||
add_dependency_defines(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_dependency_defines(-DNOMINMAX) # avoid min and max macros that can break compilation
|
||||
add_dependency_defines(-D_USE_MATH_DEFINES) #needed for M_PI with cmath.h
|
||||
add_dependency_defines(-D_WIN32_WINNT=0x0501)
|
||||
add_dependency_defines(-DXML_STATIC)
|
||||
find_library(ws2_32_LIBRARY_PATH ws2_32)
|
||||
target_link_libraries(osrm-extract wsock32 ws2_32)
|
||||
endif()
|
||||
|
||||
# Check if LTO is available
|
||||
set(LTO_FLAGS "")
|
||||
CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG)
|
||||
if (HAS_LTO_FLAG)
|
||||
set(LTO_FLAGS "${LTO_FLAGS} -flto")
|
||||
endif (HAS_LTO_FLAG)
|
||||
# Configuring linker
|
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} "-Wl,--version" ERROR_QUIET OUTPUT_VARIABLE LINKER_VERSION)
|
||||
# For ld.gold and ld.bfs (the GNU linkers) we optimize hard
|
||||
if("${LINKER_VERSION}" MATCHES "GNU gold" OR "${LINKER_VERSION}" MATCHES "GNU ld")
|
||||
message(STATUS "Setting linker optimizations")
|
||||
if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
|
||||
# Tell compiler to put every function in separate section, linker can then match sections and functions
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections")
|
||||
# Tell linker to do dead code and data eminination during link time discarding sections
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -Wl,--gc-sections")
|
||||
endif()
|
||||
# Default linker optimization flags
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -Wl,-O1 -Wl,--hash-style=gnu -Wl,--sort-common")
|
||||
else()
|
||||
message(STATUS "Using unknown linker, not setting linker optimizations")
|
||||
endif ()
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
|
||||
# disable partitioning of LTO process when possible (fixes Debian issues)
|
||||
set(LTO_PARTITION_FLAGS "")
|
||||
CHECK_CXX_COMPILER_FLAG("-flto-partition=none" HAS_LTO_PARTITION_FLAG)
|
||||
if (HAS_LTO_PARTITION_FLAG)
|
||||
set(LTO_PARTITION_FLAGS "${LTO_PARTITION_FLAGS} -flto-partition=none")
|
||||
endif (HAS_LTO_PARTITION_FLAG)
|
||||
|
||||
# Add Link-Time-Optimization flags, if supported (GCC >= 4.5) and enabled
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LTO_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LTO_FLAGS} ${LTO_PARTITION_FLAGS}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LTO_FLAGS} ${LTO_PARTITION_FLAGS}")
|
||||
# Activate C++11
|
||||
if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
endif()
|
||||
|
||||
# Configuring other platform dependencies
|
||||
if(APPLE)
|
||||
@@ -129,10 +231,6 @@ if(APPLE)
|
||||
message(STATUS "Set Architecture to x64 on OS X")
|
||||
exec_program(uname ARGS -v OUTPUT_VARIABLE DARWIN_VERSION)
|
||||
string(REGEX MATCH "[0-9]+" DARWIN_VERSION ${DARWIN_VERSION})
|
||||
if(DARWIN_VERSION GREATER 12 AND NOT OSXLIBSTD)
|
||||
message(STATUS "Activating -std=c++11 flag for >= OS X 10.9")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
endif()
|
||||
if(OSXLIBSTD)
|
||||
message(STATUS "linking against ${OSXLIBSTD}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=${OSXLIBSTD}")
|
||||
@@ -143,127 +241,260 @@ if(APPLE)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(osrm-datastore rt)
|
||||
target_link_libraries(OSRM rt)
|
||||
set(MAYBE_RT_LIBRARY rt)
|
||||
endif()
|
||||
|
||||
#Check Boost
|
||||
set(BOOST_MIN_VERSION "1.46.0")
|
||||
find_package(Boost ${BOOST_MIN_VERSION} COMPONENTS ${BOOST_COMPONENTS} REQUIRED)
|
||||
if(NOT Boost_FOUND)
|
||||
message(FATAL_ERROR "Fatal error: Boost (version >= 1.46.0) required.\n")
|
||||
endif()
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/cmake")
|
||||
set(OSMIUM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include")
|
||||
find_package(Osmium REQUIRED COMPONENTS io)
|
||||
add_dependency_includes(${OSMIUM_INCLUDE_DIR})
|
||||
|
||||
target_link_libraries(OSRM ${Boost_LIBRARIES} COORDLIB)
|
||||
target_link_libraries(osrm-extract ${Boost_LIBRARIES} UUID GITDESCRIPTION COORDLIB)
|
||||
target_link_libraries(osrm-prepare ${Boost_LIBRARIES} UUID GITDESCRIPTION COORDLIB)
|
||||
target_link_libraries(osrm-routed ${Boost_LIBRARIES} OSRM UUID GITDESCRIPTION)
|
||||
target_link_libraries(osrm-datastore ${Boost_LIBRARIES} UUID GITDESCRIPTION COORDLIB)
|
||||
|
||||
find_package(Boost 1.49.0 REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
||||
|
||||
# collect a subset of the boost libraries needed
|
||||
# by libosrm
|
||||
foreach(lib ${Boost_LIBRARIES})
|
||||
if(NOT WIN32)
|
||||
if(lib MATCHES filesystem OR lib MATCHES thread OR lib MATCHES iostreams OR lib MATCHES system)
|
||||
list(APPEND BOOST_ENGINE_LIBRARIES "${lib}")
|
||||
endif()
|
||||
else()
|
||||
list(APPEND BOOST_ENGINE_LIBRARIES "${lib}")
|
||||
endif()
|
||||
endforeach(lib)
|
||||
|
||||
if(NOT WIN32 AND NOT Boost_USE_STATIC_LIBS)
|
||||
add_dependency_defines(-DBOOST_TEST_DYN_LINK)
|
||||
endif()
|
||||
add_dependency_defines(-DBOOST_SPIRIT_USE_PHOENIX_V3)
|
||||
add_dependency_defines(-DBOOST_RESULT_OF_USE_DECLTYPE)
|
||||
add_dependency_defines(-DBOOST_FILESYSTEM_NO_DEPRECATED)
|
||||
add_dependency_includes(${Boost_INCLUDE_DIRS})
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(osrm-extract ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
find_package(Lua52)
|
||||
if(NOT LUA52_FOUND)
|
||||
find_package(Lua51 REQUIRED)
|
||||
if(NOT APPLE)
|
||||
find_package(LuaJIT 5.1)
|
||||
endif()
|
||||
else()
|
||||
if(NOT APPLE)
|
||||
find_package(LuaJIT 5.2)
|
||||
endif()
|
||||
find_package(TBB REQUIRED)
|
||||
add_dependency_includes(${TBB_INCLUDE_DIR})
|
||||
if(WIN32 AND CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
set(TBB_LIBRARIES ${TBB_DEBUG_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if( LUAJIT_FOUND )
|
||||
target_link_libraries(osrm-extract ${LUAJIT_LIBRARIES})
|
||||
target_link_libraries(osrm-prepare ${LUAJIT_LIBRARIES})
|
||||
else()
|
||||
target_link_libraries(osrm-extract ${LUA_LIBRARY})
|
||||
target_link_libraries(osrm-prepare ${LUA_LIBRARY})
|
||||
find_package(Luabind REQUIRED)
|
||||
include(check_luabind)
|
||||
add_dependency_includes(${LUABIND_INCLUDE_DIR})
|
||||
|
||||
set(USED_LUA_LIBRARIES ${LUA_LIBRARY})
|
||||
if(LUAJIT_FOUND)
|
||||
set(USED_LUA_LIBRARIES, LUAJIT_LIBRARIES)
|
||||
endif()
|
||||
include_directories(${LUA_INCLUDE_DIR})
|
||||
add_dependency_includes(${LUA_INCLUDE_DIR})
|
||||
|
||||
find_package(LibXml2 REQUIRED)
|
||||
include_directories(${LIBXML2_INCLUDE_DIR})
|
||||
target_link_libraries(osrm-extract ${LIBXML2_LIBRARIES})
|
||||
find_package(EXPAT REQUIRED)
|
||||
add_dependency_includes(${EXPAT_INCLUDE_DIRS})
|
||||
|
||||
find_package( Luabind REQUIRED )
|
||||
include_directories(${LUABIND_INCLUDE_DIR})
|
||||
target_link_libraries(osrm-extract ${LUABIND_LIBRARY})
|
||||
target_link_libraries(osrm-prepare ${LUABIND_LIBRARY})
|
||||
find_package(STXXL REQUIRED)
|
||||
add_dependency_includes(${STXXL_INCLUDE_DIR})
|
||||
|
||||
find_package( STXXL REQUIRED )
|
||||
include_directories(${STXXL_INCLUDE_DIR})
|
||||
target_link_libraries(OSRM ${STXXL_LIBRARY})
|
||||
target_link_libraries(osrm-extract ${STXXL_LIBRARY})
|
||||
target_link_libraries(osrm-prepare ${STXXL_LIBRARY})
|
||||
|
||||
find_package( OSMPBF REQUIRED )
|
||||
include_directories(${OSMPBF_INCLUDE_DIR})
|
||||
target_link_libraries(osrm-extract ${OSMPBF_LIBRARY})
|
||||
target_link_libraries(osrm-prepare ${OSMPBF_LIBRARY})
|
||||
|
||||
find_package(Protobuf REQUIRED)
|
||||
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||
target_link_libraries(osrm-extract ${PROTOBUF_LIBRARY})
|
||||
target_link_libraries(osrm-prepare ${PROTOBUF_LIBRARY})
|
||||
set(OpenMP_FIND_QUIETLY ON)
|
||||
find_package(OpenMP)
|
||||
if(OPENMP_FOUND)
|
||||
message(STATUS "OpenMP support found. Linking just in case for stxxl")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
|
||||
endif()
|
||||
|
||||
find_package(BZip2 REQUIRED)
|
||||
include_directories(${BZIP_INCLUDE_DIRS})
|
||||
target_link_libraries(osrm-extract ${BZIP2_LIBRARIES})
|
||||
add_dependency_includes(${BZIP2_INCLUDE_DIR})
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
include_directories(${ZLIB_INCLUDE_DIRS})
|
||||
target_link_libraries(osrm-extract ${ZLIB_LIBRARY})
|
||||
target_link_libraries(osrm-routed ${ZLIB_LIBRARY})
|
||||
add_dependency_includes(${ZLIB_INCLUDE_DIRS})
|
||||
|
||||
if(WITH_TOOLS)
|
||||
message(STATUS "Activating OSRM internal tools")
|
||||
find_package(GDAL)
|
||||
if(GDAL_FOUND)
|
||||
add_executable(osrm-components Tools/componentAnalysis.cpp)
|
||||
include_directories(${GDAL_INCLUDE_DIR})
|
||||
target_link_libraries(
|
||||
osrm-components
|
||||
${GDAL_LIBRARIES} ${Boost_LIBRARIES} UUID GITDESCRIPTION COORDLIB)
|
||||
endif()
|
||||
add_executable(osrm-cli Tools/simpleclient.cpp)
|
||||
target_link_libraries(osrm-cli ${Boost_LIBRARIES} OSRM UUID GITDESCRIPTION)
|
||||
add_executable(osrm-io-benchmark Tools/io-benchmark.cpp)
|
||||
target_link_libraries(osrm-io-benchmark ${Boost_LIBRARIES} GITDESCRIPTION)
|
||||
add_executable(osrm-unlock-all Tools/unlock_all_mutexes.cpp)
|
||||
target_link_libraries(osrm-unlock-all ${Boost_LIBRARIES} GITDESCRIPTION)
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(osrm-unlock-all rt)
|
||||
endif()
|
||||
if (ENABLE_JSON_LOGGING)
|
||||
message(STATUS "Enabling json logging")
|
||||
add_dependency_defines(-DENABLE_JSON_LOGGING)
|
||||
endif()
|
||||
|
||||
file(GLOB InstallGlob Include/osrm/*.h Library/OSRM.h)
|
||||
add_definitions(${OSRM_DEFINES})
|
||||
include_directories(SYSTEM ${OSRM_INCLUDE_PATHS})
|
||||
|
||||
# Binaries
|
||||
target_link_libraries(osrm-datastore osrm_store ${Boost_LIBRARIES})
|
||||
target_link_libraries(osrm-extract osrm_extract ${Boost_LIBRARIES})
|
||||
target_link_libraries(osrm-contract ${Boost_LIBRARIES} ${TBB_LIBRARIES} osrm_contract)
|
||||
target_link_libraries(osrm-routed osrm ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} ${ZLIB_LIBRARY})
|
||||
|
||||
set(EXTRACTOR_LIBRARIES
|
||||
${BZIP2_LIBRARIES}
|
||||
${Boost_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${EXPAT_LIBRARIES}
|
||||
${LUABIND_LIBRARY}
|
||||
${USED_LUA_LIBRARIES}
|
||||
${OSMIUM_LIBRARIES}
|
||||
${STXXL_LIBRARY}
|
||||
${TBB_LIBRARIES}
|
||||
${ZLIB_LIBRARY}
|
||||
${MAYBE_COVERAGE_LIBRARIES})
|
||||
set(CONTRACTOR_LIBRARIES
|
||||
${Boost_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${LUABIND_LIBRARY}
|
||||
${USED_LUA_LIBRARIES}
|
||||
${STXXL_LIBRARY}
|
||||
${TBB_LIBRARIES}
|
||||
${MAYBE_RT_LIBRARY}
|
||||
${MAYBE_COVERAGE_LIBRARIES})
|
||||
set(ENGINE_LIBRARIES
|
||||
${BOOST_ENGINE_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${TBB_LIBRARIES}
|
||||
${MAYBE_RT_LIBRARY}
|
||||
${MAYBE_COVERAGE_LIBRARIES}
|
||||
${ZLIB_LIBRARY})
|
||||
set(STORAGE_LIBRARIES
|
||||
${Boost_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${TBB_LIBRARIES}
|
||||
${MAYBE_RT_LIBRARY}
|
||||
${MAYBE_COVERAGE_LIBRARIES})
|
||||
set(UTIL_LIBRARIES
|
||||
${Boost_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${STXXL_LIBRARY}
|
||||
${TBB_LIBRARIES}
|
||||
${MAYBE_COVERAGE_LIBRARIES})
|
||||
# Libraries
|
||||
target_link_libraries(osrm ${ENGINE_LIBRARIES})
|
||||
target_link_libraries(osrm_contract ${CONTRACTOR_LIBRARIES})
|
||||
target_link_libraries(osrm_extract ${EXTRACTOR_LIBRARIES})
|
||||
target_link_libraries(osrm_store ${STORAGE_LIBRARIES})
|
||||
|
||||
if(BUILD_COMPONENTS)
|
||||
find_package(GDAL)
|
||||
if(GDAL_FOUND)
|
||||
add_executable(osrm-components src/tools/components.cpp $<TARGET_OBJECTS:UTIL>)
|
||||
target_link_libraries(osrm-components ${TBB_LIBRARIES})
|
||||
include_directories(SYSTEM ${GDAL_INCLUDE_DIR})
|
||||
target_link_libraries(osrm-components ${GDAL_LIBRARIES} ${Boost_LIBRARIES})
|
||||
install(TARGETS osrm-components DESTINATION bin)
|
||||
else()
|
||||
message(WARNING "libgdal and/or development headers not found")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(BUILD_TOOLS)
|
||||
message(STATUS "Activating OSRM internal tools")
|
||||
add_executable(osrm-io-benchmark src/tools/io-benchmark.cpp $<TARGET_OBJECTS:UTIL>)
|
||||
target_link_libraries(osrm-io-benchmark ${Boost_LIBRARIES})
|
||||
add_executable(osrm-unlock-all src/tools/unlock_all_mutexes.cpp $<TARGET_OBJECTS:UTIL>)
|
||||
target_link_libraries(osrm-unlock-all ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(osrm-unlock-all rt)
|
||||
endif()
|
||||
add_executable(osrm-springclean src/tools/springclean.cpp $<TARGET_OBJECTS:UTIL>)
|
||||
target_link_libraries(osrm-springclean ${Boost_LIBRARIES})
|
||||
|
||||
install(TARGETS osrm-io-benchmark DESTINATION bin)
|
||||
install(TARGETS osrm-unlock-all DESTINATION bin)
|
||||
install(TARGETS osrm-springclean DESTINATION bin)
|
||||
endif()
|
||||
|
||||
if (ENABLE_ASSERTIONS)
|
||||
message(STATUS "Enabling assertions")
|
||||
add_definitions(-DBOOST_ENABLE_ASSERT_HANDLER)
|
||||
endif()
|
||||
|
||||
# Add RPATH info to executables so that when they are run after being installed
|
||||
# (i.e., from /usr/local/bin/) the linker can find library dependencies. For
|
||||
# more info see http://www.cmake.org/Wiki/CMake_RPATH_handling
|
||||
set_property(TARGET osrm-extract PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
set_property(TARGET osrm-prepare PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
set_property(TARGET osrm-contract PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
set_property(TARGET osrm-datastore PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
set_property(TARGET osrm-routed PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
|
||||
install(FILES ${InstallGlob} DESTINATION include/osrm)
|
||||
file(GLOB VariantGlob third_party/variant/*.hpp)
|
||||
file(GLOB LibraryGlob include/osrm/*.hpp)
|
||||
file(GLOB ParametersGlob include/engine/api/*_parameters.hpp)
|
||||
set(EngineHeader include/engine/status.hpp include/engine/engine_config.hpp include/engine/hint.hpp include/engine/bearing.hpp include/engine/phantom_node.hpp)
|
||||
set(UtilHeader include/util/coordinate.hpp include/util/json_container.hpp include/util/typedefs.hpp include/util/strong_typedef.hpp)
|
||||
set(ExtractorHeader include/extractor/extractor.hpp include/extractor/extractor_config.hpp include/extractor/travel_mode.hpp)
|
||||
set(ContractorHeader include/contractor/contractor.hpp include/contractor/contractor_config.hpp)
|
||||
set(StorageHeader include/storage/storage.hpp include/storage/storage_config.hpp)
|
||||
install(FILES ${EngineHeader} DESTINATION include/osrm/engine)
|
||||
install(FILES ${UtilHeader} DESTINATION include/osrm/util)
|
||||
install(FILES ${StorageHeader} DESTINATION include/osrm/storage)
|
||||
install(FILES ${ExtractorHeader} DESTINATION include/osrm/extractor)
|
||||
install(FILES ${ContractorHeader} DESTINATION include/osrm/contractor)
|
||||
install(FILES ${LibraryGlob} DESTINATION include/osrm)
|
||||
install(FILES ${ParametersGlob} DESTINATION include/osrm/engine/api)
|
||||
install(FILES ${VariantGlob} DESTINATION include/variant)
|
||||
install(TARGETS osrm-extract DESTINATION bin)
|
||||
install(TARGETS osrm-prepare DESTINATION bin)
|
||||
install(TARGETS osrm-contract DESTINATION bin)
|
||||
install(TARGETS osrm-datastore DESTINATION bin)
|
||||
install(TARGETS osrm-routed DESTINATION bin)
|
||||
install(TARGETS OSRM DESTINATION lib)
|
||||
list(GET Boost_LIBRARIES 1 BOOST_LIBRARY_FIRST)
|
||||
get_filename_component(BOOST_LIBRARY_LISTING "${BOOST_LIBRARY_FIRST}" PATH)
|
||||
set(BOOST_LIBRARY_LISTING "-L${BOOST_LIBRARY_LISTING}")
|
||||
foreach (lib ${Boost_LIBRARIES})
|
||||
get_filename_component(BOOST_LIBRARY_NAME "${lib}" NAME_WE)
|
||||
string(REPLACE "lib" "" BOOST_LIBRARY_NAME ${BOOST_LIBRARY_NAME})
|
||||
set(BOOST_LIBRARY_LISTING "${BOOST_LIBRARY_LISTING} -l${BOOST_LIBRARY_NAME}")
|
||||
endforeach ()
|
||||
install(TARGETS osrm DESTINATION lib)
|
||||
install(TARGETS osrm_extract DESTINATION lib)
|
||||
install(TARGETS osrm_contract DESTINATION lib)
|
||||
install(TARGETS osrm_store DESTINATION lib)
|
||||
|
||||
configure_file(${CMAKE_SOURCE_DIR}/cmake/pkgconfig.in libosrm.pc @ONLY)
|
||||
list(GET ENGINE_LIBRARIES 1 ENGINE_LIBRARY_FIRST)
|
||||
foreach(lib ${ENGINE_LIBRARIES})
|
||||
get_filename_component(ENGINE_LIBRARY_PATH "${ENGINE_LIBRARY_FIRST}" PATH)
|
||||
get_filename_component(ENGINE_LIBRARY_NAME "${lib}" NAME_WE)
|
||||
string(REPLACE "lib" "" ENGINE_LIBRARY_NAME ${ENGINE_LIBRARY_NAME})
|
||||
string(REPLACE "-l" "" ENGINE_LIBRARY_NAME ${ENGINE_LIBRARY_NAME})
|
||||
set(ENGINE_LIBRARY_LISTING "${ENGINE_LIBRARY_LISTING} -L${ENGINE_LIBRARY_PATH} -l${ENGINE_LIBRARY_NAME}")
|
||||
endforeach()
|
||||
|
||||
if(BUILD_DEBIAN_PACKAGE)
|
||||
include(CPackDebianConfig)
|
||||
include(CPack)
|
||||
endif()
|
||||
|
||||
function(JOIN VALUES GLUE OUTPUT)
|
||||
string (REPLACE ";" "${GLUE}" _TMP_STR "${VALUES}")
|
||||
set (${OUTPUT} "${_TMP_STR}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Set up variables, then write to pkgconfig file
|
||||
JOIN("${OSRM_DEFINES}" " " OSRM_DEFINES_STRING)
|
||||
JOIN("-I${OSRM_INCLUDE_PATHS}" " -I" OSRM_INCLUDE_PATHS_STRING)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkgconfig.in libosrm.pc @ONLY)
|
||||
install(FILES ${PROJECT_BINARY_DIR}/libosrm.pc DESTINATION lib/pkgconfig)
|
||||
|
||||
# add a target to generate API documentation with Doxygen
|
||||
find_package(Doxygen)
|
||||
if(DOXYGEN_FOUND)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
|
||||
add_custom_target(doc
|
||||
${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Generating API documentation with Doxygen" VERBATIM
|
||||
)
|
||||
endif()
|
||||
|
||||
# prefix compilation with ccache by default if available and on clang or gcc
|
||||
if(ENABLE_CCACHE AND (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU"))
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(CCACHE_FOUND)
|
||||
message(STATUS "Using ccache to speed up incremental builds")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
set(ENV{CCACHE_CPP2} "true")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# uninstall target
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake"
|
||||
IMMEDIATE @ONLY)
|
||||
|
||||
add_custom_target(uninstall
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake)
|
||||
|
||||
|
||||
# Modular build system: each directory registered here provides its own CMakeLists.txt
|
||||
add_subdirectory(unit_tests)
|
||||
add_subdirectory(src/benchmarks)
|
||||
|
||||
@@ -1,789 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CONTRACTOR_H_INCLUDED
|
||||
#define CONTRACTOR_H_INCLUDED
|
||||
|
||||
#include "TemporaryStorage.h"
|
||||
#include "../DataStructures/BinaryHeap.h"
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
#include "../DataStructures/DynamicGraph.h"
|
||||
#include "../DataStructures/Percent.h"
|
||||
#include "../DataStructures/XORFastHash.h"
|
||||
#include "../DataStructures/XORFastHashStorage.h"
|
||||
#include "../Util/OpenMPWrapper.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
class Contractor {
|
||||
|
||||
private:
|
||||
struct ContractorEdgeData {
|
||||
ContractorEdgeData() :
|
||||
distance(0), id(0), originalEdges(0), shortcut(0), forward(0), backward(0), originalViaNodeID(false) {}
|
||||
ContractorEdgeData( unsigned _distance, unsigned _originalEdges, unsigned _id, bool _shortcut, bool _forward, bool _backward) :
|
||||
distance(_distance), id(_id), originalEdges(std::min((unsigned)1<<28, _originalEdges) ), shortcut(_shortcut), forward(_forward), backward(_backward), originalViaNodeID(false) {}
|
||||
unsigned distance;
|
||||
unsigned id;
|
||||
unsigned originalEdges:28;
|
||||
bool shortcut:1;
|
||||
bool forward:1;
|
||||
bool backward:1;
|
||||
bool originalViaNodeID:1;
|
||||
} data;
|
||||
|
||||
struct _HeapData {
|
||||
short hop;
|
||||
bool target;
|
||||
_HeapData() : hop(0), target(false) {}
|
||||
_HeapData( short h, bool t ) : hop(h), target(t) {}
|
||||
};
|
||||
|
||||
typedef DynamicGraph< ContractorEdgeData > _DynamicGraph;
|
||||
// typedef BinaryHeap< NodeID, NodeID, int, _HeapData, ArrayStorage<NodeID, NodeID> > _Heap;
|
||||
typedef BinaryHeap< NodeID, NodeID, int, _HeapData, XORFastHashStorage<NodeID, NodeID> > _Heap;
|
||||
typedef _DynamicGraph::InputEdge _ContractorEdge;
|
||||
|
||||
struct _ThreadData {
|
||||
_Heap heap;
|
||||
std::vector< _ContractorEdge > insertedEdges;
|
||||
std::vector< NodeID > neighbours;
|
||||
_ThreadData( NodeID nodes ): heap( nodes ) { }
|
||||
};
|
||||
|
||||
struct _PriorityData {
|
||||
int depth;
|
||||
_PriorityData() : depth(0) { }
|
||||
};
|
||||
|
||||
struct _ContractionInformation {
|
||||
int edgesDeleted;
|
||||
int edgesAdded;
|
||||
int originalEdgesDeleted;
|
||||
int originalEdgesAdded;
|
||||
_ContractionInformation() : edgesDeleted(0), edgesAdded(0), originalEdgesDeleted(0), originalEdgesAdded(0) {}
|
||||
};
|
||||
|
||||
struct _RemainingNodeData {
|
||||
_RemainingNodeData() : id (0), isIndependent(false) {}
|
||||
NodeID id:31;
|
||||
bool isIndependent:1;
|
||||
};
|
||||
|
||||
struct _NodePartitionor {
|
||||
inline bool operator()(_RemainingNodeData & nodeData ) const {
|
||||
return !nodeData.isIndependent;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
template<class ContainerT >
|
||||
Contractor( int nodes, ContainerT& inputEdges) {
|
||||
std::vector< _ContractorEdge > edges;
|
||||
edges.reserve(inputEdges.size()*2);
|
||||
temp_edge_counter = 0;
|
||||
|
||||
typename ContainerT::deallocation_iterator diter = inputEdges.dbegin();
|
||||
typename ContainerT::deallocation_iterator dend = inputEdges.dend();
|
||||
|
||||
_ContractorEdge newEdge;
|
||||
while(diter!=dend) {
|
||||
newEdge.source = diter->source();
|
||||
newEdge.target = diter->target();
|
||||
newEdge.data = ContractorEdgeData( (std::max)((int)diter->weight(), 1 ), 1, diter->id(), false, diter->isForward(), diter->isBackward());
|
||||
BOOST_ASSERT_MSG( newEdge.data.distance > 0, "edge distance < 1" );
|
||||
#ifndef NDEBUG
|
||||
if ( newEdge.data.distance > 24 * 60 * 60 * 10 ) {
|
||||
SimpleLogger().Write(logWARNING) <<
|
||||
"Edge weight large -> " << newEdge.data.distance;
|
||||
}
|
||||
#endif
|
||||
edges.push_back( newEdge );
|
||||
std::swap( newEdge.source, newEdge.target );
|
||||
newEdge.data.forward = diter->isBackward();
|
||||
newEdge.data.backward = diter->isForward();
|
||||
edges.push_back( newEdge );
|
||||
++diter;
|
||||
}
|
||||
//clear input vector and trim the current set of edges with the well-known swap trick
|
||||
inputEdges.clear();
|
||||
sort( edges.begin(), edges.end() );
|
||||
NodeID edge = 0;
|
||||
for ( NodeID i = 0; i < edges.size(); ) {
|
||||
const NodeID source = edges[i].source;
|
||||
const NodeID target = edges[i].target;
|
||||
const NodeID id = edges[i].data.id;
|
||||
//remove eigenloops
|
||||
if ( source == target ) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
_ContractorEdge forwardEdge;
|
||||
_ContractorEdge backwardEdge;
|
||||
forwardEdge.source = backwardEdge.source = source;
|
||||
forwardEdge.target = backwardEdge.target = target;
|
||||
forwardEdge.data.forward = backwardEdge.data.backward = true;
|
||||
forwardEdge.data.backward = backwardEdge.data.forward = false;
|
||||
forwardEdge.data.shortcut = backwardEdge.data.shortcut = false;
|
||||
forwardEdge.data.id = backwardEdge.data.id = id;
|
||||
forwardEdge.data.originalEdges = backwardEdge.data.originalEdges = 1;
|
||||
forwardEdge.data.distance = backwardEdge.data.distance = std::numeric_limits< int >::max();
|
||||
//remove parallel edges
|
||||
while ( i < edges.size() && edges[i].source == source && edges[i].target == target ) {
|
||||
if ( edges[i].data.forward) {
|
||||
forwardEdge.data.distance = std::min( edges[i].data.distance, forwardEdge.data.distance );
|
||||
}
|
||||
if ( edges[i].data.backward) {
|
||||
backwardEdge.data.distance = std::min( edges[i].data.distance, backwardEdge.data.distance );
|
||||
}
|
||||
++i;
|
||||
}
|
||||
//merge edges (s,t) and (t,s) into bidirectional edge
|
||||
if ( forwardEdge.data.distance == backwardEdge.data.distance ) {
|
||||
if ( (int)forwardEdge.data.distance != std::numeric_limits< int >::max() ) {
|
||||
forwardEdge.data.backward = true;
|
||||
edges[edge++] = forwardEdge;
|
||||
}
|
||||
} else { //insert seperate edges
|
||||
if ( ((int)forwardEdge.data.distance) != std::numeric_limits< int >::max() ) {
|
||||
edges[edge++] = forwardEdge;
|
||||
}
|
||||
if ( (int)backwardEdge.data.distance != std::numeric_limits< int >::max() ) {
|
||||
edges[edge++] = backwardEdge;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << "merged " << edges.size() - edge << " edges out of " << edges.size() << std::endl;
|
||||
edges.resize( edge );
|
||||
_graph = boost::make_shared<_DynamicGraph>( nodes, edges );
|
||||
edges.clear();
|
||||
std::vector<_ContractorEdge>().swap(edges);
|
||||
BOOST_ASSERT( 0 == edges.capacity() );
|
||||
// unsigned maxdegree = 0;
|
||||
// NodeID highestNode = 0;
|
||||
//
|
||||
// for(unsigned i = 0; i < _graph->GetNumberOfNodes(); ++i) {
|
||||
// unsigned degree = _graph->EndEdges(i) - _graph->BeginEdges(i);
|
||||
// if(degree > maxdegree) {
|
||||
// maxdegree = degree;
|
||||
// highestNode = i;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// SimpleLogger().Write() << "edges at node with id " << highestNode << " has degree " << maxdegree;
|
||||
// for(unsigned i = _graph->BeginEdges(highestNode); i < _graph->EndEdges(highestNode); ++i) {
|
||||
// SimpleLogger().Write() << " ->(" << highestNode << "," << _graph->GetTarget(i) << "); via: " << _graph->GetEdgeData(i).via;
|
||||
// }
|
||||
|
||||
//Create temporary file
|
||||
|
||||
// GetTemporaryFileName(temporaryEdgeStorageFilename);
|
||||
edge_storage_slot = TemporaryStorage::GetInstance().AllocateSlot();
|
||||
std::cout << "contractor finished initalization" << std::endl;
|
||||
}
|
||||
|
||||
~Contractor() {
|
||||
//Delete temporary file
|
||||
// remove(temporaryEdgeStorageFilename.c_str());
|
||||
TemporaryStorage::GetInstance().DeallocateSlot(edge_storage_slot);
|
||||
}
|
||||
|
||||
void Run() {
|
||||
const NodeID numberOfNodes = _graph->GetNumberOfNodes();
|
||||
Percent p (numberOfNodes);
|
||||
|
||||
const unsigned maxThreads = omp_get_max_threads();
|
||||
std::vector < _ThreadData* > threadData;
|
||||
for ( unsigned threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
||||
threadData.push_back( new _ThreadData( numberOfNodes ) );
|
||||
}
|
||||
std::cout << "Contractor is using " << maxThreads << " threads" << std::endl;
|
||||
|
||||
NodeID numberOfContractedNodes = 0;
|
||||
std::vector< _RemainingNodeData > remainingNodes( numberOfNodes );
|
||||
std::vector< float > nodePriority( numberOfNodes );
|
||||
std::vector< _PriorityData > nodeData( numberOfNodes );
|
||||
|
||||
//initialize the variables
|
||||
#pragma omp parallel for schedule ( guided )
|
||||
for ( int x = 0; x < ( int ) numberOfNodes; ++x ) {
|
||||
remainingNodes[x].id = x;
|
||||
}
|
||||
|
||||
std::cout << "initializing elimination PQ ..." << std::flush;
|
||||
#pragma omp parallel
|
||||
{
|
||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||
#pragma omp parallel for schedule ( guided )
|
||||
for ( int x = 0; x < ( int ) numberOfNodes; ++x ) {
|
||||
nodePriority[x] = _Evaluate( data, &nodeData[x], x );
|
||||
}
|
||||
}
|
||||
std::cout << "ok" << std::endl << "preprocessing " << numberOfNodes << " nodes ..." << std::flush;
|
||||
|
||||
bool flushedContractor = false;
|
||||
while ( numberOfNodes > 2 && numberOfContractedNodes < numberOfNodes ) {
|
||||
if(!flushedContractor && (numberOfContractedNodes > (numberOfNodes*0.65) ) ){
|
||||
DeallocatingVector<_ContractorEdge> newSetOfEdges; //this one is not explicitely cleared since it goes out of scope anywa
|
||||
std::cout << " [flush " << numberOfContractedNodes << " nodes] " << std::flush;
|
||||
|
||||
//Delete old heap data to free memory that we need for the coming operations
|
||||
BOOST_FOREACH(_ThreadData * data, threadData) {
|
||||
delete data;
|
||||
}
|
||||
threadData.clear();
|
||||
|
||||
//Create new priority array
|
||||
std::vector<float> newNodePriority(remainingNodes.size());
|
||||
//this map gives the old IDs from the new ones, necessary to get a consistent graph at the end of contraction
|
||||
oldNodeIDFromNewNodeIDMap.resize(remainingNodes.size());
|
||||
//this map gives the new IDs from the old ones, necessary to remap targets from the remaining graph
|
||||
std::vector<NodeID> newNodeIDFromOldNodeIDMap(numberOfNodes, UINT_MAX);
|
||||
|
||||
//build forward and backward renumbering map and remap ids in remainingNodes and Priorities.
|
||||
for(unsigned newNodeID = 0; newNodeID < remainingNodes.size(); ++newNodeID) {
|
||||
//create renumbering maps in both directions
|
||||
oldNodeIDFromNewNodeIDMap[newNodeID] = remainingNodes[newNodeID].id;
|
||||
newNodeIDFromOldNodeIDMap[remainingNodes[newNodeID].id] = newNodeID;
|
||||
newNodePriority[newNodeID] = nodePriority[remainingNodes[newNodeID].id];
|
||||
remainingNodes[newNodeID].id = newNodeID;
|
||||
}
|
||||
TemporaryStorage & tempStorage = TemporaryStorage::GetInstance();
|
||||
//walk over all nodes
|
||||
for(unsigned i = 0; i < _graph->GetNumberOfNodes(); ++i) {
|
||||
const NodeID start = i;
|
||||
for(_DynamicGraph::EdgeIterator currentEdge = _graph->BeginEdges(start); currentEdge < _graph->EndEdges(start); ++currentEdge) {
|
||||
_DynamicGraph::EdgeData & data = _graph->GetEdgeData(currentEdge);
|
||||
const NodeID target = _graph->GetTarget(currentEdge);
|
||||
if(UINT_MAX == newNodeIDFromOldNodeIDMap[i] ){
|
||||
//Save edges of this node w/o renumbering.
|
||||
tempStorage.WriteToSlot(edge_storage_slot, (char*)&start, sizeof(NodeID));
|
||||
tempStorage.WriteToSlot(edge_storage_slot, (char*)&target, sizeof(NodeID));
|
||||
tempStorage.WriteToSlot(edge_storage_slot, (char*)&data, sizeof(_DynamicGraph::EdgeData));
|
||||
++temp_edge_counter;
|
||||
} else {
|
||||
//node is not yet contracted.
|
||||
//add (renumbered) outgoing edges to new DynamicGraph.
|
||||
_ContractorEdge newEdge;
|
||||
newEdge.source = newNodeIDFromOldNodeIDMap[start];
|
||||
newEdge.target = newNodeIDFromOldNodeIDMap[target];
|
||||
newEdge.data = data;
|
||||
newEdge.data.originalViaNodeID = true;
|
||||
BOOST_ASSERT_MSG(
|
||||
UINT_MAX != newNodeIDFromOldNodeIDMap[start],
|
||||
"new start id not resolveable"
|
||||
);
|
||||
BOOST_ASSERT_MSG(
|
||||
UINT_MAX != newNodeIDFromOldNodeIDMap[target],
|
||||
"new target id not resolveable"
|
||||
);
|
||||
newSetOfEdges.push_back(newEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Delete map from old NodeIDs to new ones.
|
||||
std::vector<NodeID>().swap(newNodeIDFromOldNodeIDMap);
|
||||
|
||||
//Replace old priorities array by new one
|
||||
nodePriority.swap(newNodePriority);
|
||||
//Delete old nodePriority vector
|
||||
std::vector<float>().swap(newNodePriority);
|
||||
//old Graph is removed
|
||||
_graph.reset();
|
||||
|
||||
//create new graph
|
||||
std::sort(newSetOfEdges.begin(), newSetOfEdges.end());
|
||||
_graph = boost::make_shared<_DynamicGraph>(remainingNodes.size(), newSetOfEdges);
|
||||
|
||||
newSetOfEdges.clear();
|
||||
flushedContractor = true;
|
||||
|
||||
//INFO: MAKE SURE THIS IS THE LAST OPERATION OF THE FLUSH!
|
||||
//reinitialize heaps and ThreadData objects with appropriate size
|
||||
for ( unsigned threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
||||
threadData.push_back( new _ThreadData( _graph->GetNumberOfNodes() ) );
|
||||
}
|
||||
}
|
||||
|
||||
const int last = ( int ) remainingNodes.size();
|
||||
#pragma omp parallel
|
||||
{
|
||||
//determine independent node set
|
||||
_ThreadData* const data = threadData[omp_get_thread_num()];
|
||||
#pragma omp for schedule ( guided )
|
||||
for ( int i = 0; i < last; ++i ) {
|
||||
const NodeID node = remainingNodes[i].id;
|
||||
remainingNodes[i].isIndependent = _IsIndependent( nodePriority/*, nodeData*/, data, node );
|
||||
}
|
||||
}
|
||||
_NodePartitionor functor;
|
||||
const std::vector < _RemainingNodeData >::const_iterator first = stable_partition( remainingNodes.begin(), remainingNodes.end(), functor );
|
||||
const int firstIndependent = first - remainingNodes.begin();
|
||||
//contract independent nodes
|
||||
#pragma omp parallel
|
||||
{
|
||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||
#pragma omp for schedule ( guided ) nowait
|
||||
for ( int position = firstIndependent ; position < last; ++position ) {
|
||||
NodeID x = remainingNodes[position].id;
|
||||
_Contract< false > ( data, x );
|
||||
//nodePriority[x] = -1;
|
||||
}
|
||||
|
||||
std::sort( data->insertedEdges.begin(), data->insertedEdges.end() );
|
||||
}
|
||||
#pragma omp parallel
|
||||
{
|
||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||
#pragma omp for schedule ( guided ) nowait
|
||||
for ( int position = firstIndependent ; position < last; ++position ) {
|
||||
NodeID x = remainingNodes[position].id;
|
||||
_DeleteIncomingEdges( data, x );
|
||||
}
|
||||
}
|
||||
//insert new edges
|
||||
for ( unsigned threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
||||
_ThreadData& data = *threadData[threadNum];
|
||||
BOOST_FOREACH(const _ContractorEdge& edge, data.insertedEdges) {
|
||||
_DynamicGraph::EdgeIterator currentEdgeID = _graph->FindEdge(edge.source, edge.target);
|
||||
if(currentEdgeID < _graph->EndEdges(edge.source) ) {
|
||||
_DynamicGraph::EdgeData & currentEdgeData = _graph->GetEdgeData(currentEdgeID);
|
||||
if( currentEdgeData.shortcut &&
|
||||
edge.data.forward == currentEdgeData.forward &&
|
||||
edge.data.backward == currentEdgeData.backward &&
|
||||
edge.data.distance < currentEdgeData.distance
|
||||
) {
|
||||
// found a duplicate edge with smaller weight, update it.
|
||||
currentEdgeData = edge.data;
|
||||
// currentEdgeData.distance = std::min(currentEdgeData.distance, edge.data.distance);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_graph->InsertEdge( edge.source, edge.target, edge.data );
|
||||
}
|
||||
data.insertedEdges.clear();
|
||||
}
|
||||
//update priorities
|
||||
#pragma omp parallel
|
||||
{
|
||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||
#pragma omp for schedule ( guided ) nowait
|
||||
for ( int position = firstIndependent ; position < last; ++position ) {
|
||||
NodeID x = remainingNodes[position].id;
|
||||
_UpdateNeighbours( nodePriority, nodeData, data, x );
|
||||
}
|
||||
}
|
||||
//remove contracted nodes from the pool
|
||||
numberOfContractedNodes += last - firstIndependent;
|
||||
remainingNodes.resize( firstIndependent );
|
||||
std::vector< _RemainingNodeData>( remainingNodes ).swap( remainingNodes );
|
||||
// unsigned maxdegree = 0;
|
||||
// unsigned avgdegree = 0;
|
||||
// unsigned mindegree = UINT_MAX;
|
||||
// unsigned quaddegree = 0;
|
||||
//
|
||||
// for(unsigned i = 0; i < remainingNodes.size(); ++i) {
|
||||
// unsigned degree = _graph->EndEdges(remainingNodes[i].first) - _graph->BeginEdges(remainingNodes[i].first);
|
||||
// if(degree > maxdegree)
|
||||
// maxdegree = degree;
|
||||
// if(degree < mindegree)
|
||||
// mindegree = degree;
|
||||
//
|
||||
// avgdegree += degree;
|
||||
// quaddegree += (degree*degree);
|
||||
// }
|
||||
//
|
||||
// avgdegree /= std::max((unsigned)1,(unsigned)remainingNodes.size() );
|
||||
// quaddegree /= std::max((unsigned)1,(unsigned)remainingNodes.size() );
|
||||
//
|
||||
// SimpleLogger().Write() << "rest: " << remainingNodes.size() << ", max: " << maxdegree << ", min: " << mindegree << ", avg: " << avgdegree << ", quad: " << quaddegree;
|
||||
|
||||
p.printStatus(numberOfContractedNodes);
|
||||
}
|
||||
BOOST_FOREACH(_ThreadData * data, threadData) {
|
||||
delete data;
|
||||
}
|
||||
threadData.clear();
|
||||
}
|
||||
|
||||
template< class Edge >
|
||||
inline void GetEdges( DeallocatingVector< Edge >& edges ) {
|
||||
Percent p (_graph->GetNumberOfNodes());
|
||||
SimpleLogger().Write() << "Getting edges of minimized graph";
|
||||
NodeID numberOfNodes = _graph->GetNumberOfNodes();
|
||||
if(_graph->GetNumberOfNodes()) {
|
||||
Edge newEdge;
|
||||
for ( NodeID node = 0; node < numberOfNodes; ++node ) {
|
||||
p.printStatus(node);
|
||||
for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge < endEdges; ++edge ) {
|
||||
const NodeID target = _graph->GetTarget( edge );
|
||||
const _DynamicGraph::EdgeData& data = _graph->GetEdgeData( edge );
|
||||
if( !oldNodeIDFromNewNodeIDMap.empty() ) {
|
||||
newEdge.source = oldNodeIDFromNewNodeIDMap[node];
|
||||
newEdge.target = oldNodeIDFromNewNodeIDMap[target];
|
||||
} else {
|
||||
newEdge.source = node;
|
||||
newEdge.target = target;
|
||||
}
|
||||
BOOST_ASSERT_MSG(
|
||||
UINT_MAX != newEdge.source,
|
||||
"Source id invalid"
|
||||
);
|
||||
BOOST_ASSERT_MSG(
|
||||
UINT_MAX != newEdge.target,
|
||||
"Target id invalid"
|
||||
);
|
||||
newEdge.data.distance = data.distance;
|
||||
newEdge.data.shortcut = data.shortcut;
|
||||
if(
|
||||
!data.originalViaNodeID &&
|
||||
!oldNodeIDFromNewNodeIDMap.empty()
|
||||
) {
|
||||
newEdge.data.id = oldNodeIDFromNewNodeIDMap[data.id];
|
||||
} else {
|
||||
newEdge.data.id = data.id;
|
||||
}
|
||||
BOOST_ASSERT_MSG(
|
||||
newEdge.data.id != INT_MAX, //2^31
|
||||
"edge id invalid"
|
||||
);
|
||||
newEdge.data.forward = data.forward;
|
||||
newEdge.data.backward = data.backward;
|
||||
edges.push_back( newEdge );
|
||||
}
|
||||
}
|
||||
}
|
||||
_graph.reset();
|
||||
std::vector<NodeID>().swap(oldNodeIDFromNewNodeIDMap);
|
||||
BOOST_ASSERT( 0 == oldNodeIDFromNewNodeIDMap.capacity() );
|
||||
|
||||
TemporaryStorage & tempStorage = TemporaryStorage::GetInstance();
|
||||
//loads edges of graph before renumbering, no need for further numbering action.
|
||||
NodeID start;
|
||||
NodeID target;
|
||||
_DynamicGraph::EdgeData data;
|
||||
|
||||
Edge restored_edge;
|
||||
for(unsigned i = 0; i < temp_edge_counter; ++i) {
|
||||
tempStorage.ReadFromSlot(edge_storage_slot, (char*)&start, sizeof(NodeID));
|
||||
tempStorage.ReadFromSlot(edge_storage_slot, (char*)&target, sizeof(NodeID));
|
||||
tempStorage.ReadFromSlot(edge_storage_slot, (char*)&data, sizeof(_DynamicGraph::EdgeData));
|
||||
restored_edge.source = start;
|
||||
restored_edge.target = target;
|
||||
restored_edge.data.distance = data.distance;
|
||||
restored_edge.data.shortcut = data.shortcut;
|
||||
restored_edge.data.id = data.id;
|
||||
restored_edge.data.forward = data.forward;
|
||||
restored_edge.data.backward = data.backward;
|
||||
edges.push_back( restored_edge );
|
||||
}
|
||||
tempStorage.DeallocateSlot(edge_storage_slot);
|
||||
}
|
||||
|
||||
private:
|
||||
inline void _Dijkstra( const int maxDistance, const unsigned numTargets, const int maxNodes, _ThreadData* const data, const NodeID middleNode ){
|
||||
|
||||
_Heap& heap = data->heap;
|
||||
|
||||
int nodes = 0;
|
||||
unsigned targetsFound = 0;
|
||||
while ( heap.Size() > 0 ) {
|
||||
const NodeID node = heap.DeleteMin();
|
||||
const int distance = heap.GetKey( node );
|
||||
const short currentHop = heap.GetData( node ).hop+1;
|
||||
|
||||
if ( ++nodes > maxNodes )
|
||||
return;
|
||||
//Destination settled?
|
||||
if ( distance > maxDistance )
|
||||
return;
|
||||
|
||||
if ( heap.GetData( node ).target ) {
|
||||
++targetsFound;
|
||||
if ( targetsFound >= numTargets ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//iterate over all edges of node
|
||||
for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge != endEdges; ++edge ) {
|
||||
const ContractorEdgeData& data = _graph->GetEdgeData( edge );
|
||||
if ( !data.forward ){
|
||||
continue;
|
||||
}
|
||||
const NodeID to = _graph->GetTarget( edge );
|
||||
if(middleNode == to) {
|
||||
continue;
|
||||
}
|
||||
const int toDistance = distance + data.distance;
|
||||
|
||||
//New Node discovered -> Add to Heap + Node Info Storage
|
||||
if ( !heap.WasInserted( to ) ) {
|
||||
heap.Insert( to, toDistance, _HeapData(currentHop, false) );
|
||||
}
|
||||
//Found a shorter Path -> Update distance
|
||||
else if ( toDistance < heap.GetKey( to ) ) {
|
||||
heap.DecreaseKey( to, toDistance );
|
||||
heap.GetData( to ).hop = currentHop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline float _Evaluate( _ThreadData* const data, _PriorityData* const nodeData, const NodeID node){
|
||||
_ContractionInformation stats;
|
||||
|
||||
//perform simulated contraction
|
||||
_Contract< true> ( data, node, &stats );
|
||||
|
||||
// Result will contain the priority
|
||||
float result;
|
||||
if ( 0 == (stats.edgesDeleted*stats.originalEdgesDeleted) )
|
||||
result = 1 * nodeData->depth;
|
||||
else
|
||||
result = 2 * ((( float ) stats.edgesAdded ) / stats.edgesDeleted ) + 4 * ((( float ) stats.originalEdgesAdded ) / stats.originalEdgesDeleted ) + 1 * nodeData->depth;
|
||||
assert( result >= 0 );
|
||||
return result;
|
||||
}
|
||||
|
||||
template< bool Simulate >
|
||||
inline bool _Contract( _ThreadData* data, NodeID node, _ContractionInformation* stats = NULL ) {
|
||||
_Heap& heap = data->heap;
|
||||
int insertedEdgesSize = data->insertedEdges.size();
|
||||
std::vector< _ContractorEdge >& insertedEdges = data->insertedEdges;
|
||||
|
||||
for ( _DynamicGraph::EdgeIterator inEdge = _graph->BeginEdges( node ), endInEdges = _graph->EndEdges( node ); inEdge != endInEdges; ++inEdge ) {
|
||||
const ContractorEdgeData& inData = _graph->GetEdgeData( inEdge );
|
||||
const NodeID source = _graph->GetTarget( inEdge );
|
||||
if ( Simulate ) {
|
||||
assert( stats != NULL );
|
||||
++stats->edgesDeleted;
|
||||
stats->originalEdgesDeleted += inData.originalEdges;
|
||||
}
|
||||
if ( !inData.backward )
|
||||
continue;
|
||||
|
||||
heap.Clear();
|
||||
heap.Insert( source, 0, _HeapData() );
|
||||
int maxDistance = 0;
|
||||
unsigned numTargets = 0;
|
||||
|
||||
for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) {
|
||||
const ContractorEdgeData& outData = _graph->GetEdgeData( outEdge );
|
||||
if ( !outData.forward ) {
|
||||
continue;
|
||||
}
|
||||
const NodeID target = _graph->GetTarget( outEdge );
|
||||
const int pathDistance = inData.distance + outData.distance;
|
||||
maxDistance = std::max( maxDistance, pathDistance );
|
||||
if ( !heap.WasInserted( target ) ) {
|
||||
heap.Insert( target, INT_MAX, _HeapData( 0, true ) );
|
||||
++numTargets;
|
||||
}
|
||||
}
|
||||
|
||||
if( Simulate ) {
|
||||
_Dijkstra( maxDistance, numTargets, 1000, data, node );
|
||||
} else {
|
||||
_Dijkstra( maxDistance, numTargets, 2000, data, node );
|
||||
}
|
||||
for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) {
|
||||
const ContractorEdgeData& outData = _graph->GetEdgeData( outEdge );
|
||||
if ( !outData.forward ) {
|
||||
continue;
|
||||
}
|
||||
const NodeID target = _graph->GetTarget( outEdge );
|
||||
const int pathDistance = inData.distance + outData.distance;
|
||||
const int distance = heap.GetKey( target );
|
||||
if ( pathDistance < distance ) {
|
||||
if ( Simulate ) {
|
||||
assert( stats != NULL );
|
||||
stats->edgesAdded+=2;
|
||||
stats->originalEdgesAdded += 2* ( outData.originalEdges + inData.originalEdges );
|
||||
} else {
|
||||
_ContractorEdge newEdge;
|
||||
newEdge.source = source;
|
||||
newEdge.target = target;
|
||||
newEdge.data = ContractorEdgeData( pathDistance, outData.originalEdges + inData.originalEdges, node/*, 0, inData.turnInstruction*/, true, true, false);;
|
||||
insertedEdges.push_back( newEdge );
|
||||
std::swap( newEdge.source, newEdge.target );
|
||||
newEdge.data.forward = false;
|
||||
newEdge.data.backward = true;
|
||||
insertedEdges.push_back( newEdge );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !Simulate ) {
|
||||
for ( int i = insertedEdgesSize, iend = insertedEdges.size(); i < iend; ++i ) {
|
||||
bool found = false;
|
||||
for ( int other = i + 1 ; other < iend ; ++other ) {
|
||||
if ( insertedEdges[other].source != insertedEdges[i].source )
|
||||
continue;
|
||||
if ( insertedEdges[other].target != insertedEdges[i].target )
|
||||
continue;
|
||||
if ( insertedEdges[other].data.distance != insertedEdges[i].data.distance )
|
||||
continue;
|
||||
if ( insertedEdges[other].data.shortcut != insertedEdges[i].data.shortcut )
|
||||
continue;
|
||||
insertedEdges[other].data.forward |= insertedEdges[i].data.forward;
|
||||
insertedEdges[other].data.backward |= insertedEdges[i].data.backward;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if ( !found ) {
|
||||
insertedEdges[insertedEdgesSize++] = insertedEdges[i];
|
||||
}
|
||||
}
|
||||
insertedEdges.resize( insertedEdgesSize );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void _DeleteIncomingEdges( _ThreadData* data, const NodeID node ) {
|
||||
std::vector< NodeID >& neighbours = data->neighbours;
|
||||
neighbours.clear();
|
||||
|
||||
//find all neighbours
|
||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ) ; e < _graph->EndEdges( node ) ; ++e ) {
|
||||
const NodeID u = _graph->GetTarget( e );
|
||||
if ( u != node )
|
||||
neighbours.push_back( u );
|
||||
}
|
||||
//eliminate duplicate entries ( forward + backward edges )
|
||||
std::sort( neighbours.begin(), neighbours.end() );
|
||||
neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
|
||||
|
||||
for ( int i = 0, e = ( int ) neighbours.size(); i < e; ++i ) {
|
||||
_graph->DeleteEdgesTo( neighbours[i], node );
|
||||
}
|
||||
}
|
||||
|
||||
inline bool _UpdateNeighbours( std::vector< float > & priorities, std::vector< _PriorityData > & nodeData, _ThreadData* const data, const NodeID node) {
|
||||
std::vector< NodeID >& neighbours = data->neighbours;
|
||||
neighbours.clear();
|
||||
|
||||
//find all neighbours
|
||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ) ; e < endEdges ; ++e ) {
|
||||
const NodeID u = _graph->GetTarget( e );
|
||||
if ( u == node )
|
||||
continue;
|
||||
neighbours.push_back( u );
|
||||
nodeData[u].depth = (std::max)(nodeData[node].depth + 1, nodeData[u].depth );
|
||||
}
|
||||
//eliminate duplicate entries ( forward + backward edges )
|
||||
std::sort( neighbours.begin(), neighbours.end() );
|
||||
neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
|
||||
|
||||
BOOST_FOREACH(const NodeID u, neighbours) {
|
||||
priorities[u] = _Evaluate( data, &( nodeData )[u], u );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool _IsIndependent( const std::vector< float >& priorities/*, const std::vector< _PriorityData >& nodeData*/, _ThreadData* const data, NodeID node ) const {
|
||||
const double priority = priorities[node];
|
||||
|
||||
std::vector< NodeID >& neighbours = data->neighbours;
|
||||
neighbours.clear();
|
||||
|
||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ) ; e < _graph->EndEdges( node ) ; ++e ) {
|
||||
const NodeID target = _graph->GetTarget( e );
|
||||
if(node==target)
|
||||
continue;
|
||||
const double targetPriority = priorities[target];
|
||||
assert( targetPriority >= 0 );
|
||||
//found a neighbour with lower priority?
|
||||
if ( priority > targetPriority )
|
||||
return false;
|
||||
//tie breaking
|
||||
if ( std::abs(priority - targetPriority) < std::numeric_limits<double>::epsilon() && bias(node, target) ) {
|
||||
return false;
|
||||
}
|
||||
// TODO: C++11 copy_if with lambda
|
||||
neighbours.push_back( target );
|
||||
}
|
||||
|
||||
std::sort( neighbours.begin(), neighbours.end() );
|
||||
neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
|
||||
|
||||
//examine all neighbours that are at most 2 hops away
|
||||
BOOST_FOREACH(const NodeID u, neighbours) {
|
||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( u ) ; e < _graph->EndEdges( u ) ; ++e ) {
|
||||
const NodeID target = _graph->GetTarget( e );
|
||||
if(node==target)
|
||||
continue;
|
||||
|
||||
const double targetPriority = priorities[target];
|
||||
assert( targetPriority >= 0 );
|
||||
//found a neighbour with lower priority?
|
||||
if ( priority > targetPriority)
|
||||
return false;
|
||||
//tie breaking
|
||||
if ( std::abs(priority - targetPriority) < std::numeric_limits<double>::epsilon() && bias(node, target) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This bias function takes up 22 assembly instructions in total on X86
|
||||
*/
|
||||
inline bool bias(const NodeID a, const NodeID b) const {
|
||||
unsigned short hasha = fastHash(a);
|
||||
unsigned short hashb = fastHash(b);
|
||||
|
||||
//The compiler optimizes that to conditional register flags but without branching statements!
|
||||
if(hasha != hashb)
|
||||
return hasha < hashb;
|
||||
return a < b;
|
||||
}
|
||||
|
||||
boost::shared_ptr<_DynamicGraph> _graph;
|
||||
std::vector<_DynamicGraph::InputEdge> contractedEdges;
|
||||
unsigned edge_storage_slot;
|
||||
uint64_t temp_edge_counter;
|
||||
std::vector<NodeID> oldNodeIDFromNewNodeIDMap;
|
||||
XORFastHash fastHash;
|
||||
};
|
||||
|
||||
#endif // CONTRACTOR_H_INCLUDED
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,213 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
// This class constructs the edge-expanded routing graph
|
||||
|
||||
#ifndef EDGEBASEDGRAPHFACTORY_H_
|
||||
#define EDGEBASEDGRAPHFACTORY_H_
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
#include "../DataStructures/DynamicGraph.h"
|
||||
#include "../DataStructures/EdgeBasedNode.h"
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../DataStructures/ImportEdge.h"
|
||||
#include "../DataStructures/OriginalEdgeData.h"
|
||||
#include "../DataStructures/Percent.h"
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "../DataStructures/QueryNode.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../Util/LuaUtil.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include "GeometryCompressor.h"
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iosfwd>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
class EdgeBasedGraphFactory : boost::noncopyable {
|
||||
public:
|
||||
struct SpeedProfileProperties;
|
||||
|
||||
explicit EdgeBasedGraphFactory(
|
||||
int number_of_nodes,
|
||||
std::vector<ImportEdge> & input_edge_list,
|
||||
std::vector<NodeID> & barrier_node_list,
|
||||
std::vector<NodeID> & traffic_light_node_list,
|
||||
std::vector<TurnRestriction> & input_restrictions_list,
|
||||
std::vector<NodeInfo> & m_node_info_list,
|
||||
SpeedProfileProperties & speed_profile
|
||||
);
|
||||
|
||||
void Run(
|
||||
const std::string & original_edge_data_filename,
|
||||
const std::string & geometry_filename,
|
||||
lua_State *myLuaState
|
||||
);
|
||||
|
||||
void GetEdgeBasedEdges( DeallocatingVector< EdgeBasedEdge >& edges );
|
||||
|
||||
void GetEdgeBasedNodes( std::vector< EdgeBasedNode> & nodes);
|
||||
|
||||
TurnInstruction AnalyzeTurn(
|
||||
const NodeID u,
|
||||
const NodeID v,
|
||||
const NodeID w
|
||||
) const;
|
||||
|
||||
int GetTurnPenalty(
|
||||
const NodeID u,
|
||||
const NodeID v,
|
||||
const NodeID w,
|
||||
lua_State *myLuaState
|
||||
) const;
|
||||
|
||||
unsigned GetNumberOfEdgeBasedNodes() const;
|
||||
|
||||
struct SpeedProfileProperties{
|
||||
SpeedProfileProperties() :
|
||||
trafficSignalPenalty(0),
|
||||
uTurnPenalty(0),
|
||||
has_turn_penalty_function(false)
|
||||
{ }
|
||||
|
||||
int trafficSignalPenalty;
|
||||
int uTurnPenalty;
|
||||
bool has_turn_penalty_function;
|
||||
} speed_profile;
|
||||
|
||||
private:
|
||||
struct NodeBasedEdgeData {
|
||||
NodeBasedEdgeData() {
|
||||
//TODO: proper c'tor
|
||||
edgeBasedNodeID = UINT_MAX;
|
||||
}
|
||||
|
||||
int distance;
|
||||
unsigned edgeBasedNodeID;
|
||||
unsigned nameID;
|
||||
short type;
|
||||
bool isAccessRestricted:1;
|
||||
bool shortcut:1;
|
||||
bool forward:1;
|
||||
bool backward:1;
|
||||
bool roundabout:1;
|
||||
bool ignore_in_grid:1;
|
||||
bool contraFlow:1;
|
||||
|
||||
void SwapDirectionFlags() {
|
||||
bool temp_flag = forward;
|
||||
forward = backward;
|
||||
backward = temp_flag;
|
||||
}
|
||||
|
||||
bool IsEqualTo( const NodeBasedEdgeData & other ) const {
|
||||
return (forward == other.forward) &&
|
||||
(backward == other.backward) &&
|
||||
(nameID == other.nameID) &&
|
||||
(ignore_in_grid == other.ignore_in_grid) &&
|
||||
(contraFlow == other.contraFlow);
|
||||
}
|
||||
};
|
||||
|
||||
unsigned m_turn_restrictions_count;
|
||||
unsigned m_number_of_edge_based_nodes;
|
||||
|
||||
typedef DynamicGraph<NodeBasedEdgeData> NodeBasedDynamicGraph;
|
||||
typedef NodeBasedDynamicGraph::InputEdge NodeBasedEdge;
|
||||
typedef NodeBasedDynamicGraph::NodeIterator NodeIterator;
|
||||
typedef NodeBasedDynamicGraph::EdgeIterator EdgeIterator;
|
||||
typedef NodeBasedDynamicGraph::EdgeData EdgeData;
|
||||
typedef std::pair<NodeID, NodeID> RestrictionSource;
|
||||
typedef std::pair<NodeID, bool> RestrictionTarget;
|
||||
typedef std::vector<RestrictionTarget> EmanatingRestrictionsVector;
|
||||
typedef boost::unordered_map<RestrictionSource, unsigned > RestrictionMap;
|
||||
|
||||
std::vector<NodeInfo> m_node_info_list;
|
||||
std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list;
|
||||
std::vector<EdgeBasedNode> m_edge_based_node_list;
|
||||
DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list;
|
||||
|
||||
boost::shared_ptr<NodeBasedDynamicGraph> m_node_based_graph;
|
||||
boost::unordered_set<NodeID> m_barrier_nodes;
|
||||
boost::unordered_set<NodeID> m_traffic_lights;
|
||||
|
||||
RestrictionMap m_restriction_map;
|
||||
GeometryCompressor m_geometry_compressor;
|
||||
|
||||
NodeID CheckForEmanatingIsOnlyTurn(
|
||||
const NodeID u,
|
||||
const NodeID v
|
||||
) const;
|
||||
|
||||
bool CheckIfTurnIsRestricted(
|
||||
const NodeID u,
|
||||
const NodeID v,
|
||||
const NodeID w
|
||||
) const;
|
||||
|
||||
void InsertEdgeBasedNode(
|
||||
NodeBasedDynamicGraph::NodeIterator u,
|
||||
NodeBasedDynamicGraph::NodeIterator v,
|
||||
NodeBasedDynamicGraph::EdgeIterator e1,
|
||||
bool belongsToTinyComponent
|
||||
);
|
||||
|
||||
void BFSCompentExplorer(
|
||||
std::vector<unsigned> & component_index_list,
|
||||
std::vector<unsigned> & component_index_size
|
||||
) const;
|
||||
|
||||
void FlushVectorToStream(
|
||||
std::ofstream & edge_data_file,
|
||||
std::vector<OriginalEdgeData> & original_edge_data_vector
|
||||
) const;
|
||||
|
||||
void FixupArrivingTurnRestriction(
|
||||
const NodeID u,
|
||||
const NodeID v,
|
||||
const NodeID w
|
||||
);
|
||||
|
||||
void FixupStartingTurnRestriction(
|
||||
const NodeID u,
|
||||
const NodeID v,
|
||||
const NodeID w
|
||||
);
|
||||
|
||||
unsigned max_id;
|
||||
};
|
||||
|
||||
#endif /* EDGEBASEDGRAPHFACTORY_H_ */
|
||||
@@ -1,224 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "GeometryCompressor.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <limits>
|
||||
|
||||
int current_free_list_maximum = 0;
|
||||
int UniqueNumber() { return ++current_free_list_maximum; }
|
||||
|
||||
GeometryCompressor::GeometryCompressor()
|
||||
{
|
||||
m_free_list.reserve(100);
|
||||
IncreaseFreeList();
|
||||
}
|
||||
|
||||
void GeometryCompressor::IncreaseFreeList()
|
||||
{
|
||||
m_compressed_geometries.resize(m_compressed_geometries.size() + 100);
|
||||
for (unsigned i = 100; i > 0; --i)
|
||||
{
|
||||
m_free_list.push_back(current_free_list_maximum);
|
||||
++current_free_list_maximum;
|
||||
}
|
||||
}
|
||||
|
||||
bool GeometryCompressor::HasEntryForID(const EdgeID edge_id) const
|
||||
{
|
||||
return (m_edge_id_to_list_index_map.find(edge_id) != m_edge_id_to_list_index_map.end());
|
||||
}
|
||||
|
||||
unsigned GeometryCompressor::GetPositionForID(const EdgeID edge_id) const
|
||||
{
|
||||
boost::unordered_map<EdgeID, unsigned>::const_iterator map_iterator;
|
||||
map_iterator = m_edge_id_to_list_index_map.find(edge_id);
|
||||
BOOST_ASSERT(map_iterator != m_edge_id_to_list_index_map.end());
|
||||
BOOST_ASSERT(map_iterator->second < m_compressed_geometries.size());
|
||||
return map_iterator->second;
|
||||
}
|
||||
|
||||
void GeometryCompressor::SerializeInternalVector(const std::string &path) const
|
||||
{
|
||||
|
||||
boost::filesystem::fstream geometry_out_stream(path, std::ios::binary|std::ios::out);
|
||||
const unsigned number_of_compressed_geometries = m_compressed_geometries.size() + 1;
|
||||
BOOST_ASSERT(UINT_MAX != number_of_compressed_geometries);
|
||||
geometry_out_stream.write((char *)&number_of_compressed_geometries, sizeof(unsigned));
|
||||
|
||||
// write indices array
|
||||
unsigned prefix_sum_of_list_indices = 0;
|
||||
for (unsigned i = 0; i < m_compressed_geometries.size(); ++i)
|
||||
{
|
||||
geometry_out_stream.write((char *)&prefix_sum_of_list_indices, sizeof(unsigned));
|
||||
|
||||
const std::vector<CompressedNode> ¤t_vector = m_compressed_geometries.at(i);
|
||||
const unsigned unpacked_size = current_vector.size();
|
||||
BOOST_ASSERT(UINT_MAX != unpacked_size);
|
||||
prefix_sum_of_list_indices += unpacked_size;
|
||||
}
|
||||
// sentinel element
|
||||
geometry_out_stream.write((char *)&prefix_sum_of_list_indices, sizeof(unsigned));
|
||||
|
||||
// number of geometry entries to follow, it is the (inclusive) prefix sum
|
||||
geometry_out_stream.write((char *)&prefix_sum_of_list_indices, sizeof(unsigned));
|
||||
|
||||
unsigned control_sum = 0;
|
||||
// write compressed geometries
|
||||
for (unsigned i = 0; i < m_compressed_geometries.size(); ++i)
|
||||
{
|
||||
const std::vector<CompressedNode> ¤t_vector = m_compressed_geometries[i];
|
||||
const unsigned unpacked_size = current_vector.size();
|
||||
control_sum += unpacked_size;
|
||||
BOOST_ASSERT(UINT_MAX != unpacked_size);
|
||||
BOOST_FOREACH (const CompressedNode current_node, current_vector)
|
||||
{
|
||||
geometry_out_stream.write((char *)&(current_node.first), sizeof(NodeID));
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT(control_sum == prefix_sum_of_list_indices);
|
||||
// all done, let's close the resource
|
||||
geometry_out_stream.close();
|
||||
}
|
||||
|
||||
void GeometryCompressor::CompressEdge(const EdgeID edge_id_1,
|
||||
const EdgeID edge_id_2,
|
||||
const NodeID via_node_id,
|
||||
const NodeID target_node_id,
|
||||
const EdgeWeight weight1,
|
||||
const EdgeWeight weight2)
|
||||
{
|
||||
// remove super-trivial geometries
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != edge_id_1);
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != edge_id_2);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != via_node_id);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != target_node_id);
|
||||
BOOST_ASSERT(std::numeric_limits<int>::max() != weight1);
|
||||
BOOST_ASSERT(std::numeric_limits<int>::max() != weight2);
|
||||
|
||||
// append list of removed edge_id plus via node to surviving edge id:
|
||||
// <surv_1, .. , surv_n, via_node_id, rem_1, .. rem_n
|
||||
//
|
||||
// General scheme:
|
||||
// 1. append via node id to list of edge_id_1
|
||||
// 2. find list for edge_id_2, if yes add all elements and delete it
|
||||
|
||||
// Add via node id. List is created if it does not exist
|
||||
if (!HasEntryForID(edge_id_1))
|
||||
{
|
||||
// create a new entry in the map
|
||||
if (0 == m_free_list.size())
|
||||
{
|
||||
// make sure there is a place to put the entries
|
||||
IncreaseFreeList();
|
||||
}
|
||||
BOOST_ASSERT(!m_free_list.empty());
|
||||
m_edge_id_to_list_index_map[edge_id_1] = m_free_list.back();
|
||||
m_free_list.pop_back();
|
||||
}
|
||||
|
||||
const unsigned edge_bucket_id1 = m_edge_id_to_list_index_map[edge_id_1];
|
||||
BOOST_ASSERT(edge_bucket_id1 == GetPositionForID(edge_id_1));
|
||||
BOOST_ASSERT(edge_bucket_id1 < m_compressed_geometries.size());
|
||||
|
||||
std::vector<CompressedNode> &edge_bucket_list1 = m_compressed_geometries[edge_bucket_id1];
|
||||
|
||||
if (edge_bucket_list1.empty())
|
||||
{
|
||||
edge_bucket_list1.push_back(std::make_pair(via_node_id, weight1));
|
||||
}
|
||||
|
||||
BOOST_ASSERT(0 < edge_bucket_list1.size());
|
||||
BOOST_ASSERT(!edge_bucket_list1.empty());
|
||||
|
||||
if (HasEntryForID(edge_id_2))
|
||||
{
|
||||
// second edge is not atomic anymore
|
||||
const unsigned list_to_remove_index = GetPositionForID(edge_id_2);
|
||||
BOOST_ASSERT(list_to_remove_index < m_compressed_geometries.size());
|
||||
|
||||
std::vector<CompressedNode> &edge_bucket_list2 =
|
||||
m_compressed_geometries[list_to_remove_index];
|
||||
|
||||
// found an existing list, append it to the list of edge_id_1
|
||||
edge_bucket_list1.insert(
|
||||
edge_bucket_list1.end(), edge_bucket_list2.begin(), edge_bucket_list2.end());
|
||||
|
||||
// remove the list of edge_id_2
|
||||
m_edge_id_to_list_index_map.erase(edge_id_2);
|
||||
BOOST_ASSERT(m_edge_id_to_list_index_map.end() ==
|
||||
m_edge_id_to_list_index_map.find(edge_id_2));
|
||||
edge_bucket_list2.clear();
|
||||
BOOST_ASSERT(0 == edge_bucket_list2.size());
|
||||
m_free_list.push_back(list_to_remove_index);
|
||||
BOOST_ASSERT(list_to_remove_index == m_free_list.back());
|
||||
}
|
||||
else
|
||||
{
|
||||
// we are certain that the second edge is atomic.
|
||||
edge_bucket_list1.push_back(std::make_pair(target_node_id, weight2));
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryCompressor::PrintStatistics() const
|
||||
{
|
||||
const uint64_t compressed_edges = m_compressed_geometries.size();
|
||||
BOOST_ASSERT(0 == compressed_edges % 2);
|
||||
BOOST_ASSERT(m_compressed_geometries.size() + m_free_list.size() > 0);
|
||||
|
||||
uint64_t number_of_compressed_geometries = 0;
|
||||
uint64_t longest_chain_length = 0;
|
||||
BOOST_FOREACH (const std::vector<CompressedNode> ¤t_vector, m_compressed_geometries)
|
||||
{
|
||||
number_of_compressed_geometries += current_vector.size();
|
||||
longest_chain_length = std::max(longest_chain_length, (uint64_t)current_vector.size());
|
||||
}
|
||||
|
||||
SimpleLogger().Write() << "Geometry successfully removed:"
|
||||
"\n compressed edges: " << compressed_edges
|
||||
<< "\n compressed geometries: " << number_of_compressed_geometries
|
||||
<< "\n longest chain length: " << longest_chain_length
|
||||
<< "\n cmpr ratio: "
|
||||
<< ((float)compressed_edges /
|
||||
std::max(number_of_compressed_geometries, (uint64_t)1))
|
||||
<< "\n avg chain length: "
|
||||
<< (float)number_of_compressed_geometries /
|
||||
std::max((uint64_t)1, compressed_edges);
|
||||
}
|
||||
|
||||
const std::vector<GeometryCompressor::CompressedNode> &
|
||||
GeometryCompressor::GetBucketReference(const EdgeID edge_id) const
|
||||
{
|
||||
const unsigned index = m_edge_id_to_list_index_map.at(edge_id);
|
||||
return m_compressed_geometries.at(index);
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifndef GEOMETRY_COMPRESSOR_H
|
||||
#define GEOMETRY_COMPRESSOR_H
|
||||
|
||||
class GeometryCompressor
|
||||
{
|
||||
public:
|
||||
typedef std::pair<NodeID, EdgeWeight> CompressedNode;
|
||||
|
||||
GeometryCompressor();
|
||||
void CompressEdge(const EdgeID surviving_edge_id,
|
||||
const EdgeID removed_edge_id,
|
||||
const NodeID via_node_id,
|
||||
const NodeID target_node,
|
||||
const EdgeWeight weight1,
|
||||
const EdgeWeight weight2);
|
||||
|
||||
bool HasEntryForID(const EdgeID edge_id) const;
|
||||
void PrintStatistics() const;
|
||||
void SerializeInternalVector(const std::string &path) const;
|
||||
unsigned GetPositionForID(const EdgeID edge_id) const;
|
||||
const std::vector<GeometryCompressor::CompressedNode> &
|
||||
GetBucketReference(const EdgeID edge_id) const;
|
||||
|
||||
private:
|
||||
void IncreaseFreeList();
|
||||
std::vector<std::vector<CompressedNode> > m_compressed_geometries;
|
||||
std::vector<unsigned> m_free_list;
|
||||
boost::unordered_map<EdgeID, unsigned> m_edge_id_to_list_index_map;
|
||||
};
|
||||
|
||||
#endif // GEOMETRY_COMPRESSOR_H
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "TemporaryStorage.h"
|
||||
|
||||
TemporaryStorage::TemporaryStorage() {
|
||||
temp_directory = boost::filesystem::temp_directory_path();
|
||||
}
|
||||
|
||||
TemporaryStorage & TemporaryStorage::GetInstance(){
|
||||
static TemporaryStorage static_instance;
|
||||
return static_instance;
|
||||
}
|
||||
|
||||
TemporaryStorage::~TemporaryStorage() {
|
||||
RemoveAll();
|
||||
}
|
||||
|
||||
void TemporaryStorage::RemoveAll() {
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
for(unsigned slot_id = 0; slot_id < stream_data_list.size(); ++slot_id) {
|
||||
DeallocateSlot(slot_id);
|
||||
}
|
||||
stream_data_list.clear();
|
||||
}
|
||||
|
||||
int TemporaryStorage::AllocateSlot() {
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
try {
|
||||
stream_data_list.push_back(StreamData());
|
||||
} catch(boost::filesystem::filesystem_error & e) {
|
||||
Abort(e);
|
||||
}
|
||||
CheckIfTemporaryDeviceFull();
|
||||
return stream_data_list.size() - 1;
|
||||
}
|
||||
|
||||
void TemporaryStorage::DeallocateSlot(const int slot_id) {
|
||||
try {
|
||||
StreamData & data = stream_data_list[slot_id];
|
||||
boost::mutex::scoped_lock lock(*data.readWriteMutex);
|
||||
if(!boost::filesystem::exists(data.temp_path)) {
|
||||
return;
|
||||
}
|
||||
if(data.temp_file->is_open()) {
|
||||
data.temp_file->close();
|
||||
}
|
||||
|
||||
boost::filesystem::remove(data.temp_path);
|
||||
} catch(boost::filesystem::filesystem_error & e) {
|
||||
Abort(e);
|
||||
}
|
||||
}
|
||||
|
||||
void TemporaryStorage::WriteToSlot(
|
||||
const int slot_id,
|
||||
char * pointer,
|
||||
const std::size_t size
|
||||
) {
|
||||
try {
|
||||
StreamData & data = stream_data_list[slot_id];
|
||||
BOOST_ASSERT(data.write_mode);
|
||||
|
||||
boost::mutex::scoped_lock lock(*data.readWriteMutex);
|
||||
BOOST_ASSERT_MSG(
|
||||
data.write_mode,
|
||||
"Writing after first read is not allowed"
|
||||
);
|
||||
if( 1073741824 < data.buffer.size() ) {
|
||||
data.temp_file->write(&data.buffer[0], data.buffer.size());
|
||||
// data.temp_file->write(pointer, size);
|
||||
data.buffer.clear();
|
||||
CheckIfTemporaryDeviceFull();
|
||||
}
|
||||
data.buffer.insert(data.buffer.end(), pointer, pointer+size);
|
||||
|
||||
} catch(boost::filesystem::filesystem_error & e) {
|
||||
Abort(e);
|
||||
}
|
||||
}
|
||||
void TemporaryStorage::ReadFromSlot(
|
||||
const int slot_id,
|
||||
char * pointer,
|
||||
const std::size_t size
|
||||
) {
|
||||
try {
|
||||
StreamData & data = stream_data_list[slot_id];
|
||||
boost::mutex::scoped_lock lock(*data.readWriteMutex);
|
||||
if( data.write_mode ) {
|
||||
data.write_mode = false;
|
||||
data.temp_file->write(&data.buffer[0], data.buffer.size());
|
||||
data.buffer.clear();
|
||||
data.temp_file->seekg( data.temp_file->beg );
|
||||
BOOST_ASSERT( data.temp_file->beg == data.temp_file->tellg() );
|
||||
}
|
||||
BOOST_ASSERT( !data.write_mode );
|
||||
data.temp_file->read(pointer, size);
|
||||
} catch(boost::filesystem::filesystem_error & e) {
|
||||
Abort(e);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t TemporaryStorage::GetFreeBytesOnTemporaryDevice() {
|
||||
uint64_t value = -1;
|
||||
try {
|
||||
boost::filesystem::path p = boost::filesystem::temp_directory_path();
|
||||
boost::filesystem::space_info s = boost::filesystem::space( p );
|
||||
value = s.free;
|
||||
} catch(boost::filesystem::filesystem_error & e) {
|
||||
Abort(e);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void TemporaryStorage::CheckIfTemporaryDeviceFull() {
|
||||
boost::filesystem::path p = boost::filesystem::temp_directory_path();
|
||||
boost::filesystem::space_info s = boost::filesystem::space( p );
|
||||
if( (1024*1024) > s.free ) {
|
||||
throw OSRMException("temporary device is full");
|
||||
}
|
||||
}
|
||||
|
||||
boost::filesystem::fstream::pos_type TemporaryStorage::Tell(const int slot_id) {
|
||||
boost::filesystem::fstream::pos_type position;
|
||||
try {
|
||||
StreamData & data = stream_data_list[slot_id];
|
||||
boost::mutex::scoped_lock lock(*data.readWriteMutex);
|
||||
position = data.temp_file->tellp();
|
||||
} catch(boost::filesystem::filesystem_error & e) {
|
||||
Abort(e);
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
void TemporaryStorage::Abort(const boost::filesystem::filesystem_error& e) {
|
||||
RemoveAll();
|
||||
throw OSRMException(e.what());
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TEMPORARYSTORAGE_H_
|
||||
#define TEMPORARYSTORAGE_H_
|
||||
|
||||
#include "../Util/BoostFileSystemFix.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/integer.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
|
||||
/**
|
||||
* This class implements a singleton file storage for temporary data.
|
||||
* temporary slots can be accessed by other objects through an int
|
||||
* On deallocation every slot gets deallocated
|
||||
*
|
||||
* Access is sequential, which means, that there is no random access
|
||||
* -> Data is written in first phase and reread in second.
|
||||
*/
|
||||
|
||||
static boost::filesystem::path temp_directory;
|
||||
static std::string TemporaryFilePattern("OSRM-%%%%-%%%%-%%%%");
|
||||
class TemporaryStorage {
|
||||
public:
|
||||
static TemporaryStorage & GetInstance();
|
||||
virtual ~TemporaryStorage();
|
||||
|
||||
int AllocateSlot();
|
||||
void DeallocateSlot(const int slot_id);
|
||||
void WriteToSlot(const int slot_id, char * pointer, const std::size_t size);
|
||||
void ReadFromSlot(const int slot_id, char * pointer, const std::size_t size);
|
||||
//returns the number of free bytes
|
||||
uint64_t GetFreeBytesOnTemporaryDevice();
|
||||
boost::filesystem::fstream::pos_type Tell(const int slot_id);
|
||||
void RemoveAll();
|
||||
private:
|
||||
TemporaryStorage();
|
||||
TemporaryStorage(TemporaryStorage const &){};
|
||||
|
||||
TemporaryStorage & operator=(TemporaryStorage const &) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Abort(const boost::filesystem::filesystem_error& e);
|
||||
void CheckIfTemporaryDeviceFull();
|
||||
|
||||
struct StreamData {
|
||||
bool write_mode;
|
||||
boost::filesystem::path temp_path;
|
||||
boost::shared_ptr<boost::filesystem::fstream> temp_file;
|
||||
boost::shared_ptr<boost::mutex> readWriteMutex;
|
||||
std::vector<char> buffer;
|
||||
|
||||
StreamData() :
|
||||
write_mode(true),
|
||||
temp_path(
|
||||
boost::filesystem::unique_path(
|
||||
temp_directory.append(
|
||||
TemporaryFilePattern.begin(),
|
||||
TemporaryFilePattern.end()
|
||||
)
|
||||
)
|
||||
),
|
||||
temp_file(
|
||||
new boost::filesystem::fstream(
|
||||
temp_path,
|
||||
std::ios::in|std::ios::out|std::ios::trunc|std::ios::binary
|
||||
)
|
||||
),
|
||||
readWriteMutex(boost::make_shared<boost::mutex>())
|
||||
{
|
||||
if( temp_file->fail() ) {
|
||||
throw OSRMException("temporary file could not be created");
|
||||
}
|
||||
}
|
||||
};
|
||||
//vector of file streams that is used to store temporary data
|
||||
boost::mutex mutex;
|
||||
std::vector<StreamData> stream_data_list;
|
||||
};
|
||||
|
||||
#endif /* TEMPORARYSTORAGE_H_ */
|
||||
@@ -1,300 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BINARY_HEAP_H
|
||||
#define BINARY_HEAP_H
|
||||
|
||||
//Not compatible with non contiguous node ids
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class ArrayStorage {
|
||||
public:
|
||||
|
||||
explicit ArrayStorage( size_t size ) : positions( new Key[size] ) {
|
||||
memset(positions, 0, size*sizeof(Key));
|
||||
}
|
||||
|
||||
~ArrayStorage() {
|
||||
delete[] positions;
|
||||
}
|
||||
|
||||
Key &operator[]( NodeID node ) {
|
||||
return positions[node];
|
||||
}
|
||||
|
||||
void Clear() {}
|
||||
|
||||
private:
|
||||
Key* positions;
|
||||
};
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class MapStorage {
|
||||
public:
|
||||
|
||||
explicit MapStorage( size_t ) {}
|
||||
|
||||
Key &operator[]( NodeID node ) {
|
||||
return nodes[node];
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
nodes.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
std::map< NodeID, Key > nodes;
|
||||
|
||||
};
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class UnorderedMapStorage {
|
||||
typedef boost::unordered_map<NodeID, Key> UnorderedMapType;
|
||||
typedef typename UnorderedMapType::iterator UnorderedMapIterator;
|
||||
typedef typename UnorderedMapType::const_iterator UnorderedMapConstIterator;
|
||||
public:
|
||||
|
||||
explicit UnorderedMapStorage( size_t ) {
|
||||
//hash table gets 1000 Buckets
|
||||
nodes.rehash(1000);
|
||||
}
|
||||
|
||||
Key & operator[]( const NodeID node ) {
|
||||
return nodes[node];
|
||||
}
|
||||
|
||||
Key const & operator[]( const NodeID node ) const {
|
||||
UnorderedMapConstIterator iter = nodes.find(node);
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
nodes.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
boost::unordered_map< NodeID, Key > nodes;
|
||||
};
|
||||
|
||||
template<
|
||||
typename NodeID,
|
||||
typename Key,
|
||||
typename Weight,
|
||||
typename Data,
|
||||
typename IndexStorage = ArrayStorage<NodeID, NodeID>
|
||||
>
|
||||
class BinaryHeap {
|
||||
private:
|
||||
BinaryHeap( const BinaryHeap& right );
|
||||
void operator=( const BinaryHeap& right );
|
||||
public:
|
||||
typedef Weight WeightType;
|
||||
typedef Data DataType;
|
||||
|
||||
explicit BinaryHeap( size_t maxID )
|
||||
:
|
||||
nodeIndex( maxID )
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
heap.resize( 1 );
|
||||
insertedNodes.clear();
|
||||
heap[0].weight = std::numeric_limits< Weight >::min();
|
||||
nodeIndex.Clear();
|
||||
}
|
||||
|
||||
Key Size() const {
|
||||
return static_cast<Key>( heap.size() - 1 );
|
||||
}
|
||||
|
||||
bool Empty() const {
|
||||
return 0 == Size();
|
||||
}
|
||||
|
||||
void Insert( NodeID node, Weight weight, const Data &data ) {
|
||||
HeapElement element;
|
||||
element.index = static_cast<NodeID>(insertedNodes.size());
|
||||
element.weight = weight;
|
||||
const Key key = static_cast<Key>(heap.size());
|
||||
heap.push_back( element );
|
||||
insertedNodes.push_back( HeapNode( node, key, weight, data ) );
|
||||
nodeIndex[node] = element.index;
|
||||
Upheap( key );
|
||||
CheckHeap();
|
||||
}
|
||||
|
||||
Data& GetData( NodeID node ) {
|
||||
const Key index = nodeIndex[node];
|
||||
return insertedNodes[index].data;
|
||||
}
|
||||
|
||||
Data const & GetData( NodeID node ) const {
|
||||
const Key index = nodeIndex[node];
|
||||
return insertedNodes[index].data;
|
||||
}
|
||||
|
||||
Weight& GetKey( NodeID node ) {
|
||||
const Key index = nodeIndex[node];
|
||||
return insertedNodes[index].weight;
|
||||
}
|
||||
|
||||
bool WasRemoved( const NodeID node ) {
|
||||
BOOST_ASSERT( WasInserted( node ) );
|
||||
const Key index = nodeIndex[node];
|
||||
return insertedNodes[index].key == 0;
|
||||
}
|
||||
|
||||
bool WasInserted( const NodeID node ) {
|
||||
const Key index = nodeIndex[node];
|
||||
if ( index >= static_cast<Key> (insertedNodes.size()) )
|
||||
return false;
|
||||
return insertedNodes[index].node == node;
|
||||
}
|
||||
|
||||
NodeID Min() const {
|
||||
BOOST_ASSERT( heap.size() > 1 );
|
||||
return insertedNodes[heap[1].index].node;
|
||||
}
|
||||
|
||||
NodeID DeleteMin() {
|
||||
BOOST_ASSERT( heap.size() > 1 );
|
||||
const Key removedIndex = heap[1].index;
|
||||
heap[1] = heap[heap.size()-1];
|
||||
heap.pop_back();
|
||||
if ( heap.size() > 1 )
|
||||
Downheap( 1 );
|
||||
insertedNodes[removedIndex].key = 0;
|
||||
CheckHeap();
|
||||
return insertedNodes[removedIndex].node;
|
||||
}
|
||||
|
||||
void DeleteAll() {
|
||||
for ( typename std::vector< HeapElement >::iterator i = heap.begin() + 1, iend = heap.end(); i != iend; ++i )
|
||||
insertedNodes[i->index].key = 0;
|
||||
heap.resize( 1 );
|
||||
heap[0].weight = (std::numeric_limits< Weight >::min)();
|
||||
}
|
||||
|
||||
void DecreaseKey( NodeID node, Weight weight ) {
|
||||
BOOST_ASSERT( UINT_MAX != node );
|
||||
const Key & index = nodeIndex[node];
|
||||
Key & key = insertedNodes[index].key;
|
||||
BOOST_ASSERT ( key >= 0 );
|
||||
|
||||
insertedNodes[index].weight = weight;
|
||||
heap[key].weight = weight;
|
||||
Upheap( key );
|
||||
CheckHeap();
|
||||
}
|
||||
|
||||
private:
|
||||
class HeapNode {
|
||||
public:
|
||||
HeapNode( NodeID n, Key k, Weight w, Data d )
|
||||
:
|
||||
node(n),
|
||||
key(k),
|
||||
weight(w),
|
||||
data(d)
|
||||
{ }
|
||||
|
||||
NodeID node;
|
||||
Key key;
|
||||
Weight weight;
|
||||
Data data;
|
||||
};
|
||||
struct HeapElement {
|
||||
Key index;
|
||||
Weight weight;
|
||||
};
|
||||
|
||||
std::vector< HeapNode > insertedNodes;
|
||||
std::vector< HeapElement > heap;
|
||||
IndexStorage nodeIndex;
|
||||
|
||||
void Downheap( Key key ) {
|
||||
const Key droppingIndex = heap[key].index;
|
||||
const Weight weight = heap[key].weight;
|
||||
Key nextKey = key << 1;
|
||||
while( nextKey < static_cast<Key>( heap.size() ) ){
|
||||
const Key nextKeyOther = nextKey + 1;
|
||||
if (
|
||||
( nextKeyOther < static_cast<Key>( heap.size() ) ) &&
|
||||
( heap[nextKey].weight > heap[nextKeyOther].weight )
|
||||
) {
|
||||
nextKey = nextKeyOther;
|
||||
}
|
||||
if ( weight <= heap[nextKey].weight ){
|
||||
break;
|
||||
}
|
||||
heap[key] = heap[nextKey];
|
||||
insertedNodes[heap[key].index].key = key;
|
||||
key = nextKey;
|
||||
nextKey <<= 1;
|
||||
}
|
||||
heap[key].index = droppingIndex;
|
||||
heap[key].weight = weight;
|
||||
insertedNodes[droppingIndex].key = key;
|
||||
}
|
||||
|
||||
void Upheap( Key key ) {
|
||||
const Key risingIndex = heap[key].index;
|
||||
const Weight weight = heap[key].weight;
|
||||
Key nextKey = key >> 1;
|
||||
while ( heap[nextKey].weight > weight ) {
|
||||
BOOST_ASSERT( nextKey != 0 );
|
||||
heap[key] = heap[nextKey];
|
||||
insertedNodes[heap[key].index].key = key;
|
||||
key = nextKey;
|
||||
nextKey >>= 1;
|
||||
}
|
||||
heap[key].index = risingIndex;
|
||||
heap[key].weight = weight;
|
||||
insertedNodes[risingIndex].key = key;
|
||||
}
|
||||
|
||||
void CheckHeap() {
|
||||
#ifndef NDEBUG
|
||||
for ( Key i = 2; i < (Key) heap.size(); ++i ) {
|
||||
BOOST_ASSERT( heap[i].weight >= heap[i >> 1].weight );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#endif //BINARY_HEAP_H
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CONCURRENTQUEUE_H_
|
||||
#define CONCURRENTQUEUE_H_
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/circular_buffer.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
template<typename Data>
|
||||
class ConcurrentQueue {
|
||||
|
||||
public:
|
||||
explicit ConcurrentQueue(const size_t max_size) : m_internal_queue(max_size) { }
|
||||
|
||||
inline void push(const Data & data) {
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
m_not_full.wait(
|
||||
lock,
|
||||
boost::bind(&ConcurrentQueue<Data>::is_not_full, this)
|
||||
);
|
||||
m_internal_queue.push_back(data);
|
||||
lock.unlock();
|
||||
m_not_empty.notify_one();
|
||||
}
|
||||
|
||||
inline bool empty() const {
|
||||
return m_internal_queue.empty();
|
||||
}
|
||||
|
||||
inline void wait_and_pop(Data & popped_value) {
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
m_not_empty.wait(
|
||||
lock,
|
||||
boost::bind(&ConcurrentQueue<Data>::is_not_empty, this)
|
||||
);
|
||||
popped_value = m_internal_queue.front();
|
||||
m_internal_queue.pop_front();
|
||||
lock.unlock();
|
||||
m_not_full.notify_one();
|
||||
}
|
||||
|
||||
inline bool try_pop(Data& popped_value) {
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
if(m_internal_queue.empty()) {
|
||||
return false;
|
||||
}
|
||||
popped_value=m_internal_queue.front();
|
||||
m_internal_queue.pop_front();
|
||||
lock.unlock();
|
||||
m_not_full.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
inline bool is_not_empty() const {
|
||||
return !m_internal_queue.empty();
|
||||
}
|
||||
|
||||
inline bool is_not_full() const {
|
||||
return m_internal_queue.size() < m_internal_queue.capacity();
|
||||
}
|
||||
|
||||
boost::circular_buffer<Data> m_internal_queue;
|
||||
boost::mutex m_mutex;
|
||||
boost::condition m_not_empty;
|
||||
boost::condition m_not_full;
|
||||
};
|
||||
|
||||
#endif /* CONCURRENTQUEUE_H_ */
|
||||
@@ -1,183 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include <bitset>
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
FixedPointCoordinate::FixedPointCoordinate()
|
||||
: lat(std::numeric_limits<int>::min()),
|
||||
lon(std::numeric_limits<int>::min())
|
||||
{ }
|
||||
|
||||
FixedPointCoordinate::FixedPointCoordinate(int lat, int lon)
|
||||
: lat(lat),
|
||||
lon(lon)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if(0 != (std::abs(lat) >> 30))
|
||||
{
|
||||
std::bitset<32> y(lat);
|
||||
SimpleLogger().Write(logDEBUG) << "broken lat: " << lat << ", bits: " << y;
|
||||
}
|
||||
if(0 != (std::abs(lon) >> 30))
|
||||
{
|
||||
std::bitset<32> x(lon);
|
||||
SimpleLogger().Write(logDEBUG) << "broken lon: " << lon << ", bits: " << x;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FixedPointCoordinate::Reset() {
|
||||
lat = std::numeric_limits<int>::min();
|
||||
lon = std::numeric_limits<int>::min();
|
||||
}
|
||||
bool FixedPointCoordinate::isSet() const {
|
||||
return (std::numeric_limits<int>::min() != lat) &&
|
||||
(std::numeric_limits<int>::min() != lon);
|
||||
}
|
||||
bool FixedPointCoordinate::isValid() const {
|
||||
if (lat > 90*COORDINATE_PRECISION ||
|
||||
lat < -90*COORDINATE_PRECISION ||
|
||||
lon > 180*COORDINATE_PRECISION ||
|
||||
lon < -180*COORDINATE_PRECISION)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool FixedPointCoordinate::operator==(const FixedPointCoordinate & other) const {
|
||||
return lat == other.lat && lon == other.lon;
|
||||
}
|
||||
|
||||
double FixedPointCoordinate::ApproximateDistance(
|
||||
const int lat1,
|
||||
const int lon1,
|
||||
const int lat2,
|
||||
const int lon2
|
||||
) {
|
||||
BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
|
||||
double RAD = 0.017453292519943295769236907684886;
|
||||
double lt1 = lat1/COORDINATE_PRECISION;
|
||||
double ln1 = lon1/COORDINATE_PRECISION;
|
||||
double lt2 = lat2/COORDINATE_PRECISION;
|
||||
double ln2 = lon2/COORDINATE_PRECISION;
|
||||
double dlat1=lt1*(RAD);
|
||||
|
||||
double dlong1=ln1*(RAD);
|
||||
double dlat2=lt2*(RAD);
|
||||
double dlong2=ln2*(RAD);
|
||||
|
||||
double dLong=dlong1-dlong2;
|
||||
double dLat=dlat1-dlat2;
|
||||
|
||||
double aHarv= pow(sin(dLat/2.0),2.0)+cos(dlat1)*cos(dlat2)*pow(sin(dLong/2.),2);
|
||||
double cHarv=2.*atan2(sqrt(aHarv),sqrt(1.0-aHarv));
|
||||
//earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
|
||||
//The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
|
||||
const double earth=6372797.560856;
|
||||
return earth*cHarv;
|
||||
}
|
||||
|
||||
double FixedPointCoordinate::ApproximateDistance(
|
||||
const FixedPointCoordinate &c1,
|
||||
const FixedPointCoordinate &c2
|
||||
) {
|
||||
return ApproximateDistance(c1.lat, c1.lon, c2.lat, c2.lon);
|
||||
}
|
||||
|
||||
double FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
const FixedPointCoordinate &c1,
|
||||
const FixedPointCoordinate &c2
|
||||
) {
|
||||
BOOST_ASSERT(c1.lat != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(c1.lon != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(c2.lat != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(c2.lon != std::numeric_limits<int>::min());
|
||||
const double RAD = 0.017453292519943295769236907684886;
|
||||
const double lat1 = (c1.lat/COORDINATE_PRECISION)*RAD;
|
||||
const double lon1 = (c1.lon/COORDINATE_PRECISION)*RAD;
|
||||
const double lat2 = (c2.lat/COORDINATE_PRECISION)*RAD;
|
||||
const double lon2 = (c2.lon/COORDINATE_PRECISION)*RAD;
|
||||
|
||||
const double x = (lon2-lon1) * cos((lat1+lat2)/2.);
|
||||
const double y = (lat2-lat1);
|
||||
const double earthRadius = 6372797.560856;
|
||||
return sqrt(x*x + y*y) * earthRadius;
|
||||
}
|
||||
|
||||
void FixedPointCoordinate::convertInternalLatLonToString(
|
||||
const int value,
|
||||
std::string & output
|
||||
) {
|
||||
char buffer[100];
|
||||
buffer[11] = 0; // zero termination
|
||||
char* string = printInt< 11, 6 >( buffer, value );
|
||||
output = string;
|
||||
}
|
||||
|
||||
void FixedPointCoordinate::convertInternalCoordinateToString(
|
||||
const FixedPointCoordinate & coord,
|
||||
std::string & output
|
||||
) {
|
||||
std::string tmp;
|
||||
tmp.reserve(23);
|
||||
convertInternalLatLonToString(coord.lon, tmp);
|
||||
output = tmp;
|
||||
output += ",";
|
||||
convertInternalLatLonToString(coord.lat, tmp);
|
||||
output += tmp;
|
||||
}
|
||||
|
||||
void FixedPointCoordinate::convertInternalReversedCoordinateToString(
|
||||
const FixedPointCoordinate & coord,
|
||||
std::string & output
|
||||
) {
|
||||
std::string tmp;
|
||||
tmp.reserve(23);
|
||||
convertInternalLatLonToString(coord.lat, tmp);
|
||||
output = tmp;
|
||||
output += ",";
|
||||
convertInternalLatLonToString(coord.lon, tmp);
|
||||
output += tmp;
|
||||
}
|
||||
|
||||
void FixedPointCoordinate::Output(std::ostream & out) const
|
||||
{
|
||||
out << "(" << lat/COORDINATE_PRECISION << "," << lon/COORDINATE_PRECISION << ")";
|
||||
}
|
||||
@@ -1,324 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DEALLOCATINGVECTOR_H_
|
||||
#define DEALLOCATINGVECTOR_H_
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#if __cplusplus > 199711L
|
||||
#define DEALLOCATION_VECTOR_NULL_PTR nullptr
|
||||
#else
|
||||
#define DEALLOCATION_VECTOR_NULL_PTR NULL
|
||||
#endif
|
||||
|
||||
|
||||
template<typename ElementT, std::size_t bucketSizeC = 8388608/sizeof(ElementT), bool DeallocateC = false>
|
||||
class DeallocatingVectorIterator : public std::iterator<std::random_access_iterator_tag, ElementT> {
|
||||
protected:
|
||||
|
||||
class DeallocatingVectorIteratorState {
|
||||
private:
|
||||
//make constructors explicit, so we do not mix random access and deallocation iterators.
|
||||
DeallocatingVectorIteratorState();
|
||||
public:
|
||||
explicit DeallocatingVectorIteratorState(const DeallocatingVectorIteratorState &r) : /*mData(r.mData),*/ mIndex(r.mIndex), mBucketList(r.mBucketList) {}
|
||||
explicit DeallocatingVectorIteratorState(const std::size_t idx, std::vector<ElementT *> & input_list) : /*mData(DEALLOCATION_VECTOR_NULL_PTR),*/ mIndex(idx), mBucketList(input_list) {
|
||||
}
|
||||
std::size_t mIndex;
|
||||
std::vector<ElementT *> & mBucketList;
|
||||
|
||||
inline bool operator!=(const DeallocatingVectorIteratorState &other) {
|
||||
return mIndex != other.mIndex;
|
||||
}
|
||||
|
||||
inline bool operator==(const DeallocatingVectorIteratorState &other) {
|
||||
return mIndex == other.mIndex;
|
||||
}
|
||||
|
||||
bool operator<(const DeallocatingVectorIteratorState &other) const {
|
||||
return mIndex < other.mIndex;
|
||||
}
|
||||
|
||||
bool operator>(const DeallocatingVectorIteratorState &other) const {
|
||||
return mIndex > other.mIndex;
|
||||
}
|
||||
|
||||
bool operator>=(const DeallocatingVectorIteratorState &other) const {
|
||||
return mIndex >= other.mIndex;
|
||||
}
|
||||
|
||||
//This is a hack to make assignment operator possible with reference member
|
||||
inline DeallocatingVectorIteratorState& operator= (const DeallocatingVectorIteratorState &a) {
|
||||
if (this != &a) {
|
||||
this->DeallocatingVectorIteratorState::~DeallocatingVectorIteratorState(); // explicit non-virtual destructor
|
||||
new (this) DeallocatingVectorIteratorState(a); // placement new
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
DeallocatingVectorIteratorState mState;
|
||||
|
||||
public:
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::value_type value_type;
|
||||
typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::difference_type difference_type;
|
||||
typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::reference reference;
|
||||
typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::pointer pointer;
|
||||
|
||||
DeallocatingVectorIterator() {}
|
||||
|
||||
template<typename T2>
|
||||
explicit DeallocatingVectorIterator(const DeallocatingVectorIterator<T2> & r) : mState(r.mState) {}
|
||||
|
||||
DeallocatingVectorIterator(std::size_t idx, std::vector<ElementT *> & input_list) : mState(idx, input_list) {}
|
||||
explicit DeallocatingVectorIterator(const DeallocatingVectorIteratorState & r) : mState(r) {}
|
||||
|
||||
template<typename T2>
|
||||
DeallocatingVectorIterator& operator=(const DeallocatingVectorIterator<T2> &r) {
|
||||
if(DeallocateC) BOOST_ASSERT(false);
|
||||
mState = r.mState; return *this;
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator& operator++() { //prefix
|
||||
++mState.mIndex;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator& operator--() { //prefix
|
||||
if(DeallocateC) BOOST_ASSERT(false);
|
||||
--mState.mIndex;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator operator++(int) { //postfix
|
||||
DeallocatingVectorIteratorState _myState(mState);
|
||||
mState.mIndex++;
|
||||
return DeallocatingVectorIterator(_myState);
|
||||
}
|
||||
inline DeallocatingVectorIterator operator--(int) { //postfix
|
||||
if(DeallocateC) BOOST_ASSERT(false);
|
||||
DeallocatingVectorIteratorState _myState(mState);
|
||||
mState.mIndex--;
|
||||
return DeallocatingVectorIterator(_myState);
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator operator+(const difference_type& n) const {
|
||||
DeallocatingVectorIteratorState _myState(mState);
|
||||
_myState.mIndex+=n;
|
||||
return DeallocatingVectorIterator(_myState);
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator& operator+=(const difference_type& n) {
|
||||
mState.mIndex+=n; return *this;
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator operator-(const difference_type& n) const {
|
||||
if(DeallocateC) BOOST_ASSERT(false);
|
||||
DeallocatingVectorIteratorState _myState(mState);
|
||||
_myState.mIndex-=n;
|
||||
return DeallocatingVectorIterator(_myState);
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator& operator-=(const difference_type &n) const {
|
||||
if(DeallocateC) BOOST_ASSERT(false);
|
||||
mState.mIndex-=n; return *this;
|
||||
}
|
||||
|
||||
inline reference operator*() const {
|
||||
std::size_t _bucket = mState.mIndex/bucketSizeC;
|
||||
std::size_t _index = mState.mIndex%bucketSizeC;
|
||||
return (mState.mBucketList[_bucket][_index]);
|
||||
}
|
||||
|
||||
inline pointer operator->() const {
|
||||
std::size_t _bucket = mState.mIndex/bucketSizeC;
|
||||
std::size_t _index = mState.mIndex%bucketSizeC;
|
||||
return &(mState.mBucketList[_bucket][_index]);
|
||||
}
|
||||
|
||||
inline bool operator!=(const DeallocatingVectorIterator & other) {
|
||||
return mState != other.mState;
|
||||
}
|
||||
|
||||
inline bool operator==(const DeallocatingVectorIterator & other) {
|
||||
return mState == other.mState;
|
||||
}
|
||||
|
||||
inline bool operator<(const DeallocatingVectorIterator & other) const {
|
||||
return mState < other.mState;
|
||||
}
|
||||
|
||||
inline bool operator>(const DeallocatingVectorIterator & other) const {
|
||||
return mState > other.mState;
|
||||
}
|
||||
|
||||
inline bool operator>=(const DeallocatingVectorIterator & other) const {
|
||||
return mState >= other.mState;
|
||||
}
|
||||
|
||||
difference_type operator-(const DeallocatingVectorIterator & other) {
|
||||
if(DeallocateC) BOOST_ASSERT(false);
|
||||
return mState.mIndex-other.mState.mIndex;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ElementT, std::size_t bucketSizeC = 8388608/sizeof(ElementT) >
|
||||
class DeallocatingVector {
|
||||
private:
|
||||
std::size_t mCurrentSize;
|
||||
std::vector<ElementT *> mBucketList;
|
||||
|
||||
public:
|
||||
typedef ElementT value_type;
|
||||
typedef DeallocatingVectorIterator<ElementT, bucketSizeC, false> iterator;
|
||||
typedef DeallocatingVectorIterator<ElementT, bucketSizeC, false> const_iterator;
|
||||
|
||||
//this iterator deallocates all buckets that have been visited. Iterators to visited objects become invalid.
|
||||
typedef DeallocatingVectorIterator<ElementT, bucketSizeC, true> deallocation_iterator;
|
||||
|
||||
DeallocatingVector() : mCurrentSize(0) {
|
||||
//initial bucket
|
||||
mBucketList.push_back(new ElementT[bucketSizeC]);
|
||||
}
|
||||
|
||||
~DeallocatingVector() {
|
||||
clear();
|
||||
}
|
||||
|
||||
inline void swap(DeallocatingVector<ElementT, bucketSizeC> & other) {
|
||||
std::swap(mCurrentSize, other.mCurrentSize);
|
||||
mBucketList.swap(other.mBucketList);
|
||||
}
|
||||
|
||||
inline void clear() {
|
||||
//Delete[]'ing ptr's to all Buckets
|
||||
for(unsigned i = 0; i < mBucketList.size(); ++i) {
|
||||
if(DEALLOCATION_VECTOR_NULL_PTR != mBucketList[i]) {
|
||||
delete[] mBucketList[i];
|
||||
mBucketList[i] = DEALLOCATION_VECTOR_NULL_PTR;
|
||||
}
|
||||
}
|
||||
//Removing all ptrs from vector
|
||||
std::vector<ElementT *>().swap(mBucketList);
|
||||
mCurrentSize = 0;
|
||||
}
|
||||
|
||||
inline void push_back(const ElementT & element) {
|
||||
std::size_t _capacity = capacity();
|
||||
if(mCurrentSize == _capacity) {
|
||||
mBucketList.push_back(new ElementT[bucketSizeC]);
|
||||
}
|
||||
|
||||
std::size_t _index = size()%bucketSizeC;
|
||||
mBucketList.back()[_index] = element;
|
||||
++mCurrentSize;
|
||||
}
|
||||
|
||||
inline void reserve(const std::size_t) const {
|
||||
//don't do anything
|
||||
}
|
||||
|
||||
inline void resize(const std::size_t new_size) {
|
||||
if(new_size > mCurrentSize) {
|
||||
while(capacity() < new_size) {
|
||||
mBucketList.push_back(new ElementT[bucketSizeC]);
|
||||
}
|
||||
mCurrentSize = new_size;
|
||||
}
|
||||
if(new_size < mCurrentSize) {
|
||||
std::size_t number_of_necessary_buckets = 1+(new_size / bucketSizeC);
|
||||
|
||||
for(unsigned i = number_of_necessary_buckets; i < mBucketList.size(); ++i) {
|
||||
delete[] mBucketList[i];
|
||||
}
|
||||
mBucketList.resize(number_of_necessary_buckets);
|
||||
mCurrentSize = new_size;
|
||||
}
|
||||
}
|
||||
|
||||
inline std::size_t size() const {
|
||||
return mCurrentSize;
|
||||
}
|
||||
|
||||
inline std::size_t capacity() const {
|
||||
return mBucketList.size() * bucketSizeC;
|
||||
}
|
||||
|
||||
inline iterator begin() {
|
||||
return iterator(static_cast<std::size_t>(0), mBucketList);
|
||||
}
|
||||
|
||||
inline iterator end() {
|
||||
return iterator(size(), mBucketList);
|
||||
}
|
||||
|
||||
inline deallocation_iterator dbegin() {
|
||||
return deallocation_iterator(static_cast<std::size_t>(0), mBucketList);
|
||||
}
|
||||
|
||||
inline deallocation_iterator dend() {
|
||||
return deallocation_iterator(size(), mBucketList);
|
||||
}
|
||||
|
||||
inline const_iterator begin() const {
|
||||
return const_iterator(static_cast<std::size_t>(0), mBucketList);
|
||||
}
|
||||
|
||||
inline const_iterator end() const {
|
||||
return const_iterator(size(), mBucketList);
|
||||
}
|
||||
|
||||
inline ElementT & operator[](const std::size_t index) {
|
||||
std::size_t _bucket = index / bucketSizeC;
|
||||
std::size_t _index = index % bucketSizeC;
|
||||
return (mBucketList[_bucket][_index]);
|
||||
}
|
||||
|
||||
const inline ElementT & operator[](const std::size_t index) const {
|
||||
std::size_t _bucket = index / bucketSizeC;
|
||||
std::size_t _index = index % bucketSizeC;
|
||||
return (mBucketList[_bucket][_index]);
|
||||
}
|
||||
|
||||
inline ElementT & back() {
|
||||
std::size_t _bucket = mCurrentSize / bucketSizeC;
|
||||
std::size_t _index = mCurrentSize % bucketSizeC;
|
||||
return (mBucketList[_bucket][_index]);
|
||||
}
|
||||
|
||||
const inline ElementT & back() const {
|
||||
std::size_t _bucket = mCurrentSize / bucketSizeC;
|
||||
std::size_t _index = mCurrentSize % bucketSizeC;
|
||||
return (mBucketList[_bucket][_index]);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* DEALLOCATINGVECTOR_H_ */
|
||||
@@ -1,247 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DYNAMICGRAPH_H_INCLUDED
|
||||
#define DYNAMICGRAPH_H_INCLUDED
|
||||
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/integer.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
template< typename EdgeDataT>
|
||||
class DynamicGraph {
|
||||
public:
|
||||
typedef EdgeDataT EdgeData;
|
||||
typedef unsigned NodeIterator;
|
||||
typedef unsigned EdgeIterator;
|
||||
|
||||
class InputEdge {
|
||||
public:
|
||||
NodeIterator source;
|
||||
NodeIterator target;
|
||||
EdgeDataT data;
|
||||
bool operator<( const InputEdge& right ) const {
|
||||
if ( source != right.source )
|
||||
return source < right.source;
|
||||
return target < right.target;
|
||||
}
|
||||
};
|
||||
|
||||
//Constructs an empty graph with a given number of nodes.
|
||||
explicit DynamicGraph( int32_t nodes ) : m_numNodes(nodes), m_numEdges(0) {
|
||||
m_nodes.reserve( m_numNodes );
|
||||
m_nodes.resize( m_numNodes );
|
||||
|
||||
m_edges.reserve( m_numNodes * 1.1 );
|
||||
m_edges.resize( m_numNodes );
|
||||
}
|
||||
|
||||
template<class ContainerT>
|
||||
DynamicGraph( const int32_t nodes, const ContainerT &graph ) {
|
||||
m_numNodes = nodes;
|
||||
m_numEdges = ( EdgeIterator ) graph.size();
|
||||
m_nodes.reserve( m_numNodes +1);
|
||||
m_nodes.resize( m_numNodes +1);
|
||||
EdgeIterator edge = 0;
|
||||
EdgeIterator position = 0;
|
||||
for ( NodeIterator node = 0; node < m_numNodes; ++node ) {
|
||||
EdgeIterator lastEdge = edge;
|
||||
while ( edge < m_numEdges && graph[edge].source == node ) {
|
||||
++edge;
|
||||
}
|
||||
m_nodes[node].firstEdge = position;
|
||||
m_nodes[node].edges = edge - lastEdge;
|
||||
position += m_nodes[node].edges;
|
||||
}
|
||||
m_nodes.back().firstEdge = position;
|
||||
m_edges.reserve( position * 1.1 );
|
||||
m_edges.resize( position );
|
||||
edge = 0;
|
||||
for ( NodeIterator node = 0; node < m_numNodes; ++node ) {
|
||||
for ( EdgeIterator i = m_nodes[node].firstEdge, e = m_nodes[node].firstEdge + m_nodes[node].edges; i != e; ++i ) {
|
||||
m_edges[i].target = graph[edge].target;
|
||||
m_edges[i].data = graph[edge].data;
|
||||
BOOST_ASSERT_MSG(
|
||||
graph[edge].data.distance > 0,
|
||||
"edge distance invalid"
|
||||
);
|
||||
++edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~DynamicGraph(){ }
|
||||
|
||||
unsigned GetNumberOfNodes() const {
|
||||
return m_numNodes;
|
||||
}
|
||||
|
||||
unsigned GetNumberOfEdges() const {
|
||||
return m_numEdges;
|
||||
}
|
||||
|
||||
unsigned GetOutDegree( const NodeIterator n ) const {
|
||||
return m_nodes[n].edges;
|
||||
}
|
||||
|
||||
NodeIterator GetTarget( const EdgeIterator e ) const {
|
||||
return NodeIterator( m_edges[e].target );
|
||||
}
|
||||
|
||||
void SetTarget( const EdgeIterator e, const NodeIterator n ) {
|
||||
m_edges[e].target = n;
|
||||
}
|
||||
|
||||
EdgeDataT &GetEdgeData( const EdgeIterator e ) {
|
||||
return m_edges[e].data;
|
||||
}
|
||||
|
||||
const EdgeDataT &GetEdgeData( const EdgeIterator e ) const {
|
||||
return m_edges[e].data;
|
||||
}
|
||||
|
||||
EdgeIterator BeginEdges( const NodeIterator n ) const {
|
||||
return EdgeIterator( m_nodes[n].firstEdge );
|
||||
}
|
||||
|
||||
EdgeIterator EndEdges( const NodeIterator n ) const {
|
||||
return EdgeIterator( m_nodes[n].firstEdge + m_nodes[n].edges );
|
||||
}
|
||||
|
||||
//adds an edge. Invalidates edge iterators for the source node
|
||||
EdgeIterator InsertEdge( const NodeIterator from, const NodeIterator to, const EdgeDataT &data ) {
|
||||
Node &node = m_nodes[from];
|
||||
EdgeIterator newFirstEdge = node.edges + node.firstEdge;
|
||||
if ( newFirstEdge >= m_edges.size() || !isDummy( newFirstEdge ) ) {
|
||||
if ( node.firstEdge != 0 && isDummy( node.firstEdge - 1 ) ) {
|
||||
node.firstEdge--;
|
||||
m_edges[node.firstEdge] = m_edges[node.firstEdge + node.edges];
|
||||
} else {
|
||||
EdgeIterator newFirstEdge = ( EdgeIterator ) m_edges.size();
|
||||
unsigned newSize = node.edges * 1.1 + 2;
|
||||
EdgeIterator requiredCapacity = newSize + m_edges.size();
|
||||
EdgeIterator oldCapacity = m_edges.capacity();
|
||||
if ( requiredCapacity >= oldCapacity ) {
|
||||
m_edges.reserve( requiredCapacity * 1.1 );
|
||||
}
|
||||
m_edges.resize( m_edges.size() + newSize );
|
||||
for ( EdgeIterator i = 0; i < node.edges; ++i ) {
|
||||
m_edges[newFirstEdge + i ] = m_edges[node.firstEdge + i];
|
||||
makeDummy( node.firstEdge + i );
|
||||
}
|
||||
for ( EdgeIterator i = node.edges + 1; i < newSize; ++i )
|
||||
makeDummy( newFirstEdge + i );
|
||||
node.firstEdge = newFirstEdge;
|
||||
}
|
||||
}
|
||||
Edge &edge = m_edges[node.firstEdge + node.edges];
|
||||
edge.target = to;
|
||||
edge.data = data;
|
||||
++m_numEdges;
|
||||
++node.edges;
|
||||
return EdgeIterator( node.firstEdge + node.edges );
|
||||
}
|
||||
|
||||
//removes an edge. Invalidates edge iterators for the source node
|
||||
void DeleteEdge( const NodeIterator source, const EdgeIterator e ) {
|
||||
Node &node = m_nodes[source];
|
||||
#pragma omp atomic
|
||||
--m_numEdges;
|
||||
--node.edges;
|
||||
BOOST_ASSERT(UINT_MAX != node.edges);
|
||||
const unsigned last = node.firstEdge + node.edges;
|
||||
BOOST_ASSERT( UINT_MAX != last);
|
||||
//swap with last edge
|
||||
m_edges[e] = m_edges[last];
|
||||
makeDummy( last );
|
||||
}
|
||||
|
||||
//removes all edges (source,target)
|
||||
int32_t DeleteEdgesTo( const NodeIterator source, const NodeIterator target ) {
|
||||
int32_t deleted = 0;
|
||||
for ( EdgeIterator i = BeginEdges( source ), iend = EndEdges( source ); i < iend - deleted; ++i ) {
|
||||
if ( m_edges[i].target == target ) {
|
||||
do {
|
||||
deleted++;
|
||||
m_edges[i] = m_edges[iend - deleted];
|
||||
makeDummy( iend - deleted );
|
||||
} while ( i < iend - deleted && m_edges[i].target == target );
|
||||
}
|
||||
}
|
||||
|
||||
#pragma omp atomic
|
||||
m_numEdges -= deleted;
|
||||
m_nodes[source].edges -= deleted;
|
||||
|
||||
return deleted;
|
||||
}
|
||||
|
||||
//searches for a specific edge
|
||||
EdgeIterator FindEdge( const NodeIterator from, const NodeIterator to ) const {
|
||||
for ( EdgeIterator i = BeginEdges( from ), iend = EndEdges( from ); i != iend; ++i ) {
|
||||
if ( to == m_edges[i].target ) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return EndEdges( from );
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
bool isDummy( const EdgeIterator edge ) const {
|
||||
return m_edges[edge].target == (std::numeric_limits< NodeIterator >::max)();
|
||||
}
|
||||
|
||||
void makeDummy( const EdgeIterator edge ) {
|
||||
m_edges[edge].target = (std::numeric_limits< NodeIterator >::max)();
|
||||
}
|
||||
|
||||
struct Node {
|
||||
//index of the first edge
|
||||
EdgeIterator firstEdge;
|
||||
//amount of edges
|
||||
unsigned edges;
|
||||
};
|
||||
|
||||
struct Edge {
|
||||
NodeIterator target;
|
||||
EdgeDataT data;
|
||||
};
|
||||
|
||||
NodeIterator m_numNodes;
|
||||
EdgeIterator m_numEdges;
|
||||
|
||||
std::vector< Node > m_nodes;
|
||||
DeallocatingVector< Edge > m_edges;
|
||||
};
|
||||
|
||||
#endif // DYNAMICGRAPH_H_INCLUDED
|
||||
@@ -1,160 +0,0 @@
|
||||
#ifndef EDGE_BASED_NODE_H
|
||||
#define EDGE_BASED_NODE_H
|
||||
|
||||
#include "../Util/MercatorUtil.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <limits>
|
||||
|
||||
struct EdgeBasedNode {
|
||||
|
||||
EdgeBasedNode() :
|
||||
forward_edge_based_node_id(SPECIAL_NODEID),
|
||||
reverse_edge_based_node_id(SPECIAL_NODEID),
|
||||
u(SPECIAL_NODEID),
|
||||
v(SPECIAL_NODEID),
|
||||
name_id(0),
|
||||
forward_weight(INVALID_EDGE_WEIGHT >> 1),
|
||||
reverse_weight(INVALID_EDGE_WEIGHT >> 1),
|
||||
forward_offset(0),
|
||||
reverse_offset(0),
|
||||
packed_geometry_id(SPECIAL_EDGEID),
|
||||
fwd_segment_position( std::numeric_limits<unsigned short>::max() ),
|
||||
belongsToTinyComponent(false)
|
||||
{ }
|
||||
|
||||
explicit EdgeBasedNode(
|
||||
NodeID forward_edge_based_node_id,
|
||||
NodeID reverse_edge_based_node_id,
|
||||
NodeID u,
|
||||
NodeID v,
|
||||
unsigned name_id,
|
||||
int forward_weight,
|
||||
int reverse_weight,
|
||||
int forward_offset,
|
||||
int reverse_offset,
|
||||
unsigned packed_geometry_id,
|
||||
unsigned short fwd_segment_position,
|
||||
bool belongs_to_tiny_component
|
||||
) :
|
||||
forward_edge_based_node_id(forward_edge_based_node_id),
|
||||
reverse_edge_based_node_id(reverse_edge_based_node_id),
|
||||
u(u),
|
||||
v(v),
|
||||
name_id(name_id),
|
||||
forward_weight(forward_weight),
|
||||
reverse_weight(reverse_weight),
|
||||
forward_offset(forward_offset),
|
||||
reverse_offset(reverse_offset),
|
||||
packed_geometry_id(packed_geometry_id),
|
||||
fwd_segment_position(fwd_segment_position),
|
||||
belongsToTinyComponent(belongs_to_tiny_component)
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
( forward_edge_based_node_id != SPECIAL_NODEID ) ||
|
||||
( reverse_edge_based_node_id != SPECIAL_NODEID )
|
||||
);
|
||||
}
|
||||
|
||||
inline static double ComputePerpendicularDistance(
|
||||
const FixedPointCoordinate & coord_a,
|
||||
const FixedPointCoordinate & coord_b,
|
||||
const FixedPointCoordinate & query_location,
|
||||
FixedPointCoordinate & nearest_location,
|
||||
double & r
|
||||
) {
|
||||
BOOST_ASSERT( query_location.isValid() );
|
||||
|
||||
const double x = lat2y(query_location.lat/COORDINATE_PRECISION);
|
||||
const double y = query_location.lon/COORDINATE_PRECISION;
|
||||
const double a = lat2y(coord_a.lat/COORDINATE_PRECISION);
|
||||
const double b = coord_a.lon/COORDINATE_PRECISION;
|
||||
const double c = lat2y(coord_b.lat/COORDINATE_PRECISION);
|
||||
const double d = coord_b.lon/COORDINATE_PRECISION;
|
||||
double p,q/*,mX*/,nY;
|
||||
if( std::abs(a-c) > std::numeric_limits<double>::epsilon() ){
|
||||
const double m = (d-b)/(c-a); // slope
|
||||
// Projection of (x,y) on line joining (a,b) and (c,d)
|
||||
p = ((x + (m*y)) + (m*m*a - m*b))/(1. + m*m);
|
||||
q = b + m*(p - a);
|
||||
} else {
|
||||
p = c;
|
||||
q = y;
|
||||
}
|
||||
nY = (d*p - c*q)/(a*d - b*c);
|
||||
|
||||
//discretize the result to coordinate precision. it's a hack!
|
||||
if( std::abs(nY) < (1./COORDINATE_PRECISION) ) {
|
||||
nY = 0.;
|
||||
}
|
||||
|
||||
r = (p - nY*a)/c;// These values are actually n/m+n and m/m+n , we need
|
||||
// not calculate the explicit values of m an n as we
|
||||
// are just interested in the ratio
|
||||
if( std::isnan(r) ) {
|
||||
r = ((coord_b.lat == query_location.lat) && (coord_b.lon == query_location.lon)) ? 1. : 0.;
|
||||
} else if( std::abs(r) <= std::numeric_limits<double>::epsilon() ) {
|
||||
r = 0.;
|
||||
} else if( std::abs(r-1.) <= std::numeric_limits<double>::epsilon() ) {
|
||||
r = 1.;
|
||||
}
|
||||
BOOST_ASSERT( !std::isnan(r) );
|
||||
if( r <= 0. ){
|
||||
nearest_location.lat = coord_a.lat;
|
||||
nearest_location.lon = coord_a.lon;
|
||||
} else if( r >= 1. ){
|
||||
nearest_location.lat = coord_b.lat;
|
||||
nearest_location.lon = coord_b.lon;
|
||||
} else {
|
||||
// point lies in between
|
||||
nearest_location.lat = y2lat(p)*COORDINATE_PRECISION;
|
||||
nearest_location.lon = q*COORDINATE_PRECISION;
|
||||
}
|
||||
BOOST_ASSERT( nearest_location.isValid() );
|
||||
|
||||
// TODO: Replace with euclidean approximation when k-NN search is done
|
||||
// const double approximated_distance = FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
const double approximated_distance = FixedPointCoordinate::ApproximateDistance(
|
||||
query_location,
|
||||
nearest_location
|
||||
);
|
||||
BOOST_ASSERT( 0. <= approximated_distance );
|
||||
return approximated_distance;
|
||||
}
|
||||
|
||||
static inline FixedPointCoordinate Centroid(
|
||||
const FixedPointCoordinate & a,
|
||||
const FixedPointCoordinate & b
|
||||
) {
|
||||
FixedPointCoordinate centroid;
|
||||
//The coordinates of the midpoint are given by:
|
||||
//x = (x1 + x2) /2 and y = (y1 + y2) /2.
|
||||
centroid.lon = (std::min(a.lon, b.lon) + std::max(a.lon, b.lon))/2;
|
||||
centroid.lat = (std::min(a.lat, b.lat) + std::max(a.lat, b.lat))/2;
|
||||
return centroid;
|
||||
}
|
||||
|
||||
bool IsCompressed() {
|
||||
return packed_geometry_id != SPECIAL_EDGEID;
|
||||
}
|
||||
|
||||
NodeID forward_edge_based_node_id; // needed for edge-expanded graph
|
||||
NodeID reverse_edge_based_node_id; // needed for edge-expanded graph
|
||||
NodeID u; // indices into the coordinates array
|
||||
NodeID v; // indices into the coordinates array
|
||||
unsigned name_id; // id of the edge name
|
||||
int forward_weight; // weight of the edge
|
||||
int reverse_weight; // weight in the other direction (may be different)
|
||||
int forward_offset; // prefix sum of the weight up the edge TODO: short must suffice
|
||||
int reverse_offset; // prefix sum of the weight from the edge TODO: short must suffice
|
||||
unsigned packed_geometry_id; // if set, then the edge represents a packed geometry
|
||||
unsigned short fwd_segment_position; // segment id in a compressed geometry
|
||||
bool belongsToTinyComponent;
|
||||
};
|
||||
|
||||
#endif //EDGE_BASED_NODE_H
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HASH_TABLE_H
|
||||
#define HASH_TABLE_H
|
||||
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
template<typename Key, typename Value, typename Hash = boost::hash<Key> >
|
||||
class HashTable : public boost::unordered_map<Key, Value> {
|
||||
private:
|
||||
typedef boost::unordered_map<Key, Value, Hash> super;
|
||||
public:
|
||||
static Value default_value;
|
||||
|
||||
HashTable() : super() { }
|
||||
|
||||
explicit HashTable(const unsigned size) : super(size) { }
|
||||
|
||||
inline void Add( Key const & key, Value const & value) {
|
||||
super::emplace(std::make_pair(key, value));
|
||||
}
|
||||
|
||||
inline const Value Find(Key const & key) const
|
||||
{
|
||||
typename super::const_iterator iter = super::find(key);
|
||||
if (iter == super::end())
|
||||
{
|
||||
return boost::cref(default_value);
|
||||
}
|
||||
return boost::cref(iter->second);
|
||||
}
|
||||
|
||||
inline const bool Holds( Key const & key) const
|
||||
{
|
||||
if(super::find(key) == super::end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Key, typename Value, typename Hash>
|
||||
Value HashTable<Key, Value, Hash>::default_value;
|
||||
|
||||
#endif /* HASH_TABLE_H */
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "HilbertValue.h"
|
||||
|
||||
uint64_t HilbertCode::operator() (
|
||||
const FixedPointCoordinate & current_coordinate
|
||||
) const {
|
||||
unsigned location[2];
|
||||
location[0] = current_coordinate.lat+( 90*COORDINATE_PRECISION);
|
||||
location[1] = current_coordinate.lon+(180*COORDINATE_PRECISION);
|
||||
|
||||
TransposeCoordinate(location);
|
||||
return BitInterleaving(location[0], location[1]);
|
||||
}
|
||||
|
||||
uint64_t HilbertCode::BitInterleaving(const uint32_t latitude, const uint32_t longitude) const
|
||||
{
|
||||
uint64_t result = 0;
|
||||
for(int8_t index = 31; index >= 0; --index){
|
||||
result |= (latitude >> index) & 1;
|
||||
result <<= 1;
|
||||
result |= (longitude >> index) & 1;
|
||||
if(0 != index){
|
||||
result <<= 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void HilbertCode::TransposeCoordinate( uint32_t * X) const
|
||||
{
|
||||
uint32_t M = 1 << (32-1), P, Q, t;
|
||||
int i;
|
||||
// Inverse undo
|
||||
for( Q = M; Q > 1; Q >>= 1 ) {
|
||||
P=Q-1;
|
||||
for( i = 0; i < 2; ++i ) {
|
||||
|
||||
const bool condition = (X[i] & Q);
|
||||
if( condition ) {
|
||||
X[0] ^= P; // invert
|
||||
} else {
|
||||
t = (X[0]^X[i]) & P;
|
||||
X[0] ^= t;
|
||||
X[i] ^= t;
|
||||
}
|
||||
} // exchange
|
||||
}
|
||||
// Gray encode
|
||||
for( i = 1; i < 2; ++i ) {
|
||||
X[i] ^= X[i-1];
|
||||
}
|
||||
t=0;
|
||||
for( Q = M; Q > 1; Q >>= 1 ) {
|
||||
const bool condition = (X[2-1] & Q);
|
||||
if( condition ) {
|
||||
t ^= Q-1;
|
||||
}
|
||||
} //check if this for loop is wrong
|
||||
for( i = 0; i < 2; ++i ) {
|
||||
X[i] ^= t;
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HILBERTVALUE_H_
|
||||
#define HILBERTVALUE_H_
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/integer.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
// computes a 64 bit value that corresponds to the hilbert space filling curve
|
||||
|
||||
class HilbertCode : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
uint64_t operator()
|
||||
(
|
||||
const FixedPointCoordinate & current_coordinate
|
||||
) const;
|
||||
private:
|
||||
inline uint64_t BitInterleaving( const uint32_t a, const uint32_t b) const;
|
||||
inline void TransposeCoordinate( uint32_t * X) const;
|
||||
};
|
||||
|
||||
#endif /* HILBERTVALUE_H_ */
|
||||
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef IMPORT_EDGE_H
|
||||
#define IMPORT_EDGE_H
|
||||
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
class NodeBasedEdge {
|
||||
|
||||
public:
|
||||
bool operator< (const NodeBasedEdge& e) const {
|
||||
if (source() == e.source()) {
|
||||
if (target() == e.target()) {
|
||||
if (weight() == e.weight()) {
|
||||
return (isForward() && isBackward() &&
|
||||
((! e.isForward()) || (! e.isBackward())));
|
||||
}
|
||||
return (weight() < e.weight());
|
||||
}
|
||||
return (target() < e.target());
|
||||
}
|
||||
return (source() < e.source());
|
||||
}
|
||||
|
||||
explicit NodeBasedEdge(
|
||||
NodeID s,
|
||||
NodeID t,
|
||||
NodeID n,
|
||||
EdgeWeight w,
|
||||
bool f,
|
||||
bool b,
|
||||
short ty,
|
||||
bool ra,
|
||||
bool ig,
|
||||
bool ar,
|
||||
bool cf,
|
||||
bool is_split
|
||||
) : _source(s),
|
||||
_target(t),
|
||||
_name(n),
|
||||
_weight(w),
|
||||
_type(ty),
|
||||
forward(f),
|
||||
backward(b),
|
||||
_roundabout(ra),
|
||||
_ignoreInGrid(ig),
|
||||
_accessRestricted(ar),
|
||||
_contraFlow(cf),
|
||||
is_split(is_split)
|
||||
{
|
||||
if(ty < 0) {
|
||||
throw OSRMException("negative edge type");
|
||||
}
|
||||
}
|
||||
|
||||
NodeID target() const {return _target; }
|
||||
NodeID source() const {return _source; }
|
||||
NodeID name() const { return _name; }
|
||||
EdgeWeight weight() const {return _weight; }
|
||||
short type() const {
|
||||
BOOST_ASSERT_MSG(_type >= 0, "type of ImportEdge invalid");
|
||||
return _type; }
|
||||
bool isBackward() const { return backward; }
|
||||
bool isForward() const { return forward; }
|
||||
bool isLocatable() const { return _type != 14; }
|
||||
bool isRoundabout() const { return _roundabout; }
|
||||
bool ignoreInGrid() const { return _ignoreInGrid; }
|
||||
bool isAccessRestricted() const { return _accessRestricted; }
|
||||
bool isContraFlow() const { return _contraFlow; }
|
||||
bool IsSplit() const { return is_split; }
|
||||
|
||||
//TODO: names need to be fixed.
|
||||
NodeID _source;
|
||||
NodeID _target;
|
||||
NodeID _name;
|
||||
EdgeWeight _weight;
|
||||
short _type;
|
||||
bool forward:1;
|
||||
bool backward:1;
|
||||
bool _roundabout:1;
|
||||
bool _ignoreInGrid:1;
|
||||
bool _accessRestricted:1;
|
||||
bool _contraFlow:1;
|
||||
bool is_split:1;
|
||||
|
||||
private:
|
||||
NodeBasedEdge() { }
|
||||
};
|
||||
|
||||
class EdgeBasedEdge {
|
||||
|
||||
public:
|
||||
bool operator< (const EdgeBasedEdge& e) const {
|
||||
if (source() == e.source()) {
|
||||
if (target() == e.target()) {
|
||||
if (weight() == e.weight()) {
|
||||
return (isForward() && isBackward() &&
|
||||
((! e.isForward()) || (! e.isBackward())));
|
||||
}
|
||||
return (weight() < e.weight());
|
||||
}
|
||||
return (target() < e.target());
|
||||
}
|
||||
return (source() < e.source());
|
||||
}
|
||||
|
||||
template<class EdgeT>
|
||||
explicit EdgeBasedEdge(const EdgeT & myEdge ) :
|
||||
m_source(myEdge.source),
|
||||
m_target(myEdge.target),
|
||||
m_edgeID(myEdge.data.via),
|
||||
m_weight(myEdge.data.distance),
|
||||
m_forward(myEdge.data.forward),
|
||||
m_backward(myEdge.data.backward)
|
||||
{ }
|
||||
|
||||
/** Default constructor. target and weight are set to 0.*/
|
||||
EdgeBasedEdge() :
|
||||
m_source(0),
|
||||
m_target(0),
|
||||
m_edgeID(0),
|
||||
m_weight(0),
|
||||
m_forward(false),
|
||||
m_backward(false)
|
||||
{ }
|
||||
|
||||
explicit EdgeBasedEdge(
|
||||
const NodeID s,
|
||||
const NodeID t,
|
||||
const NodeID v,
|
||||
const EdgeWeight w,
|
||||
const bool f,
|
||||
const bool b
|
||||
) :
|
||||
m_source(s),
|
||||
m_target(t),
|
||||
m_edgeID(v),
|
||||
m_weight(w),
|
||||
m_forward(f),
|
||||
m_backward(b)
|
||||
{ }
|
||||
|
||||
NodeID target() const { return m_target; }
|
||||
NodeID source() const { return m_source; }
|
||||
EdgeWeight weight() const { return m_weight; }
|
||||
NodeID id() const { return m_edgeID; }
|
||||
bool isBackward() const { return m_backward; }
|
||||
bool isForward() const { return m_forward; }
|
||||
|
||||
private:
|
||||
NodeID m_source;
|
||||
NodeID m_target;
|
||||
NodeID m_edgeID;
|
||||
EdgeWeight m_weight:30;
|
||||
bool m_forward:1;
|
||||
bool m_backward:1;
|
||||
};
|
||||
|
||||
typedef NodeBasedEdge ImportEdge;
|
||||
|
||||
#endif /* IMPORT_EDGE_H */
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef IMPORTNODE_H_
|
||||
#define IMPORTNODE_H_
|
||||
|
||||
#include "QueryNode.h"
|
||||
#include "../DataStructures/HashTable.h"
|
||||
|
||||
|
||||
struct ExternalMemoryNode : NodeInfo {
|
||||
ExternalMemoryNode(
|
||||
int lat,
|
||||
int lon,
|
||||
unsigned int id,
|
||||
bool bollard,
|
||||
bool traffic_light
|
||||
) :
|
||||
NodeInfo(lat, lon, id),
|
||||
bollard(bollard),
|
||||
trafficLight(traffic_light)
|
||||
{ }
|
||||
|
||||
ExternalMemoryNode()
|
||||
:
|
||||
bollard(false),
|
||||
trafficLight(false)
|
||||
{ }
|
||||
|
||||
static ExternalMemoryNode min_value() {
|
||||
return ExternalMemoryNode(0,0,0, false, false);
|
||||
}
|
||||
|
||||
static ExternalMemoryNode max_value() {
|
||||
return ExternalMemoryNode(
|
||||
std::numeric_limits<int>::max(),
|
||||
std::numeric_limits<int>::max(),
|
||||
std::numeric_limits<unsigned>::max(),
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
NodeID key() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
bool bollard;
|
||||
bool trafficLight;
|
||||
};
|
||||
|
||||
struct ImportNode : public ExternalMemoryNode {
|
||||
HashTable<std::string, std::string> keyVals;
|
||||
|
||||
inline void Clear() {
|
||||
keyVals.clear();
|
||||
lat = 0; lon = 0; id = 0; bollard = false; trafficLight = false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* IMPORTNODE_H_ */
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INPUTREADERFACTORY_H
|
||||
#define INPUTREADERFACTORY_H
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <bzlib.h>
|
||||
#include <libxml/xmlreader.h>
|
||||
|
||||
struct BZ2Context {
|
||||
FILE* file;
|
||||
BZFILE* bz2;
|
||||
int error;
|
||||
int nUnused;
|
||||
char unused[BZ_MAX_UNUSED];
|
||||
};
|
||||
|
||||
int readFromBz2Stream( void* pointer, char* buffer, int len ) {
|
||||
void *unusedTmpVoid=NULL;
|
||||
char *unusedTmp=NULL;
|
||||
BZ2Context* context = (BZ2Context*) pointer;
|
||||
int read = 0;
|
||||
while(0 == read && !(BZ_STREAM_END == context->error && 0 == context->nUnused && feof(context->file))) {
|
||||
read = BZ2_bzRead(&context->error, context->bz2, buffer, len);
|
||||
if(BZ_OK == context->error) {
|
||||
return read;
|
||||
} else if(BZ_STREAM_END == context->error) {
|
||||
BZ2_bzReadGetUnused(&context->error, context->bz2, &unusedTmpVoid, &context->nUnused);
|
||||
BOOST_ASSERT_MSG(BZ_OK == context->error, "Could not BZ2_bzReadGetUnused");
|
||||
unusedTmp = (char*)unusedTmpVoid;
|
||||
for(int i=0;i<context->nUnused;i++) {
|
||||
context->unused[i] = unusedTmp[i];
|
||||
}
|
||||
BZ2_bzReadClose(&context->error, context->bz2);
|
||||
BOOST_ASSERT_MSG(BZ_OK == context->error, "Could not BZ2_bzReadClose");
|
||||
context->error = BZ_STREAM_END; // set to the stream end for next call to this function
|
||||
if(0 == context->nUnused && feof(context->file)) {
|
||||
return read;
|
||||
} else {
|
||||
context->bz2 = BZ2_bzReadOpen(&context->error, context->file, 0, 0, context->unused, context->nUnused);
|
||||
BOOST_ASSERT_MSG(NULL != context->bz2, "Could not open file");
|
||||
}
|
||||
} else { BOOST_ASSERT_MSG(false, "Could not read bz2 file"); }
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
int closeBz2Stream( void *pointer )
|
||||
{
|
||||
BZ2Context* context = (BZ2Context*) pointer;
|
||||
fclose( context->file );
|
||||
delete context;
|
||||
return 0;
|
||||
}
|
||||
|
||||
xmlTextReaderPtr inputReaderFactory( const char* name )
|
||||
{
|
||||
std::string inputName(name);
|
||||
|
||||
if(inputName.find(".osm.bz2")!=std::string::npos)
|
||||
{
|
||||
BZ2Context* context = new BZ2Context();
|
||||
context->error = false;
|
||||
context->file = fopen( name, "r" );
|
||||
int error;
|
||||
context->bz2 = BZ2_bzReadOpen( &error, context->file, 0, 0, context->unused, context->nUnused );
|
||||
if ( context->bz2 == NULL || context->file == NULL ) {
|
||||
delete context;
|
||||
return NULL;
|
||||
}
|
||||
return xmlReaderForIO( readFromBz2Stream, closeBz2Stream, (void*) context, NULL, NULL, 0 );
|
||||
} else {
|
||||
return xmlNewTextReaderFilename(name);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // INPUTREADERFACTORY_H
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef LRUCACHE_H
|
||||
#define LRUCACHE_H
|
||||
|
||||
#include <list>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
template<typename KeyT, typename ValueT>
|
||||
class LRUCache {
|
||||
private:
|
||||
struct CacheEntry {
|
||||
CacheEntry(KeyT k, ValueT v) : key(k), value(v) {}
|
||||
KeyT key;
|
||||
ValueT value;
|
||||
};
|
||||
unsigned capacity;
|
||||
std::list<CacheEntry> itemsInCache;
|
||||
boost::unordered_map<KeyT, typename std::list<CacheEntry>::iterator > positionMap;
|
||||
public:
|
||||
explicit LRUCache(unsigned c) : capacity(c) {}
|
||||
|
||||
bool Holds(KeyT key) {
|
||||
if(positionMap.find(key) != positionMap.end()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Insert(const KeyT key, ValueT &value) {
|
||||
itemsInCache.push_front(CacheEntry(key, value));
|
||||
positionMap.insert(std::make_pair(key, itemsInCache.begin()));
|
||||
if(itemsInCache.size() > capacity) {
|
||||
positionMap.erase(itemsInCache.back().key);
|
||||
itemsInCache.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void Insert(const KeyT key, ValueT value) {
|
||||
itemsInCache.push_front(CacheEntry(key, value));
|
||||
positionMap.insert(std::make_pair(key, itemsInCache.begin()));
|
||||
if(itemsInCache.size() > capacity) {
|
||||
positionMap.erase(itemsInCache.back().key);
|
||||
itemsInCache.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
bool Fetch(const KeyT key, ValueT& result) {
|
||||
if(Holds(key)) {
|
||||
CacheEntry e = *(positionMap.find(key)->second);
|
||||
result = e.value;
|
||||
|
||||
//move to front
|
||||
itemsInCache.splice(positionMap.find(key)->second, itemsInCache, itemsInCache.begin());
|
||||
positionMap.find(key)->second = itemsInCache.begin();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
unsigned Size() const {
|
||||
return itemsInCache.size();
|
||||
}
|
||||
};
|
||||
#endif //LRUCACHE_H
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ORIGINAL_EDGE_DATA_H
|
||||
#define ORIGINAL_EDGE_DATA_H
|
||||
|
||||
#include "TurnInstructions.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
struct OriginalEdgeData{
|
||||
explicit OriginalEdgeData(
|
||||
NodeID via_node,
|
||||
unsigned name_id,
|
||||
TurnInstruction turn_instruction,
|
||||
bool compressed_geometry
|
||||
) :
|
||||
via_node( via_node ),
|
||||
name_id( name_id ),
|
||||
turn_instruction( turn_instruction ),
|
||||
compressed_geometry( compressed_geometry )
|
||||
{ }
|
||||
|
||||
OriginalEdgeData() :
|
||||
via_node( std::numeric_limits<unsigned>::max() ),
|
||||
name_id( std::numeric_limits<unsigned>::max() ),
|
||||
turn_instruction( std::numeric_limits<unsigned char>::max() ),
|
||||
compressed_geometry( false )
|
||||
{ }
|
||||
|
||||
NodeID via_node;
|
||||
unsigned name_id;
|
||||
TurnInstruction turn_instruction;
|
||||
bool compressed_geometry;
|
||||
};
|
||||
|
||||
#endif //ORIGINAL_EDGE_DATA_H
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef PERCENT_H
|
||||
#define PERCENT_H
|
||||
|
||||
#include "../Util/OpenMPWrapper.h"
|
||||
#include <iostream>
|
||||
|
||||
class Percent {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param maxValue the value that corresponds to 100%
|
||||
* @param step the progress is shown in steps of 'step' percent
|
||||
*/
|
||||
explicit Percent(unsigned maxValue, unsigned step = 5) {
|
||||
reinit(maxValue, step);
|
||||
}
|
||||
|
||||
/** Reinitializes this object. */
|
||||
void reinit(unsigned maxValue, unsigned step = 5) {
|
||||
_maxValue = maxValue;
|
||||
_current_value = 0;
|
||||
_intervalPercent = _maxValue / 100;
|
||||
_nextThreshold = _intervalPercent;
|
||||
_lastPercent = 0;
|
||||
_step = step;
|
||||
}
|
||||
|
||||
/** If there has been significant progress, display it. */
|
||||
void printStatus(unsigned currentValue) {
|
||||
if (currentValue >= _nextThreshold) {
|
||||
_nextThreshold += _intervalPercent;
|
||||
printPercent( currentValue / (double)_maxValue * 100 );
|
||||
}
|
||||
if (currentValue + 1 == _maxValue)
|
||||
std::cout << " 100%" << std::endl;
|
||||
}
|
||||
|
||||
void printIncrement() {
|
||||
#pragma omp atomic
|
||||
++_current_value;
|
||||
printStatus(_current_value);
|
||||
}
|
||||
|
||||
void printAddition(const unsigned addition) {
|
||||
#pragma omp atomic
|
||||
_current_value += addition;
|
||||
printStatus(_current_value);
|
||||
}
|
||||
private:
|
||||
unsigned _current_value;
|
||||
unsigned _maxValue;
|
||||
unsigned _intervalPercent;
|
||||
unsigned _nextThreshold;
|
||||
unsigned _lastPercent;
|
||||
unsigned _step;
|
||||
|
||||
/** Displays the new progress. */
|
||||
void printPercent(double percent) {
|
||||
while (percent >= _lastPercent+_step) {
|
||||
_lastPercent+=_step;
|
||||
if (_lastPercent % 10 == 0) {
|
||||
std::cout << " " << _lastPercent << "% ";
|
||||
}
|
||||
else {
|
||||
std::cout << ".";
|
||||
}
|
||||
std::cout.flush();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // PERCENT_H
|
||||
@@ -1,174 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef PHANTOMNODES_H_
|
||||
#define PHANTOMNODES_H_
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
struct PhantomNode
|
||||
{
|
||||
PhantomNode() :
|
||||
forward_node_id(SPECIAL_NODEID),
|
||||
reverse_node_id(SPECIAL_NODEID),
|
||||
name_id(std::numeric_limits<unsigned>::max()),
|
||||
forward_weight(INVALID_EDGE_WEIGHT),
|
||||
reverse_weight(INVALID_EDGE_WEIGHT),
|
||||
forward_offset(0),
|
||||
reverse_offset(0),
|
||||
packed_geometry_id(SPECIAL_EDGEID),
|
||||
fwd_segment_position(0)
|
||||
{ }
|
||||
|
||||
NodeID forward_node_id;
|
||||
NodeID reverse_node_id;
|
||||
unsigned name_id;
|
||||
int forward_weight;
|
||||
int reverse_weight;
|
||||
int forward_offset;
|
||||
int reverse_offset;
|
||||
unsigned packed_geometry_id;
|
||||
FixedPointCoordinate location;
|
||||
unsigned short fwd_segment_position;
|
||||
|
||||
int GetForwardWeightPlusOffset() const
|
||||
{
|
||||
if (SPECIAL_NODEID == forward_node_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
const int result = (forward_offset + forward_weight);
|
||||
return result;
|
||||
}
|
||||
|
||||
int GetReverseWeightPlusOffset() const
|
||||
{
|
||||
if (SPECIAL_NODEID == reverse_node_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
const int result = (reverse_offset + reverse_weight);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
forward_node_id = SPECIAL_NODEID;
|
||||
name_id = SPECIAL_NODEID;
|
||||
forward_weight = INVALID_EDGE_WEIGHT;
|
||||
reverse_weight = INVALID_EDGE_WEIGHT;
|
||||
forward_offset = 0;
|
||||
reverse_offset = 0;
|
||||
location.Reset();
|
||||
}
|
||||
|
||||
bool isBidirected() const
|
||||
{
|
||||
return (forward_node_id != SPECIAL_NODEID) &&
|
||||
(reverse_node_id != SPECIAL_NODEID);
|
||||
}
|
||||
|
||||
bool IsCompressed() const
|
||||
{
|
||||
return (forward_offset != 0) || (reverse_offset != 0);
|
||||
}
|
||||
|
||||
bool isValid(const unsigned numberOfNodes) const
|
||||
{
|
||||
return
|
||||
location.isValid() &&
|
||||
(
|
||||
(forward_node_id < numberOfNodes) ||
|
||||
(reverse_node_id < numberOfNodes)
|
||||
) &&
|
||||
(
|
||||
(forward_weight != INVALID_EDGE_WEIGHT) ||
|
||||
(reverse_weight != INVALID_EDGE_WEIGHT)
|
||||
) &&
|
||||
(name_id != std::numeric_limits<unsigned>::max()
|
||||
);
|
||||
}
|
||||
|
||||
bool operator==(const PhantomNode & other) const
|
||||
{
|
||||
return location == other.location;
|
||||
}
|
||||
};
|
||||
|
||||
struct PhantomNodes
|
||||
{
|
||||
PhantomNode source_phantom;
|
||||
PhantomNode target_phantom;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
source_phantom.Reset();
|
||||
target_phantom.Reset();
|
||||
}
|
||||
|
||||
bool PhantomsAreOnSameNodeBasedEdge() const
|
||||
{
|
||||
return (source_phantom.forward_node_id == target_phantom.forward_node_id);
|
||||
}
|
||||
|
||||
bool AtLeastOnePhantomNodeIsInvalid() const
|
||||
{
|
||||
return ((source_phantom.forward_node_id == SPECIAL_NODEID) && (source_phantom.reverse_node_id == SPECIAL_NODEID)) ||
|
||||
((target_phantom.forward_node_id == SPECIAL_NODEID) && (target_phantom.reverse_node_id == SPECIAL_NODEID));
|
||||
}
|
||||
|
||||
bool PhantomNodesHaveEqualLocation() const
|
||||
{
|
||||
return source_phantom == target_phantom;
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream &out, const PhantomNodes & pn)
|
||||
{
|
||||
out << "source_coord: " << pn.source_phantom.location << "\n";
|
||||
out << "target_coord: " << pn.target_phantom.location << std::endl;
|
||||
return out;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream &out, const PhantomNode & pn)
|
||||
{
|
||||
out << "node1: " << pn.forward_node_id << ", " <<
|
||||
"node2: " << pn.reverse_node_id << ", " <<
|
||||
"name: " << pn.name_id << ", " <<
|
||||
"fwd-w: " << pn.forward_weight << ", " <<
|
||||
"rev-w: " << pn.reverse_weight << ", " <<
|
||||
"fwd-o: " << pn.forward_offset << ", " <<
|
||||
"rev-o: " << pn.reverse_offset << ", " <<
|
||||
"geom: " << pn.packed_geometry_id << ", " <<
|
||||
"pos: " << pn.fwd_segment_position << ", " <<
|
||||
"loc: " << pn.location;
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif /* PHANTOMNODES_H_ */
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef QUERYEDGE_H_
|
||||
#define QUERYEDGE_H_
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
struct QueryEdge {
|
||||
NodeID source;
|
||||
NodeID target;
|
||||
struct EdgeData {
|
||||
NodeID id:31;
|
||||
bool shortcut:1;
|
||||
int distance:30;
|
||||
bool forward:1;
|
||||
bool backward:1;
|
||||
} data;
|
||||
|
||||
bool operator<( const QueryEdge& right ) const {
|
||||
if ( source != right.source ) {
|
||||
return source < right.source;
|
||||
}
|
||||
return target < right.target;
|
||||
}
|
||||
|
||||
bool operator== ( const QueryEdge& right ) const {
|
||||
return (
|
||||
source == right.source &&
|
||||
target == right.target &&
|
||||
data.distance == right.data.distance &&
|
||||
data.shortcut == right.data.shortcut &&
|
||||
data.forward == right.data.forward &&
|
||||
data.backward == right.data.backward &&
|
||||
data.id == right.data.id
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* QUERYEDGE_H_ */
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef QUERY_NODE_H
|
||||
#define QUERY_NODE_H
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <limits>
|
||||
|
||||
struct NodeInfo {
|
||||
typedef NodeID key_type; //type of NodeID
|
||||
typedef int value_type; //type of lat,lons
|
||||
|
||||
NodeInfo(int lat, int lon, NodeID id) : lat(lat), lon(lon), id(id) { }
|
||||
NodeInfo()
|
||||
:
|
||||
lat(std::numeric_limits<int>::max()),
|
||||
lon(std::numeric_limits<int>::max()),
|
||||
id(std::numeric_limits<unsigned>::max())
|
||||
{ }
|
||||
|
||||
int lat;
|
||||
int lon;
|
||||
NodeID id;
|
||||
|
||||
static NodeInfo min_value() {
|
||||
return NodeInfo(
|
||||
-90*COORDINATE_PRECISION,
|
||||
-180*COORDINATE_PRECISION,
|
||||
std::numeric_limits<NodeID>::min()
|
||||
);
|
||||
}
|
||||
|
||||
static NodeInfo max_value() {
|
||||
return NodeInfo(
|
||||
90*COORDINATE_PRECISION,
|
||||
180*COORDINATE_PRECISION,
|
||||
std::numeric_limits<NodeID>::max()
|
||||
);
|
||||
}
|
||||
|
||||
value_type operator[](const std::size_t n) const {
|
||||
switch(n) {
|
||||
case 1:
|
||||
return lat;
|
||||
// break;
|
||||
case 0:
|
||||
return lon;
|
||||
// break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
BOOST_ASSERT_MSG(false, "should not happen");
|
||||
return std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
};
|
||||
|
||||
#endif //QUERY_NODE_H
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef RAWROUTEDATA_H_
|
||||
#define RAWROUTEDATA_H_
|
||||
|
||||
#include "../DataStructures/PhantomNodes.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct PathData {
|
||||
PathData() :
|
||||
node(UINT_MAX),
|
||||
name_id(UINT_MAX),
|
||||
durationOfSegment(UINT_MAX),
|
||||
turnInstruction(UCHAR_MAX)
|
||||
{ }
|
||||
|
||||
PathData(
|
||||
NodeID no,
|
||||
unsigned na,
|
||||
unsigned tu,
|
||||
unsigned dur
|
||||
) :
|
||||
node(no),
|
||||
name_id(na),
|
||||
durationOfSegment(dur),
|
||||
turnInstruction(tu)
|
||||
{ }
|
||||
NodeID node;
|
||||
unsigned name_id;
|
||||
unsigned durationOfSegment;
|
||||
short turnInstruction;
|
||||
};
|
||||
|
||||
struct RawRouteData {
|
||||
std::vector< std::vector<PathData> > unpacked_path_segments;
|
||||
std::vector< PathData > unpacked_alternative;
|
||||
std::vector< PhantomNodes > segmentEndCoordinates;
|
||||
std::vector< FixedPointCoordinate > rawViaNodeCoordinates;
|
||||
unsigned checkSum;
|
||||
int lengthOfShortestPath;
|
||||
int lengthOfAlternativePath;
|
||||
bool source_traversed_in_reverse;
|
||||
bool target_traversed_in_reverse;
|
||||
bool alt_source_traversed_in_reverse;
|
||||
bool alt_target_traversed_in_reverse;
|
||||
|
||||
RawRouteData() :
|
||||
checkSum(UINT_MAX),
|
||||
lengthOfShortestPath(INT_MAX),
|
||||
lengthOfAlternativePath(INT_MAX),
|
||||
source_traversed_in_reverse(false),
|
||||
target_traversed_in_reverse(false),
|
||||
alt_source_traversed_in_reverse(false),
|
||||
alt_target_traversed_in_reverse(false)
|
||||
{ }
|
||||
};
|
||||
|
||||
#endif /* RAWROUTEDATA_H_ */
|
||||
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef RESTRICTION_H_
|
||||
#define RESTRICTION_H_
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
struct TurnRestriction {
|
||||
NodeID viaNode;
|
||||
NodeID fromNode;
|
||||
NodeID toNode;
|
||||
struct Bits { //mostly unused
|
||||
Bits()
|
||||
:
|
||||
isOnly(false),
|
||||
unused1(false),
|
||||
unused2(false),
|
||||
unused3(false),
|
||||
unused4(false),
|
||||
unused5(false),
|
||||
unused6(false),
|
||||
unused7(false)
|
||||
{ }
|
||||
|
||||
bool isOnly:1;
|
||||
bool unused1:1;
|
||||
bool unused2:1;
|
||||
bool unused3:1;
|
||||
bool unused4:1;
|
||||
bool unused5:1;
|
||||
bool unused6:1;
|
||||
bool unused7:1;
|
||||
} flags;
|
||||
|
||||
explicit TurnRestriction(NodeID viaNode) :
|
||||
viaNode(viaNode),
|
||||
fromNode(std::numeric_limits<unsigned>::max()),
|
||||
toNode(std::numeric_limits<unsigned>::max()) {
|
||||
}
|
||||
|
||||
explicit TurnRestriction(const bool isOnly = false) :
|
||||
viaNode(UINT_MAX),
|
||||
fromNode(UINT_MAX),
|
||||
toNode(UINT_MAX) {
|
||||
flags.isOnly = isOnly;
|
||||
}
|
||||
};
|
||||
|
||||
struct InputRestrictionContainer {
|
||||
EdgeID fromWay;
|
||||
EdgeID toWay;
|
||||
unsigned viaNode;
|
||||
TurnRestriction restriction;
|
||||
|
||||
InputRestrictionContainer(
|
||||
EdgeID fromWay,
|
||||
EdgeID toWay,
|
||||
NodeID vn,
|
||||
unsigned vw
|
||||
) :
|
||||
fromWay(fromWay),
|
||||
toWay(toWay),
|
||||
viaNode(vw)
|
||||
{
|
||||
restriction.viaNode = vn;
|
||||
}
|
||||
explicit InputRestrictionContainer(
|
||||
bool isOnly = false
|
||||
) :
|
||||
fromWay(std::numeric_limits<unsigned>::max()),
|
||||
toWay(std::numeric_limits<unsigned>::max()),
|
||||
viaNode(std::numeric_limits<unsigned>::max())
|
||||
{
|
||||
restriction.flags.isOnly = isOnly;
|
||||
}
|
||||
|
||||
static InputRestrictionContainer min_value() {
|
||||
return InputRestrictionContainer(0, 0, 0, 0);
|
||||
}
|
||||
static InputRestrictionContainer max_value() {
|
||||
return InputRestrictionContainer(
|
||||
std::numeric_limits<unsigned>::max(),
|
||||
std::numeric_limits<unsigned>::max(),
|
||||
std::numeric_limits<unsigned>::max(),
|
||||
std::numeric_limits<unsigned>::max()
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct CmpRestrictionContainerByFrom {
|
||||
typedef InputRestrictionContainer value_type;
|
||||
inline bool operator()(
|
||||
const InputRestrictionContainer & a,
|
||||
const InputRestrictionContainer & b
|
||||
) const {
|
||||
return a.fromWay < b.fromWay;
|
||||
}
|
||||
inline value_type max_value() const {
|
||||
return InputRestrictionContainer::max_value();
|
||||
}
|
||||
inline value_type min_value() const {
|
||||
return InputRestrictionContainer::min_value();
|
||||
}
|
||||
};
|
||||
|
||||
struct CmpRestrictionContainerByTo {
|
||||
typedef InputRestrictionContainer value_type;
|
||||
inline bool operator()(
|
||||
const InputRestrictionContainer & a,
|
||||
const InputRestrictionContainer & b
|
||||
) const {
|
||||
return a.toWay < b.toWay;
|
||||
}
|
||||
value_type max_value() const {
|
||||
return InputRestrictionContainer::max_value();
|
||||
}
|
||||
value_type min_value() const {
|
||||
return InputRestrictionContainer::min_value();
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* RESTRICTION_H_ */
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SEARCHENGINE_H
|
||||
#define SEARCHENGINE_H
|
||||
|
||||
#include "SearchEngineData.h"
|
||||
#include "PhantomNodes.h"
|
||||
#include "QueryEdge.h"
|
||||
#include "../RoutingAlgorithms/AlternativePathRouting.h"
|
||||
#include "../RoutingAlgorithms/ShortestPathRouting.h"
|
||||
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <climits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template<class DataFacadeT>
|
||||
class SearchEngine {
|
||||
private:
|
||||
DataFacadeT * facade;
|
||||
SearchEngineData engine_working_data;
|
||||
public:
|
||||
ShortestPathRouting<DataFacadeT> shortest_path;
|
||||
AlternativeRouting <DataFacadeT> alternative_path;
|
||||
|
||||
explicit SearchEngine( DataFacadeT * facade )
|
||||
:
|
||||
facade (facade),
|
||||
shortest_path (facade, engine_working_data),
|
||||
alternative_path (facade, engine_working_data)
|
||||
{}
|
||||
|
||||
~SearchEngine() {}
|
||||
|
||||
};
|
||||
|
||||
#endif // SEARCHENGINE_H
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SEARCH_ENGINE_DATA_H
|
||||
#define SEARCH_ENGINE_DATA_H
|
||||
|
||||
#include "BinaryHeap.h"
|
||||
#include "QueryEdge.h"
|
||||
#include "StaticGraph.h"
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct _HeapData {
|
||||
NodeID parent;
|
||||
/* explicit */ _HeapData( NodeID p ) : parent(p) { }
|
||||
};
|
||||
|
||||
// typedef StaticGraph<QueryEdge::EdgeData> QueryGraph;
|
||||
|
||||
struct SearchEngineData {
|
||||
typedef BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> > QueryHeap;
|
||||
typedef boost::thread_specific_ptr<QueryHeap> SearchEngineHeapPtr;
|
||||
|
||||
static SearchEngineHeapPtr forwardHeap;
|
||||
static SearchEngineHeapPtr backwardHeap;
|
||||
static SearchEngineHeapPtr forwardHeap2;
|
||||
static SearchEngineHeapPtr backwardHeap2;
|
||||
static SearchEngineHeapPtr forwardHeap3;
|
||||
static SearchEngineHeapPtr backwardHeap3;
|
||||
|
||||
void InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes);
|
||||
|
||||
void InitializeOrClearSecondThreadLocalStorage(const unsigned number_of_nodes);
|
||||
|
||||
void InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes);
|
||||
};
|
||||
|
||||
#endif // SEARCH_ENGINE_DATA_H
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SEGMENTINFORMATION_H_
|
||||
#define SEGMENTINFORMATION_H_
|
||||
|
||||
#include "TurnInstructions.h"
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
// Struct fits everything in one cache line
|
||||
struct SegmentInformation {
|
||||
FixedPointCoordinate location;
|
||||
NodeID name_id;
|
||||
unsigned duration;
|
||||
double length;
|
||||
short bearing; //more than enough [0..3600] fits into 12 bits
|
||||
TurnInstruction turn_instruction;
|
||||
bool necessary;
|
||||
|
||||
explicit SegmentInformation(
|
||||
const FixedPointCoordinate & location,
|
||||
const NodeID name_id,
|
||||
const unsigned duration,
|
||||
const double length,
|
||||
const TurnInstruction turn_instruction,
|
||||
const bool necessary
|
||||
) :
|
||||
location(location),
|
||||
name_id(name_id),
|
||||
duration(duration),
|
||||
length(length),
|
||||
bearing(0),
|
||||
turn_instruction(turn_instruction),
|
||||
necessary(necessary)
|
||||
{ }
|
||||
|
||||
explicit SegmentInformation(
|
||||
const FixedPointCoordinate & location,
|
||||
const NodeID name_id,
|
||||
const unsigned duration,
|
||||
const double length,
|
||||
const TurnInstruction turn_instruction
|
||||
) :
|
||||
location(location),
|
||||
name_id(name_id),
|
||||
duration(duration),
|
||||
length(length),
|
||||
bearing(0),
|
||||
turn_instruction(turn_instruction),
|
||||
necessary(turn_instruction != 0)
|
||||
{ }
|
||||
};
|
||||
|
||||
#endif /* SEGMENTINFORMATION_H_ */
|
||||
@@ -1,250 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SHARED_MEMORY_FACTORY_H
|
||||
#define SHARED_MEMORY_FACTORY_H
|
||||
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/integer.hpp>
|
||||
#include <boost/interprocess/mapped_region.hpp>
|
||||
#include <boost/interprocess/xsi_shared_memory.hpp>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
|
||||
struct OSRMLockFile {
|
||||
boost::filesystem::path operator()() {
|
||||
boost::filesystem::path temp_dir =
|
||||
boost::filesystem::temp_directory_path();
|
||||
boost::filesystem::path lock_file = temp_dir / "osrm.lock";
|
||||
return lock_file;
|
||||
}
|
||||
};
|
||||
|
||||
class SharedMemory : boost::noncopyable {
|
||||
|
||||
//Remove shared memory on destruction
|
||||
class shm_remove : boost::noncopyable {
|
||||
private:
|
||||
int m_shmid;
|
||||
bool m_initialized;
|
||||
public:
|
||||
void SetID(int shmid) {
|
||||
m_shmid = shmid;
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
shm_remove() : m_shmid(INT_MIN), m_initialized(false) {}
|
||||
|
||||
~shm_remove(){
|
||||
if(m_initialized) {
|
||||
SimpleLogger().Write(logDEBUG) <<
|
||||
"automatic memory deallocation";
|
||||
if(!boost::interprocess::xsi_shared_memory::remove(m_shmid)) {
|
||||
SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
void * Ptr() const {
|
||||
return region.get_address();
|
||||
}
|
||||
|
||||
template<typename IdentifierT >
|
||||
SharedMemory(
|
||||
const boost::filesystem::path & lock_file,
|
||||
const IdentifierT id,
|
||||
const uint64_t size = 0,
|
||||
bool read_write = false,
|
||||
bool remove_prev = true
|
||||
) : key(
|
||||
lock_file.string().c_str(),
|
||||
id
|
||||
) {
|
||||
if( 0 == size ){ //read_only
|
||||
shm = boost::interprocess::xsi_shared_memory (
|
||||
boost::interprocess::open_only,
|
||||
key
|
||||
);
|
||||
|
||||
region = boost::interprocess::mapped_region (
|
||||
shm,
|
||||
(
|
||||
read_write ?
|
||||
boost::interprocess::read_write :
|
||||
boost::interprocess::read_only
|
||||
)
|
||||
);
|
||||
} else { //writeable pointer
|
||||
//remove previously allocated mem
|
||||
if( remove_prev ) {
|
||||
Remove(key);
|
||||
}
|
||||
shm = boost::interprocess::xsi_shared_memory (
|
||||
boost::interprocess::open_or_create,
|
||||
key,
|
||||
size
|
||||
);
|
||||
#ifdef __linux__
|
||||
if( -1 == shmctl(shm.get_shmid(), SHM_LOCK, 0) ) {
|
||||
if( ENOMEM == errno ) {
|
||||
SimpleLogger().Write(logWARNING) <<
|
||||
"could not lock shared memory to RAM";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
region = boost::interprocess::mapped_region (
|
||||
shm,
|
||||
boost::interprocess::read_write
|
||||
);
|
||||
|
||||
remover.SetID( shm.get_shmid() );
|
||||
SimpleLogger().Write(logDEBUG) <<
|
||||
"writeable memory allocated " << size << " bytes";
|
||||
}
|
||||
}
|
||||
|
||||
template<typename IdentifierT >
|
||||
static bool RegionExists(
|
||||
const IdentifierT id
|
||||
) {
|
||||
bool result = true;
|
||||
try {
|
||||
OSRMLockFile lock_file;
|
||||
boost::interprocess::xsi_key key( lock_file().string().c_str(), id );
|
||||
result = RegionExists(key);
|
||||
} catch(...) {
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename IdentifierT >
|
||||
static bool Remove(
|
||||
const IdentifierT id
|
||||
) {
|
||||
OSRMLockFile lock_file;
|
||||
boost::interprocess::xsi_key key( lock_file().string().c_str(), id );
|
||||
return Remove(key);
|
||||
}
|
||||
|
||||
private:
|
||||
static bool RegionExists( const boost::interprocess::xsi_key &key ) {
|
||||
bool result = true;
|
||||
try {
|
||||
boost::interprocess::xsi_shared_memory shm(
|
||||
boost::interprocess::open_only,
|
||||
key
|
||||
);
|
||||
} catch(...) {
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool Remove(
|
||||
const boost::interprocess::xsi_key &key
|
||||
) {
|
||||
bool ret = false;
|
||||
try{
|
||||
SimpleLogger().Write(logDEBUG) << "deallocating prev memory";
|
||||
boost::interprocess::xsi_shared_memory xsi(
|
||||
boost::interprocess::open_only,
|
||||
key
|
||||
);
|
||||
ret = boost::interprocess::xsi_shared_memory::remove(xsi.get_shmid());
|
||||
} catch(const boost::interprocess::interprocess_exception &e){
|
||||
if(e.get_error_code() != boost::interprocess::not_found_error) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
boost::interprocess::xsi_key key;
|
||||
boost::interprocess::xsi_shared_memory shm;
|
||||
boost::interprocess::mapped_region region;
|
||||
shm_remove remover;
|
||||
};
|
||||
|
||||
template<class LockFileT = OSRMLockFile>
|
||||
class SharedMemoryFactory_tmpl : boost::noncopyable {
|
||||
public:
|
||||
|
||||
template<typename IdentifierT >
|
||||
static SharedMemory * Get(
|
||||
const IdentifierT & id,
|
||||
const uint64_t size = 0,
|
||||
bool read_write = false,
|
||||
bool remove_prev = true
|
||||
) {
|
||||
try {
|
||||
LockFileT lock_file;
|
||||
if(!boost::filesystem::exists(lock_file()) ) {
|
||||
if( 0 == size ) {
|
||||
throw OSRMException("lock file does not exist, exiting");
|
||||
} else {
|
||||
boost::filesystem::ofstream ofs(lock_file());
|
||||
ofs.close();
|
||||
}
|
||||
}
|
||||
return new SharedMemory(
|
||||
lock_file(),
|
||||
id,
|
||||
size,
|
||||
read_write,
|
||||
remove_prev
|
||||
);
|
||||
} catch(const boost::interprocess::interprocess_exception &e){
|
||||
SimpleLogger().Write(logWARNING) <<
|
||||
"caught exception: " << e.what() <<
|
||||
", code " << e.get_error_code();
|
||||
throw OSRMException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SharedMemoryFactory_tmpl() {}
|
||||
};
|
||||
|
||||
typedef SharedMemoryFactory_tmpl<> SharedMemoryFactory;
|
||||
|
||||
#endif /* SHARED_MEMORY_POINTER_FACTORY_H */
|
||||
@@ -1,197 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SHARED_MEMORY_VECTOR_WRAPPER_H
|
||||
#define SHARED_MEMORY_VECTOR_WRAPPER_H
|
||||
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
template<typename DataT>
|
||||
class ShMemIterator : public std::iterator<std::input_iterator_tag, DataT> {
|
||||
DataT * p;
|
||||
public:
|
||||
explicit ShMemIterator(DataT * x) : p(x) {}
|
||||
ShMemIterator(const ShMemIterator & mit) : p(mit.p) {}
|
||||
ShMemIterator& operator++() {
|
||||
++p;
|
||||
return *this;
|
||||
}
|
||||
ShMemIterator operator++(int) {
|
||||
ShMemIterator tmp(*this);
|
||||
operator++();
|
||||
return tmp;
|
||||
}
|
||||
ShMemIterator operator+(std::ptrdiff_t diff) {
|
||||
ShMemIterator tmp(p+diff);
|
||||
return tmp;
|
||||
}
|
||||
bool operator==(const ShMemIterator& rhs) {
|
||||
return p==rhs.p;
|
||||
}
|
||||
bool operator!=(const ShMemIterator& rhs) {
|
||||
return p!=rhs.p;
|
||||
}
|
||||
DataT& operator*() {
|
||||
return *p;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename DataT>
|
||||
class SharedMemoryWrapper {
|
||||
private:
|
||||
DataT * m_ptr;
|
||||
std::size_t m_size;
|
||||
|
||||
public:
|
||||
SharedMemoryWrapper() :
|
||||
m_ptr(NULL),
|
||||
m_size(0)
|
||||
{ }
|
||||
|
||||
SharedMemoryWrapper(DataT * ptr, std::size_t size) :
|
||||
m_ptr(ptr),
|
||||
m_size(size)
|
||||
{ }
|
||||
|
||||
void swap( SharedMemoryWrapper<DataT> & other ) {
|
||||
BOOST_ASSERT_MSG(m_size != 0 || other.size() != 0, "size invalid");
|
||||
std::swap( m_size, other.m_size);
|
||||
std::swap( m_ptr , other.m_ptr );
|
||||
}
|
||||
|
||||
// void SetData(const DataT * ptr, const std::size_t size) {
|
||||
// BOOST_ASSERT_MSG( 0 == m_size, "vector not empty");
|
||||
// BOOST_ASSERT_MSG( 0 < size , "new vector empty");
|
||||
// m_ptr.reset(ptr);
|
||||
// m_size = size;
|
||||
// }
|
||||
|
||||
DataT & at(const std::size_t index) {
|
||||
return m_ptr[index];
|
||||
}
|
||||
|
||||
const DataT & at(const std::size_t index) const {
|
||||
return m_ptr[index];
|
||||
}
|
||||
|
||||
ShMemIterator<DataT> begin() const {
|
||||
return ShMemIterator<DataT>(m_ptr);
|
||||
}
|
||||
|
||||
ShMemIterator<DataT> end() const {
|
||||
return ShMemIterator<DataT>(m_ptr+m_size);
|
||||
}
|
||||
|
||||
std::size_t size() const { return m_size; }
|
||||
|
||||
bool empty() const { return 0 == size(); }
|
||||
|
||||
DataT & operator[](const unsigned index) {
|
||||
BOOST_ASSERT_MSG(index < m_size, "invalid size");
|
||||
return m_ptr[index];
|
||||
}
|
||||
|
||||
const DataT & operator[](const unsigned index) const {
|
||||
BOOST_ASSERT_MSG(index < m_size, "invalid size");
|
||||
return m_ptr[index];
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class SharedMemoryWrapper<bool> {
|
||||
private:
|
||||
unsigned * m_ptr;
|
||||
std::size_t m_size;
|
||||
|
||||
public:
|
||||
SharedMemoryWrapper() :
|
||||
m_ptr(NULL),
|
||||
m_size(0)
|
||||
{ }
|
||||
|
||||
SharedMemoryWrapper(unsigned * ptr, std::size_t size) :
|
||||
m_ptr(ptr),
|
||||
m_size(size)
|
||||
{ }
|
||||
|
||||
void swap( SharedMemoryWrapper<bool> & other ) {
|
||||
BOOST_ASSERT_MSG(m_size != 0 || other.size() != 0, "size invalid");
|
||||
std::swap( m_size, other.m_size);
|
||||
std::swap( m_ptr , other.m_ptr );
|
||||
}
|
||||
|
||||
// void SetData(const DataT * ptr, const std::size_t size) {
|
||||
// BOOST_ASSERT_MSG( 0 == m_size, "vector not empty");
|
||||
// BOOST_ASSERT_MSG( 0 < size , "new vector empty");
|
||||
// m_ptr.reset(ptr);
|
||||
// m_size = size;
|
||||
// }
|
||||
|
||||
bool at(const std::size_t index) const {
|
||||
// BOOST_ASSERT_MSG(index < m_size, "invalid size");
|
||||
const unsigned bucket = index / 32;
|
||||
const unsigned offset = index % 32;
|
||||
return m_ptr[bucket] & (1 << offset);
|
||||
}
|
||||
|
||||
// ShMemIterator<DataT> begin() const {
|
||||
// return ShMemIterator<DataT>(m_ptr);
|
||||
// }
|
||||
|
||||
// ShMemIterator<DataT> end() const {
|
||||
// return ShMemIterator<DataT>(m_ptr+m_size);
|
||||
// }
|
||||
|
||||
std::size_t size() const { return m_size; }
|
||||
|
||||
bool empty() const { return 0 == size(); }
|
||||
|
||||
bool operator[](const unsigned index) {
|
||||
BOOST_ASSERT_MSG(index < m_size, "invalid size");
|
||||
const unsigned bucket = index / 32;
|
||||
const unsigned offset = index % 32;
|
||||
return m_ptr[bucket] & (1 << offset);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename DataT, bool UseSharedMemory>
|
||||
struct ShM {
|
||||
typedef typename boost::conditional<
|
||||
UseSharedMemory,
|
||||
SharedMemoryWrapper<DataT>,
|
||||
std::vector<DataT>
|
||||
>::type vector;
|
||||
};
|
||||
|
||||
#endif //SHARED_MEMORY_VECTOR_WRAPPER_H
|
||||
@@ -1,206 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef STATICGRAPH_H_INCLUDED
|
||||
#define STATICGRAPH_H_INCLUDED
|
||||
|
||||
#include "../DataStructures/Percent.h"
|
||||
#include "../DataStructures/SharedMemoryVectorWrapper.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
template< typename EdgeDataT, bool UseSharedMemory = false>
|
||||
class StaticGraph {
|
||||
public:
|
||||
typedef NodeID NodeIterator;
|
||||
typedef NodeID EdgeIterator;
|
||||
typedef EdgeDataT EdgeData;
|
||||
class InputEdge {
|
||||
public:
|
||||
EdgeDataT data;
|
||||
NodeIterator source;
|
||||
NodeIterator target;
|
||||
bool operator<( const InputEdge& right ) const {
|
||||
if ( source != right.source ) {
|
||||
return source < right.source;
|
||||
}
|
||||
return target < right.target;
|
||||
}
|
||||
};
|
||||
|
||||
struct _StrNode {
|
||||
//index of the first edge
|
||||
EdgeIterator firstEdge;
|
||||
};
|
||||
|
||||
struct _StrEdge {
|
||||
NodeID target;
|
||||
EdgeDataT data;
|
||||
};
|
||||
|
||||
StaticGraph( const int nodes, std::vector< InputEdge > &graph ) {
|
||||
std::sort( graph.begin(), graph.end() );
|
||||
_numNodes = nodes;
|
||||
_numEdges = ( EdgeIterator ) graph.size();
|
||||
_nodes.resize( _numNodes + 1);
|
||||
EdgeIterator edge = 0;
|
||||
EdgeIterator position = 0;
|
||||
for ( NodeIterator node = 0; node <= _numNodes; ++node ) {
|
||||
EdgeIterator lastEdge = edge;
|
||||
while ( edge < _numEdges && graph[edge].source == node )
|
||||
++edge;
|
||||
_nodes[node].firstEdge = position; //=edge
|
||||
position += edge - lastEdge; //remove
|
||||
}
|
||||
_edges.resize( position ); //(edge)
|
||||
edge = 0;
|
||||
for ( NodeIterator node = 0; node < _numNodes; ++node ) {
|
||||
for ( EdgeIterator i = _nodes[node].firstEdge, e = _nodes[node+1].firstEdge; i != e; ++i ) {
|
||||
_edges[i].target = graph[edge].target;
|
||||
_edges[i].data = graph[edge].data;
|
||||
assert(_edges[i].data.distance > 0);
|
||||
edge++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StaticGraph(
|
||||
typename ShM<_StrNode, UseSharedMemory>::vector & nodes,
|
||||
typename ShM<_StrEdge, UseSharedMemory>::vector & edges
|
||||
) {
|
||||
_numNodes = nodes.size()-1;
|
||||
_numEdges = edges.size();
|
||||
|
||||
_nodes.swap(nodes);
|
||||
_edges.swap(edges);
|
||||
|
||||
#ifndef NDEBUG
|
||||
Percent p(GetNumberOfNodes());
|
||||
for(unsigned u = 0; u < GetNumberOfNodes(); ++u) {
|
||||
for(unsigned eid = BeginEdges(u); eid < EndEdges(u); ++eid) {
|
||||
unsigned v = GetTarget(eid);
|
||||
EdgeData & data = GetEdgeData(eid);
|
||||
if(data.shortcut) {
|
||||
unsigned eid2 = FindEdgeInEitherDirection(u, data.id);
|
||||
if(eid2 == UINT_MAX) {
|
||||
SimpleLogger().Write(logWARNING) <<
|
||||
"cannot find first segment of edge (" <<
|
||||
u << "," << data.id << "," << v << "), eid: " << eid;
|
||||
|
||||
data.shortcut = false;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
eid2 = FindEdgeInEitherDirection(data.id, v);
|
||||
if(eid2 == UINT_MAX) {
|
||||
SimpleLogger().Write(logWARNING) <<
|
||||
"cannot find second segment of edge (" <<
|
||||
u << "," << data.id << "," << v << "), eid2: " << eid2;
|
||||
data.shortcut = false;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
p.printIncrement();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned GetNumberOfNodes() const {
|
||||
return _numNodes;
|
||||
}
|
||||
|
||||
unsigned GetNumberOfEdges() const {
|
||||
return _numEdges;
|
||||
}
|
||||
|
||||
unsigned GetOutDegree( const NodeIterator n ) const {
|
||||
return BeginEdges(n)-EndEdges(n) - 1;
|
||||
}
|
||||
|
||||
inline NodeIterator GetTarget( const EdgeIterator e ) const {
|
||||
return NodeIterator( _edges[e].target );
|
||||
}
|
||||
|
||||
inline EdgeDataT &GetEdgeData( const EdgeIterator e ) {
|
||||
return _edges[e].data;
|
||||
}
|
||||
|
||||
const EdgeDataT &GetEdgeData( const EdgeIterator e ) const {
|
||||
return _edges[e].data;
|
||||
}
|
||||
|
||||
EdgeIterator BeginEdges( const NodeIterator n ) const {
|
||||
return EdgeIterator( _nodes.at(n).firstEdge );
|
||||
}
|
||||
|
||||
EdgeIterator EndEdges( const NodeIterator n ) const {
|
||||
return EdgeIterator( _nodes.at(n+1).firstEdge );
|
||||
}
|
||||
|
||||
//searches for a specific edge
|
||||
EdgeIterator FindEdge( const NodeIterator from, const NodeIterator to ) const {
|
||||
EdgeIterator smallestEdge = SPECIAL_EDGEID;
|
||||
EdgeWeight smallestWeight = INVALID_EDGE_WEIGHT;
|
||||
for ( EdgeIterator edge = BeginEdges( from ); edge < EndEdges(from); edge++ ) {
|
||||
const NodeID target = GetTarget(edge);
|
||||
const EdgeWeight weight = GetEdgeData(edge).distance;
|
||||
if(target == to && weight < smallestWeight) {
|
||||
smallestEdge = edge; smallestWeight = weight;
|
||||
}
|
||||
}
|
||||
return smallestEdge;
|
||||
}
|
||||
|
||||
EdgeIterator FindEdgeInEitherDirection( const NodeIterator from, const NodeIterator to ) const {
|
||||
EdgeIterator tmp = FindEdge( from, to );
|
||||
return (UINT_MAX != tmp ? tmp : FindEdge( to, from ));
|
||||
}
|
||||
|
||||
EdgeIterator FindEdgeIndicateIfReverse( const NodeIterator from, const NodeIterator to, bool & result ) const {
|
||||
EdgeIterator tmp = FindEdge( from, to );
|
||||
if(UINT_MAX == tmp) {
|
||||
tmp = FindEdge( to, from );
|
||||
if(UINT_MAX != tmp) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
NodeIterator _numNodes;
|
||||
EdgeIterator _numEdges;
|
||||
|
||||
typename ShM< _StrNode, UseSharedMemory >::vector _nodes;
|
||||
typename ShM< _StrEdge, UseSharedMemory >::vector _edges;
|
||||
};
|
||||
|
||||
#endif // STATICGRAPH_H_INCLUDED
|
||||
@@ -1,230 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
// KD Tree coded by Christian Vetter, Monav Project
|
||||
|
||||
#ifndef STATICKDTREE_H_INCLUDED
|
||||
#define STATICKDTREE_H_INCLUDED
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stack>
|
||||
#include <limits>
|
||||
|
||||
namespace KDTree {
|
||||
|
||||
#define KDTREE_BASESIZE (8)
|
||||
|
||||
template< unsigned k, typename T >
|
||||
class BoundingBox {
|
||||
public:
|
||||
BoundingBox() {
|
||||
for ( unsigned dim = 0; dim < k; ++dim ) {
|
||||
min[dim] = std::numeric_limits< T >::min();
|
||||
max[dim] = std::numeric_limits< T >::max();
|
||||
}
|
||||
}
|
||||
|
||||
T min[k];
|
||||
T max[k];
|
||||
};
|
||||
|
||||
struct NoData {};
|
||||
|
||||
template< unsigned k, typename T >
|
||||
class EuclidianMetric {
|
||||
public:
|
||||
double operator() ( const T left[k], const T right[k] ) {
|
||||
double result = 0;
|
||||
for ( unsigned i = 0; i < k; ++i ) {
|
||||
double temp = (double)left[i] - (double)right[i];
|
||||
result += temp * temp;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
double operator() ( const BoundingBox< k, T > &box, const T point[k] ) {
|
||||
T nearest[k];
|
||||
for ( unsigned dim = 0; dim < k; ++dim ) {
|
||||
if ( point[dim] < box.min[dim] )
|
||||
nearest[dim] = box.min[dim];
|
||||
else if ( point[dim] > box.max[dim] )
|
||||
nearest[dim] = box.max[dim];
|
||||
else
|
||||
nearest[dim] = point[dim];
|
||||
}
|
||||
return operator() ( point, nearest );
|
||||
}
|
||||
};
|
||||
|
||||
template < unsigned k, typename T, typename Data = NoData, typename Metric = EuclidianMetric< k, T > >
|
||||
class StaticKDTree {
|
||||
public:
|
||||
|
||||
struct InputPoint {
|
||||
T coordinates[k];
|
||||
Data data;
|
||||
bool operator==( const InputPoint& right )
|
||||
{
|
||||
for ( int i = 0; i < k; i++ ) {
|
||||
if ( coordinates[i] != right.coordinates[i] )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
explicit StaticKDTree( std::vector< InputPoint > * points ){
|
||||
BOOST_ASSERT( k > 0 );
|
||||
BOOST_ASSERT ( points->size() > 0 );
|
||||
size = points->size();
|
||||
kdtree = new InputPoint[size];
|
||||
for ( Iterator i = 0; i != size; ++i ) {
|
||||
kdtree[i] = points->at(i);
|
||||
for ( unsigned dim = 0; dim < k; ++dim ) {
|
||||
if ( kdtree[i].coordinates[dim] < boundingBox.min[dim] )
|
||||
boundingBox.min[dim] = kdtree[i].coordinates[dim];
|
||||
if ( kdtree[i].coordinates[dim] > boundingBox.max[dim] )
|
||||
boundingBox.max[dim] = kdtree[i].coordinates[dim];
|
||||
}
|
||||
}
|
||||
std::stack< Tree > s;
|
||||
s.push ( Tree ( 0, size, 0 ) );
|
||||
while ( !s.empty() ) {
|
||||
Tree tree = s.top();
|
||||
s.pop();
|
||||
|
||||
if ( tree.right - tree.left < KDTREE_BASESIZE )
|
||||
continue;
|
||||
|
||||
Iterator middle = tree.left + ( tree.right - tree.left ) / 2;
|
||||
std::nth_element( kdtree + tree.left, kdtree + middle, kdtree + tree.right, Less( tree.dimension ) );
|
||||
s.push( Tree( tree.left, middle, ( tree.dimension + 1 ) % k ) );
|
||||
s.push( Tree( middle + 1, tree.right, ( tree.dimension + 1 ) % k ) );
|
||||
}
|
||||
}
|
||||
|
||||
~StaticKDTree(){
|
||||
delete[] kdtree;
|
||||
}
|
||||
|
||||
bool NearestNeighbor( InputPoint* result, const InputPoint& point ) {
|
||||
Metric distance;
|
||||
bool found = false;
|
||||
double nearestDistance = std::numeric_limits< T >::max();
|
||||
std::stack< NNTree > s;
|
||||
s.push ( NNTree ( 0, size, 0, boundingBox ) );
|
||||
while ( !s.empty() ) {
|
||||
NNTree tree = s.top();
|
||||
s.pop();
|
||||
|
||||
if ( distance( tree.box, point.coordinates ) >= nearestDistance )
|
||||
continue;
|
||||
|
||||
if ( tree.right - tree.left < KDTREE_BASESIZE ) {
|
||||
for ( unsigned i = tree.left; i < tree.right; i++ ) {
|
||||
double newDistance = distance( kdtree[i].coordinates, point.coordinates );
|
||||
if ( newDistance < nearestDistance ) {
|
||||
nearestDistance = newDistance;
|
||||
*result = kdtree[i];
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Iterator middle = tree.left + ( tree.right - tree.left ) / 2;
|
||||
|
||||
double newDistance = distance( kdtree[middle].coordinates, point.coordinates );
|
||||
if ( newDistance < nearestDistance ) {
|
||||
nearestDistance = newDistance;
|
||||
*result = kdtree[middle];
|
||||
found = true;
|
||||
}
|
||||
|
||||
Less comperator( tree.dimension );
|
||||
if ( !comperator( point, kdtree[middle] ) ) {
|
||||
NNTree first( middle + 1, tree.right, ( tree.dimension + 1 ) % k, tree.box );
|
||||
NNTree second( tree.left, middle, ( tree.dimension + 1 ) % k, tree.box );
|
||||
first.box.min[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
|
||||
second.box.max[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
|
||||
s.push( second );
|
||||
s.push( first );
|
||||
}
|
||||
else {
|
||||
NNTree first( middle + 1, tree.right, ( tree.dimension + 1 ) % k, tree.box );
|
||||
NNTree second( tree.left, middle, ( tree.dimension + 1 ) % k, tree.box );
|
||||
first.box.min[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
|
||||
second.box.max[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
|
||||
s.push( first );
|
||||
s.push( second );
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef unsigned Iterator;
|
||||
struct Tree {
|
||||
Iterator left;
|
||||
Iterator right;
|
||||
unsigned dimension;
|
||||
Tree() {}
|
||||
Tree( Iterator l, Iterator r, unsigned d ): left( l ), right( r ), dimension( d ) {}
|
||||
};
|
||||
struct NNTree {
|
||||
Iterator left;
|
||||
Iterator right;
|
||||
unsigned dimension;
|
||||
BoundingBox< k, T > box;
|
||||
NNTree() {}
|
||||
NNTree( Iterator l, Iterator r, unsigned d, const BoundingBox< k, T >& b ): left( l ), right( r ), dimension( d ), box ( b ) {}
|
||||
};
|
||||
class Less {
|
||||
public:
|
||||
explicit Less( unsigned d ) {
|
||||
dimension = d;
|
||||
BOOST_ASSERT( dimension < k );
|
||||
}
|
||||
|
||||
bool operator() ( const InputPoint& left, const InputPoint& right ) {
|
||||
BOOST_ASSERT( dimension < k );
|
||||
return left.coordinates[dimension] < right.coordinates[dimension];
|
||||
}
|
||||
private:
|
||||
unsigned dimension;
|
||||
};
|
||||
|
||||
BoundingBox< k, T > boundingBox;
|
||||
InputPoint* kdtree;
|
||||
Iterator size;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // STATICKDTREE_H_INCLUDED
|
||||
@@ -1,828 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef STATICRTREE_H_
|
||||
#define STATICRTREE_H_
|
||||
|
||||
#include "DeallocatingVector.h"
|
||||
#include "HilbertValue.h"
|
||||
#include "PhantomNodes.h"
|
||||
#include "QueryNode.h"
|
||||
#include "SharedMemoryFactory.h"
|
||||
#include "SharedMemoryVectorWrapper.h"
|
||||
|
||||
#include "../Util/MercatorUtil.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/algorithm/minmax.hpp>
|
||||
#include <boost/algorithm/minmax_element.hpp>
|
||||
#include <boost/range/algorithm_ext/erase.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
//tuning parameters
|
||||
const static uint32_t RTREE_BRANCHING_FACTOR = 50;
|
||||
const static uint32_t RTREE_LEAF_NODE_SIZE = 1170;
|
||||
|
||||
// Implements a static, i.e. packed, R-tree
|
||||
|
||||
static boost::thread_specific_ptr<boost::filesystem::ifstream> thread_local_rtree_stream;
|
||||
|
||||
template<class DataT, class CoordinateListT = std::vector<FixedPointCoordinate>, bool UseSharedMemory = false>
|
||||
class StaticRTree : boost::noncopyable {
|
||||
public:
|
||||
struct RectangleInt2D {
|
||||
RectangleInt2D() :
|
||||
min_lon(INT_MAX),
|
||||
max_lon(INT_MIN),
|
||||
min_lat(INT_MAX),
|
||||
max_lat(INT_MIN) {}
|
||||
|
||||
int32_t min_lon, max_lon;
|
||||
int32_t min_lat, max_lat;
|
||||
|
||||
inline void InitializeMBRectangle(
|
||||
DataT const * objects,
|
||||
const uint32_t element_count,
|
||||
const std::vector<NodeInfo> & coordinate_list
|
||||
) {
|
||||
for(uint32_t i = 0; i < element_count; ++i) {
|
||||
min_lon = std::min(
|
||||
min_lon, std::min(
|
||||
coordinate_list.at(objects[i].u).lon,
|
||||
coordinate_list.at(objects[i].v).lon
|
||||
)
|
||||
);
|
||||
max_lon = std::max(
|
||||
max_lon, std::max(
|
||||
coordinate_list.at(objects[i].u).lon,
|
||||
coordinate_list.at(objects[i].v).lon
|
||||
)
|
||||
);
|
||||
|
||||
min_lat = std::min(
|
||||
min_lat, std::min(
|
||||
coordinate_list.at(objects[i].u).lat,
|
||||
coordinate_list.at(objects[i].v).lon
|
||||
)
|
||||
);
|
||||
max_lat = std::max(
|
||||
max_lat, std::max(
|
||||
coordinate_list.at(objects[i].u).lat,
|
||||
coordinate_list.at(objects[i].v).lon
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
inline void AugmentMBRectangle(const RectangleInt2D & other) {
|
||||
min_lon = std::min(min_lon, other.min_lon);
|
||||
max_lon = std::max(max_lon, other.max_lon);
|
||||
min_lat = std::min(min_lat, other.min_lat);
|
||||
max_lat = std::max(max_lat, other.max_lat);
|
||||
}
|
||||
|
||||
inline FixedPointCoordinate Centroid() const {
|
||||
FixedPointCoordinate centroid;
|
||||
//The coordinates of the midpoints are given by:
|
||||
//x = (x1 + x2) /2 and y = (y1 + y2) /2.
|
||||
centroid.lon = (min_lon + max_lon)/2;
|
||||
centroid.lat = (min_lat + max_lat)/2;
|
||||
return centroid;
|
||||
}
|
||||
|
||||
inline bool Intersects(const RectangleInt2D & other) const {
|
||||
FixedPointCoordinate upper_left (other.max_lat, other.min_lon);
|
||||
FixedPointCoordinate upper_right(other.max_lat, other.max_lon);
|
||||
FixedPointCoordinate lower_right(other.min_lat, other.max_lon);
|
||||
FixedPointCoordinate lower_left (other.min_lat, other.min_lon);
|
||||
|
||||
return (
|
||||
Contains(upper_left ) ||
|
||||
Contains(upper_right) ||
|
||||
Contains(lower_right) ||
|
||||
Contains(lower_left )
|
||||
);
|
||||
}
|
||||
|
||||
inline double GetMinDist(const FixedPointCoordinate & location) const {
|
||||
bool is_contained = Contains(location);
|
||||
if (is_contained) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double min_dist = std::numeric_limits<double>::max();
|
||||
min_dist = std::min(
|
||||
min_dist,
|
||||
FixedPointCoordinate::ApproximateDistance(
|
||||
location.lat,
|
||||
location.lon,
|
||||
max_lat,
|
||||
min_lon
|
||||
)
|
||||
);
|
||||
min_dist = std::min(
|
||||
min_dist,
|
||||
FixedPointCoordinate::ApproximateDistance(
|
||||
location.lat,
|
||||
location.lon,
|
||||
max_lat,
|
||||
max_lon
|
||||
)
|
||||
);
|
||||
min_dist = std::min(
|
||||
min_dist,
|
||||
FixedPointCoordinate::ApproximateDistance(
|
||||
location.lat,
|
||||
location.lon,
|
||||
min_lat,
|
||||
max_lon
|
||||
)
|
||||
);
|
||||
min_dist = std::min(
|
||||
min_dist,
|
||||
FixedPointCoordinate::ApproximateDistance(
|
||||
location.lat,
|
||||
location.lon,
|
||||
min_lat,
|
||||
min_lon
|
||||
)
|
||||
);
|
||||
return min_dist;
|
||||
}
|
||||
|
||||
inline double GetMinMaxDist(const FixedPointCoordinate & location) const {
|
||||
double min_max_dist = std::numeric_limits<double>::max();
|
||||
//Get minmax distance to each of the four sides
|
||||
FixedPointCoordinate upper_left (max_lat, min_lon);
|
||||
FixedPointCoordinate upper_right(max_lat, max_lon);
|
||||
FixedPointCoordinate lower_right(min_lat, max_lon);
|
||||
FixedPointCoordinate lower_left (min_lat, min_lon);
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(
|
||||
FixedPointCoordinate::ApproximateDistance(location, upper_left ),
|
||||
FixedPointCoordinate::ApproximateDistance(location, upper_right)
|
||||
)
|
||||
);
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(
|
||||
FixedPointCoordinate::ApproximateDistance(location, upper_right),
|
||||
FixedPointCoordinate::ApproximateDistance(location, lower_right)
|
||||
)
|
||||
);
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(
|
||||
FixedPointCoordinate::ApproximateDistance(location, lower_right),
|
||||
FixedPointCoordinate::ApproximateDistance(location, lower_left )
|
||||
)
|
||||
);
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(
|
||||
FixedPointCoordinate::ApproximateDistance(location, lower_left ),
|
||||
FixedPointCoordinate::ApproximateDistance(location, upper_left )
|
||||
)
|
||||
);
|
||||
return min_max_dist;
|
||||
}
|
||||
|
||||
inline bool Contains(const FixedPointCoordinate & location) const {
|
||||
const bool lats_contained =
|
||||
(location.lat > min_lat) && (location.lat < max_lat);
|
||||
const bool lons_contained =
|
||||
(location.lon > min_lon) && (location.lon < max_lon);
|
||||
return lats_contained && lons_contained;
|
||||
}
|
||||
|
||||
inline friend std::ostream & operator<< (
|
||||
std::ostream & out,
|
||||
const RectangleInt2D & rect
|
||||
) {
|
||||
out << rect.min_lat/COORDINATE_PRECISION << ","
|
||||
<< rect.min_lon/COORDINATE_PRECISION << " "
|
||||
<< rect.max_lat/COORDINATE_PRECISION << ","
|
||||
<< rect.max_lon/COORDINATE_PRECISION;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
typedef RectangleInt2D RectangleT;
|
||||
|
||||
struct TreeNode {
|
||||
TreeNode() : child_count(0), child_is_on_disk(false) {}
|
||||
RectangleT minimum_bounding_rectangle;
|
||||
uint32_t child_count:31;
|
||||
bool child_is_on_disk:1;
|
||||
uint32_t children[RTREE_BRANCHING_FACTOR];
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
struct WrappedInputElement {
|
||||
explicit WrappedInputElement(
|
||||
const uint32_t _array_index,
|
||||
const uint64_t _hilbert_value
|
||||
) : m_array_index(_array_index), m_hilbert_value(_hilbert_value) {}
|
||||
|
||||
WrappedInputElement() : m_array_index(UINT_MAX), m_hilbert_value(0) {}
|
||||
|
||||
uint32_t m_array_index;
|
||||
uint64_t m_hilbert_value;
|
||||
|
||||
inline bool operator<(const WrappedInputElement & other) const {
|
||||
return m_hilbert_value < other.m_hilbert_value;
|
||||
}
|
||||
};
|
||||
|
||||
struct LeafNode {
|
||||
LeafNode() : object_count(0) {}
|
||||
uint32_t object_count;
|
||||
DataT objects[RTREE_LEAF_NODE_SIZE];
|
||||
};
|
||||
|
||||
struct QueryCandidate {
|
||||
explicit QueryCandidate(
|
||||
const uint32_t n_id,
|
||||
const double dist
|
||||
) : node_id(n_id), min_dist(dist) {}
|
||||
QueryCandidate() : node_id(UINT_MAX), min_dist(std::numeric_limits<double>::max()) {}
|
||||
uint32_t node_id;
|
||||
double min_dist;
|
||||
inline bool operator<(const QueryCandidate & other) const {
|
||||
return min_dist < other.min_dist;
|
||||
}
|
||||
};
|
||||
|
||||
typename ShM<TreeNode, UseSharedMemory>::vector m_search_tree;
|
||||
uint64_t m_element_count;
|
||||
const std::string m_leaf_node_filename;
|
||||
boost::shared_ptr<CoordinateListT> m_coordinate_list;
|
||||
|
||||
public:
|
||||
//Construct a packed Hilbert-R-Tree with Kamel-Faloutsos algorithm [1]
|
||||
explicit StaticRTree(
|
||||
std::vector<DataT> & input_data_vector,
|
||||
const std::string tree_node_filename,
|
||||
const std::string leaf_node_filename,
|
||||
const std::vector<NodeInfo> & coordinate_list
|
||||
)
|
||||
: m_element_count(input_data_vector.size()),
|
||||
m_leaf_node_filename(leaf_node_filename)
|
||||
{
|
||||
SimpleLogger().Write() <<
|
||||
"constructing r-tree of " << m_element_count <<
|
||||
" edge elements build on-top of " << coordinate_list.size() << " coordinates";
|
||||
|
||||
double time1 = get_timestamp();
|
||||
std::vector<WrappedInputElement> input_wrapper_vector(m_element_count);
|
||||
|
||||
HilbertCode get_hilbert_number;
|
||||
|
||||
//generate auxiliary vector of hilbert-values
|
||||
#pragma omp parallel for schedule(guided)
|
||||
for(uint64_t element_counter = 0; element_counter < m_element_count; ++element_counter) {
|
||||
input_wrapper_vector[element_counter].m_array_index = element_counter;
|
||||
//Get Hilbert-Value for centroid in mercartor projection
|
||||
DataT const & current_element = input_data_vector[element_counter];
|
||||
FixedPointCoordinate current_centroid = DataT::Centroid(
|
||||
FixedPointCoordinate(
|
||||
coordinate_list.at(current_element.u).lat,
|
||||
coordinate_list.at(current_element.u).lon
|
||||
),
|
||||
FixedPointCoordinate(
|
||||
coordinate_list.at(current_element.v).lat,
|
||||
coordinate_list.at(current_element.v).lon
|
||||
)
|
||||
);
|
||||
current_centroid.lat = COORDINATE_PRECISION*lat2y(current_centroid.lat/COORDINATE_PRECISION);
|
||||
|
||||
uint64_t current_hilbert_value = get_hilbert_number(current_centroid);
|
||||
input_wrapper_vector[element_counter].m_hilbert_value = current_hilbert_value;
|
||||
}
|
||||
|
||||
//open leaf file
|
||||
boost::filesystem::ofstream leaf_node_file(leaf_node_filename, std::ios::binary);
|
||||
leaf_node_file.write((char*) &m_element_count, sizeof(uint64_t));
|
||||
|
||||
//sort the hilbert-value representatives
|
||||
std::sort(input_wrapper_vector.begin(), input_wrapper_vector.end());
|
||||
std::vector<TreeNode> tree_nodes_in_level;
|
||||
|
||||
//pack M elements into leaf node and write to leaf file
|
||||
uint64_t processed_objects_count = 0;
|
||||
while(processed_objects_count < m_element_count) {
|
||||
|
||||
LeafNode current_leaf;
|
||||
TreeNode current_node;
|
||||
//SimpleLogger().Write() << "reading " << tree_size << " tree nodes in " << (sizeof(TreeNode)*tree_size) << " bytes";
|
||||
for(uint32_t current_element_index = 0; RTREE_LEAF_NODE_SIZE > current_element_index; ++current_element_index) {
|
||||
if(m_element_count > (processed_objects_count + current_element_index)) {
|
||||
uint32_t index_of_next_object = input_wrapper_vector[processed_objects_count + current_element_index].m_array_index;
|
||||
current_leaf.objects[current_element_index] = input_data_vector[index_of_next_object];
|
||||
++current_leaf.object_count;
|
||||
}
|
||||
}
|
||||
|
||||
//generate tree node that resemble the objects in leaf and store it for next level
|
||||
current_node.minimum_bounding_rectangle.InitializeMBRectangle(
|
||||
current_leaf.objects,
|
||||
current_leaf.object_count,
|
||||
coordinate_list
|
||||
);
|
||||
current_node.child_is_on_disk = true;
|
||||
current_node.children[0] = tree_nodes_in_level.size();
|
||||
tree_nodes_in_level.push_back(current_node);
|
||||
|
||||
//write leaf_node to leaf node file
|
||||
leaf_node_file.write((char*)¤t_leaf, sizeof(current_leaf));
|
||||
processed_objects_count += current_leaf.object_count;
|
||||
}
|
||||
|
||||
//close leaf file
|
||||
leaf_node_file.close();
|
||||
|
||||
uint32_t processing_level = 0;
|
||||
while(1 < tree_nodes_in_level.size()) {
|
||||
std::vector<TreeNode> tree_nodes_in_next_level;
|
||||
uint32_t processed_tree_nodes_in_level = 0;
|
||||
while(processed_tree_nodes_in_level < tree_nodes_in_level.size()) {
|
||||
TreeNode parent_node;
|
||||
//pack RTREE_BRANCHING_FACTOR elements into tree_nodes each
|
||||
for(
|
||||
uint32_t current_child_node_index = 0;
|
||||
RTREE_BRANCHING_FACTOR > current_child_node_index;
|
||||
++current_child_node_index
|
||||
) {
|
||||
if(processed_tree_nodes_in_level < tree_nodes_in_level.size()) {
|
||||
TreeNode & current_child_node = tree_nodes_in_level[processed_tree_nodes_in_level];
|
||||
//add tree node to parent entry
|
||||
parent_node.children[current_child_node_index] = m_search_tree.size();
|
||||
m_search_tree.push_back(current_child_node);
|
||||
//augment MBR of parent
|
||||
parent_node.minimum_bounding_rectangle.AugmentMBRectangle(current_child_node.minimum_bounding_rectangle);
|
||||
//increase counters
|
||||
++parent_node.child_count;
|
||||
++processed_tree_nodes_in_level;
|
||||
}
|
||||
}
|
||||
tree_nodes_in_next_level.push_back(parent_node);
|
||||
}
|
||||
tree_nodes_in_level.swap(tree_nodes_in_next_level);
|
||||
++processing_level;
|
||||
}
|
||||
BOOST_ASSERT_MSG(1 == tree_nodes_in_level.size(), "tree broken, more than one root node");
|
||||
//last remaining entry is the root node, store it
|
||||
m_search_tree.push_back(tree_nodes_in_level[0]);
|
||||
|
||||
//reverse and renumber tree to have root at index 0
|
||||
std::reverse(m_search_tree.begin(), m_search_tree.end());
|
||||
|
||||
#pragma omp parallel for schedule(guided)
|
||||
for(uint32_t i = 0; i < m_search_tree.size(); ++i) {
|
||||
TreeNode & current_tree_node = m_search_tree[i];
|
||||
for(uint32_t j = 0; j < current_tree_node.child_count; ++j) {
|
||||
const uint32_t old_id = current_tree_node.children[j];
|
||||
const uint32_t new_id = m_search_tree.size() - old_id - 1;
|
||||
current_tree_node.children[j] = new_id;
|
||||
}
|
||||
}
|
||||
|
||||
//open tree file
|
||||
boost::filesystem::ofstream tree_node_file(
|
||||
tree_node_filename,
|
||||
std::ios::binary
|
||||
);
|
||||
|
||||
uint32_t size_of_tree = m_search_tree.size();
|
||||
BOOST_ASSERT_MSG(0 < size_of_tree, "tree empty");
|
||||
tree_node_file.write((char *)&size_of_tree, sizeof(uint32_t));
|
||||
tree_node_file.write((char *)&m_search_tree[0], sizeof(TreeNode)*size_of_tree);
|
||||
//close tree node file.
|
||||
tree_node_file.close();
|
||||
double time2 = get_timestamp();
|
||||
SimpleLogger().Write() <<
|
||||
"finished r-tree construction in " << (time2-time1) << " seconds";
|
||||
}
|
||||
|
||||
//Read-only operation for queries
|
||||
explicit StaticRTree(
|
||||
const boost::filesystem::path & node_file,
|
||||
const boost::filesystem::path & leaf_file,
|
||||
const boost::shared_ptr<CoordinateListT> coordinate_list
|
||||
) : m_leaf_node_filename( leaf_file.string() ) {
|
||||
//open tree node file and load into RAM.
|
||||
m_coordinate_list = coordinate_list;
|
||||
|
||||
if ( !boost::filesystem::exists( node_file ) ) {
|
||||
throw OSRMException("ram index file does not exist");
|
||||
}
|
||||
if ( 0 == boost::filesystem::file_size( node_file ) ) {
|
||||
throw OSRMException("ram index file is empty");
|
||||
}
|
||||
boost::filesystem::ifstream tree_node_file( node_file, std::ios::binary );
|
||||
|
||||
uint32_t tree_size = 0;
|
||||
tree_node_file.read((char*)&tree_size, sizeof(uint32_t));
|
||||
|
||||
m_search_tree.resize(tree_size);
|
||||
tree_node_file.read((char*)&m_search_tree[0], sizeof(TreeNode)*tree_size);
|
||||
tree_node_file.close();
|
||||
//open leaf node file and store thread specific pointer
|
||||
if ( !boost::filesystem::exists( leaf_file ) ) {
|
||||
throw OSRMException("mem index file does not exist");
|
||||
}
|
||||
if ( 0 == boost::filesystem::file_size( leaf_file ) ) {
|
||||
throw OSRMException("mem index file is empty");
|
||||
}
|
||||
|
||||
boost::filesystem::ifstream leaf_node_file( leaf_file, std::ios::binary );
|
||||
leaf_node_file.read((char*)&m_element_count, sizeof(uint64_t));
|
||||
leaf_node_file.close();
|
||||
|
||||
//SimpleLogger().Write() << tree_size << " nodes in search tree";
|
||||
//SimpleLogger().Write() << m_element_count << " elements in leafs";
|
||||
}
|
||||
|
||||
explicit StaticRTree(
|
||||
TreeNode * tree_node_ptr,
|
||||
const uint32_t number_of_nodes,
|
||||
const boost::filesystem::path & leaf_file,
|
||||
boost::shared_ptr<CoordinateListT> coordinate_list
|
||||
) : m_search_tree(tree_node_ptr, number_of_nodes),
|
||||
m_leaf_node_filename(leaf_file.string()),
|
||||
m_coordinate_list(coordinate_list)
|
||||
{
|
||||
//open leaf node file and store thread specific pointer
|
||||
if ( !boost::filesystem::exists( leaf_file ) ) {
|
||||
throw OSRMException("mem index file does not exist");
|
||||
}
|
||||
if ( 0 == boost::filesystem::file_size( leaf_file ) ) {
|
||||
throw OSRMException("mem index file is empty");
|
||||
}
|
||||
|
||||
boost::filesystem::ifstream leaf_node_file( leaf_file, std::ios::binary );
|
||||
leaf_node_file.read((char*)&m_element_count, sizeof(uint64_t));
|
||||
leaf_node_file.close();
|
||||
|
||||
if( thread_local_rtree_stream.get() ) {
|
||||
thread_local_rtree_stream->close();
|
||||
}
|
||||
|
||||
//SimpleLogger().Write() << tree_size << " nodes in search tree";
|
||||
//SimpleLogger().Write() << m_element_count << " elements in leafs";
|
||||
}
|
||||
//Read-only operation for queries
|
||||
|
||||
bool LocateClosestEndPointForCoordinate(
|
||||
const FixedPointCoordinate & input_coordinate,
|
||||
FixedPointCoordinate & result_coordinate,
|
||||
const unsigned zoom_level
|
||||
) {
|
||||
bool ignore_tiny_components = (zoom_level <= 14);
|
||||
DataT nearest_edge;
|
||||
double min_dist = std::numeric_limits<double>::max();
|
||||
double min_max_dist = std::numeric_limits<double>::max();
|
||||
bool found_a_nearest_edge = false;
|
||||
|
||||
//initialize queue with root element
|
||||
std::priority_queue<QueryCandidate> traversal_queue;
|
||||
double current_min_dist = m_search_tree[0].minimum_bounding_rectangle.GetMinDist(input_coordinate);
|
||||
traversal_queue.push(
|
||||
QueryCandidate(0, current_min_dist)
|
||||
);
|
||||
|
||||
BOOST_ASSERT_MSG(
|
||||
std::numeric_limits<double>::epsilon() > (0. - traversal_queue.top().min_dist),
|
||||
"Root element in NN Search has min dist != 0."
|
||||
);
|
||||
|
||||
while(!traversal_queue.empty()) {
|
||||
const QueryCandidate current_query_node = traversal_queue.top();
|
||||
traversal_queue.pop();
|
||||
|
||||
const bool prune_downward = (current_query_node.min_dist >= min_max_dist);
|
||||
const bool prune_upward = (current_query_node.min_dist >= min_dist);
|
||||
if( !prune_downward && !prune_upward ) { //downward pruning
|
||||
TreeNode & current_tree_node = m_search_tree[current_query_node.node_id];
|
||||
if (current_tree_node.child_is_on_disk) {
|
||||
LeafNode current_leaf_node;
|
||||
LoadLeafFromDisk(
|
||||
current_tree_node.children[0],
|
||||
current_leaf_node
|
||||
);
|
||||
for(uint32_t i = 0; i < current_leaf_node.object_count; ++i) {
|
||||
DataT const & current_edge = current_leaf_node.objects[i];
|
||||
if(
|
||||
ignore_tiny_components &&
|
||||
current_edge.belongsToTinyComponent
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double current_minimum_distance = FixedPointCoordinate::ApproximateDistance(
|
||||
input_coordinate.lat,
|
||||
input_coordinate.lon,
|
||||
m_coordinate_list->at(current_edge.u).lat,
|
||||
m_coordinate_list->at(current_edge.u).lon
|
||||
);
|
||||
if( current_minimum_distance < min_dist ) {
|
||||
//found a new minimum
|
||||
min_dist = current_minimum_distance;
|
||||
result_coordinate.lat = m_coordinate_list->at(current_edge.u).lat;
|
||||
result_coordinate.lon = m_coordinate_list->at(current_edge.u).lon;
|
||||
found_a_nearest_edge = true;
|
||||
}
|
||||
|
||||
current_minimum_distance = FixedPointCoordinate::ApproximateDistance(
|
||||
input_coordinate.lat,
|
||||
input_coordinate.lon,
|
||||
m_coordinate_list->at(current_edge.v).lat,
|
||||
m_coordinate_list->at(current_edge.v).lon
|
||||
);
|
||||
|
||||
if( current_minimum_distance < min_dist ) {
|
||||
//found a new minimum
|
||||
min_dist = current_minimum_distance;
|
||||
result_coordinate.lat = m_coordinate_list->at(current_edge.v).lat;
|
||||
result_coordinate.lon = m_coordinate_list->at(current_edge.v).lon;
|
||||
found_a_nearest_edge = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//traverse children, prune if global mindist is smaller than local one
|
||||
for (uint32_t i = 0; i < current_tree_node.child_count; ++i) {
|
||||
const int32_t child_id = current_tree_node.children[i];
|
||||
const TreeNode & child_tree_node = m_search_tree[child_id];
|
||||
const RectangleT & child_rectangle = child_tree_node.minimum_bounding_rectangle;
|
||||
const double current_min_dist = child_rectangle.GetMinDist(input_coordinate);
|
||||
const double current_min_max_dist = child_rectangle.GetMinMaxDist(input_coordinate);
|
||||
if( current_min_max_dist < min_max_dist ) {
|
||||
min_max_dist = current_min_max_dist;
|
||||
}
|
||||
if (current_min_dist > min_max_dist) {
|
||||
continue;
|
||||
}
|
||||
if (current_min_dist > min_dist) { //upward pruning
|
||||
continue;
|
||||
}
|
||||
traversal_queue.push(
|
||||
QueryCandidate(child_id, current_min_dist)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found_a_nearest_edge;
|
||||
}
|
||||
|
||||
bool FindPhantomNodeForCoordinate(
|
||||
const FixedPointCoordinate & input_coordinate,
|
||||
PhantomNode & result_phantom_node,
|
||||
const unsigned zoom_level
|
||||
) {
|
||||
|
||||
bool ignore_tiny_components = (zoom_level <= 14);
|
||||
DataT nearest_edge;
|
||||
|
||||
// uint32_t io_count = 0;
|
||||
uint32_t explored_tree_nodes_count = 0;
|
||||
//SimpleLogger().Write() << "searching for coordinate " << input_coordinate;
|
||||
double min_dist = std::numeric_limits<double>::max();
|
||||
double min_max_dist = std::numeric_limits<double>::max();
|
||||
bool found_a_nearest_edge = false;
|
||||
|
||||
FixedPointCoordinate nearest, current_start_coordinate, current_end_coordinate;
|
||||
|
||||
//initialize queue with root element
|
||||
std::priority_queue<QueryCandidate> traversal_queue;
|
||||
double current_min_dist = m_search_tree[0].minimum_bounding_rectangle.GetMinDist(input_coordinate);
|
||||
traversal_queue.push( QueryCandidate(0, current_min_dist) );
|
||||
|
||||
BOOST_ASSERT_MSG(
|
||||
std::numeric_limits<double>::epsilon() > (0. - traversal_queue.top().min_dist),
|
||||
"Root element in NN Search has min dist != 0."
|
||||
);
|
||||
|
||||
LeafNode current_leaf_node;
|
||||
while(!traversal_queue.empty()) {
|
||||
const QueryCandidate current_query_node = traversal_queue.top(); traversal_queue.pop();
|
||||
|
||||
++explored_tree_nodes_count;
|
||||
bool prune_downward = (current_query_node.min_dist >= min_max_dist);
|
||||
bool prune_upward = (current_query_node.min_dist >= min_dist);
|
||||
if( !prune_downward && !prune_upward ) { //downward pruning
|
||||
TreeNode & current_tree_node = m_search_tree[current_query_node.node_id];
|
||||
if (current_tree_node.child_is_on_disk) {
|
||||
LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
|
||||
// ++io_count;
|
||||
for(uint32_t i = 0; i < current_leaf_node.object_count; ++i) {
|
||||
DataT & current_edge = current_leaf_node.objects[i];
|
||||
if(ignore_tiny_components && current_edge.belongsToTinyComponent) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double current_ratio = 0.;
|
||||
const double current_perpendicular_distance = current_edge.ComputePerpendicularDistance(
|
||||
m_coordinate_list->at(current_edge.u),
|
||||
m_coordinate_list->at(current_edge.v),
|
||||
input_coordinate,
|
||||
nearest,
|
||||
current_ratio
|
||||
);
|
||||
|
||||
BOOST_ASSERT( 0. <= current_perpendicular_distance );
|
||||
|
||||
if(
|
||||
( current_perpendicular_distance < min_dist ) &&
|
||||
!DoubleEpsilonCompare(
|
||||
current_perpendicular_distance,
|
||||
min_dist
|
||||
)
|
||||
) { //found a new minimum
|
||||
min_dist = current_perpendicular_distance;
|
||||
//TODO: use assignment c'tor in PhantomNode
|
||||
result_phantom_node.forward_node_id = current_edge.forward_edge_based_node_id;
|
||||
result_phantom_node.reverse_node_id = current_edge.reverse_edge_based_node_id;
|
||||
result_phantom_node.name_id = current_edge.name_id;
|
||||
result_phantom_node.forward_weight = current_edge.forward_weight;
|
||||
result_phantom_node.reverse_weight = current_edge.reverse_weight;
|
||||
result_phantom_node.forward_offset = current_edge.forward_offset;
|
||||
result_phantom_node.reverse_offset = current_edge.reverse_offset;
|
||||
result_phantom_node.packed_geometry_id = current_edge.packed_geometry_id;
|
||||
result_phantom_node.fwd_segment_position = current_edge.fwd_segment_position;
|
||||
|
||||
result_phantom_node.location = nearest;
|
||||
current_start_coordinate.lat = m_coordinate_list->at(current_edge.u).lat;
|
||||
current_start_coordinate.lon = m_coordinate_list->at(current_edge.u).lon;
|
||||
current_end_coordinate.lat = m_coordinate_list->at(current_edge.v).lat;
|
||||
current_end_coordinate.lon = m_coordinate_list->at(current_edge.v).lon;
|
||||
nearest_edge = current_edge;
|
||||
found_a_nearest_edge = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//traverse children, prune if global mindist is smaller than local one
|
||||
for (uint32_t i = 0; i < current_tree_node.child_count; ++i) {
|
||||
const int32_t child_id = current_tree_node.children[i];
|
||||
TreeNode & child_tree_node = m_search_tree[child_id];
|
||||
RectangleT & child_rectangle = child_tree_node.minimum_bounding_rectangle;
|
||||
const double current_min_dist = child_rectangle.GetMinDist(input_coordinate);
|
||||
const double current_min_max_dist = child_rectangle.GetMinMaxDist(input_coordinate);
|
||||
if( current_min_max_dist < min_max_dist ) {
|
||||
min_max_dist = current_min_max_dist;
|
||||
}
|
||||
if( current_min_dist > min_max_dist ) {
|
||||
continue;
|
||||
}
|
||||
if( current_min_dist > min_dist ) { //upward pruning
|
||||
continue;
|
||||
}
|
||||
traversal_queue.push(QueryCandidate(child_id, current_min_dist));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Hack to fix rounding errors and wandering via nodes.
|
||||
if(std::abs(input_coordinate.lon - result_phantom_node.location.lon) == 1) {
|
||||
result_phantom_node.location.lon = input_coordinate.lon;
|
||||
}
|
||||
if(std::abs(input_coordinate.lat - result_phantom_node.location.lat) == 1) {
|
||||
result_phantom_node.location.lat = input_coordinate.lat;
|
||||
}
|
||||
|
||||
double ratio = 0.;
|
||||
|
||||
if( found_a_nearest_edge) {
|
||||
const double distance_1 = FixedPointCoordinate::ApproximateDistance(
|
||||
current_start_coordinate,
|
||||
result_phantom_node.location
|
||||
);
|
||||
|
||||
const double distance_2 = FixedPointCoordinate::ApproximateDistance(
|
||||
current_start_coordinate,
|
||||
current_end_coordinate
|
||||
);
|
||||
|
||||
ratio = distance_1/distance_2;
|
||||
ratio = std::min(1., ratio);
|
||||
}
|
||||
|
||||
// SimpleLogger().Write(logDEBUG) << "[rtree] result_phantom_node.forward_offset: " << result_phantom_node.forward_offset;
|
||||
// SimpleLogger().Write(logDEBUG) << "[rtree] result_phantom_node.reverse_offset: " << result_phantom_node.reverse_offset;
|
||||
// SimpleLogger().Write(logDEBUG) << "[rtree] result_phantom_node.forward_weight: " << result_phantom_node.forward_weight;
|
||||
// SimpleLogger().Write(logDEBUG) << "[rtree] result_phantom_node.reverse_weight: " << result_phantom_node.reverse_weight;
|
||||
|
||||
if (SPECIAL_NODEID != result_phantom_node.forward_node_id)
|
||||
{
|
||||
result_phantom_node.forward_weight *= ratio;
|
||||
}
|
||||
if (SPECIAL_NODEID != result_phantom_node.reverse_node_id)
|
||||
{
|
||||
result_phantom_node.reverse_weight *= (1.-ratio);
|
||||
}
|
||||
|
||||
// SimpleLogger().Write(logDEBUG) << "[rtree] result location: " << result_phantom_node.location << ", start: " << current_start_coordinate << ", end: " << current_end_coordinate;
|
||||
// SimpleLogger().Write(logDEBUG) << "[rtree] fwd node: " << result_phantom_node.forward_node_id << ", rev node: " << result_phantom_node.reverse_node_id;
|
||||
// SimpleLogger().Write(logDEBUG) << "[rtree] fwd weight: " << result_phantom_node.forward_weight << ", rev weight: " << result_phantom_node.reverse_weight;
|
||||
// SimpleLogger().Write(logDEBUG) << "[rtree] fwd offset: " << result_phantom_node.forward_offset << ", rev offset: " << result_phantom_node.reverse_offset;
|
||||
// SimpleLogger().Write(logDEBUG) << "[rtree] bidirected: " << (result_phantom_node.isBidirected() ? "y" : "n");
|
||||
// SimpleLogger().Write(logDEBUG) << "[rtree] name id: " << result_phantom_node.name_id;
|
||||
// SimpleLogger().Write(logDEBUG) << "[rtree] geom id: " << result_phantom_node.packed_geometry_id;
|
||||
// SimpleLogger().Write(logDEBUG) << "[rtree] ratio: " << ratio;
|
||||
|
||||
return found_a_nearest_edge;
|
||||
}
|
||||
|
||||
private:
|
||||
inline void LoadLeafFromDisk(const uint32_t leaf_id, LeafNode& result_node) {
|
||||
if(
|
||||
!thread_local_rtree_stream.get() ||
|
||||
!thread_local_rtree_stream->is_open()
|
||||
) {
|
||||
thread_local_rtree_stream.reset(
|
||||
new boost::filesystem::ifstream(
|
||||
m_leaf_node_filename,
|
||||
std::ios::in | std::ios::binary
|
||||
)
|
||||
);
|
||||
}
|
||||
if(!thread_local_rtree_stream->good()) {
|
||||
thread_local_rtree_stream->clear(std::ios::goodbit);
|
||||
SimpleLogger().Write(logDEBUG) << "Resetting stale filestream";
|
||||
}
|
||||
uint64_t seek_pos = sizeof(uint64_t) + leaf_id*sizeof(LeafNode);
|
||||
thread_local_rtree_stream->seekg(seek_pos);
|
||||
thread_local_rtree_stream->read((char *)&result_node, sizeof(LeafNode));
|
||||
}
|
||||
|
||||
inline bool EdgesAreEquivalent(
|
||||
const FixedPointCoordinate & a,
|
||||
const FixedPointCoordinate & b,
|
||||
const FixedPointCoordinate & c,
|
||||
const FixedPointCoordinate & d
|
||||
) const {
|
||||
return (a == b && c == d) || (a == c && b == d) || (a == d && b == c);
|
||||
}
|
||||
|
||||
inline bool DoubleEpsilonCompare(const double d1, const double d2) const {
|
||||
return (std::abs(d1 - d2) < std::numeric_limits<double>::epsilon() );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//[1] "On Packing R-Trees"; I. Kamel, C. Faloutsos; 1993; DOI: 10.1145/170088.170403
|
||||
//[2] "Nearest Neighbor Queries", N. Roussopulos et al; 1995; DOI: 10.1145/223784.223794
|
||||
|
||||
|
||||
#endif /* STATICRTREE_H_ */
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TURNINSTRUCTIONS_H_
|
||||
#define TURNINSTRUCTIONS_H_
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
typedef unsigned char TurnInstruction;
|
||||
|
||||
//This is a hack until c++0x is available enough to use scoped enums
|
||||
struct TurnInstructionsClass : boost::noncopyable {
|
||||
|
||||
const static TurnInstruction NoTurn = 0; //Give no instruction at all
|
||||
const static TurnInstruction GoStraight = 1; //Tell user to go straight!
|
||||
const static TurnInstruction TurnSlightRight = 2;
|
||||
const static TurnInstruction TurnRight = 3;
|
||||
const static TurnInstruction TurnSharpRight = 4;
|
||||
const static TurnInstruction UTurn = 5;
|
||||
const static TurnInstruction TurnSharpLeft = 6;
|
||||
const static TurnInstruction TurnLeft = 7;
|
||||
const static TurnInstruction TurnSlightLeft = 8;
|
||||
const static TurnInstruction ReachViaPoint = 9;
|
||||
const static TurnInstruction HeadOn = 10;
|
||||
const static TurnInstruction EnterRoundAbout = 11;
|
||||
const static TurnInstruction LeaveRoundAbout = 12;
|
||||
const static TurnInstruction StayOnRoundAbout = 13;
|
||||
const static TurnInstruction StartAtEndOfStreet = 14;
|
||||
const static TurnInstruction ReachedYourDestination = 15;
|
||||
const static TurnInstruction EnterAgainstAllowedDirection = 16;
|
||||
const static TurnInstruction LeaveAgainstAllowedDirection = 17;
|
||||
|
||||
const static TurnInstruction AccessRestrictionFlag = 128;
|
||||
const static TurnInstruction InverseAccessRestrictionFlag = 0x7f; // ~128 does not work without a warning.
|
||||
|
||||
const static int AccessRestrictionPenalty = 1 << 15; //unrelated to the bit set in the restriction flag
|
||||
|
||||
static inline TurnInstruction GetTurnDirectionOfInstruction( const double angle ) {
|
||||
if(angle >= 23 && angle < 67) {
|
||||
return TurnSharpRight;
|
||||
}
|
||||
if (angle >= 67 && angle < 113) {
|
||||
return TurnRight;
|
||||
}
|
||||
if (angle >= 113 && angle < 158) {
|
||||
return TurnSlightRight;
|
||||
}
|
||||
if (angle >= 158 && angle < 202) {
|
||||
return GoStraight;
|
||||
}
|
||||
if (angle >= 202 && angle < 248) {
|
||||
return TurnSlightLeft;
|
||||
}
|
||||
if (angle >= 248 && angle < 292) {
|
||||
return TurnLeft;
|
||||
}
|
||||
if (angle >= 292 && angle < 336) {
|
||||
return TurnSharpLeft;
|
||||
}
|
||||
return UTurn;
|
||||
}
|
||||
|
||||
static inline bool TurnIsNecessary ( const short turnInstruction ) {
|
||||
if(NoTurn == turnInstruction || StayOnRoundAbout == turnInstruction)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif /* TURNINSTRUCTIONS_H_ */
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef FASTXORHASH_H_
|
||||
#define FASTXORHASH_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
/*
|
||||
This is an implementation of Tabulation hashing, which has suprising properties like universality.
|
||||
The space requirement is 2*2^16 = 256 kb of memory, which fits into L2 cache.
|
||||
Evaluation boils down to 10 or less assembly instruction on any recent X86 CPU:
|
||||
|
||||
1: movq table2(%rip), %rdx
|
||||
2: movl %edi, %eax
|
||||
3: movzwl %di, %edi
|
||||
4: shrl $16, %eax
|
||||
5: movzwl %ax, %eax
|
||||
6: movzbl (%rdx,%rax), %eax
|
||||
7: movq table1(%rip), %rdx
|
||||
8: xorb (%rdx,%rdi), %al
|
||||
9: movzbl %al, %eax
|
||||
10: ret
|
||||
|
||||
*/
|
||||
class XORFastHash { //65k entries
|
||||
std::vector<unsigned short> table1;
|
||||
std::vector<unsigned short> table2;
|
||||
public:
|
||||
XORFastHash() {
|
||||
table1.resize(2 << 16);
|
||||
table2.resize(2 << 16);
|
||||
for(unsigned i = 0; i < (2 << 16); ++i) {
|
||||
table1[i] = i; table2[i] = i;
|
||||
}
|
||||
std::random_shuffle(table1.begin(), table1.end());
|
||||
std::random_shuffle(table2.begin(), table2.end());
|
||||
}
|
||||
|
||||
inline unsigned short operator()(const unsigned originalValue) const {
|
||||
unsigned short lsb = ((originalValue) & 0xffff);
|
||||
unsigned short msb = (((originalValue) >> 16) & 0xffff);
|
||||
return table1[lsb] ^ table2[msb];
|
||||
}
|
||||
};
|
||||
|
||||
class XORMiniHash { //256 entries
|
||||
std::vector<unsigned char> table1;
|
||||
std::vector<unsigned char> table2;
|
||||
std::vector<unsigned char> table3;
|
||||
std::vector<unsigned char> table4;
|
||||
|
||||
public:
|
||||
XORMiniHash() {
|
||||
table1.resize(1 << 8);
|
||||
table2.resize(1 << 8);
|
||||
table3.resize(1 << 8);
|
||||
table4.resize(1 << 8);
|
||||
for(unsigned i = 0; i < (1 << 8); ++i) {
|
||||
table1[i] = i; table2[i] = i;
|
||||
table3[i] = i; table4[i] = i;
|
||||
}
|
||||
std::random_shuffle(table1.begin(), table1.end());
|
||||
std::random_shuffle(table2.begin(), table2.end());
|
||||
std::random_shuffle(table3.begin(), table3.end());
|
||||
std::random_shuffle(table4.begin(), table4.end());
|
||||
}
|
||||
unsigned char operator()(const unsigned originalValue) const {
|
||||
unsigned char byte1 = ((originalValue) & 0xff);
|
||||
unsigned char byte2 = ((originalValue >> 8) & 0xff);
|
||||
unsigned char byte3 = ((originalValue >> 16) & 0xff);
|
||||
unsigned char byte4 = ((originalValue >> 24) & 0xff);
|
||||
return table1[byte1] ^ table2[byte2] ^ table3[byte3] ^ table4[byte4];
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* FASTXORHASH_H_ */
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef XORFASTHASHSTORAGE_H_
|
||||
#define XORFASTHASHSTORAGE_H_
|
||||
|
||||
#include "XORFastHash.h"
|
||||
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
#include <bitset>
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class XORFastHashStorage {
|
||||
public:
|
||||
struct HashCell{
|
||||
Key key;
|
||||
NodeID id;
|
||||
unsigned time;
|
||||
HashCell() : key(UINT_MAX), id(UINT_MAX), time(UINT_MAX) {}
|
||||
|
||||
HashCell(const HashCell & other) : key(other.key), id(other.id), time(other.time) { }
|
||||
|
||||
inline operator Key() const {
|
||||
return key;
|
||||
}
|
||||
|
||||
inline void operator=(const Key & keyToInsert) {
|
||||
key = keyToInsert;
|
||||
}
|
||||
};
|
||||
|
||||
explicit XORFastHashStorage( size_t ) : positions(2<<16), currentTimestamp(0) { }
|
||||
|
||||
inline HashCell& operator[]( const NodeID node ) {
|
||||
unsigned short position = fastHash(node);
|
||||
while((positions[position].time == currentTimestamp) && (positions[position].id != node)){
|
||||
++position %= (2<<16);
|
||||
}
|
||||
|
||||
positions[position].id = node;
|
||||
positions[position].time = currentTimestamp;
|
||||
return positions[position];
|
||||
}
|
||||
|
||||
inline void Clear() {
|
||||
++currentTimestamp;
|
||||
if(UINT_MAX == currentTimestamp) {
|
||||
positions.clear();
|
||||
positions.resize((2<<16));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
XORFastHashStorage() : positions(2<<16), currentTimestamp(0) {}
|
||||
std::vector<HashCell> positions;
|
||||
XORFastHash fastHash;
|
||||
unsigned currentTimestamp;
|
||||
};
|
||||
|
||||
|
||||
#endif /* XORFASTHASHSTORAGE_H_ */
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BASE_DESCRIPTOR_H_
|
||||
#define BASE_DESCRIPTOR_H_
|
||||
|
||||
#include "../DataStructures/PhantomNodes.h"
|
||||
#include "../DataStructures/RawRouteData.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Reply.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct DescriptorConfig {
|
||||
DescriptorConfig() :
|
||||
instructions(true),
|
||||
geometry(true),
|
||||
encode_geometry(true),
|
||||
zoom_level(18)
|
||||
{ }
|
||||
bool instructions;
|
||||
bool geometry;
|
||||
bool encode_geometry;
|
||||
unsigned short zoom_level;
|
||||
};
|
||||
|
||||
template<class DataFacadeT>
|
||||
class BaseDescriptor {
|
||||
public:
|
||||
BaseDescriptor() { }
|
||||
//Maybe someone can explain the pure virtual destructor thing to me (dennis)
|
||||
virtual ~BaseDescriptor() { }
|
||||
virtual void Run(
|
||||
const RawRouteData & rawRoute,
|
||||
const PhantomNodes & phantomNodes,
|
||||
DataFacadeT * facade,
|
||||
http::Reply & reply
|
||||
) = 0;
|
||||
virtual void SetConfig(const DescriptorConfig & config) = 0;
|
||||
};
|
||||
|
||||
#endif /* BASE_DESCRIPTOR_H_ */
|
||||
@@ -1,140 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "DescriptionFactory.h"
|
||||
|
||||
DescriptionFactory::DescriptionFactory() : entireLength(0) { }
|
||||
|
||||
DescriptionFactory::~DescriptionFactory() { }
|
||||
|
||||
inline double DescriptionFactory::DegreeToRadian(const double degree) const
|
||||
{
|
||||
return degree * (M_PI/180.);
|
||||
}
|
||||
|
||||
inline double DescriptionFactory::RadianToDegree(const double radian) const
|
||||
{
|
||||
return radian * (180./M_PI);
|
||||
}
|
||||
|
||||
double DescriptionFactory::GetBearing(const FixedPointCoordinate & A, const FixedPointCoordinate & B) const
|
||||
{
|
||||
double delta_long = DegreeToRadian(B.lon/COORDINATE_PRECISION - A.lon/COORDINATE_PRECISION);
|
||||
|
||||
const double lat1 = DegreeToRadian(A.lat/COORDINATE_PRECISION);
|
||||
const double lat2 = DegreeToRadian(B.lat/COORDINATE_PRECISION);
|
||||
|
||||
const double y = sin(delta_long) * cos(lat2);
|
||||
const double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(delta_long);
|
||||
double result = RadianToDegree(atan2(y, x));
|
||||
while (result < 0.)
|
||||
{
|
||||
result += 360.;
|
||||
}
|
||||
|
||||
while (result >= 360.)
|
||||
{
|
||||
result -= 360.;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void DescriptionFactory::SetStartSegment(const PhantomNode & source, const bool source_traversed_in_reverse)
|
||||
{
|
||||
start_phantom = source;
|
||||
AppendSegment(
|
||||
source.location,
|
||||
PathData(0, source.name_id, 10, source.forward_weight)
|
||||
);
|
||||
}
|
||||
|
||||
void DescriptionFactory::SetEndSegment(const PhantomNode & target, const bool target_traversed_in_reverse)
|
||||
{
|
||||
target_phantom = target;
|
||||
pathDescription.push_back(
|
||||
SegmentInformation(
|
||||
target.location,
|
||||
target.name_id,
|
||||
0,
|
||||
target.reverse_weight,
|
||||
0,
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendSegment(const FixedPointCoordinate & coordinate, const PathData & path_point)
|
||||
{
|
||||
if ((1 == pathDescription.size()) && ( pathDescription.back().location == coordinate))
|
||||
{
|
||||
pathDescription.back().name_id = path_point.name_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
pathDescription.push_back(
|
||||
SegmentInformation(coordinate, path_point.name_id, path_point.durationOfSegment, 0, path_point.turnInstruction)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendEncodedPolylineString(
|
||||
const bool return_encoded,
|
||||
std::vector<std::string> & output
|
||||
) {
|
||||
std::string temp;
|
||||
if(return_encoded) {
|
||||
polyline_compressor.printEncodedString(pathDescription, temp);
|
||||
} else {
|
||||
polyline_compressor.printUnencodedString(pathDescription, temp);
|
||||
}
|
||||
output.push_back(temp);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendEncodedPolylineString(
|
||||
std::vector<std::string> &output
|
||||
) const {
|
||||
std::string temp;
|
||||
polyline_compressor.printEncodedString(pathDescription, temp);
|
||||
output.push_back(temp);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendUnencodedPolylineString(
|
||||
std::vector<std::string>& output
|
||||
) const {
|
||||
std::string temp;
|
||||
polyline_compressor.printUnencodedString(pathDescription, temp);
|
||||
output.push_back(temp);
|
||||
}
|
||||
|
||||
void DescriptionFactory::BuildRouteSummary(
|
||||
const double distance,
|
||||
const unsigned time
|
||||
) {
|
||||
summary.startName = start_phantom.name_id;
|
||||
summary.destName = target_phantom.name_id;
|
||||
summary.BuildDurationAndLengthStrings(distance, time);
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DESCRIPTIONFACTORY_H_
|
||||
#define DESCRIPTIONFACTORY_H_
|
||||
|
||||
#include "../Algorithms/DouglasPeucker.h"
|
||||
#include "../Algorithms/PolylineCompressor.h"
|
||||
#include "../DataStructures/PhantomNodes.h"
|
||||
#include "../DataStructures/RawRouteData.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
/* This class is fed with all way segments in consecutive order
|
||||
* and produces the description plus the encoded polyline */
|
||||
|
||||
class DescriptionFactory {
|
||||
DouglasPeucker polyline_generalizer;
|
||||
PolylineCompressor polyline_compressor;
|
||||
PhantomNode start_phantom, target_phantom;
|
||||
|
||||
double DegreeToRadian(const double degree) const;
|
||||
double RadianToDegree(const double degree) const;
|
||||
public:
|
||||
struct RouteSummary {
|
||||
std::string lengthString;
|
||||
std::string durationString;
|
||||
unsigned startName;
|
||||
unsigned destName;
|
||||
RouteSummary() :
|
||||
lengthString("0"),
|
||||
durationString("0"),
|
||||
startName(0),
|
||||
destName(0)
|
||||
{}
|
||||
|
||||
void BuildDurationAndLengthStrings(
|
||||
const double distance,
|
||||
const unsigned time
|
||||
) {
|
||||
//compute distance/duration for route summary
|
||||
intToString(round(distance), lengthString);
|
||||
int travel_time = round(time/10.);
|
||||
intToString(std::max(travel_time, 1), durationString);
|
||||
}
|
||||
} summary;
|
||||
|
||||
double entireLength;
|
||||
|
||||
//I know, declaring this public is considered bad. I'm lazy
|
||||
std::vector <SegmentInformation> pathDescription;
|
||||
DescriptionFactory();
|
||||
virtual ~DescriptionFactory();
|
||||
double GetBearing(const FixedPointCoordinate& C, const FixedPointCoordinate& B) const;
|
||||
void AppendEncodedPolylineString(std::vector<std::string> &output) const;
|
||||
void AppendUnencodedPolylineString(std::vector<std::string> &output) const;
|
||||
void AppendSegment(const FixedPointCoordinate & coordinate, const PathData & data);
|
||||
void BuildRouteSummary(const double distance, const unsigned time);
|
||||
void SetStartSegment(const PhantomNode & start_phantom, const bool source_traversed_in_reverse);
|
||||
void SetEndSegment(const PhantomNode & start_phantom, const bool target_traversed_in_reverse);
|
||||
void AppendEncodedPolylineString(
|
||||
const bool return_encoded,
|
||||
std::vector<std::string> & output
|
||||
);
|
||||
|
||||
template<class DataFacadeT>
|
||||
void Run(
|
||||
const DataFacadeT * facade,
|
||||
const unsigned zoomLevel
|
||||
) {
|
||||
if( pathDescription.empty() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** starts at index 1 */
|
||||
pathDescription[0].length = 0;
|
||||
for (unsigned i = 1; i < pathDescription.size(); ++i)
|
||||
{
|
||||
//move down names by one, q&d hack
|
||||
pathDescription[i-1].name_id = pathDescription[i].name_id;
|
||||
pathDescription[i].length = FixedPointCoordinate::ApproximateEuclideanDistance(pathDescription[i-1].location, pathDescription[i].location);
|
||||
}
|
||||
|
||||
/*Simplify turn instructions
|
||||
Input :
|
||||
10. Turn left on B 36 for 20 km
|
||||
11. Continue on B 35; B 36 for 2 km
|
||||
12. Continue on B 36 for 13 km
|
||||
|
||||
becomes:
|
||||
10. Turn left on B 36 for 35 km
|
||||
*/
|
||||
//TODO: rework to check only end and start of string.
|
||||
// stl string is way to expensive
|
||||
|
||||
// unsigned lastTurn = 0;
|
||||
// for(unsigned i = 1; i < pathDescription.size(); ++i) {
|
||||
// string1 = sEngine.GetEscapedNameForNameID(pathDescription[i].name_id);
|
||||
// if(TurnInstructionsClass::GoStraight == pathDescription[i].turn_instruction) {
|
||||
// if(std::string::npos != string0.find(string1+";")
|
||||
// || std::string::npos != string0.find(";"+string1)
|
||||
// || std::string::npos != string0.find(string1+" ;")
|
||||
// || std::string::npos != string0.find("; "+string1)
|
||||
// ){
|
||||
// SimpleLogger().Write() << "->next correct: " << string0 << " contains " << string1;
|
||||
// for(; lastTurn != i; ++lastTurn)
|
||||
// pathDescription[lastTurn].name_id = pathDescription[i].name_id;
|
||||
// pathDescription[i].turn_instruction = TurnInstructionsClass::NoTurn;
|
||||
// } else if(std::string::npos != string1.find(string0+";")
|
||||
// || std::string::npos != string1.find(";"+string0)
|
||||
// || std::string::npos != string1.find(string0+" ;")
|
||||
// || std::string::npos != string1.find("; "+string0)
|
||||
// ){
|
||||
// SimpleLogger().Write() << "->prev correct: " << string1 << " contains " << string0;
|
||||
// pathDescription[i].name_id = pathDescription[i-1].name_id;
|
||||
// pathDescription[i].turn_instruction = TurnInstructionsClass::NoTurn;
|
||||
// }
|
||||
// }
|
||||
// if (TurnInstructionsClass::NoTurn != pathDescription[i].turn_instruction) {
|
||||
// lastTurn = i;
|
||||
// }
|
||||
// string0 = string1;
|
||||
// }
|
||||
|
||||
double segment_length = 0.;
|
||||
unsigned segment_duration = 0;
|
||||
unsigned segment_start_index = 0;
|
||||
|
||||
for(unsigned i = 1; i < pathDescription.size(); ++i) {
|
||||
entireLength += pathDescription[i].length;
|
||||
segment_length += pathDescription[i].length;
|
||||
segment_duration += pathDescription[i].duration;
|
||||
pathDescription[segment_start_index].length = segment_length;
|
||||
pathDescription[segment_start_index].duration = segment_duration;
|
||||
|
||||
|
||||
if(TurnInstructionsClass::NoTurn != pathDescription[i].turn_instruction) {
|
||||
BOOST_ASSERT(pathDescription[i].necessary);
|
||||
segment_length = 0;
|
||||
segment_duration = 0;
|
||||
segment_start_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
//Post-processing to remove empty or nearly empty path segments
|
||||
if(std::numeric_limits<double>::epsilon() > pathDescription.back().length) {
|
||||
if(pathDescription.size() > 2){
|
||||
pathDescription.pop_back();
|
||||
pathDescription.back().necessary = true;
|
||||
pathDescription.back().turn_instruction = TurnInstructionsClass::NoTurn;
|
||||
target_phantom.name_id = (pathDescription.end()-2)->name_id;
|
||||
}
|
||||
}
|
||||
if(std::numeric_limits<double>::epsilon() > pathDescription[0].length) {
|
||||
if(pathDescription.size() > 2) {
|
||||
pathDescription.erase(pathDescription.begin());
|
||||
pathDescription[0].turn_instruction = TurnInstructionsClass::HeadOn;
|
||||
pathDescription[0].necessary = true;
|
||||
start_phantom.name_id = pathDescription[0].name_id;
|
||||
}
|
||||
}
|
||||
|
||||
//Generalize poly line
|
||||
polyline_generalizer.Run(pathDescription, zoomLevel);
|
||||
|
||||
//fix what needs to be fixed else
|
||||
for(unsigned i = 0; i < pathDescription.size()-1 && pathDescription.size() >= 2; ++i){
|
||||
if(pathDescription[i].necessary) {
|
||||
double angle = GetBearing(pathDescription[i].location, pathDescription[i+1].location);
|
||||
pathDescription[i].bearing = angle*10;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* DESCRIPTIONFACTORY_H_ */
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GPX_DESCRIPTOR_H_
|
||||
#define GPX_DESCRIPTOR_H_
|
||||
|
||||
#include "BaseDescriptor.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
template<class DataFacadeT>
|
||||
class GPXDescriptor : public BaseDescriptor<DataFacadeT> {
|
||||
private:
|
||||
DescriptorConfig config;
|
||||
FixedPointCoordinate current;
|
||||
|
||||
std::string tmp;
|
||||
public:
|
||||
void SetConfig(const DescriptorConfig & c) { config = c; }
|
||||
|
||||
//TODO: reorder parameters
|
||||
void Run(
|
||||
const RawRouteData &raw_route,
|
||||
const PhantomNodes &phantom_node_list,
|
||||
DataFacadeT * facade,
|
||||
http::Reply & reply
|
||||
) {
|
||||
reply.content.push_back("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
reply.content.push_back(
|
||||
"<gpx creator=\"OSRM Routing Engine\" version=\"1.1\" "
|
||||
"xmlns=\"http://www.topografix.com/GPX/1/1\" "
|
||||
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
||||
"xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd"
|
||||
"\">");
|
||||
reply.content.push_back(
|
||||
"<metadata><copyright author=\"Project OSRM\"><license>Data (c)"
|
||||
" OpenStreetMap contributors (ODbL)</license></copyright>"
|
||||
"</metadata>");
|
||||
reply.content.push_back("<rte>");
|
||||
bool found_route = (raw_route.lengthOfShortestPath != INT_MAX) &&
|
||||
(raw_route.unpacked_path_segments[0].size());
|
||||
if( found_route ) {
|
||||
FixedPointCoordinate::convertInternalLatLonToString(
|
||||
phantom_node_list.source_phantom.location.lat,
|
||||
tmp
|
||||
);
|
||||
reply.content.push_back("<rtept lat=\"" + tmp + "\" ");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(
|
||||
phantom_node_list.source_phantom.location.lon,
|
||||
tmp
|
||||
);
|
||||
reply.content.push_back("lon=\"" + tmp + "\"></rtept>");
|
||||
|
||||
for(unsigned i=0; i < raw_route.unpacked_path_segments.size(); ++i){
|
||||
BOOST_FOREACH(
|
||||
const PathData & pathData,
|
||||
raw_route.unpacked_path_segments[i]
|
||||
) {
|
||||
current = facade->GetCoordinateOfNode(pathData.node);
|
||||
|
||||
FixedPointCoordinate::convertInternalLatLonToString(current.lat, tmp);
|
||||
reply.content.push_back("<rtept lat=\"" + tmp + "\" ");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(current.lon, tmp);
|
||||
reply.content.push_back("lon=\"" + tmp + "\"></rtept>");
|
||||
}
|
||||
}
|
||||
// Add the via point or the end coordinate
|
||||
FixedPointCoordinate::convertInternalLatLonToString(
|
||||
phantom_node_list.target_phantom.location.lat,
|
||||
tmp
|
||||
);
|
||||
reply.content.push_back("<rtept lat=\"" + tmp + "\" ");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(
|
||||
phantom_node_list.target_phantom.location.lon,
|
||||
tmp
|
||||
);
|
||||
reply.content.push_back("lon=\"" + tmp + "\"></rtept>");
|
||||
}
|
||||
reply.content.push_back("</rte></gpx>");
|
||||
}
|
||||
};
|
||||
#endif // GPX_DESCRIPTOR_H_
|
||||
@@ -1,542 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef JSON_DESCRIPTOR_H_
|
||||
#define JSON_DESCRIPTOR_H_
|
||||
|
||||
#include "BaseDescriptor.h"
|
||||
#include "DescriptionFactory.h"
|
||||
#include "../Algorithms/ObjectToBase64.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../Util/Azimuth.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
template<class DataFacadeT>
|
||||
class JSONDescriptor : public BaseDescriptor<DataFacadeT> {
|
||||
private:
|
||||
// TODO: initalize in c'tor
|
||||
DataFacadeT * facade;
|
||||
DescriptorConfig config;
|
||||
DescriptionFactory description_factory;
|
||||
DescriptionFactory alternate_descriptionFactory;
|
||||
FixedPointCoordinate current;
|
||||
unsigned entered_restricted_area_count;
|
||||
struct RoundAbout{
|
||||
RoundAbout() :
|
||||
start_index(INT_MAX),
|
||||
name_id(INT_MAX),
|
||||
leave_at_exit(INT_MAX)
|
||||
{}
|
||||
int start_index;
|
||||
int name_id;
|
||||
int leave_at_exit;
|
||||
} round_about;
|
||||
|
||||
struct Segment {
|
||||
Segment() : name_id(-1), length(-1), position(-1) {}
|
||||
Segment(int n, int l, int p) : name_id(n), length(l), position(p) {}
|
||||
int name_id;
|
||||
int length;
|
||||
int position;
|
||||
};
|
||||
std::vector<Segment> shortest_path_segments, alternative_path_segments;
|
||||
std::vector<unsigned> shortest_leg_end_indices, alternative_leg_end_indices;
|
||||
|
||||
struct RouteNames {
|
||||
std::string shortestPathName1;
|
||||
std::string shortestPathName2;
|
||||
std::string alternativePathName1;
|
||||
std::string alternativePathName2;
|
||||
};
|
||||
|
||||
public:
|
||||
JSONDescriptor() :
|
||||
facade(NULL),
|
||||
entered_restricted_area_count(0)
|
||||
{
|
||||
shortest_leg_end_indices.push_back(0);
|
||||
alternative_leg_end_indices.push_back(0);
|
||||
}
|
||||
|
||||
void SetConfig(const DescriptorConfig & c) { config = c; }
|
||||
|
||||
int DescribeLeg(
|
||||
const std::vector<PathData> route_leg,
|
||||
const PhantomNodes & leg_phantoms
|
||||
) {
|
||||
int added_element_count = 0;
|
||||
//Get all the coordinates for the computed route
|
||||
FixedPointCoordinate current_coordinate;
|
||||
BOOST_FOREACH(const PathData & path_data, route_leg) {
|
||||
current_coordinate = facade->GetCoordinateOfNode(path_data.node);
|
||||
description_factory.AppendSegment(current_coordinate, path_data);
|
||||
++added_element_count;
|
||||
}
|
||||
// description_factory.SetEndSegment( leg_phantoms.target_phantom );
|
||||
++added_element_count;
|
||||
BOOST_ASSERT( (int)(route_leg.size() + 1) == added_element_count );
|
||||
return added_element_count;
|
||||
}
|
||||
|
||||
void Run(
|
||||
const RawRouteData & raw_route,
|
||||
const PhantomNodes & phantom_nodes,
|
||||
// TODO: move facade initalization to c'tor
|
||||
DataFacadeT * f,
|
||||
http::Reply & reply
|
||||
) {
|
||||
facade = f;
|
||||
reply.content.push_back(
|
||||
"{\"status\":"
|
||||
);
|
||||
|
||||
if (INVALID_EDGE_WEIGHT == raw_route.lengthOfShortestPath)
|
||||
{
|
||||
//We do not need to do much, if there is no route ;-)
|
||||
reply.content.push_back(
|
||||
"207,\"status_message\": \"Cannot find route between points\"}"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
SimpleLogger().Write(logDEBUG) << "distance: " << raw_route.lengthOfShortestPath;
|
||||
|
||||
//check if first segment is non-zero
|
||||
std::string road_name;
|
||||
road_name = facade->GetEscapedNameForNameID(phantom_nodes.source_phantom.name_id);
|
||||
|
||||
// for each unpacked segment add the leg to the description
|
||||
BOOST_ASSERT( raw_route.unpacked_path_segments.size() == raw_route.segmentEndCoordinates.size() );
|
||||
|
||||
for (unsigned i = 0; i < raw_route.unpacked_path_segments.size(); ++i)
|
||||
{
|
||||
const std::vector<PathData> & leg_path = raw_route.unpacked_path_segments[i];
|
||||
FixedPointCoordinate current_coordinate;
|
||||
BOOST_FOREACH(const PathData & path_data, leg_path)
|
||||
{
|
||||
current_coordinate = facade->GetCoordinateOfNode(path_data.node);
|
||||
road_name = facade->GetEscapedNameForNameID(path_data.name_id);
|
||||
}
|
||||
}
|
||||
|
||||
//check if last segment is non-zero
|
||||
road_name = facade->GetEscapedNameForNameID(phantom_nodes.target_phantom.name_id);
|
||||
|
||||
description_factory.SetStartSegment(phantom_nodes.source_phantom, raw_route.source_traversed_in_reverse);
|
||||
reply.content.push_back("0,"
|
||||
"\"status_message\": \"Found route between points\",");
|
||||
|
||||
BOOST_ASSERT( raw_route.unpacked_path_segments.size() == raw_route.segmentEndCoordinates.size() );
|
||||
for (unsigned i = 0; i < raw_route.unpacked_path_segments.size(); ++i)
|
||||
{
|
||||
const int added_segments = DescribeLeg(
|
||||
raw_route.unpacked_path_segments[i],
|
||||
raw_route.segmentEndCoordinates[i]
|
||||
);
|
||||
BOOST_ASSERT( 0 < added_segments );
|
||||
shortest_leg_end_indices.push_back(
|
||||
added_segments + shortest_leg_end_indices.back()
|
||||
);
|
||||
}
|
||||
description_factory.SetEndSegment(phantom_nodes.target_phantom, raw_route.target_traversed_in_reverse);
|
||||
description_factory.Run(facade, config.zoom_level);
|
||||
|
||||
reply.content.push_back("\"route_geometry\": ");
|
||||
if(config.geometry) {
|
||||
description_factory.AppendEncodedPolylineString(
|
||||
config.encode_geometry,
|
||||
reply.content
|
||||
);
|
||||
} else {
|
||||
reply.content.push_back("[]");
|
||||
}
|
||||
|
||||
reply.content.push_back(",\"route_instructions\": [");
|
||||
if(config.instructions) {
|
||||
BuildTextualDescription(
|
||||
description_factory,
|
||||
reply,
|
||||
raw_route.lengthOfShortestPath,
|
||||
facade,
|
||||
shortest_path_segments
|
||||
);
|
||||
}
|
||||
reply.content.push_back("],");
|
||||
description_factory.BuildRouteSummary(
|
||||
description_factory.entireLength,
|
||||
raw_route.lengthOfShortestPath
|
||||
);
|
||||
|
||||
reply.content.push_back("\"route_summary\":");
|
||||
reply.content.push_back("{");
|
||||
reply.content.push_back("\"total_distance\":");
|
||||
reply.content.push_back(description_factory.summary.lengthString);
|
||||
reply.content.push_back(","
|
||||
"\"total_time\":");
|
||||
reply.content.push_back(description_factory.summary.durationString);
|
||||
reply.content.push_back(","
|
||||
"\"start_point\":\"");
|
||||
reply.content.push_back(
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.startName)
|
||||
);
|
||||
reply.content.push_back("\","
|
||||
"\"end_point\":\"");
|
||||
reply.content.push_back(
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.destName)
|
||||
);
|
||||
reply.content.push_back("\"");
|
||||
reply.content.push_back("}");
|
||||
reply.content.push_back(",");
|
||||
|
||||
//only one alternative route is computed at this time, so this is hardcoded
|
||||
|
||||
if(raw_route.lengthOfAlternativePath != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
alternate_descriptionFactory.SetStartSegment(phantom_nodes.source_phantom, raw_route.alt_source_traversed_in_reverse);
|
||||
//Get all the coordinates for the computed route
|
||||
BOOST_FOREACH(const PathData & path_data, raw_route.unpacked_alternative) {
|
||||
current = facade->GetCoordinateOfNode(path_data.node);
|
||||
alternate_descriptionFactory.AppendSegment(current, path_data );
|
||||
}
|
||||
alternate_descriptionFactory.SetEndSegment(phantom_nodes.target_phantom, raw_route.alt_target_traversed_in_reverse);
|
||||
}
|
||||
alternate_descriptionFactory.Run(facade, config.zoom_level);
|
||||
|
||||
// //give an array of alternative routes
|
||||
reply.content.push_back("\"alternative_geometries\": [");
|
||||
if(config.geometry && INT_MAX != raw_route.lengthOfAlternativePath) {
|
||||
//Generate the linestrings for each alternative
|
||||
alternate_descriptionFactory.AppendEncodedPolylineString(
|
||||
config.encode_geometry,
|
||||
reply.content
|
||||
);
|
||||
}
|
||||
reply.content.push_back("],");
|
||||
reply.content.push_back("\"alternative_instructions\":[");
|
||||
if(INT_MAX != raw_route.lengthOfAlternativePath) {
|
||||
reply.content.push_back("[");
|
||||
//Generate instructions for each alternative
|
||||
if(config.instructions) {
|
||||
BuildTextualDescription(
|
||||
alternate_descriptionFactory,
|
||||
reply,
|
||||
raw_route.lengthOfAlternativePath,
|
||||
facade,
|
||||
alternative_path_segments
|
||||
);
|
||||
}
|
||||
reply.content.push_back("]");
|
||||
}
|
||||
reply.content.push_back("],");
|
||||
reply.content.push_back("\"alternative_summaries\":[");
|
||||
if(INT_MAX != raw_route.lengthOfAlternativePath) {
|
||||
//Generate route summary (length, duration) for each alternative
|
||||
alternate_descriptionFactory.BuildRouteSummary(
|
||||
alternate_descriptionFactory.entireLength,
|
||||
raw_route.lengthOfAlternativePath
|
||||
);
|
||||
reply.content.push_back("{");
|
||||
reply.content.push_back("\"total_distance\":");
|
||||
reply.content.push_back(
|
||||
alternate_descriptionFactory.summary.lengthString
|
||||
);
|
||||
reply.content.push_back(","
|
||||
"\"total_time\":");
|
||||
reply.content.push_back(
|
||||
alternate_descriptionFactory.summary.durationString
|
||||
);
|
||||
reply.content.push_back(","
|
||||
"\"start_point\":\"");
|
||||
reply.content.push_back(
|
||||
facade->GetEscapedNameForNameID(
|
||||
description_factory.summary.startName
|
||||
)
|
||||
);
|
||||
reply.content.push_back("\","
|
||||
"\"end_point\":\"");
|
||||
reply.content.push_back(facade->GetEscapedNameForNameID(description_factory.summary.destName));
|
||||
reply.content.push_back("\"");
|
||||
reply.content.push_back("}");
|
||||
}
|
||||
reply.content.push_back("],");
|
||||
|
||||
// //Get Names for both routes
|
||||
RouteNames routeNames;
|
||||
GetRouteNames(shortest_path_segments, alternative_path_segments, facade, routeNames);
|
||||
|
||||
reply.content.push_back("\"route_name\":[\"");
|
||||
reply.content.push_back(routeNames.shortestPathName1);
|
||||
reply.content.push_back("\",\"");
|
||||
reply.content.push_back(routeNames.shortestPathName2);
|
||||
reply.content.push_back("\"],"
|
||||
"\"alternative_names\":[");
|
||||
reply.content.push_back("[\"");
|
||||
reply.content.push_back(routeNames.alternativePathName1);
|
||||
reply.content.push_back("\",\"");
|
||||
reply.content.push_back(routeNames.alternativePathName2);
|
||||
reply.content.push_back("\"]");
|
||||
reply.content.push_back("],");
|
||||
//list all viapoints so that the client may display it
|
||||
reply.content.push_back("\"via_points\":[");
|
||||
|
||||
BOOST_ASSERT( !raw_route.segmentEndCoordinates.empty() );
|
||||
|
||||
std::string tmp;
|
||||
FixedPointCoordinate::convertInternalReversedCoordinateToString(
|
||||
raw_route.segmentEndCoordinates.front().source_phantom.location,
|
||||
tmp
|
||||
);
|
||||
reply.content.push_back("[");
|
||||
reply.content.push_back(tmp);
|
||||
reply.content.push_back("]");
|
||||
|
||||
BOOST_FOREACH(const PhantomNodes & nodes, raw_route.segmentEndCoordinates) {
|
||||
tmp.clear();
|
||||
FixedPointCoordinate::convertInternalReversedCoordinateToString(
|
||||
nodes.target_phantom.location,
|
||||
tmp
|
||||
);
|
||||
reply.content.push_back(",[");
|
||||
reply.content.push_back(tmp);
|
||||
reply.content.push_back("]");
|
||||
}
|
||||
|
||||
reply.content.push_back("],");
|
||||
reply.content.push_back("\"via_indices\":[");
|
||||
BOOST_FOREACH(const unsigned index, shortest_leg_end_indices) {
|
||||
tmp.clear();
|
||||
intToString(index, tmp);
|
||||
reply.content.push_back(tmp);
|
||||
if( index != shortest_leg_end_indices.back() ) {
|
||||
reply.content.push_back(",");
|
||||
}
|
||||
}
|
||||
reply.content.push_back("],\"alternative_indices\":[");
|
||||
if(INT_MAX != raw_route.lengthOfAlternativePath) {
|
||||
reply.content.push_back("0,");
|
||||
tmp.clear();
|
||||
intToString(alternate_descriptionFactory.pathDescription.size(), tmp);
|
||||
reply.content.push_back(tmp);
|
||||
}
|
||||
|
||||
reply.content.push_back("],");
|
||||
reply.content.push_back("\"hint_data\": {");
|
||||
reply.content.push_back("\"checksum\":");
|
||||
intToString(raw_route.checkSum, tmp);
|
||||
reply.content.push_back(tmp);
|
||||
reply.content.push_back(", \"locations\": [");
|
||||
|
||||
std::string hint;
|
||||
for(unsigned i = 0; i < raw_route.segmentEndCoordinates.size(); ++i) {
|
||||
reply.content.push_back("\"");
|
||||
EncodeObjectToBase64(raw_route.segmentEndCoordinates[i].source_phantom, hint);
|
||||
reply.content.push_back(hint);
|
||||
reply.content.push_back("\", ");
|
||||
}
|
||||
EncodeObjectToBase64(raw_route.segmentEndCoordinates.back().target_phantom, hint);
|
||||
reply.content.push_back("\"");
|
||||
reply.content.push_back(hint);
|
||||
reply.content.push_back("\"]");
|
||||
reply.content.push_back("}}");
|
||||
}
|
||||
|
||||
// construct routes names
|
||||
void GetRouteNames(
|
||||
std::vector<Segment> & shortest_path_segments,
|
||||
std::vector<Segment> & alternative_path_segments,
|
||||
const DataFacadeT * facade,
|
||||
RouteNames & routeNames
|
||||
) {
|
||||
|
||||
Segment shortestSegment1, shortestSegment2;
|
||||
Segment alternativeSegment1, alternativeSegment2;
|
||||
|
||||
if(0 < shortest_path_segments.size()) {
|
||||
sort(shortest_path_segments.begin(), shortest_path_segments.end(), boost::bind(&Segment::length, _1) > boost::bind(&Segment::length, _2) );
|
||||
shortestSegment1 = shortest_path_segments[0];
|
||||
if(0 < alternative_path_segments.size()) {
|
||||
sort(alternative_path_segments.begin(), alternative_path_segments.end(), boost::bind(&Segment::length, _1) > boost::bind(&Segment::length, _2) );
|
||||
alternativeSegment1 = alternative_path_segments[0];
|
||||
}
|
||||
std::vector<Segment> shortestDifference(shortest_path_segments.size());
|
||||
std::vector<Segment> alternativeDifference(alternative_path_segments.size());
|
||||
std::set_difference(shortest_path_segments.begin(), shortest_path_segments.end(), alternative_path_segments.begin(), alternative_path_segments.end(), shortestDifference.begin(), boost::bind(&Segment::name_id, _1) < boost::bind(&Segment::name_id, _2) );
|
||||
int size_of_difference = shortestDifference.size();
|
||||
if(0 < size_of_difference ) {
|
||||
int i = 0;
|
||||
while( i < size_of_difference && shortestDifference[i].name_id == shortest_path_segments[0].name_id) {
|
||||
++i;
|
||||
}
|
||||
if(i < size_of_difference ) {
|
||||
shortestSegment2 = shortestDifference[i];
|
||||
}
|
||||
}
|
||||
|
||||
std::set_difference(alternative_path_segments.begin(), alternative_path_segments.end(), shortest_path_segments.begin(), shortest_path_segments.end(), alternativeDifference.begin(), boost::bind(&Segment::name_id, _1) < boost::bind(&Segment::name_id, _2) );
|
||||
size_of_difference = alternativeDifference.size();
|
||||
if(0 < size_of_difference ) {
|
||||
int i = 0;
|
||||
while( i < size_of_difference && alternativeDifference[i].name_id == alternative_path_segments[0].name_id) {
|
||||
++i;
|
||||
}
|
||||
if(i < size_of_difference ) {
|
||||
alternativeSegment2 = alternativeDifference[i];
|
||||
}
|
||||
}
|
||||
if(shortestSegment1.position > shortestSegment2.position)
|
||||
std::swap(shortestSegment1, shortestSegment2);
|
||||
|
||||
if(alternativeSegment1.position > alternativeSegment2.position)
|
||||
std::swap(alternativeSegment1, alternativeSegment2);
|
||||
|
||||
routeNames.shortestPathName1 = facade->GetEscapedNameForNameID(
|
||||
shortestSegment1.name_id
|
||||
);
|
||||
routeNames.shortestPathName2 = facade->GetEscapedNameForNameID(
|
||||
shortestSegment2.name_id
|
||||
);
|
||||
|
||||
routeNames.alternativePathName1 = facade->GetEscapedNameForNameID(
|
||||
alternativeSegment1.name_id
|
||||
);
|
||||
routeNames.alternativePathName2 = facade->GetEscapedNameForNameID(
|
||||
alternativeSegment2.name_id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: reorder parameters
|
||||
inline void BuildTextualDescription(
|
||||
DescriptionFactory & description_factory,
|
||||
http::Reply & reply,
|
||||
const int route_length,
|
||||
const DataFacadeT * facade,
|
||||
std::vector<Segment> & route_segments_list
|
||||
) {
|
||||
//Segment information has following format:
|
||||
//["instruction","streetname",length,position,time,"length","earth_direction",azimuth]
|
||||
//Example: ["Turn left","High Street",200,4,10,"200m","NE",22.5]
|
||||
unsigned necessary_segments_running_index = 0;
|
||||
round_about.leave_at_exit = 0;
|
||||
round_about.name_id = 0;
|
||||
std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction;
|
||||
|
||||
//Fetch data from Factory and generate a string from it.
|
||||
BOOST_FOREACH(const SegmentInformation & segment, description_factory.pathDescription) {
|
||||
TurnInstruction current_instruction = segment.turn_instruction & TurnInstructionsClass::InverseAccessRestrictionFlag;
|
||||
entered_restricted_area_count += (current_instruction != segment.turn_instruction);
|
||||
if (TurnInstructionsClass::TurnIsNecessary( current_instruction) )
|
||||
{
|
||||
if (TurnInstructionsClass::EnterRoundAbout == current_instruction)
|
||||
{
|
||||
round_about.name_id = segment.name_id;
|
||||
round_about.start_index = necessary_segments_running_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (0 != necessary_segments_running_index)
|
||||
{
|
||||
reply.content.push_back(",");
|
||||
}
|
||||
reply.content.push_back("[\"");
|
||||
if(TurnInstructionsClass::LeaveRoundAbout == current_instruction) {
|
||||
intToString(TurnInstructionsClass::EnterRoundAbout, temp_instruction);
|
||||
reply.content.push_back(temp_instruction);
|
||||
reply.content.push_back("-");
|
||||
intToString(round_about.leave_at_exit+1, temp_instruction);
|
||||
reply.content.push_back(temp_instruction);
|
||||
round_about.leave_at_exit = 0;
|
||||
} else {
|
||||
intToString(current_instruction, temp_instruction);
|
||||
reply.content.push_back(temp_instruction);
|
||||
}
|
||||
|
||||
reply.content.push_back("\",\"");
|
||||
reply.content.push_back(facade->GetEscapedNameForNameID(segment.name_id));
|
||||
reply.content.push_back("\",");
|
||||
intToString(segment.length, temp_dist);
|
||||
reply.content.push_back(temp_dist);
|
||||
reply.content.push_back(",");
|
||||
intToString(necessary_segments_running_index, temp_length);
|
||||
reply.content.push_back(temp_length);
|
||||
reply.content.push_back(",");
|
||||
intToString(round(segment.duration/10.), temp_duration);
|
||||
reply.content.push_back(temp_duration);
|
||||
reply.content.push_back(",\"");
|
||||
intToString(segment.length, temp_length);
|
||||
reply.content.push_back(temp_length);
|
||||
reply.content.push_back("m\",\"");
|
||||
double bearing_value = round(segment.bearing/10.);
|
||||
reply.content.push_back(Azimuth::Get(bearing_value));
|
||||
reply.content.push_back("\",");
|
||||
intToString(bearing_value, temp_bearing);
|
||||
reply.content.push_back(temp_bearing);
|
||||
reply.content.push_back("]");
|
||||
|
||||
route_segments_list.push_back(
|
||||
Segment(
|
||||
segment.name_id,
|
||||
segment.length,
|
||||
route_segments_list.size()
|
||||
)
|
||||
);
|
||||
}
|
||||
} else if(TurnInstructionsClass::StayOnRoundAbout == current_instruction) {
|
||||
++round_about.leave_at_exit;
|
||||
}
|
||||
if(segment.necessary)
|
||||
++necessary_segments_running_index;
|
||||
}
|
||||
if(INT_MAX != route_length) {
|
||||
reply.content.push_back(",[\"");
|
||||
intToString(TurnInstructionsClass::ReachedYourDestination, temp_instruction);
|
||||
reply.content.push_back(temp_instruction);
|
||||
reply.content.push_back("\",\"");
|
||||
reply.content.push_back("\",");
|
||||
reply.content.push_back("0");
|
||||
reply.content.push_back(",");
|
||||
intToString(necessary_segments_running_index-1, temp_length);
|
||||
reply.content.push_back(temp_length);
|
||||
reply.content.push_back(",");
|
||||
reply.content.push_back("0");
|
||||
reply.content.push_back(",\"");
|
||||
reply.content.push_back("\",\"");
|
||||
reply.content.push_back(Azimuth::Get(0.0));
|
||||
reply.content.push_back("\",");
|
||||
reply.content.push_back("0.0");
|
||||
reply.content.push_back("]");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* JSON_DESCRIPTOR_H_ */
|
||||
@@ -1,3 +0,0 @@
|
||||
The javascript based web client is a seperate project available at
|
||||
|
||||
https://github.com/DennisSchiefer/Project-OSRM-Web
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
PROJECT_NAME = "Project OSRM"
|
||||
PROJECT_BRIEF = "Open Source Routing Machine"
|
||||
BUILTIN_STL_SUPPORT = YES
|
||||
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = YES
|
||||
EXTRACT_PACKAGE = YES
|
||||
EXTRACT_STATIC = YES
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_ANON_NSPACES = YES
|
||||
|
||||
QUIET = YES
|
||||
|
||||
INPUT = @CMAKE_CURRENT_SOURCE_DIR@
|
||||
USE_MDFILE_AS_MAINPAGE = @CMAKE_CURRENT_SOURCE_DIR@/README.md
|
||||
FILE_PATTERNS = *.h *.hpp *.c *.cc *.cpp *.md
|
||||
RECURSIVE = YES
|
||||
|
||||
EXCLUDE = @CMAKE_CURRENT_SOURCE_DIR@/third_party \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/build \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/node_modules \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/unit_tests \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/benchmarks \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/features
|
||||
|
||||
SOURCE_BROWSER = YES
|
||||
|
||||
CLANG_ASSISTED_PARSING = NO
|
||||
|
||||
HTML_COLORSTYLE_HUE = 217
|
||||
HTML_COLORSTYLE_SAT = 71
|
||||
HTML_COLORSTYLE_GAMMA = 50
|
||||
|
||||
GENERATE_TREEVIEW = YES
|
||||
|
||||
HAVE_DOT = @DOXYGEN_DOT_FOUND@
|
||||
CALL_GRAPH = YES
|
||||
CALLER_GRAPH = YES
|
||||
|
||||
DOT_IMAGE_FORMAT = svg
|
||||
INTERACTIVE_SVG = YES
|
||||
DOT_GRAPH_MAX_NODES = 500
|
||||
DOT_TRANSPARENT = YES
|
||||
DOT_MULTI_TARGETS = YES
|
||||
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "BaseParser.h"
|
||||
#include "ExtractionWay.h"
|
||||
#include "ScriptingEnvironment.h"
|
||||
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
#include "../Util/LuaUtil.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/regex.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
BaseParser::BaseParser(
|
||||
ExtractorCallbacks * extractor_callbacks,
|
||||
ScriptingEnvironment & scripting_environment
|
||||
) : extractor_callbacks(extractor_callbacks),
|
||||
lua_state(scripting_environment.getLuaStateForThreadID(0)),
|
||||
scripting_environment(scripting_environment),
|
||||
use_turn_restrictions(true)
|
||||
{
|
||||
ReadUseRestrictionsSetting();
|
||||
ReadRestrictionExceptions();
|
||||
}
|
||||
|
||||
void BaseParser::ReadUseRestrictionsSetting() {
|
||||
if( 0 != luaL_dostring( lua_state, "return use_turn_restrictions\n") ) {
|
||||
throw OSRMException("ERROR occured in scripting block");
|
||||
}
|
||||
if( lua_isboolean( lua_state, -1) ) {
|
||||
use_turn_restrictions = lua_toboolean(lua_state, -1);
|
||||
}
|
||||
if( use_turn_restrictions ) {
|
||||
SimpleLogger().Write() << "Using turn restrictions";
|
||||
} else {
|
||||
SimpleLogger().Write() << "Ignoring turn restrictions";
|
||||
}
|
||||
}
|
||||
|
||||
void BaseParser::ReadRestrictionExceptions() {
|
||||
if(lua_function_exists(lua_state, "get_exceptions" )) {
|
||||
//get list of turn restriction exceptions
|
||||
luabind::call_function<void>(
|
||||
lua_state,
|
||||
"get_exceptions",
|
||||
boost::ref(restriction_exceptions)
|
||||
);
|
||||
const unsigned exception_count = restriction_exceptions.size();
|
||||
SimpleLogger().Write() <<
|
||||
"Found " << exception_count << " exceptions to turn restrictions:";
|
||||
BOOST_FOREACH(const std::string & str, restriction_exceptions) {
|
||||
SimpleLogger().Write() << " " << str;
|
||||
}
|
||||
} else {
|
||||
SimpleLogger().Write() << "Found no exceptions to turn restrictions";
|
||||
}
|
||||
}
|
||||
|
||||
void BaseParser::report_errors(lua_State *L, const int status) const {
|
||||
if( 0!=status ) {
|
||||
std::cerr << "-- " << lua_tostring(L, -1) << std::endl;
|
||||
lua_pop(L, 1); // remove error message
|
||||
}
|
||||
}
|
||||
|
||||
void BaseParser::ParseNodeInLua(ImportNode& n, lua_State* local_lua_state) {
|
||||
luabind::call_function<void>(
|
||||
local_lua_state,
|
||||
"node_function",
|
||||
boost::ref(n)
|
||||
);
|
||||
}
|
||||
|
||||
void BaseParser::ParseWayInLua(ExtractionWay& w, lua_State* local_lua_state) {
|
||||
luabind::call_function<void>(
|
||||
local_lua_state,
|
||||
"way_function",
|
||||
boost::ref(w)
|
||||
);
|
||||
}
|
||||
|
||||
bool BaseParser::ShouldIgnoreRestriction(
|
||||
const std::string & except_tag_string
|
||||
) const {
|
||||
//should this restriction be ignored? yes if there's an overlap between:
|
||||
// a) the list of modes in the except tag of the restriction
|
||||
// (except_tag_string), eg: except=bus;bicycle
|
||||
// b) the lua profile defines a hierachy of modes,
|
||||
// eg: [access, vehicle, bicycle]
|
||||
|
||||
if( except_tag_string.empty() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Be warned, this is quadratic work here, but we assume that
|
||||
//only a few exceptions are actually defined.
|
||||
std::vector<std::string> exceptions;
|
||||
boost::algorithm::split_regex(exceptions, except_tag_string, boost::regex("[;][ ]*"));
|
||||
BOOST_FOREACH(std::string& current_string, exceptions) {
|
||||
std::vector<std::string>::const_iterator string_iterator;
|
||||
string_iterator = std::find(
|
||||
restriction_exceptions.begin(),
|
||||
restriction_exceptions.end(),
|
||||
current_string
|
||||
);
|
||||
if( restriction_exceptions.end() != string_iterator ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BASEPARSER_H_
|
||||
#define BASEPARSER_H_
|
||||
|
||||
extern "C" {
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
}
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class ExtractorCallbacks;
|
||||
class ScriptingEnvironment;
|
||||
struct ExtractionWay;
|
||||
struct ImportNode;
|
||||
|
||||
class BaseParser : boost::noncopyable {
|
||||
public:
|
||||
BaseParser(
|
||||
ExtractorCallbacks * extractor_callbacks,
|
||||
ScriptingEnvironment & scripting_environment
|
||||
);
|
||||
virtual ~BaseParser() {}
|
||||
virtual bool ReadHeader() = 0;
|
||||
virtual bool Parse() = 0;
|
||||
|
||||
virtual void ParseNodeInLua(ImportNode & n, lua_State* thread_lua_state);
|
||||
virtual void ParseWayInLua(ExtractionWay & n, lua_State* thread_lua_state);
|
||||
virtual void report_errors(lua_State * lua_state, const int status) const;
|
||||
|
||||
protected:
|
||||
virtual void ReadUseRestrictionsSetting();
|
||||
virtual void ReadRestrictionExceptions();
|
||||
virtual bool ShouldIgnoreRestriction(
|
||||
const std::string & except_tag_string
|
||||
) const;
|
||||
|
||||
ExtractorCallbacks * extractor_callbacks;
|
||||
lua_State * lua_state;
|
||||
ScriptingEnvironment & scripting_environment;
|
||||
std::vector<std::string> restriction_exceptions;
|
||||
bool use_turn_restrictions;
|
||||
};
|
||||
|
||||
#endif /* BASEPARSER_H_ */
|
||||
@@ -1,463 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "ExtractionContainers.h"
|
||||
#include "ExtractionWay.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
#include <stxxl/sort>
|
||||
|
||||
ExtractionContainers::ExtractionContainers() {
|
||||
//Check if stxxl can be instantiated
|
||||
stxxl::vector<unsigned> dummy_vector;
|
||||
name_list.push_back("");
|
||||
}
|
||||
|
||||
ExtractionContainers::~ExtractionContainers() {
|
||||
used_node_id_list.clear();
|
||||
all_nodes_list.clear();
|
||||
all_edges_list.clear();
|
||||
name_list.clear();
|
||||
restrictions_list.clear();
|
||||
way_start_end_id_list.clear();
|
||||
}
|
||||
|
||||
void ExtractionContainers::PrepareData(
|
||||
const std::string & output_file_name,
|
||||
const std::string & restrictions_file_name
|
||||
) {
|
||||
try {
|
||||
unsigned number_of_used_nodes = 0;
|
||||
unsigned number_of_used_edges = 0;
|
||||
double time = get_timestamp();
|
||||
|
||||
std::cout << "[extractor] Sorting used nodes ... " << std::flush;
|
||||
stxxl::sort(
|
||||
used_node_id_list.begin(),
|
||||
used_node_id_list.end(),
|
||||
Cmp(),
|
||||
4294967296
|
||||
);
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
|
||||
time = get_timestamp();
|
||||
std::cout << "[extractor] Erasing duplicate nodes ... " << std::flush;
|
||||
stxxl::vector<NodeID>::iterator NewEnd = std::unique ( used_node_id_list.begin(),used_node_id_list.end() ) ;
|
||||
used_node_id_list.resize ( NewEnd - used_node_id_list.begin() );
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
time = get_timestamp();
|
||||
|
||||
std::cout << "[extractor] Sorting all nodes ... " << std::flush;
|
||||
stxxl::sort(
|
||||
all_nodes_list.begin(),
|
||||
all_nodes_list.end(),
|
||||
CmpNodeByID(),
|
||||
4294967296
|
||||
);
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
time = get_timestamp();
|
||||
|
||||
std::cout << "[extractor] Sorting used ways ... " << std::flush;
|
||||
stxxl::sort(
|
||||
way_start_end_id_list.begin(),
|
||||
way_start_end_id_list.end(),
|
||||
CmpWayByID(),
|
||||
4294967296
|
||||
);
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] Sorting restrctns. by from... " << std::flush;
|
||||
stxxl::sort(
|
||||
restrictions_list.begin(),
|
||||
restrictions_list.end(),
|
||||
CmpRestrictionContainerByFrom(),
|
||||
4294967296
|
||||
);
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] Fixing restriction starts ... " << std::flush;
|
||||
STXXLRestrictionsVector::iterator restrictions_iterator = restrictions_list.begin();
|
||||
STXXLWayIDStartEndVector::iterator way_start_and_end_iterator = way_start_end_id_list.begin();
|
||||
|
||||
while(
|
||||
way_start_and_end_iterator != way_start_end_id_list.end() &&
|
||||
restrictions_iterator != restrictions_list.end()
|
||||
) {
|
||||
|
||||
if(way_start_and_end_iterator->wayID < restrictions_iterator->fromWay){
|
||||
++way_start_and_end_iterator;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(way_start_and_end_iterator->wayID > restrictions_iterator->fromWay) {
|
||||
++restrictions_iterator;
|
||||
continue;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(way_start_and_end_iterator->wayID == restrictions_iterator->fromWay);
|
||||
NodeID via_node_id = restrictions_iterator->restriction.viaNode;
|
||||
|
||||
if(way_start_and_end_iterator->firstStart == via_node_id) {
|
||||
restrictions_iterator->restriction.fromNode = way_start_and_end_iterator->firstTarget;
|
||||
} else if(way_start_and_end_iterator->firstTarget == via_node_id) {
|
||||
restrictions_iterator->restriction.fromNode = way_start_and_end_iterator->firstStart;
|
||||
} else if(way_start_and_end_iterator->lastStart == via_node_id) {
|
||||
restrictions_iterator->restriction.fromNode = way_start_and_end_iterator->lastTarget;
|
||||
} else if(way_start_and_end_iterator->lastTarget == via_node_id) {
|
||||
restrictions_iterator->restriction.fromNode = way_start_and_end_iterator->lastStart;
|
||||
}
|
||||
++restrictions_iterator;
|
||||
}
|
||||
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
time = get_timestamp();
|
||||
|
||||
std::cout << "[extractor] Sorting restrctns. by to ... " << std::flush;
|
||||
stxxl::sort(
|
||||
restrictions_list.begin(),
|
||||
restrictions_list.end(),
|
||||
CmpRestrictionContainerByTo(),
|
||||
4294967296
|
||||
);
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
|
||||
time = get_timestamp();
|
||||
unsigned usableRestrictionsCounter(0);
|
||||
std::cout << "[extractor] Fixing restriction ends ... " << std::flush;
|
||||
restrictions_iterator = restrictions_list.begin();
|
||||
way_start_and_end_iterator = way_start_end_id_list.begin();
|
||||
while(
|
||||
way_start_and_end_iterator != way_start_end_id_list.end() &&
|
||||
restrictions_iterator != restrictions_list.end()
|
||||
) {
|
||||
if(way_start_and_end_iterator->wayID < restrictions_iterator->toWay){
|
||||
++way_start_and_end_iterator;
|
||||
continue;
|
||||
}
|
||||
if(way_start_and_end_iterator->wayID > restrictions_iterator->toWay) {
|
||||
++restrictions_iterator;
|
||||
continue;
|
||||
}
|
||||
NodeID via_node_id = restrictions_iterator->restriction.viaNode;
|
||||
if(way_start_and_end_iterator->lastStart == via_node_id) {
|
||||
restrictions_iterator->restriction.toNode = way_start_and_end_iterator->lastTarget;
|
||||
} else if(way_start_and_end_iterator->lastTarget == via_node_id) {
|
||||
restrictions_iterator->restriction.toNode = way_start_and_end_iterator->lastStart;
|
||||
} else if(way_start_and_end_iterator->firstStart == via_node_id) {
|
||||
restrictions_iterator->restriction.toNode = way_start_and_end_iterator->firstTarget;
|
||||
} else if(way_start_and_end_iterator->firstTarget == via_node_id) {
|
||||
restrictions_iterator->restriction.toNode = way_start_and_end_iterator->firstStart;
|
||||
}
|
||||
|
||||
if(
|
||||
UINT_MAX != restrictions_iterator->restriction.fromNode &&
|
||||
UINT_MAX != restrictions_iterator->restriction.toNode
|
||||
) {
|
||||
++usableRestrictionsCounter;
|
||||
}
|
||||
++restrictions_iterator;
|
||||
}
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
SimpleLogger().Write() << "usable restrictions: " << usableRestrictionsCounter;
|
||||
//serialize restrictions
|
||||
std::ofstream restrictions_out_stream;
|
||||
restrictions_out_stream.open(restrictions_file_name.c_str(), std::ios::binary);
|
||||
restrictions_out_stream.write((char*)&uuid, sizeof(UUID));
|
||||
restrictions_out_stream.write(
|
||||
(char*)&usableRestrictionsCounter,
|
||||
sizeof(unsigned)
|
||||
);
|
||||
for(
|
||||
restrictions_iterator = restrictions_list.begin();
|
||||
restrictions_iterator != restrictions_list.end();
|
||||
++restrictions_iterator
|
||||
) {
|
||||
if(
|
||||
UINT_MAX != restrictions_iterator->restriction.fromNode &&
|
||||
UINT_MAX != restrictions_iterator->restriction.toNode
|
||||
) {
|
||||
restrictions_out_stream.write(
|
||||
(char *)&(restrictions_iterator->restriction),
|
||||
sizeof(TurnRestriction)
|
||||
);
|
||||
}
|
||||
}
|
||||
restrictions_out_stream.close();
|
||||
|
||||
std::ofstream file_out_stream;
|
||||
file_out_stream.open(output_file_name.c_str(), std::ios::binary);
|
||||
file_out_stream.write((char*)&uuid, sizeof(UUID));
|
||||
file_out_stream.write((char*)&number_of_used_nodes, sizeof(unsigned));
|
||||
time = get_timestamp();
|
||||
std::cout << "[extractor] Confirming/Writing used nodes ... " << std::flush;
|
||||
|
||||
//identify all used nodes by a merging step of two sorted lists
|
||||
STXXLNodeVector::iterator node_iterator = all_nodes_list.begin();
|
||||
STXXLNodeIDVector::iterator node_id_iterator = used_node_id_list.begin();
|
||||
while(
|
||||
node_id_iterator != used_node_id_list.end() &&
|
||||
node_iterator != all_nodes_list.end()
|
||||
) {
|
||||
if(*node_id_iterator < node_iterator->id){
|
||||
++node_id_iterator;
|
||||
continue;
|
||||
}
|
||||
if(*node_id_iterator > node_iterator->id) {
|
||||
++node_iterator;
|
||||
continue;
|
||||
}
|
||||
BOOST_ASSERT( *node_id_iterator == node_iterator->id);
|
||||
|
||||
file_out_stream.write(
|
||||
(char*)&(*node_iterator),
|
||||
sizeof(ExternalMemoryNode)
|
||||
);
|
||||
|
||||
++number_of_used_nodes;
|
||||
++node_id_iterator;
|
||||
++node_iterator;
|
||||
}
|
||||
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] setting number of nodes ... " << std::flush;
|
||||
std::ios::pos_type previous_file_position = file_out_stream.tellp();
|
||||
file_out_stream.seekp(std::ios::beg+sizeof(UUID));
|
||||
file_out_stream.write((char*)&number_of_used_nodes, sizeof(unsigned));
|
||||
file_out_stream.seekp(previous_file_position);
|
||||
|
||||
std::cout << "ok" << std::endl;
|
||||
time = get_timestamp();
|
||||
|
||||
// Sort edges by start.
|
||||
std::cout << "[extractor] Sorting edges by start ... " << std::flush;
|
||||
stxxl::sort(
|
||||
all_edges_list.begin(),
|
||||
all_edges_list.end(),
|
||||
CmpEdgeByStartID(),
|
||||
4294967296
|
||||
);
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
time = get_timestamp();
|
||||
|
||||
std::cout << "[extractor] Setting start coords ... " << std::flush;
|
||||
file_out_stream.write((char*)&number_of_used_edges, sizeof(unsigned));
|
||||
// Traverse list of edges and nodes in parallel and set start coord
|
||||
node_iterator = all_nodes_list.begin();
|
||||
STXXLEdgeVector::iterator edge_iterator = all_edges_list.begin();
|
||||
while(
|
||||
edge_iterator != all_edges_list.end() &&
|
||||
node_iterator != all_nodes_list.end()
|
||||
) {
|
||||
if(edge_iterator->start < node_iterator->id){
|
||||
++edge_iterator;
|
||||
continue;
|
||||
}
|
||||
if(edge_iterator->start > node_iterator->id) {
|
||||
node_iterator++;
|
||||
continue;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(edge_iterator->start == node_iterator->id);
|
||||
edge_iterator->startCoord.lat = node_iterator->lat;
|
||||
edge_iterator->startCoord.lon = node_iterator->lon;
|
||||
++edge_iterator;
|
||||
}
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
time = get_timestamp();
|
||||
|
||||
// Sort Edges by target
|
||||
std::cout << "[extractor] Sorting edges by target ... " << std::flush;
|
||||
stxxl::sort(
|
||||
all_edges_list.begin(),
|
||||
all_edges_list.end(),
|
||||
CmpEdgeByTargetID(),
|
||||
4294967296
|
||||
);
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
time = get_timestamp();
|
||||
|
||||
std::cout << "[extractor] Setting target coords ... " << std::flush;
|
||||
// Traverse list of edges and nodes in parallel and set target coord
|
||||
node_iterator = all_nodes_list.begin();
|
||||
edge_iterator = all_edges_list.begin();
|
||||
|
||||
while(
|
||||
edge_iterator != all_edges_list.end() &&
|
||||
node_iterator != all_nodes_list.end()
|
||||
) {
|
||||
if(edge_iterator->target < node_iterator->id){
|
||||
++edge_iterator;
|
||||
continue;
|
||||
}
|
||||
if(edge_iterator->target > node_iterator->id) {
|
||||
++node_iterator;
|
||||
continue;
|
||||
}
|
||||
BOOST_ASSERT(edge_iterator->target == node_iterator->id);
|
||||
if(edge_iterator->startCoord.lat != INT_MIN && edge_iterator->startCoord.lon != INT_MIN) {
|
||||
edge_iterator->targetCoord.lat = node_iterator->lat;
|
||||
edge_iterator->targetCoord.lon = node_iterator->lon;
|
||||
|
||||
const double distance = FixedPointCoordinate::ApproximateDistance(
|
||||
edge_iterator->startCoord.lat,
|
||||
edge_iterator->startCoord.lon,
|
||||
node_iterator->lat,
|
||||
node_iterator->lon
|
||||
);
|
||||
|
||||
BOOST_ASSERT(edge_iterator->speed != -1);
|
||||
const double weight = ( distance * 10. ) / (edge_iterator->speed / 3.6);
|
||||
int integer_weight = std::max( 1, (int)std::floor((edge_iterator->isDurationSet ? edge_iterator->speed : weight)+.5) );
|
||||
int integer_distance = std::max( 1, (int)distance );
|
||||
short zero = 0;
|
||||
short one = 1;
|
||||
|
||||
file_out_stream.write((char*)&edge_iterator->start, sizeof(unsigned));
|
||||
file_out_stream.write((char*)&edge_iterator->target, sizeof(unsigned));
|
||||
file_out_stream.write((char*)&integer_distance, sizeof(int));
|
||||
switch(edge_iterator->direction) {
|
||||
case ExtractionWay::notSure:
|
||||
file_out_stream.write((char*)&zero, sizeof(short));
|
||||
break;
|
||||
case ExtractionWay::oneway:
|
||||
file_out_stream.write((char*)&one, sizeof(short));
|
||||
break;
|
||||
case ExtractionWay::bidirectional:
|
||||
file_out_stream.write((char*)&zero, sizeof(short));
|
||||
|
||||
break;
|
||||
case ExtractionWay::opposite:
|
||||
file_out_stream.write((char*)&one, sizeof(short));
|
||||
break;
|
||||
default:
|
||||
throw OSRMException("edge has broken direction");
|
||||
}
|
||||
file_out_stream.write(
|
||||
(char*)&integer_weight, sizeof(int)
|
||||
);
|
||||
BOOST_ASSERT(edge_iterator->type >= 0);
|
||||
file_out_stream.write(
|
||||
(char*)&edge_iterator->type,
|
||||
sizeof(short)
|
||||
);
|
||||
file_out_stream.write(
|
||||
(char *) &edge_iterator->nameID,
|
||||
sizeof(unsigned)
|
||||
);
|
||||
file_out_stream.write(
|
||||
(char *) &edge_iterator->isRoundabout,
|
||||
sizeof(bool)
|
||||
);
|
||||
file_out_stream.write(
|
||||
(char *) &edge_iterator->ignoreInGrid,
|
||||
sizeof(bool)
|
||||
);
|
||||
file_out_stream.write(
|
||||
(char *) &edge_iterator->isAccessRestricted,
|
||||
sizeof(bool)
|
||||
);
|
||||
file_out_stream.write(
|
||||
(char *) &edge_iterator->isContraFlow,
|
||||
sizeof(bool)
|
||||
);
|
||||
file_out_stream.write(
|
||||
(char *) &edge_iterator->is_split,
|
||||
sizeof(bool)
|
||||
);
|
||||
++number_of_used_edges;
|
||||
}
|
||||
++edge_iterator;
|
||||
}
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
std::cout << "[extractor] setting number of edges ... " << std::flush;
|
||||
|
||||
file_out_stream.seekp(previous_file_position);
|
||||
file_out_stream.write((char*)&number_of_used_edges, sizeof(unsigned));
|
||||
file_out_stream.close();
|
||||
std::cout << "ok" << std::endl;
|
||||
time = get_timestamp();
|
||||
|
||||
std::cout << "[extractor] writing street name index ... " << std::flush;
|
||||
std::string name_file_streamName = (output_file_name + ".names");
|
||||
boost::filesystem::ofstream name_file_stream(
|
||||
name_file_streamName,
|
||||
std::ios::binary
|
||||
);
|
||||
|
||||
//write number of names
|
||||
const unsigned number_of_names = name_list.size()+1;
|
||||
name_file_stream.write((char *)&(number_of_names), sizeof(unsigned));
|
||||
|
||||
//compute total number of chars
|
||||
unsigned total_number_of_chars = 0;
|
||||
BOOST_FOREACH(const std::string & temp_string, name_list) {
|
||||
total_number_of_chars += temp_string.length();
|
||||
}
|
||||
//write total number of chars
|
||||
name_file_stream.write(
|
||||
(char *)&(total_number_of_chars),
|
||||
sizeof(unsigned)
|
||||
);
|
||||
//write prefixe sums
|
||||
unsigned name_lengths_prefix_sum = 0;
|
||||
BOOST_FOREACH(const std::string & temp_string, name_list) {
|
||||
name_file_stream.write(
|
||||
(char *)&(name_lengths_prefix_sum),
|
||||
sizeof(unsigned)
|
||||
);
|
||||
name_lengths_prefix_sum += temp_string.length();
|
||||
}
|
||||
//duplicate on purpose!
|
||||
name_file_stream.write(
|
||||
(char *)&(name_lengths_prefix_sum),
|
||||
sizeof(unsigned)
|
||||
);
|
||||
|
||||
//write all chars consecutively
|
||||
BOOST_FOREACH(const std::string & temp_string, name_list) {
|
||||
const unsigned string_length = temp_string.length();
|
||||
name_file_stream.write(temp_string.c_str(), string_length);
|
||||
}
|
||||
|
||||
name_file_stream.close();
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
SimpleLogger().Write() << "Processed " <<
|
||||
number_of_used_nodes << " nodes and " <<
|
||||
number_of_used_edges << " edges";
|
||||
|
||||
} catch ( const std::exception& e ) {
|
||||
std::cerr << "Caught Execption:" << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTIONCONTAINERS_H_
|
||||
#define EXTRACTIONCONTAINERS_H_
|
||||
|
||||
#include "InternalExtractorEdge.h"
|
||||
#include "ExtractorStructs.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../Util/UUID.h"
|
||||
|
||||
#include <stxxl/vector>
|
||||
|
||||
class ExtractionContainers {
|
||||
public:
|
||||
typedef stxxl::vector<NodeID> STXXLNodeIDVector;
|
||||
typedef stxxl::vector<ExternalMemoryNode> STXXLNodeVector;
|
||||
typedef stxxl::vector<InternalExtractorEdge> STXXLEdgeVector;
|
||||
typedef stxxl::vector<std::string> STXXLStringVector;
|
||||
typedef stxxl::vector<InputRestrictionContainer> STXXLRestrictionsVector;
|
||||
typedef stxxl::vector<_WayIDStartAndEndEdge> STXXLWayIDStartEndVector;
|
||||
|
||||
STXXLNodeIDVector used_node_id_list;
|
||||
STXXLNodeVector all_nodes_list;
|
||||
STXXLEdgeVector all_edges_list;
|
||||
STXXLStringVector name_list;
|
||||
STXXLRestrictionsVector restrictions_list;
|
||||
STXXLWayIDStartEndVector way_start_end_id_list;
|
||||
const UUID uuid;
|
||||
|
||||
ExtractionContainers();
|
||||
|
||||
virtual ~ExtractionContainers();
|
||||
|
||||
void PrepareData(
|
||||
const std::string & output_file_name,
|
||||
const std::string & restrictions_file_name
|
||||
);
|
||||
};
|
||||
|
||||
#endif /* EXTRACTIONCONTAINERS_H_ */
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTIONHELPERFUNCTIONS_H_
|
||||
#define EXTRACTIONHELPERFUNCTIONS_H_
|
||||
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string_regex.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <climits>
|
||||
|
||||
namespace qi = boost::spirit::qi;
|
||||
|
||||
//TODO: Move into LUA
|
||||
|
||||
inline bool durationIsValid(const std::string &s) {
|
||||
boost::regex e ("((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",boost::regex_constants::icase|boost::regex_constants::perl);
|
||||
|
||||
std::vector< std::string > result;
|
||||
boost::algorithm::split_regex( result, s, boost::regex( ":" ) ) ;
|
||||
bool matched = regex_match(s, e);
|
||||
return matched;
|
||||
}
|
||||
|
||||
inline unsigned parseDuration(const std::string &s) {
|
||||
unsigned hours = 0;
|
||||
unsigned minutes = 0;
|
||||
unsigned seconds = 0;
|
||||
boost::regex e ("((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",boost::regex_constants::icase|boost::regex_constants::perl);
|
||||
|
||||
std::vector< std::string > result;
|
||||
boost::algorithm::split_regex( result, s, boost::regex( ":" ) ) ;
|
||||
bool matched = regex_match(s, e);
|
||||
if(matched) {
|
||||
if(1 == result.size()) {
|
||||
minutes = stringToInt(result[0]);
|
||||
}
|
||||
if(2 == result.size()) {
|
||||
minutes = stringToInt(result[1]);
|
||||
hours = stringToInt(result[0]);
|
||||
}
|
||||
if(3 == result.size()) {
|
||||
seconds = stringToInt(result[2]);
|
||||
minutes = stringToInt(result[1]);
|
||||
hours = stringToInt(result[0]);
|
||||
}
|
||||
return 10*(3600*hours+60*minutes+seconds);
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
// inline int parseMaxspeed(std::string input) { //call-by-value on purpose.
|
||||
// boost::algorithm::to_lower(input);
|
||||
// int n = stringToInt(input);
|
||||
// if (input.find("mph") != std::string::npos || input.find("mp/h") != std::string::npos) {
|
||||
// n = (n*1609)/1000;
|
||||
// }
|
||||
// return n;
|
||||
// }
|
||||
|
||||
#endif /* EXTRACTIONHELPERFUNCTIONS_H_ */
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTION_WAY_H
|
||||
#define EXTRACTION_WAY_H
|
||||
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct ExtractionWay {
|
||||
ExtractionWay() {
|
||||
Clear();
|
||||
}
|
||||
|
||||
inline void Clear(){
|
||||
id = UINT_MAX;
|
||||
nameID = UINT_MAX;
|
||||
path.clear();
|
||||
keyVals.clear();
|
||||
direction = ExtractionWay::notSure;
|
||||
speed = -1;
|
||||
backward_speed = -1;
|
||||
duration = -1;
|
||||
type = -1;
|
||||
access = true;
|
||||
roundabout = false;
|
||||
isAccessRestricted = false;
|
||||
ignoreInGrid = false;
|
||||
}
|
||||
|
||||
enum Directions {
|
||||
notSure = 0, oneway, bidirectional, opposite
|
||||
};
|
||||
unsigned id;
|
||||
unsigned nameID;
|
||||
double speed;
|
||||
double backward_speed;
|
||||
double duration;
|
||||
Directions direction;
|
||||
std::string name;
|
||||
short type;
|
||||
bool access;
|
||||
bool roundabout;
|
||||
bool isAccessRestricted;
|
||||
bool ignoreInGrid;
|
||||
std::vector< NodeID > path;
|
||||
HashTable<std::string, std::string> keyVals;
|
||||
};
|
||||
|
||||
|
||||
#endif //EXTRACTION_WAY_H
|
||||
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "ExtractorCallbacks.h"
|
||||
#include "ExtractionContainers.h"
|
||||
#include "ExtractionWay.h"
|
||||
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
ExtractorCallbacks::ExtractorCallbacks()
|
||||
:
|
||||
string_map(NULL),
|
||||
externalMemory(NULL)
|
||||
{ }
|
||||
|
||||
ExtractorCallbacks::ExtractorCallbacks(
|
||||
ExtractionContainers * ext,
|
||||
boost::unordered_map<std::string, NodeID> * string_map
|
||||
) :
|
||||
string_map(string_map),
|
||||
externalMemory(ext)
|
||||
{ }
|
||||
|
||||
ExtractorCallbacks::~ExtractorCallbacks() { }
|
||||
|
||||
/** warning: caller needs to take care of synchronization! */
|
||||
void ExtractorCallbacks::nodeFunction(const ExternalMemoryNode &n) {
|
||||
if(n.lat <= 85*COORDINATE_PRECISION && n.lat >= -85*COORDINATE_PRECISION) {
|
||||
externalMemory->all_nodes_list.push_back(n);
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtractorCallbacks::restrictionFunction(const InputRestrictionContainer &r) {
|
||||
externalMemory->restrictions_list.push_back(r);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** warning: caller needs to take care of synchronization! */
|
||||
void ExtractorCallbacks::wayFunction(ExtractionWay &parsed_way) {
|
||||
if((0 < parsed_way.speed) || (0 < parsed_way.duration)) { //Only true if the way is specified by the speed profile
|
||||
if(UINT_MAX == parsed_way.id){
|
||||
SimpleLogger().Write(logDEBUG) <<
|
||||
"found bogus way with id: " << parsed_way.id <<
|
||||
" of size " << parsed_way.path.size();
|
||||
return;
|
||||
}
|
||||
|
||||
if(0 < parsed_way.duration) {
|
||||
//TODO: iterate all way segments and set duration corresponding to the length of each segment
|
||||
parsed_way.speed = parsed_way.duration/(parsed_way.path.size()-1);
|
||||
}
|
||||
|
||||
if(std::numeric_limits<double>::epsilon() >= std::abs(-1. - parsed_way.speed)){
|
||||
SimpleLogger().Write(logDEBUG) <<
|
||||
"found way with bogus speed, id: " << parsed_way.id;
|
||||
return;
|
||||
}
|
||||
|
||||
//Get the unique identifier for the street name
|
||||
const boost::unordered_map<std::string, NodeID>::const_iterator & string_map_iterator = string_map->find(parsed_way.name);
|
||||
if(string_map->end() == string_map_iterator) {
|
||||
parsed_way.nameID = externalMemory->name_list.size();
|
||||
externalMemory->name_list.push_back(parsed_way.name);
|
||||
string_map->insert(std::make_pair(parsed_way.name, parsed_way.nameID));
|
||||
} else {
|
||||
parsed_way.nameID = string_map_iterator->second;
|
||||
}
|
||||
|
||||
if(ExtractionWay::opposite == parsed_way.direction) {
|
||||
std::reverse( parsed_way.path.begin(), parsed_way.path.end() );
|
||||
parsed_way.direction = ExtractionWay::oneway;
|
||||
}
|
||||
|
||||
const bool split_bidirectional_edge = (parsed_way.backward_speed > 0) && (parsed_way.speed != parsed_way.backward_speed);
|
||||
|
||||
for(std::vector< NodeID >::size_type n = 0; n < parsed_way.path.size()-1; ++n) {
|
||||
externalMemory->all_edges_list.push_back(
|
||||
InternalExtractorEdge(
|
||||
parsed_way.path[n],
|
||||
parsed_way.path[n+1],
|
||||
parsed_way.type,
|
||||
(split_bidirectional_edge ? ExtractionWay::oneway : parsed_way.direction),
|
||||
parsed_way.speed,
|
||||
parsed_way.nameID,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.ignoreInGrid,
|
||||
(0 < parsed_way.duration),
|
||||
parsed_way.isAccessRestricted,
|
||||
false,
|
||||
split_bidirectional_edge
|
||||
)
|
||||
);
|
||||
externalMemory->used_node_id_list.push_back(parsed_way.path[n]);
|
||||
}
|
||||
externalMemory->used_node_id_list.push_back(parsed_way.path.back());
|
||||
|
||||
//The following information is needed to identify start and end segments of restrictions
|
||||
externalMemory->way_start_end_id_list.push_back(_WayIDStartAndEndEdge(parsed_way.id, parsed_way.path[0], parsed_way.path[1], parsed_way.path[parsed_way.path.size()-2], parsed_way.path.back()));
|
||||
|
||||
if(split_bidirectional_edge) { //Only true if the way should be split
|
||||
std::reverse( parsed_way.path.begin(), parsed_way.path.end() );
|
||||
for(std::vector< NodeID >::size_type n = 0; n < parsed_way.path.size()-1; ++n) {
|
||||
externalMemory->all_edges_list.push_back(
|
||||
InternalExtractorEdge(
|
||||
parsed_way.path[n],
|
||||
parsed_way.path[n+1],
|
||||
parsed_way.type,
|
||||
ExtractionWay::oneway,
|
||||
parsed_way.backward_speed,
|
||||
parsed_way.nameID,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.ignoreInGrid,
|
||||
(0 < parsed_way.duration),
|
||||
parsed_way.isAccessRestricted,
|
||||
(ExtractionWay::oneway == parsed_way.direction),
|
||||
split_bidirectional_edge
|
||||
)
|
||||
);
|
||||
}
|
||||
externalMemory->way_start_end_id_list.push_back(_WayIDStartAndEndEdge(parsed_way.id, parsed_way.path[0], parsed_way.path[1], parsed_way.path[parsed_way.path.size()-2], parsed_way.path.back()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTORSTRUCTS_H_
|
||||
#define EXTRACTORSTRUCTS_H_
|
||||
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
struct ExtractorRelation {
|
||||
ExtractorRelation() : type(unknown){}
|
||||
enum {
|
||||
unknown = 0, ferry, turnRestriction
|
||||
} type;
|
||||
HashTable<std::string, std::string> keyVals;
|
||||
};
|
||||
|
||||
struct _WayIDStartAndEndEdge {
|
||||
unsigned wayID;
|
||||
NodeID firstStart;
|
||||
NodeID firstTarget;
|
||||
NodeID lastStart;
|
||||
NodeID lastTarget;
|
||||
_WayIDStartAndEndEdge()
|
||||
:
|
||||
wayID(UINT_MAX),
|
||||
firstStart(UINT_MAX),
|
||||
firstTarget(UINT_MAX),
|
||||
lastStart(UINT_MAX),
|
||||
lastTarget(UINT_MAX)
|
||||
{ }
|
||||
|
||||
explicit _WayIDStartAndEndEdge(
|
||||
unsigned w,
|
||||
NodeID fs,
|
||||
NodeID ft,
|
||||
NodeID ls,
|
||||
NodeID lt
|
||||
) :
|
||||
wayID(w),
|
||||
firstStart(fs),
|
||||
firstTarget(ft),
|
||||
lastStart(ls),
|
||||
lastTarget(lt)
|
||||
{ }
|
||||
|
||||
static _WayIDStartAndEndEdge min_value() {
|
||||
return _WayIDStartAndEndEdge((std::numeric_limits<unsigned>::min)(), (std::numeric_limits<unsigned>::min)(), (std::numeric_limits<unsigned>::min)(), (std::numeric_limits<unsigned>::min)(), (std::numeric_limits<unsigned>::min)());
|
||||
}
|
||||
static _WayIDStartAndEndEdge max_value() {
|
||||
return _WayIDStartAndEndEdge((std::numeric_limits<unsigned>::max)(), (std::numeric_limits<unsigned>::max)(), (std::numeric_limits<unsigned>::max)(), (std::numeric_limits<unsigned>::max)(), (std::numeric_limits<unsigned>::max)());
|
||||
}
|
||||
};
|
||||
|
||||
struct CmpWayByID {
|
||||
typedef _WayIDStartAndEndEdge value_type;
|
||||
bool operator ()(
|
||||
const _WayIDStartAndEndEdge & a,
|
||||
const _WayIDStartAndEndEdge & b
|
||||
) const {
|
||||
return a.wayID < b.wayID;
|
||||
}
|
||||
value_type max_value() {
|
||||
return _WayIDStartAndEndEdge::max_value();
|
||||
}
|
||||
value_type min_value() {
|
||||
return _WayIDStartAndEndEdge::min_value();
|
||||
}
|
||||
};
|
||||
|
||||
struct Cmp {
|
||||
typedef NodeID value_type;
|
||||
bool operator ()(
|
||||
const NodeID a,
|
||||
const NodeID b
|
||||
) const {
|
||||
return a < b;
|
||||
}
|
||||
value_type max_value() {
|
||||
return 0xffffffff;
|
||||
}
|
||||
value_type min_value() {
|
||||
return 0x0;
|
||||
}
|
||||
};
|
||||
|
||||
struct CmpNodeByID {
|
||||
typedef ExternalMemoryNode value_type;
|
||||
bool operator () (
|
||||
const ExternalMemoryNode & a,
|
||||
const ExternalMemoryNode & b
|
||||
) const {
|
||||
return a.id < b.id;
|
||||
}
|
||||
value_type max_value() {
|
||||
return ExternalMemoryNode::max_value();
|
||||
}
|
||||
value_type min_value() {
|
||||
return ExternalMemoryNode::min_value();
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* EXTRACTORSTRUCTS_H_ */
|
||||
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INTERNAL_EXTRACTOR_EDGE_H
|
||||
#define INTERNAL_EXTRACTOR_EDGE_H
|
||||
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
struct InternalExtractorEdge {
|
||||
InternalExtractorEdge()
|
||||
:
|
||||
start(0),
|
||||
target(0),
|
||||
type(0),
|
||||
direction(0),
|
||||
speed(0),
|
||||
nameID(0),
|
||||
isRoundabout(false),
|
||||
ignoreInGrid(false),
|
||||
isDurationSet(false),
|
||||
isAccessRestricted(false),
|
||||
isContraFlow(false),
|
||||
is_split(false)
|
||||
{ }
|
||||
|
||||
|
||||
explicit InternalExtractorEdge(
|
||||
NodeID start,
|
||||
NodeID target,
|
||||
short type,
|
||||
short direction,
|
||||
double speed,
|
||||
unsigned nameID,
|
||||
bool isRoundabout,
|
||||
bool ignoreInGrid,
|
||||
bool isDurationSet,
|
||||
bool isAccressRestricted,
|
||||
bool isContraFlow,
|
||||
bool is_split
|
||||
) :
|
||||
start(start),
|
||||
target(target),
|
||||
type(type),
|
||||
direction(direction),
|
||||
speed(speed),
|
||||
nameID(nameID),
|
||||
isRoundabout(isRoundabout),
|
||||
ignoreInGrid(ignoreInGrid),
|
||||
isDurationSet(isDurationSet),
|
||||
isAccessRestricted(isAccressRestricted),
|
||||
isContraFlow(isContraFlow),
|
||||
is_split(is_split)
|
||||
{
|
||||
BOOST_ASSERT(0 <= type);
|
||||
}
|
||||
|
||||
// necessary static util functions for stxxl's sorting
|
||||
static InternalExtractorEdge min_value() {
|
||||
return InternalExtractorEdge(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
static InternalExtractorEdge max_value() {
|
||||
return InternalExtractorEdge(
|
||||
std::numeric_limits<unsigned>::max(),
|
||||
std::numeric_limits<unsigned>::max(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
NodeID start;
|
||||
NodeID target;
|
||||
short type;
|
||||
short direction;
|
||||
double speed;
|
||||
unsigned nameID;
|
||||
bool isRoundabout;
|
||||
bool ignoreInGrid;
|
||||
bool isDurationSet;
|
||||
bool isAccessRestricted;
|
||||
bool isContraFlow;
|
||||
bool is_split;
|
||||
|
||||
FixedPointCoordinate startCoord;
|
||||
FixedPointCoordinate targetCoord;
|
||||
};
|
||||
|
||||
struct CmpEdgeByStartID {
|
||||
typedef InternalExtractorEdge value_type;
|
||||
bool operator ()(
|
||||
const InternalExtractorEdge & a,
|
||||
const InternalExtractorEdge & b
|
||||
) const {
|
||||
return a.start < b.start;
|
||||
}
|
||||
|
||||
value_type max_value() {
|
||||
return InternalExtractorEdge::max_value();
|
||||
}
|
||||
|
||||
value_type min_value() {
|
||||
return InternalExtractorEdge::min_value();
|
||||
}
|
||||
};
|
||||
|
||||
struct CmpEdgeByTargetID {
|
||||
typedef InternalExtractorEdge value_type;
|
||||
|
||||
bool operator ()(
|
||||
const InternalExtractorEdge & a,
|
||||
const InternalExtractorEdge & b
|
||||
) const {
|
||||
return a.target < b.target;
|
||||
}
|
||||
|
||||
value_type max_value() {
|
||||
return InternalExtractorEdge::max_value();
|
||||
}
|
||||
|
||||
value_type min_value() {
|
||||
return InternalExtractorEdge::min_value();
|
||||
}
|
||||
};
|
||||
|
||||
#endif //INTERNAL_EXTRACTOR_EDGE_H
|
||||
@@ -1,535 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "PBFParser.h"
|
||||
|
||||
#include "ExtractionWay.h"
|
||||
#include "ExtractorCallbacks.h"
|
||||
#include "ScriptingEnvironment.h"
|
||||
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../Util/MachineInfo.h"
|
||||
#include "../Util/OpenMPWrapper.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
PBFParser::PBFParser(
|
||||
const char * fileName,
|
||||
ExtractorCallbacks * extractor_callbacks,
|
||||
ScriptingEnvironment& scripting_environment
|
||||
) : BaseParser( extractor_callbacks, scripting_environment ) {
|
||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||
//TODO: What is the bottleneck here? Filling the queue or reading the stuff from disk?
|
||||
//NOTE: With Lua scripting, it is parsing the stuff. I/O is virtually for free.
|
||||
|
||||
// Max 2500 items in queue, hardcoded.
|
||||
threadDataQueue = boost::make_shared<ConcurrentQueue<_ThreadData*> >( 2500 );
|
||||
input.open(fileName, std::ios::in | std::ios::binary);
|
||||
|
||||
if (!input) {
|
||||
throw OSRMException("pbf file not found.");
|
||||
}
|
||||
|
||||
blockCount = 0;
|
||||
groupCount = 0;
|
||||
}
|
||||
|
||||
PBFParser::~PBFParser() {
|
||||
if(input.is_open()) {
|
||||
input.close();
|
||||
}
|
||||
|
||||
// Clean up any leftover ThreadData objects in the queue
|
||||
_ThreadData* thread_data;
|
||||
while (threadDataQueue->try_pop(thread_data))
|
||||
{
|
||||
delete thread_data;
|
||||
}
|
||||
google::protobuf::ShutdownProtobufLibrary();
|
||||
|
||||
SimpleLogger().Write(logDEBUG) <<
|
||||
"parsed " << blockCount <<
|
||||
" blocks from pbf with " << groupCount <<
|
||||
" groups";
|
||||
}
|
||||
|
||||
inline bool PBFParser::ReadHeader() {
|
||||
_ThreadData initData;
|
||||
/** read Header */
|
||||
if(!readPBFBlobHeader(input, &initData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(readBlob(input, &initData)) {
|
||||
if(!initData.PBFHeaderBlock.ParseFromArray(&(initData.charBuffer[0]), initData.charBuffer.size() ) ) {
|
||||
std::cerr << "[error] Header not parseable!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i = 0, featureSize = initData.PBFHeaderBlock.required_features_size(); i < featureSize; ++i) {
|
||||
const std::string& feature = initData.PBFHeaderBlock.required_features( i );
|
||||
bool supported = false;
|
||||
if ( "OsmSchema-V0.6" == feature ) {
|
||||
supported = true;
|
||||
}
|
||||
else if ( "DenseNodes" == feature ) {
|
||||
supported = true;
|
||||
}
|
||||
|
||||
if ( !supported ) {
|
||||
std::cerr << "[error] required feature not supported: " << feature.data() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::cerr << "[error] blob not loaded!" << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void PBFParser::ReadData() {
|
||||
bool keepRunning = true;
|
||||
do {
|
||||
_ThreadData *threadData = new _ThreadData();
|
||||
keepRunning = readNextBlock(input, threadData);
|
||||
|
||||
if (keepRunning) {
|
||||
threadDataQueue->push(threadData);
|
||||
} else {
|
||||
threadDataQueue->push(NULL); // No more data to read, parse stops when NULL encountered
|
||||
delete threadData;
|
||||
}
|
||||
} while(keepRunning);
|
||||
}
|
||||
|
||||
inline void PBFParser::ParseData() {
|
||||
while (true) {
|
||||
_ThreadData *threadData;
|
||||
threadDataQueue->wait_and_pop(threadData);
|
||||
if( NULL==threadData ) {
|
||||
SimpleLogger().Write() << "Parse Data Thread Finished";
|
||||
threadDataQueue->push(NULL); // Signal end of data for other threads
|
||||
break;
|
||||
}
|
||||
|
||||
loadBlock(threadData);
|
||||
|
||||
for(int i = 0, groupSize = threadData->PBFprimitiveBlock.primitivegroup_size(); i < groupSize; ++i) {
|
||||
threadData->currentGroupID = i;
|
||||
loadGroup(threadData);
|
||||
|
||||
if(threadData->entityTypeIndicator == TypeNode) {
|
||||
parseNode(threadData);
|
||||
}
|
||||
if(threadData->entityTypeIndicator == TypeWay) {
|
||||
parseWay(threadData);
|
||||
}
|
||||
if(threadData->entityTypeIndicator == TypeRelation) {
|
||||
parseRelation(threadData);
|
||||
}
|
||||
if(threadData->entityTypeIndicator == TypeDenseNode) {
|
||||
parseDenseNode(threadData);
|
||||
}
|
||||
}
|
||||
|
||||
delete threadData;
|
||||
threadData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool PBFParser::Parse() {
|
||||
// Start the read and parse threads
|
||||
boost::thread readThread(boost::bind(&PBFParser::ReadData, this));
|
||||
|
||||
//Open several parse threads that are synchronized before call to
|
||||
boost::thread parseThread(boost::bind(&PBFParser::ParseData, this));
|
||||
|
||||
// Wait for the threads to finish
|
||||
readThread.join();
|
||||
parseThread.join();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void PBFParser::parseDenseNode(_ThreadData * threadData) {
|
||||
const OSMPBF::DenseNodes& dense = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).dense();
|
||||
int denseTagIndex = 0;
|
||||
int64_t m_lastDenseID = 0;
|
||||
int64_t m_lastDenseLatitude = 0;
|
||||
int64_t m_lastDenseLongitude = 0;
|
||||
|
||||
const int number_of_nodes = dense.id_size();
|
||||
std::vector<ImportNode> extracted_nodes_vector(number_of_nodes);
|
||||
for(int i = 0; i < number_of_nodes; ++i) {
|
||||
m_lastDenseID += dense.id( i );
|
||||
m_lastDenseLatitude += dense.lat( i );
|
||||
m_lastDenseLongitude += dense.lon( i );
|
||||
extracted_nodes_vector[i].id = m_lastDenseID;
|
||||
extracted_nodes_vector[i].lat = COORDINATE_PRECISION*( ( double ) m_lastDenseLatitude * threadData->PBFprimitiveBlock.granularity() + threadData->PBFprimitiveBlock.lat_offset() ) / NANO;
|
||||
extracted_nodes_vector[i].lon = COORDINATE_PRECISION*( ( double ) m_lastDenseLongitude * threadData->PBFprimitiveBlock.granularity() + threadData->PBFprimitiveBlock.lon_offset() ) / NANO;
|
||||
while (denseTagIndex < dense.keys_vals_size()) {
|
||||
const int tagValue = dense.keys_vals( denseTagIndex );
|
||||
if( 0 == tagValue ) {
|
||||
++denseTagIndex;
|
||||
break;
|
||||
}
|
||||
const int keyValue = dense.keys_vals ( denseTagIndex+1 );
|
||||
const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(tagValue);
|
||||
const std::string & value = threadData->PBFprimitiveBlock.stringtable().s(keyValue);
|
||||
extracted_nodes_vector[i].keyVals.emplace(key, value);
|
||||
denseTagIndex += 2;
|
||||
}
|
||||
}
|
||||
#pragma omp parallel
|
||||
{
|
||||
const int thread_num = omp_get_thread_num();
|
||||
#pragma omp parallel for schedule ( guided )
|
||||
for(int i = 0; i < number_of_nodes; ++i)
|
||||
{
|
||||
ImportNode & import_node = extracted_nodes_vector[i];
|
||||
ParseNodeInLua(import_node, scripting_environment.getLuaStateForThreadID(thread_num));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const ImportNode &import_node, extracted_nodes_vector)
|
||||
{
|
||||
extractor_callbacks->nodeFunction(import_node);
|
||||
}
|
||||
}
|
||||
|
||||
inline void PBFParser::parseNode(_ThreadData * )
|
||||
{
|
||||
throw OSRMException("Parsing of simple nodes not supported. PBF should use dense nodes");
|
||||
}
|
||||
|
||||
inline void PBFParser::parseRelation(_ThreadData * threadData) {
|
||||
//TODO: leave early, if relation is not a restriction
|
||||
//TODO: reuse rawRestriction container
|
||||
if( !use_turn_restrictions ) {
|
||||
return;
|
||||
}
|
||||
const OSMPBF::PrimitiveGroup& group = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID );
|
||||
|
||||
for(int i = 0, relation_size = group.relations_size(); i < relation_size; ++i ) {
|
||||
std::string except_tag_string;
|
||||
const OSMPBF::Relation& inputRelation = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).relations(i);
|
||||
bool isRestriction = false;
|
||||
bool isOnlyRestriction = false;
|
||||
for(int k = 0, endOfKeys = inputRelation.keys_size(); k < endOfKeys; ++k) {
|
||||
const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputRelation.keys(k));
|
||||
const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputRelation.vals(k));
|
||||
if ("type" == key) {
|
||||
if( "restriction" == val) {
|
||||
isRestriction = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( ("restriction" == key) && (val.find("only_") == 0) )
|
||||
{
|
||||
isOnlyRestriction = true;
|
||||
}
|
||||
if ("except" == key)
|
||||
{
|
||||
except_tag_string = val;
|
||||
}
|
||||
}
|
||||
|
||||
if( isRestriction && ShouldIgnoreRestriction(except_tag_string) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(isRestriction) {
|
||||
int64_t lastRef = 0;
|
||||
InputRestrictionContainer currentRestrictionContainer(isOnlyRestriction);
|
||||
for(
|
||||
int rolesIndex = 0, last_role = inputRelation.roles_sid_size();
|
||||
rolesIndex < last_role;
|
||||
++rolesIndex
|
||||
) {
|
||||
const std::string & role = threadData->PBFprimitiveBlock.stringtable().s( inputRelation.roles_sid( rolesIndex ) );
|
||||
lastRef += inputRelation.memids(rolesIndex);
|
||||
|
||||
if(!("from" == role || "to" == role || "via" == role)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(inputRelation.types(rolesIndex)) {
|
||||
case 0: //node
|
||||
if("from" == role || "to" == role) { //Only via should be a node
|
||||
continue;
|
||||
}
|
||||
assert("via" == role);
|
||||
if(UINT_MAX != currentRestrictionContainer.viaNode) {
|
||||
currentRestrictionContainer.viaNode = UINT_MAX;
|
||||
}
|
||||
assert(UINT_MAX == currentRestrictionContainer.viaNode);
|
||||
currentRestrictionContainer.restriction.viaNode = lastRef;
|
||||
break;
|
||||
case 1: //way
|
||||
assert("from" == role || "to" == role || "via" == role);
|
||||
if("from" == role) {
|
||||
currentRestrictionContainer.fromWay = lastRef;
|
||||
}
|
||||
if ("to" == role) {
|
||||
currentRestrictionContainer.toWay = lastRef;
|
||||
}
|
||||
if ("via" == role) {
|
||||
assert(currentRestrictionContainer.restriction.toNode == UINT_MAX);
|
||||
currentRestrictionContainer.viaNode = lastRef;
|
||||
}
|
||||
break;
|
||||
case 2: //relation, not used. relations relating to relations are evil.
|
||||
continue;
|
||||
assert(false);
|
||||
break;
|
||||
|
||||
default: //should not happen
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!extractor_callbacks->restrictionFunction(currentRestrictionContainer)) {
|
||||
std::cerr << "[PBFParser] relation not parsed" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void PBFParser::parseWay(_ThreadData * threadData) {
|
||||
const int number_of_ways = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways_size();
|
||||
std::vector<ExtractionWay> parsed_way_vector(number_of_ways);
|
||||
for(int i = 0; i < number_of_ways; ++i) {
|
||||
const OSMPBF::Way& inputWay = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways( i );
|
||||
parsed_way_vector[i].id = inputWay.id();
|
||||
unsigned pathNode(0);
|
||||
const int number_of_referenced_nodes = inputWay.refs_size();
|
||||
for(int j = 0; j < number_of_referenced_nodes; ++j) {
|
||||
pathNode += inputWay.refs(j);
|
||||
parsed_way_vector[i].path.push_back(pathNode);
|
||||
}
|
||||
assert(inputWay.keys_size() == inputWay.vals_size());
|
||||
const int number_of_keys = inputWay.keys_size();
|
||||
for(int j = 0; j < number_of_keys; ++j) {
|
||||
const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputWay.keys(j));
|
||||
const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputWay.vals(j));
|
||||
parsed_way_vector[i].keyVals.emplace(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma omp parallel for schedule ( guided )
|
||||
for(int i = 0; i < number_of_ways; ++i)
|
||||
{
|
||||
ExtractionWay & extraction_way = parsed_way_vector[i];
|
||||
if (2 <= extraction_way.path.size())
|
||||
{
|
||||
ParseWayInLua(
|
||||
extraction_way,
|
||||
scripting_environment.getLuaStateForThreadID(omp_get_thread_num())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FOREACH(ExtractionWay & extraction_way, parsed_way_vector)
|
||||
{
|
||||
if (2 <= extraction_way.path.size())
|
||||
{
|
||||
extractor_callbacks->wayFunction(extraction_way);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void PBFParser::loadGroup(_ThreadData * threadData) {
|
||||
#ifndef NDEBUG
|
||||
++groupCount;
|
||||
#endif
|
||||
|
||||
const OSMPBF::PrimitiveGroup& group = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID );
|
||||
threadData->entityTypeIndicator = TypeDummy;
|
||||
if ( 0 != group.nodes_size() ) {
|
||||
threadData->entityTypeIndicator = TypeNode;
|
||||
}
|
||||
if ( 0 != group.ways_size() ) {
|
||||
threadData->entityTypeIndicator = TypeWay;
|
||||
}
|
||||
if ( 0 != group.relations_size() ) {
|
||||
threadData->entityTypeIndicator = TypeRelation;
|
||||
}
|
||||
if ( group.has_dense() ) {
|
||||
threadData->entityTypeIndicator = TypeDenseNode;
|
||||
assert( 0 != group.dense().id_size() );
|
||||
}
|
||||
assert( threadData->entityTypeIndicator != TypeDummy );
|
||||
}
|
||||
|
||||
inline void PBFParser::loadBlock(_ThreadData * threadData) {
|
||||
++blockCount;
|
||||
threadData->currentGroupID = 0;
|
||||
threadData->currentEntityID = 0;
|
||||
}
|
||||
|
||||
inline bool PBFParser::readPBFBlobHeader(std::fstream& stream, _ThreadData * threadData) {
|
||||
int size(0);
|
||||
stream.read((char *)&size, sizeof(int));
|
||||
size = swapEndian(size);
|
||||
if(stream.eof()) {
|
||||
return false;
|
||||
}
|
||||
if ( size > MAX_BLOB_HEADER_SIZE || size < 0 ) {
|
||||
return false;
|
||||
}
|
||||
char *data = new char[size];
|
||||
stream.read(data, size*sizeof(data[0]));
|
||||
|
||||
bool dataSuccessfullyParsed = (threadData->PBFBlobHeader).ParseFromArray( data, size);
|
||||
delete[] data;
|
||||
return dataSuccessfullyParsed;
|
||||
}
|
||||
|
||||
inline bool PBFParser::unpackZLIB(std::fstream &, _ThreadData * threadData) {
|
||||
unsigned rawSize = threadData->PBFBlob.raw_size();
|
||||
char* unpackedDataArray = new char[rawSize];
|
||||
z_stream compressedDataStream;
|
||||
compressedDataStream.next_in = ( unsigned char* ) threadData->PBFBlob.zlib_data().data();
|
||||
compressedDataStream.avail_in = threadData->PBFBlob.zlib_data().size();
|
||||
compressedDataStream.next_out = ( unsigned char* ) unpackedDataArray;
|
||||
compressedDataStream.avail_out = rawSize;
|
||||
compressedDataStream.zalloc = Z_NULL;
|
||||
compressedDataStream.zfree = Z_NULL;
|
||||
compressedDataStream.opaque = Z_NULL;
|
||||
int ret = inflateInit( &compressedDataStream );
|
||||
if ( ret != Z_OK ) {
|
||||
std::cerr << "[error] failed to init zlib stream" << std::endl;
|
||||
delete[] unpackedDataArray;
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = inflate( &compressedDataStream, Z_FINISH );
|
||||
if ( ret != Z_STREAM_END ) {
|
||||
std::cerr << "[error] failed to inflate zlib stream" << std::endl;
|
||||
std::cerr << "[error] Error type: " << ret << std::endl;
|
||||
delete[] unpackedDataArray;
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = inflateEnd( &compressedDataStream );
|
||||
if ( ret != Z_OK ) {
|
||||
std::cerr << "[error] failed to deinit zlib stream" << std::endl;
|
||||
delete[] unpackedDataArray;
|
||||
return false;
|
||||
}
|
||||
|
||||
threadData->charBuffer.clear(); threadData->charBuffer.resize(rawSize);
|
||||
std::copy(unpackedDataArray, unpackedDataArray + rawSize, threadData->charBuffer.begin());
|
||||
delete[] unpackedDataArray;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool PBFParser::unpackLZMA(std::fstream &, _ThreadData * ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool PBFParser::readBlob(std::fstream& stream, _ThreadData * threadData) {
|
||||
if(stream.eof()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int size = threadData->PBFBlobHeader.datasize();
|
||||
if ( size < 0 || size > MAX_BLOB_SIZE ) {
|
||||
std::cerr << "[error] invalid Blob size:" << size << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
char* data = new char[size];
|
||||
stream.read(data, sizeof(data[0])*size);
|
||||
|
||||
if ( !threadData->PBFBlob.ParseFromArray( data, size ) ) {
|
||||
std::cerr << "[error] failed to parse blob" << std::endl;
|
||||
delete[] data;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( threadData->PBFBlob.has_raw() ) {
|
||||
const std::string& data = threadData->PBFBlob.raw();
|
||||
threadData->charBuffer.clear();
|
||||
threadData->charBuffer.resize( data.size() );
|
||||
std::copy(data.begin(), data.end(), threadData->charBuffer.begin());
|
||||
} else if ( threadData->PBFBlob.has_zlib_data() ) {
|
||||
if ( !unpackZLIB(stream, threadData) ) {
|
||||
std::cerr << "[error] zlib data encountered that could not be unpacked" << std::endl;
|
||||
delete[] data;
|
||||
return false;
|
||||
}
|
||||
} else if ( threadData->PBFBlob.has_lzma_data() ) {
|
||||
if ( !unpackLZMA(stream, threadData) ) {
|
||||
std::cerr << "[error] lzma data encountered that could not be unpacked" << std::endl;
|
||||
}
|
||||
delete[] data;
|
||||
return false;
|
||||
} else {
|
||||
std::cerr << "[error] Blob contains no data" << std::endl;
|
||||
delete[] data;
|
||||
return false;
|
||||
}
|
||||
delete[] data;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PBFParser::readNextBlock(std::fstream& stream, _ThreadData * threadData) {
|
||||
if(stream.eof()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !readPBFBlobHeader(stream, threadData) ){
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( threadData->PBFBlobHeader.type() != "OSMData" ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !readBlob(stream, threadData) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !threadData->PBFprimitiveBlock.ParseFromArray( &(threadData->charBuffer[0]), threadData-> charBuffer.size() ) ) {
|
||||
std::cerr << "failed to parse PrimitiveBlock" << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef PBFPARSER_H_
|
||||
#define PBFPARSER_H_
|
||||
|
||||
#include "BaseParser.h"
|
||||
#include "../DataStructures/ConcurrentQueue.h"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <osmpbf/fileformat.pb.h>
|
||||
#include <osmpbf/osmformat.pb.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
class PBFParser : public BaseParser {
|
||||
|
||||
enum EntityType {
|
||||
TypeDummy = 0,
|
||||
TypeNode = 1,
|
||||
TypeWay = 2,
|
||||
TypeRelation = 4,
|
||||
TypeDenseNode = 8
|
||||
};
|
||||
|
||||
struct _ThreadData {
|
||||
int currentGroupID;
|
||||
int currentEntityID;
|
||||
EntityType entityTypeIndicator;
|
||||
|
||||
OSMPBF::BlobHeader PBFBlobHeader;
|
||||
OSMPBF::Blob PBFBlob;
|
||||
|
||||
OSMPBF::HeaderBlock PBFHeaderBlock;
|
||||
OSMPBF::PrimitiveBlock PBFprimitiveBlock;
|
||||
|
||||
std::vector<char> charBuffer;
|
||||
};
|
||||
|
||||
public:
|
||||
PBFParser(
|
||||
const char * fileName,
|
||||
ExtractorCallbacks* ec,
|
||||
ScriptingEnvironment& se
|
||||
);
|
||||
virtual ~PBFParser();
|
||||
|
||||
inline bool ReadHeader();
|
||||
inline bool Parse();
|
||||
|
||||
private:
|
||||
inline void ReadData();
|
||||
inline void ParseData();
|
||||
inline void parseDenseNode (_ThreadData * threadData);
|
||||
inline void parseNode (_ThreadData * threadData);
|
||||
inline void parseRelation (_ThreadData * threadData);
|
||||
inline void parseWay (_ThreadData * threadData);
|
||||
|
||||
inline void loadGroup (_ThreadData * threadData);
|
||||
inline void loadBlock (_ThreadData * threadData);
|
||||
inline bool readPBFBlobHeader(std::fstream & stream, _ThreadData * threadData);
|
||||
inline bool unpackZLIB (std::fstream & stream, _ThreadData * threadData);
|
||||
inline bool unpackLZMA (std::fstream & stream, _ThreadData * threadData);
|
||||
inline bool readBlob (std::fstream & stream, _ThreadData * threadData);
|
||||
inline bool readNextBlock (std::fstream & stream, _ThreadData * threadData);
|
||||
|
||||
static const int NANO = 1000 * 1000 * 1000;
|
||||
static const int MAX_BLOB_HEADER_SIZE = 64 * 1024;
|
||||
static const int MAX_BLOB_SIZE = 32 * 1024 * 1024;
|
||||
|
||||
unsigned groupCount;
|
||||
unsigned blockCount;
|
||||
|
||||
std::fstream input; // the input stream to parse
|
||||
boost::shared_ptr<ConcurrentQueue < _ThreadData* > > threadDataQueue;
|
||||
};
|
||||
|
||||
#endif /* PBFPARSER_H_ */
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "ScriptingEnvironment.h"
|
||||
|
||||
#include "ExtractionHelperFunctions.h"
|
||||
#include "ExtractionWay.h"
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
#include "../Util/LuaUtil.h"
|
||||
#include "../Util/OpenMPWrapper.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
ScriptingEnvironment::ScriptingEnvironment() {}
|
||||
ScriptingEnvironment::ScriptingEnvironment(const char * fileName) {
|
||||
SimpleLogger().Write() << "Using script " << fileName;
|
||||
|
||||
// Create a new lua state
|
||||
for(int i = 0; i < omp_get_max_threads(); ++i) {
|
||||
luaStateVector.push_back(luaL_newstate());
|
||||
}
|
||||
|
||||
// Connect LuaBind to this lua state for all threads
|
||||
#pragma omp parallel
|
||||
{
|
||||
lua_State * myLuaState = getLuaStateForThreadID(omp_get_thread_num());
|
||||
luabind::open(myLuaState);
|
||||
//open utility libraries string library;
|
||||
luaL_openlibs(myLuaState);
|
||||
|
||||
luaAddScriptFolderToLoadPath( myLuaState, fileName );
|
||||
|
||||
// Add our function to the state's global scope
|
||||
luabind::module(myLuaState) [
|
||||
luabind::def("print", LUA_print<std::string>),
|
||||
luabind::def("durationIsValid", durationIsValid),
|
||||
luabind::def("parseDuration", parseDuration)
|
||||
];
|
||||
|
||||
luabind::module(myLuaState) [
|
||||
luabind::class_<HashTable<std::string, std::string> >("keyVals")
|
||||
.def("Add", &HashTable<std::string, std::string>::Add)
|
||||
.def("Find", &HashTable<std::string, std::string>::Find)
|
||||
.def("Holds", &HashTable<std::string, std::string>::Holds)
|
||||
];
|
||||
|
||||
luabind::module(myLuaState) [
|
||||
luabind::class_<ImportNode>("Node")
|
||||
.def(luabind::constructor<>())
|
||||
.def_readwrite("lat", &ImportNode::lat)
|
||||
.def_readwrite("lon", &ImportNode::lon)
|
||||
.def_readonly("id", &ImportNode::id)
|
||||
.def_readwrite("bollard", &ImportNode::bollard)
|
||||
.def_readwrite("traffic_light", &ImportNode::trafficLight)
|
||||
.def_readwrite("tags", &ImportNode::keyVals)
|
||||
];
|
||||
|
||||
luabind::module(myLuaState) [
|
||||
luabind::class_<ExtractionWay>("Way")
|
||||
.def(luabind::constructor<>())
|
||||
.def_readonly("id", &ExtractionWay::id)
|
||||
.def_readwrite("name", &ExtractionWay::name)
|
||||
.def_readwrite("speed", &ExtractionWay::speed)
|
||||
.def_readwrite("backward_speed", &ExtractionWay::backward_speed)
|
||||
.def_readwrite("duration", &ExtractionWay::duration)
|
||||
.def_readwrite("type", &ExtractionWay::type)
|
||||
.def_readwrite("access", &ExtractionWay::access)
|
||||
.def_readwrite("roundabout", &ExtractionWay::roundabout)
|
||||
.def_readwrite("is_access_restricted", &ExtractionWay::isAccessRestricted)
|
||||
.def_readwrite("ignore_in_grid", &ExtractionWay::ignoreInGrid)
|
||||
.def_readwrite("tags", &ExtractionWay::keyVals)
|
||||
.def_readwrite("direction", &ExtractionWay::direction)
|
||||
.enum_("constants") [
|
||||
luabind::value("notSure", 0),
|
||||
luabind::value("oneway", 1),
|
||||
luabind::value("bidirectional", 2),
|
||||
luabind::value("opposite", 3)
|
||||
]
|
||||
];
|
||||
|
||||
// fails on c++11/OS X 10.9
|
||||
luabind::module(myLuaState) [
|
||||
luabind::class_<std::vector<std::string> >("vector")
|
||||
.def("Add", static_cast<void (std::vector<std::string>::*)(const std::string&)>(&std::vector<std::string>::push_back))
|
||||
];
|
||||
|
||||
if(0 != luaL_dofile(myLuaState, fileName) ) {
|
||||
throw OSRMException("ERROR occured in scripting block");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScriptingEnvironment::~ScriptingEnvironment() {
|
||||
for(unsigned i = 0; i < luaStateVector.size(); ++i) {
|
||||
// luaStateVector[i];
|
||||
}
|
||||
}
|
||||
|
||||
lua_State * ScriptingEnvironment::getLuaStateForThreadID(const int id) {
|
||||
return luaStateVector[id];
|
||||
}
|
||||
@@ -1,348 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "XMLParser.h"
|
||||
|
||||
#include "ExtractionWay.h"
|
||||
#include "ExtractorCallbacks.h"
|
||||
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
#include "../DataStructures/InputReaderFactory.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/ref.hpp>
|
||||
|
||||
XMLParser::XMLParser(const char *filename, ExtractorCallbacks *ec, ScriptingEnvironment &se)
|
||||
: BaseParser(ec, se)
|
||||
{
|
||||
inputReader = inputReaderFactory(filename);
|
||||
}
|
||||
|
||||
bool XMLParser::ReadHeader() { return (xmlTextReaderRead(inputReader) == 1); }
|
||||
bool XMLParser::Parse()
|
||||
{
|
||||
while (xmlTextReaderRead(inputReader) == 1)
|
||||
{
|
||||
const int type = xmlTextReaderNodeType(inputReader);
|
||||
|
||||
// 1 is Element
|
||||
if (type != 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
xmlChar *currentName = xmlTextReaderName(inputReader);
|
||||
if (currentName == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(currentName, (const xmlChar *)"node") == 1)
|
||||
{
|
||||
ImportNode n = ReadXMLNode();
|
||||
ParseNodeInLua(n, lua_state);
|
||||
extractor_callbacks->nodeFunction(n);
|
||||
}
|
||||
|
||||
if (xmlStrEqual(currentName, (const xmlChar *)"way") == 1)
|
||||
{
|
||||
ExtractionWay way = ReadXMLWay();
|
||||
ParseWayInLua(way, lua_state);
|
||||
extractor_callbacks->wayFunction(way);
|
||||
}
|
||||
if (use_turn_restrictions && xmlStrEqual(currentName, (const xmlChar *)"relation") == 1)
|
||||
{
|
||||
InputRestrictionContainer r = ReadXMLRestriction();
|
||||
if ((UINT_MAX != r.fromWay) && !extractor_callbacks->restrictionFunction(r))
|
||||
{
|
||||
std::cerr << "[XMLParser] restriction not parsed" << std::endl;
|
||||
}
|
||||
}
|
||||
xmlFree(currentName);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
InputRestrictionContainer XMLParser::ReadXMLRestriction()
|
||||
{
|
||||
InputRestrictionContainer restriction;
|
||||
std::string except_tag_string;
|
||||
|
||||
if (xmlTextReaderIsEmptyElement(inputReader) != 1)
|
||||
{
|
||||
const int depth = xmlTextReaderDepth(inputReader);
|
||||
while (xmlTextReaderRead(inputReader) == 1)
|
||||
{
|
||||
const int childType = xmlTextReaderNodeType(inputReader);
|
||||
if (childType != 1 && childType != 15)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const int childDepth = xmlTextReaderDepth(inputReader);
|
||||
xmlChar *childName = xmlTextReaderName(inputReader);
|
||||
if (childName == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (depth == childDepth && childType == 15 &&
|
||||
xmlStrEqual(childName, (const xmlChar *)"relation") == 1)
|
||||
{
|
||||
xmlFree(childName);
|
||||
break;
|
||||
}
|
||||
if (childType != 1)
|
||||
{
|
||||
xmlFree(childName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(childName, (const xmlChar *)"tag") == 1)
|
||||
{
|
||||
xmlChar *k = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
|
||||
xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
|
||||
if (k != NULL && value != NULL)
|
||||
{
|
||||
if (xmlStrEqual(k, (const xmlChar *)"restriction") &&
|
||||
(0 == std::string((const char *)value).find("only_")))
|
||||
{
|
||||
restriction.restriction.flags.isOnly = true;
|
||||
}
|
||||
if (xmlStrEqual(k, (const xmlChar *)"except"))
|
||||
{
|
||||
except_tag_string = (const char *)value;
|
||||
}
|
||||
}
|
||||
|
||||
if (k != NULL)
|
||||
{
|
||||
xmlFree(k);
|
||||
}
|
||||
if (value != NULL)
|
||||
{
|
||||
xmlFree(value);
|
||||
}
|
||||
}
|
||||
else if (xmlStrEqual(childName, (const xmlChar *)"member") == 1)
|
||||
{
|
||||
xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref");
|
||||
if (ref != NULL)
|
||||
{
|
||||
xmlChar *role = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"role");
|
||||
xmlChar *type = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"type");
|
||||
|
||||
if (xmlStrEqual(role, (const xmlChar *)"to") &&
|
||||
xmlStrEqual(type, (const xmlChar *)"way"))
|
||||
{
|
||||
restriction.toWay = stringToUint((const char *)ref);
|
||||
}
|
||||
if (xmlStrEqual(role, (const xmlChar *)"from") &&
|
||||
xmlStrEqual(type, (const xmlChar *)"way"))
|
||||
{
|
||||
restriction.fromWay = stringToUint((const char *)ref);
|
||||
}
|
||||
if (xmlStrEqual(role, (const xmlChar *)"via") &&
|
||||
xmlStrEqual(type, (const xmlChar *)"node"))
|
||||
{
|
||||
restriction.restriction.viaNode = stringToUint((const char *)ref);
|
||||
}
|
||||
|
||||
if (NULL != type)
|
||||
{
|
||||
xmlFree(type);
|
||||
}
|
||||
if (NULL != role)
|
||||
{
|
||||
xmlFree(role);
|
||||
}
|
||||
if (NULL != ref)
|
||||
{
|
||||
xmlFree(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlFree(childName);
|
||||
}
|
||||
}
|
||||
|
||||
if (ShouldIgnoreRestriction(except_tag_string))
|
||||
{
|
||||
restriction.fromWay = UINT_MAX; // workaround to ignore the restriction
|
||||
}
|
||||
return restriction;
|
||||
}
|
||||
|
||||
ExtractionWay XMLParser::ReadXMLWay()
|
||||
{
|
||||
ExtractionWay way;
|
||||
if (xmlTextReaderIsEmptyElement(inputReader) != 1)
|
||||
{
|
||||
const int depth = xmlTextReaderDepth(inputReader);
|
||||
while (xmlTextReaderRead(inputReader) == 1)
|
||||
{
|
||||
const int childType = xmlTextReaderNodeType(inputReader);
|
||||
if (childType != 1 && childType != 15)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const int childDepth = xmlTextReaderDepth(inputReader);
|
||||
xmlChar *childName = xmlTextReaderName(inputReader);
|
||||
if (childName == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (depth == childDepth && childType == 15 &&
|
||||
xmlStrEqual(childName, (const xmlChar *)"way") == 1)
|
||||
{
|
||||
xmlChar *id = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id");
|
||||
way.id = stringToUint((char *)id);
|
||||
xmlFree(id);
|
||||
xmlFree(childName);
|
||||
break;
|
||||
}
|
||||
if (childType != 1)
|
||||
{
|
||||
xmlFree(childName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(childName, (const xmlChar *)"tag") == 1)
|
||||
{
|
||||
xmlChar *k = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
|
||||
xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
|
||||
|
||||
if (k != NULL && value != NULL)
|
||||
{
|
||||
way.keyVals.Add(std::string((char *)k), std::string((char *)value));
|
||||
}
|
||||
if (k != NULL)
|
||||
{
|
||||
xmlFree(k);
|
||||
}
|
||||
if (value != NULL)
|
||||
{
|
||||
xmlFree(value);
|
||||
}
|
||||
}
|
||||
else if (xmlStrEqual(childName, (const xmlChar *)"nd") == 1)
|
||||
{
|
||||
xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref");
|
||||
if (ref != NULL)
|
||||
{
|
||||
way.path.push_back(stringToUint((const char *)ref));
|
||||
xmlFree(ref);
|
||||
}
|
||||
}
|
||||
xmlFree(childName);
|
||||
}
|
||||
}
|
||||
return way;
|
||||
}
|
||||
|
||||
ImportNode XMLParser::ReadXMLNode()
|
||||
{
|
||||
ImportNode node;
|
||||
|
||||
xmlChar *attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"lat");
|
||||
if (attribute != NULL)
|
||||
{
|
||||
node.lat = COORDINATE_PRECISION * StringToDouble((const char *)attribute);
|
||||
xmlFree(attribute);
|
||||
}
|
||||
attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"lon");
|
||||
if (attribute != NULL)
|
||||
{
|
||||
node.lon = COORDINATE_PRECISION * StringToDouble((const char *)attribute);
|
||||
xmlFree(attribute);
|
||||
}
|
||||
attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id");
|
||||
if (attribute != NULL)
|
||||
{
|
||||
node.id = stringToUint((const char *)attribute);
|
||||
xmlFree(attribute);
|
||||
}
|
||||
|
||||
if (xmlTextReaderIsEmptyElement(inputReader) != 1)
|
||||
{
|
||||
const int depth = xmlTextReaderDepth(inputReader);
|
||||
while (xmlTextReaderRead(inputReader) == 1)
|
||||
{
|
||||
const int childType = xmlTextReaderNodeType(inputReader);
|
||||
// 1 = Element, 15 = EndElement
|
||||
if (childType != 1 && childType != 15)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const int childDepth = xmlTextReaderDepth(inputReader);
|
||||
xmlChar *childName = xmlTextReaderName(inputReader);
|
||||
if (childName == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (depth == childDepth && childType == 15 &&
|
||||
xmlStrEqual(childName, (const xmlChar *)"node") == 1)
|
||||
{
|
||||
xmlFree(childName);
|
||||
break;
|
||||
}
|
||||
if (childType != 1)
|
||||
{
|
||||
xmlFree(childName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(childName, (const xmlChar *)"tag") == 1)
|
||||
{
|
||||
xmlChar *k = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
|
||||
xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
|
||||
if (k != NULL && value != NULL)
|
||||
{
|
||||
node.keyVals.emplace(std::string((char *)(k)),
|
||||
std::string((char *)(value)));
|
||||
}
|
||||
if (k != NULL)
|
||||
{
|
||||
xmlFree(k);
|
||||
}
|
||||
if (value != NULL)
|
||||
{
|
||||
xmlFree(value);
|
||||
}
|
||||
}
|
||||
|
||||
xmlFree(childName);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
source "http://rubygems.org"
|
||||
|
||||
gem "cucumber"
|
||||
gem "rake"
|
||||
gem "osmlib-base"
|
||||
gem "sys-proctable"
|
||||
gem "rspec-expectations"
|
||||
@@ -1,30 +0,0 @@
|
||||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
builder (3.2.2)
|
||||
cucumber (1.3.8)
|
||||
builder (>= 2.1.2)
|
||||
diff-lcs (>= 1.1.3)
|
||||
gherkin (~> 2.12.1)
|
||||
multi_json (>= 1.7.5, < 2.0)
|
||||
multi_test (>= 0.0.2)
|
||||
diff-lcs (1.2.4)
|
||||
gherkin (2.12.1)
|
||||
multi_json (~> 1.3)
|
||||
multi_json (1.8.0)
|
||||
multi_test (0.0.2)
|
||||
osmlib-base (0.1.4)
|
||||
rake (10.1.0)
|
||||
rspec-expectations (2.14.3)
|
||||
diff-lcs (>= 1.1.3, < 2.0)
|
||||
sys-proctable (0.9.3)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
cucumber
|
||||
osmlib-base
|
||||
rake
|
||||
rspec-expectations
|
||||
sys-proctable
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef FIXED_POINT_COORDINATE_H_
|
||||
#define FIXED_POINT_COORDINATE_H_
|
||||
|
||||
#include <iosfwd> //for std::ostream
|
||||
|
||||
static const double COORDINATE_PRECISION = 1000000.;
|
||||
|
||||
struct FixedPointCoordinate {
|
||||
int lat;
|
||||
int lon;
|
||||
|
||||
FixedPointCoordinate();
|
||||
explicit FixedPointCoordinate( int lat, int lon);
|
||||
void Reset();
|
||||
bool isSet() const;
|
||||
bool isValid() const;
|
||||
bool operator==(const FixedPointCoordinate & other) const;
|
||||
|
||||
static double ApproximateDistance(
|
||||
const int lat1,
|
||||
const int lon1,
|
||||
const int lat2,
|
||||
const int lon2
|
||||
);
|
||||
|
||||
static double ApproximateDistance(
|
||||
const FixedPointCoordinate & c1,
|
||||
const FixedPointCoordinate & c2
|
||||
);
|
||||
|
||||
static double ApproximateEuclideanDistance(
|
||||
const FixedPointCoordinate & c1,
|
||||
const FixedPointCoordinate & c2
|
||||
);
|
||||
|
||||
static void convertInternalLatLonToString(
|
||||
const int value,
|
||||
std::string & output
|
||||
);
|
||||
|
||||
static void convertInternalCoordinateToString(
|
||||
const FixedPointCoordinate & coord,
|
||||
std::string & output
|
||||
);
|
||||
|
||||
static void convertInternalReversedCoordinateToString(
|
||||
const FixedPointCoordinate & coord,
|
||||
std::string & output
|
||||
);
|
||||
|
||||
void Output(std::ostream & out) const;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& o, FixedPointCoordinate const & c){
|
||||
c.Output(o);
|
||||
return o;
|
||||
}
|
||||
|
||||
#endif /* FIXED_POINT_COORDINATE_H_ */
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HTTP_HEADER_H
|
||||
#define HTTP_HEADER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace http {
|
||||
|
||||
struct Header {
|
||||
std::string name;
|
||||
std::string value;
|
||||
void Clear() {
|
||||
name.clear();
|
||||
value.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif //HTTP_HEADER_H
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef REPLY_H
|
||||
#define REPLY_H
|
||||
|
||||
#include "Header.h"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace http {
|
||||
|
||||
const char okHTML[] = "";
|
||||
const char badRequestHTML[] = "{\"status\": 400,\"status_message\":\"Bad Request\"}";
|
||||
const char internalServerErrorHTML[] = "{\"status\": 500,\"status_message\":\"Internal Server Error\"}";
|
||||
const char seperators[] = { ':', ' ' };
|
||||
const char crlf[] = { '\r', '\n' };
|
||||
const std::string okString = "HTTP/1.0 200 OK\r\n";
|
||||
const std::string badRequestString = "HTTP/1.0 400 Bad Request\r\n";
|
||||
const std::string internalServerErrorString = "HTTP/1.0 500 Internal Server Error\r\n";
|
||||
|
||||
class Reply {
|
||||
public:
|
||||
enum status_type {
|
||||
ok = 200,
|
||||
badRequest = 400,
|
||||
internalServerError = 500
|
||||
} status;
|
||||
|
||||
|
||||
std::vector<Header> headers;
|
||||
std::vector<boost::asio::const_buffer> toBuffers();
|
||||
std::vector<boost::asio::const_buffer> HeaderstoBuffers();
|
||||
std::vector<std::string> content;
|
||||
static Reply StockReply(status_type status);
|
||||
void setSize(const unsigned size);
|
||||
void SetUncompressedSize();
|
||||
|
||||
Reply();
|
||||
private:
|
||||
std::string ToString(Reply::status_type status);
|
||||
boost::asio::const_buffer ToBuffer(Reply::status_type status);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //REPLY_H
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ROUTE_PARAMETERS_H
|
||||
#define ROUTE_PARAMETERS_H
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/fusion/container/vector.hpp>
|
||||
#include <boost/fusion/sequence/intrinsic.hpp>
|
||||
#include <boost/fusion/include/at_c.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct RouteParameters {
|
||||
RouteParameters() :
|
||||
zoomLevel(18),
|
||||
printInstructions(false),
|
||||
alternateRoute(true),
|
||||
geometry(true),
|
||||
compression(true),
|
||||
deprecatedAPI(false),
|
||||
checkSum(-1)
|
||||
{ }
|
||||
|
||||
short zoomLevel;
|
||||
bool printInstructions;
|
||||
bool alternateRoute;
|
||||
bool geometry;
|
||||
bool compression;
|
||||
bool deprecatedAPI;
|
||||
unsigned checkSum;
|
||||
std::string service;
|
||||
std::string outputFormat;
|
||||
std::string jsonpParameter;
|
||||
std::string language;
|
||||
std::vector<std::string> hints;
|
||||
std::vector<FixedPointCoordinate> coordinates;
|
||||
|
||||
void setZoomLevel(const short i) {
|
||||
if (18 >= i && 0 <= i) {
|
||||
zoomLevel = i;
|
||||
}
|
||||
}
|
||||
|
||||
void setAlternateRouteFlag(const bool b) {
|
||||
alternateRoute = b;
|
||||
}
|
||||
|
||||
void setDeprecatedAPIFlag(const std::string &) {
|
||||
deprecatedAPI = true;
|
||||
}
|
||||
|
||||
void setChecksum(const unsigned c) {
|
||||
checkSum = c;
|
||||
}
|
||||
|
||||
void setInstructionFlag(const bool b) {
|
||||
printInstructions = b;
|
||||
}
|
||||
|
||||
void setService( const std::string & s) {
|
||||
service = s;
|
||||
}
|
||||
|
||||
void setOutputFormat(const std::string & s) {
|
||||
outputFormat = s;
|
||||
}
|
||||
|
||||
void setJSONpParameter(const std::string & s) {
|
||||
jsonpParameter = s;
|
||||
}
|
||||
|
||||
void addHint(const std::string & s) {
|
||||
hints.resize( coordinates.size() );
|
||||
if( !hints.empty() ) {
|
||||
hints.back() = s;
|
||||
}
|
||||
}
|
||||
|
||||
void setLanguage(const std::string & s) {
|
||||
language = s;
|
||||
}
|
||||
|
||||
void setGeometryFlag(const bool b) {
|
||||
geometry = b;
|
||||
}
|
||||
|
||||
void setCompressionFlag(const bool b) {
|
||||
compression = b;
|
||||
}
|
||||
|
||||
void addCoordinate(const boost::fusion::vector < double, double > & arg_) {
|
||||
int lat = COORDINATE_PRECISION*boost::fusion::at_c < 0 > (arg_);
|
||||
int lon = COORDINATE_PRECISION*boost::fusion::at_c < 1 > (arg_);
|
||||
coordinates.push_back(FixedPointCoordinate(lat, lon));
|
||||
}
|
||||
};
|
||||
|
||||
#endif /*ROUTE_PARAMETERS_H*/
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
Copyright (c) 2016, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OSRM_H
|
||||
#define OSRM_H
|
||||
|
||||
#include <osrm/Reply.h>
|
||||
#include <osrm/RouteParameters.h>
|
||||
#include <osrm/ServerPaths.h>
|
||||
|
||||
class OSRM_impl;
|
||||
|
||||
class OSRM {
|
||||
private:
|
||||
OSRM_impl * OSRM_pimpl_;
|
||||
public:
|
||||
explicit OSRM(
|
||||
const ServerPaths & paths,
|
||||
const bool use_shared_memory = false
|
||||
);
|
||||
~OSRM();
|
||||
void RunQuery(RouteParameters & route_parameters, http::Reply & reply);
|
||||
};
|
||||
|
||||
#endif // OSRM_H
|
||||
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "OSRM_impl.h"
|
||||
#include "OSRM.h"
|
||||
|
||||
#include "../Plugins/HelloWorldPlugin.h"
|
||||
#include "../Plugins/LocatePlugin.h"
|
||||
#include "../Plugins/NearestPlugin.h"
|
||||
#include "../Plugins/TimestampPlugin.h"
|
||||
#include "../Plugins/ViaRoutePlugin.h"
|
||||
|
||||
#include "../Server/DataStructures/BaseDataFacade.h"
|
||||
#include "../Server/DataStructures/InternalDataFacade.h"
|
||||
#include "../Server/DataStructures/SharedBarriers.h"
|
||||
#include "../Server/DataStructures/SharedDataFacade.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
OSRM_impl::OSRM_impl( const ServerPaths & server_paths, const bool use_shared_memory )
|
||||
:
|
||||
use_shared_memory(use_shared_memory)
|
||||
{
|
||||
if (use_shared_memory)
|
||||
{
|
||||
barrier = new SharedBarriers();
|
||||
query_data_facade = new SharedDataFacade<QueryEdge::EdgeData>( );
|
||||
}
|
||||
else
|
||||
{
|
||||
query_data_facade = new InternalDataFacade<QueryEdge::EdgeData>(
|
||||
server_paths
|
||||
);
|
||||
}
|
||||
|
||||
//The following plugins handle all requests.
|
||||
RegisterPlugin(
|
||||
new HelloWorldPlugin()
|
||||
);
|
||||
RegisterPlugin(
|
||||
new LocatePlugin<BaseDataFacade<QueryEdge::EdgeData> >(
|
||||
query_data_facade
|
||||
)
|
||||
);
|
||||
RegisterPlugin(
|
||||
new NearestPlugin<BaseDataFacade<QueryEdge::EdgeData> >(
|
||||
query_data_facade
|
||||
)
|
||||
);
|
||||
RegisterPlugin(
|
||||
new TimestampPlugin<BaseDataFacade<QueryEdge::EdgeData> >(
|
||||
query_data_facade
|
||||
)
|
||||
);
|
||||
RegisterPlugin(
|
||||
new ViaRoutePlugin<BaseDataFacade<QueryEdge::EdgeData> >(
|
||||
query_data_facade
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
OSRM_impl::~OSRM_impl() {
|
||||
BOOST_FOREACH(PluginMap::value_type & plugin_pointer, plugin_map) {
|
||||
delete plugin_pointer.second;
|
||||
}
|
||||
if( use_shared_memory ) {
|
||||
delete barrier;
|
||||
}
|
||||
}
|
||||
|
||||
void OSRM_impl::RegisterPlugin(BasePlugin * plugin) {
|
||||
SimpleLogger().Write() << "loaded plugin: " << plugin->GetDescriptor();
|
||||
if( plugin_map.find(plugin->GetDescriptor()) != plugin_map.end() ) {
|
||||
delete plugin_map.find(plugin->GetDescriptor())->second;
|
||||
}
|
||||
plugin_map.emplace(plugin->GetDescriptor(), plugin);
|
||||
}
|
||||
|
||||
void OSRM_impl::RunQuery(RouteParameters & route_parameters, http::Reply & reply) {
|
||||
const PluginMap::const_iterator & iter = plugin_map.find(
|
||||
route_parameters.service
|
||||
);
|
||||
|
||||
if(plugin_map.end() != iter) {
|
||||
reply.status = http::Reply::ok;
|
||||
if( use_shared_memory ) {
|
||||
// lock update pending
|
||||
boost::interprocess::scoped_lock<
|
||||
boost::interprocess::named_mutex
|
||||
> pending_lock(barrier->pending_update_mutex);
|
||||
|
||||
// lock query
|
||||
boost::interprocess::scoped_lock<
|
||||
boost::interprocess::named_mutex
|
||||
> query_lock(barrier->query_mutex);
|
||||
|
||||
// unlock update pending
|
||||
pending_lock.unlock();
|
||||
|
||||
// increment query count
|
||||
++(barrier->number_of_queries);
|
||||
|
||||
(static_cast<SharedDataFacade<QueryEdge::EdgeData>* >(query_data_facade))->CheckAndReloadFacade();
|
||||
}
|
||||
|
||||
iter->second->HandleRequest(route_parameters, reply );
|
||||
if( use_shared_memory ) {
|
||||
// lock query
|
||||
boost::interprocess::scoped_lock<
|
||||
boost::interprocess::named_mutex
|
||||
> query_lock(barrier->query_mutex);
|
||||
|
||||
// decrement query count
|
||||
--(barrier->number_of_queries);
|
||||
BOOST_ASSERT_MSG(
|
||||
0 <= barrier->number_of_queries,
|
||||
"invalid number of queries"
|
||||
);
|
||||
|
||||
// notify all processes that were waiting for this condition
|
||||
if (0 == barrier->number_of_queries) {
|
||||
barrier->no_running_queries_condition.notify_all();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
}
|
||||
}
|
||||
|
||||
// proxy code for compilation firewall
|
||||
|
||||
OSRM::OSRM(
|
||||
const ServerPaths & paths,
|
||||
const bool use_shared_memory
|
||||
) : OSRM_pimpl_(new OSRM_impl(paths, use_shared_memory)) { }
|
||||
|
||||
OSRM::~OSRM() {
|
||||
delete OSRM_pimpl_;
|
||||
}
|
||||
|
||||
void OSRM::RunQuery(RouteParameters & route_parameters, http::Reply & reply) {
|
||||
OSRM_pimpl_->RunQuery(route_parameters, reply);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OSRM_IMPL_H
|
||||
#define OSRM_IMPL_H
|
||||
|
||||
#include <osrm/Reply.h>
|
||||
#include <osrm/RouteParameters.h>
|
||||
#include <osrm/ServerPaths.h>
|
||||
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "../Plugins/BasePlugin.h"
|
||||
#include "../Util/ProgramOptions.h"
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
struct SharedBarriers;
|
||||
template<class EdgeDataT>
|
||||
class BaseDataFacade;
|
||||
|
||||
class OSRM_impl : boost::noncopyable {
|
||||
private:
|
||||
typedef boost::unordered_map<std::string, BasePlugin *> PluginMap;
|
||||
public:
|
||||
OSRM_impl(
|
||||
const ServerPaths & paths,
|
||||
const bool use_shared_memory
|
||||
);
|
||||
virtual ~OSRM_impl();
|
||||
void RunQuery(RouteParameters & route_parameters, http::Reply & reply);
|
||||
|
||||
private:
|
||||
void RegisterPlugin(BasePlugin * plugin);
|
||||
PluginMap plugin_map;
|
||||
bool use_shared_memory;
|
||||
SharedBarriers * barrier;
|
||||
//base class pointer to the objects
|
||||
BaseDataFacade<QueryEdge::EdgeData> * query_data_facade;
|
||||
};
|
||||
|
||||
#endif //OSRM_IMPL_H
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BASEPLUGIN_H_
|
||||
#define BASEPLUGIN_H_
|
||||
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
#include <osrm/Reply.h>
|
||||
#include <osrm/RouteParameters.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class BasePlugin {
|
||||
public:
|
||||
BasePlugin() { }
|
||||
//Maybe someone can explain the pure virtual destructor thing to me (dennis)
|
||||
virtual ~BasePlugin() { }
|
||||
virtual const std::string & GetDescriptor() const = 0;
|
||||
virtual void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) = 0;
|
||||
|
||||
inline bool checkCoord(const FixedPointCoordinate & c) {
|
||||
if(
|
||||
c.lat > 90*COORDINATE_PRECISION ||
|
||||
c.lat < -90*COORDINATE_PRECISION ||
|
||||
c.lon > 180*COORDINATE_PRECISION ||
|
||||
c.lon < -180*COORDINATE_PRECISION
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* BASEPLUGIN_H_ */
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HELLOWORLDPLUGIN_H_
|
||||
#define HELLOWORLDPLUGIN_H_
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class HelloWorldPlugin : public BasePlugin {
|
||||
private:
|
||||
std::string temp_string;
|
||||
public:
|
||||
HelloWorldPlugin() : descriptor_string("hello"){}
|
||||
virtual ~HelloWorldPlugin() { }
|
||||
const std::string & GetDescriptor() const { return descriptor_string; }
|
||||
|
||||
void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) {
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.push_back("<html><head><title>Hello World Demonstration Document</title></head><body><h1>Hello, World!</h1>");
|
||||
reply.content.push_back("<pre>");
|
||||
reply.content.push_back("zoom level: ");
|
||||
intToString(routeParameters.zoomLevel, temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
reply.content.push_back("\nchecksum: ");
|
||||
intToString(routeParameters.checkSum, temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
reply.content.push_back("\ninstructions: ");
|
||||
reply.content.push_back((routeParameters.printInstructions ? "yes" : "no"));
|
||||
reply.content.push_back(temp_string);
|
||||
reply.content.push_back("\ngeometry: ");
|
||||
reply.content.push_back((routeParameters.geometry ? "yes" : "no"));
|
||||
reply.content.push_back("\ncompression: ");
|
||||
reply.content.push_back((routeParameters.compression ? "yes" : "no"));
|
||||
reply.content.push_back("\noutput format: ");
|
||||
reply.content.push_back(routeParameters.outputFormat);
|
||||
reply.content.push_back("\njson parameter: ");
|
||||
reply.content.push_back(routeParameters.jsonpParameter);
|
||||
reply.content.push_back("\nlanguage: ");
|
||||
reply.content.push_back(routeParameters.language);
|
||||
reply.content.push_back("\nNumber of locations: ");
|
||||
intToString(routeParameters.coordinates.size(), temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
reply.content.push_back("\n");
|
||||
for(unsigned i = 0; i < routeParameters.coordinates.size(); ++i) {
|
||||
reply.content.push_back( " [");
|
||||
intToString(i, temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
reply.content.push_back("] ");
|
||||
doubleToString(routeParameters.coordinates[i].lat/COORDINATE_PRECISION, temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
reply.content.push_back(",");
|
||||
doubleToString(routeParameters.coordinates[i].lon/COORDINATE_PRECISION, temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
reply.content.push_back("\n");
|
||||
}
|
||||
reply.content.push_back( "Number of hints: ");
|
||||
intToString(routeParameters.hints.size(), temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
reply.content.push_back("\n");
|
||||
for(unsigned i = 0; i < routeParameters.hints.size(); ++i) {
|
||||
reply.content.push_back( " [");
|
||||
intToString(i, temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
reply.content.push_back("] ");
|
||||
reply.content.push_back(routeParameters.hints[i]);
|
||||
reply.content.push_back("\n");
|
||||
}
|
||||
reply.content.push_back( "</pre></body></html>");
|
||||
}
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
#endif /* HELLOWORLDPLUGIN_H_ */
|
||||
@@ -1,121 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef LOCATEPLUGIN_H_
|
||||
#define LOCATEPLUGIN_H_
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
//locates the nearest node in the road network for a given coordinate.
|
||||
|
||||
template<class DataFacadeT>
|
||||
class LocatePlugin : public BasePlugin {
|
||||
public:
|
||||
explicit LocatePlugin(DataFacadeT * facade)
|
||||
:
|
||||
descriptor_string("locate"),
|
||||
facade(facade)
|
||||
{ }
|
||||
const std::string & GetDescriptor() const { return descriptor_string; }
|
||||
|
||||
void HandleRequest(
|
||||
const RouteParameters & routeParameters,
|
||||
http::Reply& reply
|
||||
) {
|
||||
//check number of parameters
|
||||
if(!routeParameters.coordinates.size()) {
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
if(false == checkCoord(routeParameters.coordinates[0])) {
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
//query to helpdesk
|
||||
FixedPointCoordinate result;
|
||||
std::string tmp;
|
||||
//json
|
||||
|
||||
if(!routeParameters.jsonpParameter.empty()) {
|
||||
reply.content.push_back(routeParameters.jsonpParameter);
|
||||
reply.content.push_back("(");
|
||||
}
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.push_back ("{");
|
||||
if(
|
||||
!facade->LocateClosestEndPointForCoordinate(
|
||||
routeParameters.coordinates[0],
|
||||
result
|
||||
)
|
||||
) {
|
||||
reply.content.push_back ("\"status\":207,");
|
||||
reply.content.push_back ("\"mapped_coordinate\":[]");
|
||||
} else {
|
||||
//Write coordinate to stream
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.push_back ("\"status\":0,");
|
||||
reply.content.push_back ("\"mapped_coordinate\":");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(result.lat, tmp);
|
||||
reply.content.push_back("[");
|
||||
reply.content.push_back(tmp);
|
||||
FixedPointCoordinate::convertInternalLatLonToString(result.lon, tmp);
|
||||
reply.content.push_back(",");
|
||||
reply.content.push_back(tmp);
|
||||
reply.content.push_back("]");
|
||||
}
|
||||
reply.content.push_back("}");
|
||||
reply.headers.resize(3);
|
||||
if(!routeParameters.jsonpParameter.empty()) {
|
||||
reply.content.push_back( ")");
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.js\"";
|
||||
} else {
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.json\"";
|
||||
}
|
||||
reply.headers[0].name = "Content-Length";
|
||||
unsigned content_length = 0;
|
||||
BOOST_FOREACH(const std::string & snippet, reply.content) {
|
||||
content_length += snippet.length();
|
||||
}
|
||||
intToString(content_length, tmp);
|
||||
reply.headers[0].value = tmp;
|
||||
return;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
DataFacadeT * facade;
|
||||
};
|
||||
|
||||
#endif /* LOCATEPLUGIN_H_ */
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef NEAREST_PLUGIN_H
|
||||
#define NEAREST_PLUGIN_H
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "../DataStructures/PhantomNodes.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
/*
|
||||
* This Plugin locates the nearest point on a street in the road network for a given coordinate.
|
||||
*/
|
||||
|
||||
template<class DataFacadeT>
|
||||
class NearestPlugin : public BasePlugin {
|
||||
public:
|
||||
explicit NearestPlugin(DataFacadeT * facade )
|
||||
:
|
||||
facade(facade),
|
||||
descriptor_string("nearest")
|
||||
{
|
||||
descriptorTable.emplace("", 0); //default descriptor
|
||||
descriptorTable.emplace("json", 1);
|
||||
}
|
||||
const std::string & GetDescriptor() const { return descriptor_string; }
|
||||
void HandleRequest(
|
||||
const RouteParameters & routeParameters,
|
||||
http::Reply & reply
|
||||
) {
|
||||
//check number of parameters
|
||||
if(!routeParameters.coordinates.size()) {
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
if( !checkCoord(routeParameters.coordinates[0]) ) {
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
PhantomNode result;
|
||||
facade->FindPhantomNodeForCoordinate(
|
||||
routeParameters.coordinates[0],
|
||||
result,
|
||||
routeParameters.zoomLevel
|
||||
);
|
||||
|
||||
std::string temp_string;
|
||||
//json
|
||||
|
||||
if("" != routeParameters.jsonpParameter) {
|
||||
reply.content.push_back(routeParameters.jsonpParameter);
|
||||
reply.content.push_back("(");
|
||||
}
|
||||
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.push_back("{\"status\":");
|
||||
if(UINT_MAX != result.forward_node_id) {
|
||||
reply.content.push_back("0,");
|
||||
} else {
|
||||
reply.content.push_back("207,");
|
||||
}
|
||||
reply.content.push_back("\"mapped_coordinate\":[");
|
||||
if(UINT_MAX != result.forward_node_id) {
|
||||
FixedPointCoordinate::convertInternalLatLonToString(result.location.lat, temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
FixedPointCoordinate::convertInternalLatLonToString(result.location.lon, temp_string);
|
||||
reply.content.push_back(",");
|
||||
reply.content.push_back(temp_string);
|
||||
}
|
||||
reply.content.push_back("],\"name\":\"");
|
||||
if(UINT_MAX != result.forward_node_id) {
|
||||
facade->GetName(result.name_id, temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
}
|
||||
reply.content.push_back("\"}");
|
||||
reply.headers.resize(3);
|
||||
if( !routeParameters.jsonpParameter.empty() ) {
|
||||
reply.content.push_back(")");
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.js\"";
|
||||
} else {
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.json\"";
|
||||
}
|
||||
reply.headers[0].name = "Content-Length";
|
||||
unsigned content_length = 0;
|
||||
BOOST_FOREACH(const std::string & snippet, reply.content) {
|
||||
content_length += snippet.length();
|
||||
}
|
||||
intToString(content_length, temp_string);
|
||||
reply.headers[0].value = temp_string;
|
||||
}
|
||||
|
||||
private:
|
||||
DataFacadeT * facade;
|
||||
boost::unordered_map<std::string, unsigned> descriptorTable;
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
#endif /* NEAREST_PLUGIN_H */
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TIMESTAMPPLUGIN_H_
|
||||
#define TIMESTAMPPLUGIN_H_
|
||||
|
||||
#include "BasePlugin.h"
|
||||
|
||||
template<class DataFacadeT>
|
||||
class TimestampPlugin : public BasePlugin {
|
||||
public:
|
||||
explicit TimestampPlugin(const DataFacadeT * facade)
|
||||
: facade(facade), descriptor_string("timestamp")
|
||||
{ }
|
||||
const std::string & GetDescriptor() const { return descriptor_string; }
|
||||
void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) {
|
||||
std::string tmp;
|
||||
|
||||
//json
|
||||
if("" != routeParameters.jsonpParameter) {
|
||||
reply.content.push_back(routeParameters.jsonpParameter);
|
||||
reply.content.push_back("(");
|
||||
}
|
||||
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.push_back("{");
|
||||
reply.content.push_back("\"status\":");
|
||||
reply.content.push_back("0,");
|
||||
reply.content.push_back("\"timestamp\":\"");
|
||||
reply.content.push_back(facade->GetTimestamp());
|
||||
reply.content.push_back("\"");
|
||||
reply.content.push_back("}");
|
||||
reply.headers.resize(3);
|
||||
if("" != routeParameters.jsonpParameter) {
|
||||
reply.content.push_back(")");
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"timestamp.js\"";
|
||||
} else {
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"timestamp.json\"";
|
||||
}
|
||||
unsigned content_length = 0;
|
||||
BOOST_FOREACH(const std::string & snippet, reply.content) {
|
||||
content_length += snippet.length();
|
||||
}
|
||||
intToString(content_length, tmp);
|
||||
reply.headers[0].value = tmp;
|
||||
}
|
||||
private:
|
||||
const DataFacadeT * facade;
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
#endif /* TIMESTAMPPLUGIN_H_ */
|
||||
@@ -1,226 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef VIAROUTEPLUGIN_H_
|
||||
#define VIAROUTEPLUGIN_H_
|
||||
|
||||
#include "BasePlugin.h"
|
||||
|
||||
#include "../Algorithms/ObjectToBase64.h"
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "../DataStructures/SearchEngine.h"
|
||||
#include "../Descriptors/BaseDescriptor.h"
|
||||
#include "../Descriptors/GPXDescriptor.h"
|
||||
#include "../Descriptors/JSONDescriptor.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template<class DataFacadeT>
|
||||
class ViaRoutePlugin : public BasePlugin {
|
||||
private:
|
||||
boost::unordered_map<std::string, unsigned> descriptorTable;
|
||||
boost::shared_ptr<SearchEngine<DataFacadeT> > search_engine_ptr;
|
||||
public:
|
||||
|
||||
explicit ViaRoutePlugin(DataFacadeT * facade)
|
||||
:
|
||||
descriptor_string("viaroute"),
|
||||
facade(facade)
|
||||
{
|
||||
search_engine_ptr = boost::make_shared<SearchEngine<DataFacadeT> >(facade);
|
||||
|
||||
descriptorTable.emplace("json", 0);
|
||||
descriptorTable.emplace("gpx" , 1);
|
||||
}
|
||||
|
||||
virtual ~ViaRoutePlugin() { }
|
||||
|
||||
const std::string & GetDescriptor() const { return descriptor_string; }
|
||||
|
||||
void HandleRequest(
|
||||
const RouteParameters & routeParameters,
|
||||
http::Reply& reply
|
||||
) {
|
||||
//check number of parameters
|
||||
if( 2 > routeParameters.coordinates.size() ) {
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
RawRouteData raw_route;
|
||||
raw_route.checkSum = facade->GetCheckSum();
|
||||
const bool checksumOK = (routeParameters.checkSum == raw_route.checkSum);
|
||||
std::vector<std::string> textCoord;
|
||||
for(unsigned i = 0; i < routeParameters.coordinates.size(); ++i) {
|
||||
if( !checkCoord(routeParameters.coordinates[i]) ) {
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
raw_route.rawViaNodeCoordinates.push_back(routeParameters.coordinates[i]);
|
||||
}
|
||||
std::vector<PhantomNode> phantomNodeVector(raw_route.rawViaNodeCoordinates.size());
|
||||
for(unsigned i = 0; i < raw_route.rawViaNodeCoordinates.size(); ++i) {
|
||||
if(checksumOK && i < routeParameters.hints.size() && "" != routeParameters.hints[i]) {
|
||||
DecodeObjectFromBase64(routeParameters.hints[i], phantomNodeVector[i]);
|
||||
if(phantomNodeVector[i].isValid(facade->GetNumberOfNodes())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
facade->FindPhantomNodeForCoordinate(
|
||||
raw_route.rawViaNodeCoordinates[i],
|
||||
phantomNodeVector[i],
|
||||
routeParameters.zoomLevel
|
||||
);
|
||||
}
|
||||
|
||||
PhantomNodes current_phantom_node_pair;
|
||||
for (unsigned i = 0; i < phantomNodeVector.size()-1; ++i)
|
||||
{
|
||||
current_phantom_node_pair.source_phantom = phantomNodeVector[i];
|
||||
current_phantom_node_pair.target_phantom = phantomNodeVector[i+1];
|
||||
raw_route.segmentEndCoordinates.push_back(current_phantom_node_pair);
|
||||
}
|
||||
|
||||
if ((routeParameters.alternateRoute) && (1 == raw_route.segmentEndCoordinates.size()))
|
||||
{
|
||||
search_engine_ptr->alternative_path(raw_route.segmentEndCoordinates[0], raw_route);
|
||||
}
|
||||
else
|
||||
{
|
||||
search_engine_ptr->shortest_path(raw_route.segmentEndCoordinates, raw_route);
|
||||
}
|
||||
|
||||
if (INT_MAX == raw_route.lengthOfShortestPath)
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found";
|
||||
}
|
||||
reply.status = http::Reply::ok;
|
||||
|
||||
if (!routeParameters.jsonpParameter.empty())
|
||||
{
|
||||
reply.content.push_back(routeParameters.jsonpParameter);
|
||||
reply.content.push_back("(");
|
||||
}
|
||||
|
||||
DescriptorConfig descriptor_config;
|
||||
|
||||
unsigned descriptor_type = 0;
|
||||
if(descriptorTable.find(routeParameters.outputFormat) != descriptorTable.end() ) {
|
||||
descriptor_type = descriptorTable.find(routeParameters.outputFormat)->second;
|
||||
}
|
||||
descriptor_config.zoom_level = routeParameters.zoomLevel;
|
||||
descriptor_config.instructions = routeParameters.printInstructions;
|
||||
descriptor_config.geometry = routeParameters.geometry;
|
||||
descriptor_config.encode_geometry = routeParameters.compression;
|
||||
|
||||
boost::shared_ptr<BaseDescriptor<DataFacadeT> > descriptor;
|
||||
switch(descriptor_type){
|
||||
case 0:
|
||||
descriptor = boost::make_shared<JSONDescriptor<DataFacadeT> >();
|
||||
break;
|
||||
case 1:
|
||||
descriptor = boost::make_shared<GPXDescriptor<DataFacadeT> >();
|
||||
break;
|
||||
default:
|
||||
descriptor = boost::make_shared<JSONDescriptor<DataFacadeT> >();
|
||||
break;
|
||||
}
|
||||
|
||||
PhantomNodes phantom_nodes;
|
||||
phantom_nodes.source_phantom = raw_route.segmentEndCoordinates[0].source_phantom;
|
||||
phantom_nodes.target_phantom = raw_route.segmentEndCoordinates[raw_route.segmentEndCoordinates.size()-1].target_phantom;
|
||||
descriptor->SetConfig(descriptor_config);
|
||||
|
||||
descriptor->Run(raw_route, phantom_nodes, facade, reply);
|
||||
|
||||
if (!routeParameters.jsonpParameter.empty())
|
||||
{
|
||||
reply.content.push_back(")\n");
|
||||
}
|
||||
reply.headers.resize(3);
|
||||
reply.headers[0].name = "Content-Length";
|
||||
unsigned content_length = 0;
|
||||
BOOST_FOREACH(const std::string & snippet, reply.content) {
|
||||
content_length += snippet.length();
|
||||
}
|
||||
std::string tmp_string;
|
||||
intToString(content_length, tmp_string);
|
||||
reply.headers[0].value = tmp_string;
|
||||
switch(descriptor_type){
|
||||
case 0:
|
||||
if( !routeParameters.jsonpParameter.empty() ){
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.js\"";
|
||||
} else {
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.json\"";
|
||||
}
|
||||
|
||||
break;
|
||||
case 1:
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/gpx+xml; charset=UTF-8";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.gpx\"";
|
||||
|
||||
break;
|
||||
default:
|
||||
if( !routeParameters.jsonpParameter.empty() ){
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.js\"";
|
||||
} else {
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.json\"";
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
DataFacadeT * facade;
|
||||
};
|
||||
|
||||
|
||||
#endif /* VIAROUTEPLUGIN_H_ */
|
||||
@@ -1,12 +1,63 @@
|
||||
# Readme
|
||||
## About
|
||||
|
||||
For instructions on how to compile and run OSRM, please consult the Wiki at
|
||||
The Open Source Routing Machine is a high performance routing engine written in C++11 designed to run on OpenStreetMap data.
|
||||
|
||||
https://github.com/DennisOSRM/Project-OSRM/wiki
|
||||
## Current build status
|
||||
|
||||
or use our free and daily updated online service at
|
||||
| build config | status |
|
||||
|:-------------|:-------|
|
||||
| Linux | [](https://travis-ci.org/Project-OSRM/osrm-backend) |
|
||||
| Windows | [](https://ci.appveyor.com/project/DennisOSRM/osrm-backend) |
|
||||
| Coverage | [](https://codecov.io/gh/Project-OSRM/osrm-backend) |
|
||||
|
||||
http://map.project-osrm.org
|
||||
## Building
|
||||
|
||||
For instructions on how to [build](https://github.com/Project-OSRM/osrm-backend/wiki/Building-OSRM) and [run OSRM](https://github.com/Project-OSRM/osrm-backend/wiki/Running-OSRM), please consult [the Wiki](https://github.com/Project-OSRM/osrm-backend/wiki).
|
||||
|
||||
To quickly try OSRM use our [free and daily updated online service](http://map.project-osrm.org)
|
||||
|
||||
## Documentation
|
||||
|
||||
### Full documentation
|
||||
|
||||
- [osrm-routed HTTP API documentation](docs/http.md)
|
||||
- [libosrm API documentation](docs/libosrm.md)
|
||||
|
||||
### Quick start
|
||||
|
||||
Building OSRM assuming all dependencies are installed:
|
||||
|
||||
```
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build .
|
||||
sudo cmake --build . --target install
|
||||
```
|
||||
|
||||
Loading preparing a dataset and starting the server:
|
||||
|
||||
```
|
||||
osrm-extract data.osm.pbf -p profiles/car.lua
|
||||
osrm-contract data.osrm
|
||||
osrm-routed data.osrm
|
||||
```
|
||||
|
||||
Running a query on your local server:
|
||||
|
||||
```
|
||||
curl http://127.0.0.1:5000/13.388860,52.517037;13.385983,52.496891?steps=true&alternatives=true
|
||||
```
|
||||
|
||||
### Running a request against the Demo Server
|
||||
|
||||
First read the [API usage policy](https://github.com/Project-OSRM/osrm-backend/wiki/Api-usage-policy).
|
||||
|
||||
Then run simple query with instructions and alternatives on Berlin:
|
||||
|
||||
```
|
||||
curl https://router.project-osrm.org/13.388860,52.517037;13.385983,52.496891?steps=true&alternatives=true
|
||||
```
|
||||
|
||||
## References in publications
|
||||
|
||||
@@ -31,10 +82,3 @@ When using the code in a (scientific) publication, please cite
|
||||
}
|
||||
```
|
||||
|
||||
## Current build status
|
||||
|
||||
| build config | branch | status |
|
||||
|:-------------|:--------|:------------|
|
||||
| Project OSRM | master | [](https://travis-ci.org/DennisOSRM/Project-OSRM) |
|
||||
| Project OSRM | develop | [](https://travis-ci.org/DennisOSRM/Project-OSRM) |
|
||||
| LUAbind fork | master | [](https://travis-ci.org/DennisOSRM/luabind) |
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
require 'OSM/StreamParser'
|
||||
require 'socket'
|
||||
require 'digest/sha1'
|
||||
require 'cucumber/rake/task'
|
||||
require 'sys/proctable'
|
||||
|
||||
BUILD_FOLDER = 'build'
|
||||
DATA_FOLDER = 'sandbox'
|
||||
PROFILE = 'examples/postgis'
|
||||
OSRM_PORT = 5000
|
||||
PROFILES_FOLDER = '../profiles'
|
||||
|
||||
Cucumber::Rake::Task.new do |t|
|
||||
t.cucumber_opts = %w{--format pretty}
|
||||
end
|
||||
|
||||
areas = {
|
||||
:kbh => { :country => 'denmark', :bbox => 'top=55.6972 left=12.5222 right=12.624 bottom=55.6376' },
|
||||
:frd => { :country => 'denmark', :bbox => 'top=55.7007 left=12.4765 bottom=55.6576 right=12.5698' },
|
||||
:regh => { :country => 'denmark', :bbox => 'top=56.164 left=11.792 bottom=55.403 right=12.731' },
|
||||
:denmark => { :country => 'denmark', :bbox => nil },
|
||||
:skaane => { :country => 'sweden', :bbox => 'top=56.55 left=12.4 bottom=55.3 right=14.6' }
|
||||
}
|
||||
|
||||
|
||||
|
||||
osm_data_area_name = ARGV[1] ? ARGV[1].to_s.to_sym : :kbh
|
||||
raise "Unknown data area." unless areas[osm_data_area_name]
|
||||
osm_data_country = areas[osm_data_area_name][:country]
|
||||
osm_data_area_bbox = areas[osm_data_area_name][:bbox]
|
||||
|
||||
|
||||
task osm_data_area_name.to_sym {} #define empty task to prevent rake from whining. will break if area has same name as a task
|
||||
|
||||
|
||||
def each_process name, &block
|
||||
Sys::ProcTable.ps do |process|
|
||||
if process.comm.strip == name.strip && process.state != 'zombie'
|
||||
yield process.pid.to_i, process.state.strip
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def up?
|
||||
find_pid('osrm-routed') != nil
|
||||
end
|
||||
|
||||
def find_pid name
|
||||
each_process(name) { |pid,state| return pid.to_i }
|
||||
return nil
|
||||
end
|
||||
|
||||
def wait_for_shutdown name
|
||||
timeout = 10
|
||||
(timeout*10).times do
|
||||
return if find_pid(name) == nil
|
||||
sleep 0.1
|
||||
end
|
||||
raise "*** Could not terminate #{name}."
|
||||
end
|
||||
|
||||
|
||||
desc "Rebuild and run tests."
|
||||
task :default => [:build]
|
||||
|
||||
desc "Build using CMake."
|
||||
task :build do
|
||||
if Dir.exists? BUILD_FOLDER
|
||||
Dir.chdir BUILD_FOLDER do
|
||||
system "make"
|
||||
end
|
||||
else
|
||||
system "mkdir build; cd build; cmake ..; make"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Setup config files."
|
||||
task :setup do
|
||||
end
|
||||
|
||||
desc "Download OSM data."
|
||||
task :download do
|
||||
Dir.mkdir "#{DATA_FOLDER}" unless File.exist? "#{DATA_FOLDER}"
|
||||
puts "Downloading..."
|
||||
puts "curl http://download.geofabrik.de/europe/#{osm_data_country}-latest.osm.pbf -o #{DATA_FOLDER}/#{osm_data_country}.osm.pbf"
|
||||
raise "Error while downloading data." unless system "curl http://download.geofabrik.de/europe/#{osm_data_country}-latest.osm.pbf -o #{DATA_FOLDER}/#{osm_data_country}.osm.pbf"
|
||||
if osm_data_area_bbox
|
||||
puts "Cropping and converting to protobuffer..."
|
||||
raise "Error while cropping data." unless system "osmosis --read-pbf file=#{DATA_FOLDER}/#{osm_data_country}.osm.pbf --bounding-box #{osm_data_area_bbox} --write-pbf file=#{DATA_FOLDER}/#{osm_data_area_name}.osm.pbf omitmetadata=true"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Crop OSM data"
|
||||
task :crop do
|
||||
if osm_data_area_bbox
|
||||
raise "Error while cropping data." unless system "osmosis --read-pbf file=#{DATA_FOLDER}/#{osm_data_country}.osm.pbf --bounding-box #{osm_data_area_bbox} --write-pbf file=#{DATA_FOLDER}/#{osm_data_area_name}.osm.pbf omitmetadata=true"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Reprocess OSM data."
|
||||
task :process => [:extract,:prepare] do
|
||||
end
|
||||
|
||||
desc "Extract OSM data."
|
||||
task :extract do
|
||||
Dir.chdir DATA_FOLDER do
|
||||
raise "Error while extracting data." unless system "../#{BUILD_FOLDER}/osrm-extract #{osm_data_area_name}.osm.pbf --profile ../profiles/#{PROFILE}.lua"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Prepare OSM data."
|
||||
task :prepare do
|
||||
Dir.chdir DATA_FOLDER do
|
||||
raise "Error while preparing data." unless system "../#{BUILD_FOLDER}/osrm-prepare #{osm_data_area_name}.osrm --profile ../profiles/#{PROFILE}.lua"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Delete preprocessing files."
|
||||
task :clean do
|
||||
File.delete *Dir.glob("#{DATA_FOLDER}/*.osrm")
|
||||
File.delete *Dir.glob("#{DATA_FOLDER}/*.osrm.*")
|
||||
end
|
||||
|
||||
desc "Run all cucumber test"
|
||||
task :test do
|
||||
system "cucumber"
|
||||
puts
|
||||
end
|
||||
|
||||
desc "Run the routing server in the terminal. Press Ctrl-C to stop."
|
||||
task :run do
|
||||
Dir.chdir DATA_FOLDER do
|
||||
system "../#{BUILD_FOLDER}/osrm-routed #{osm_data_area_name}.osrm --port #{OSRM_PORT}"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Launch the routing server in the background. Use rake:down to stop it."
|
||||
task :up do
|
||||
Dir.chdir DATA_FOLDER do
|
||||
abort("Already up.") if up?
|
||||
pipe = IO.popen("../#{BUILD_FOLDER}/osrm-routed #{osm_data_area_name}.osrm --port #{OSRM_PORT} 1>>osrm-routed.log 2>>osrm-routed.log")
|
||||
timeout = 5
|
||||
(timeout*10).times do
|
||||
begin
|
||||
socket = TCPSocket.new('localhost', OSRM_PORT)
|
||||
socket.puts 'ping'
|
||||
rescue Errno::ECONNREFUSED
|
||||
sleep 0.1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc "Stop the routing server."
|
||||
task :down do
|
||||
pid = find_pid 'osrm-routed'
|
||||
if pid
|
||||
Process.kill 'TERM', pid
|
||||
else
|
||||
puts "Already down."
|
||||
end
|
||||
end
|
||||
|
||||
desc "Kill all osrm-extract, osrm-prepare and osrm-routed processes."
|
||||
task :kill do
|
||||
each_process('osrm-routed') { |pid,state| Process.kill 'KILL', pid }
|
||||
each_process('osrm-prepare') { |pid,state| Process.kill 'KILL', pid }
|
||||
each_process('osrm-extract') { |pid,state| Process.kill 'KILL', pid }
|
||||
wait_for_shutdown 'osrm-routed'
|
||||
wait_for_shutdown 'osrm-prepare'
|
||||
wait_for_shutdown 'osrm-extract'
|
||||
end
|
||||
|
||||
desc "Get PIDs of all osrm-extract, osrm-prepare and osrm-routed processes."
|
||||
task :pid do
|
||||
each_process 'osrm-routed' do |pid,state|
|
||||
puts "#{pid}\t#{state}"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Stop, reprocess and restart."
|
||||
task :update => [:down,:process,:up] do
|
||||
end
|
||||
@@ -1,879 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ALTERNATIVE_PATH_ROUTING_H
|
||||
#define ALTERNATIVE_PATH_ROUTING_H
|
||||
|
||||
#include "BasicRoutingInterface.h"
|
||||
#include "../DataStructures/SearchEngineData.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
const double VIAPATH_ALPHA = 0.10;
|
||||
const double VIAPATH_EPSILON = 0.15; // alternative at most 15% longer
|
||||
const double VIAPATH_GAMMA = 0.75; // alternative shares at most 75% with the shortest.
|
||||
|
||||
template<class DataFacadeT>
|
||||
class AlternativeRouting : private BasicRoutingInterface<DataFacadeT> {
|
||||
typedef BasicRoutingInterface<DataFacadeT> super;
|
||||
typedef typename DataFacadeT::EdgeData EdgeData;
|
||||
typedef SearchEngineData::QueryHeap QueryHeap;
|
||||
typedef std::pair<NodeID, NodeID> SearchSpaceEdge;
|
||||
|
||||
struct RankedCandidateNode
|
||||
{
|
||||
RankedCandidateNode(const NodeID node, const int length, const int sharing)
|
||||
: node(node), length(length), sharing(sharing)
|
||||
{ }
|
||||
|
||||
NodeID node;
|
||||
int length;
|
||||
int sharing;
|
||||
|
||||
bool operator<(const RankedCandidateNode& other) const
|
||||
{
|
||||
return (2*length + sharing) < (2*other.length + other.sharing);
|
||||
}
|
||||
};
|
||||
DataFacadeT * facade;
|
||||
SearchEngineData & engine_working_data;
|
||||
public:
|
||||
|
||||
AlternativeRouting(
|
||||
DataFacadeT * facade,
|
||||
SearchEngineData & engine_working_data
|
||||
) :
|
||||
super(facade),
|
||||
facade(facade),
|
||||
engine_working_data(engine_working_data)
|
||||
{ }
|
||||
|
||||
virtual ~AlternativeRouting() {}
|
||||
|
||||
void operator() (
|
||||
const PhantomNodes & phantom_node_pair,
|
||||
RawRouteData & raw_route_data
|
||||
) {
|
||||
if( //phantom_node_pair.AtLeastOnePhantomNodeIsInvalid() ||
|
||||
phantom_node_pair.PhantomNodesHaveEqualLocation()
|
||||
) {
|
||||
// raw_route_data.lengthOfShortestPath = INVALID_EDGE_WEIGHT;
|
||||
// raw_route_data.lengthOfAlternativePath = INVALID_EDGE_WEIGHT;
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<NodeID> alternative_path;
|
||||
std::vector<NodeID> via_node_candidate_list;
|
||||
std::vector<SearchSpaceEdge> forward_search_space;
|
||||
std::vector<SearchSpaceEdge> reverse_search_space;
|
||||
|
||||
//Init queues, semi-expensive because access to TSS invokes a sys-call
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes()
|
||||
);
|
||||
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes()
|
||||
);
|
||||
engine_working_data.InitializeOrClearThirdThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes()
|
||||
);
|
||||
|
||||
QueryHeap & forward_heap1 = *(engine_working_data.forwardHeap);
|
||||
QueryHeap & reverse_heap1 = *(engine_working_data.backwardHeap);
|
||||
QueryHeap & forward_heap2 = *(engine_working_data.forwardHeap2);
|
||||
QueryHeap & reverse_heap2 = *(engine_working_data.backwardHeap2);
|
||||
|
||||
int upper_bound_to_shortest_path_distance = INVALID_EDGE_WEIGHT;
|
||||
NodeID middle_node = SPECIAL_NODEID;
|
||||
if(phantom_node_pair.source_phantom.forward_node_id != SPECIAL_NODEID ) {
|
||||
// SimpleLogger().Write(logDEBUG) << "fwd-a insert: " << phantom_node_pair.source_phantom.forward_node_id << ", w: " << -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset();
|
||||
forward_heap1.Insert(
|
||||
phantom_node_pair.source_phantom.forward_node_id,
|
||||
-phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
|
||||
phantom_node_pair.source_phantom.forward_node_id
|
||||
);
|
||||
}
|
||||
if(phantom_node_pair.source_phantom.reverse_node_id != SPECIAL_NODEID ) {
|
||||
// SimpleLogger().Write(logDEBUG) << "fwd-b insert: " << phantom_node_pair.source_phantom.reverse_node_id << ", w: " << -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset();
|
||||
forward_heap1.Insert(
|
||||
phantom_node_pair.source_phantom.reverse_node_id,
|
||||
-phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
|
||||
phantom_node_pair.source_phantom.reverse_node_id
|
||||
);
|
||||
}
|
||||
|
||||
if(phantom_node_pair.target_phantom.forward_node_id != SPECIAL_NODEID ) {
|
||||
// SimpleLogger().Write(logDEBUG) << "rev-a insert: " << phantom_node_pair.target_phantom.forward_node_id << ", w: " << phantom_node_pair.target_phantom.GetForwardWeightPlusOffset();
|
||||
reverse_heap1.Insert(
|
||||
phantom_node_pair.target_phantom.forward_node_id,
|
||||
phantom_node_pair.target_phantom.GetForwardWeightPlusOffset(),
|
||||
phantom_node_pair.target_phantom.forward_node_id
|
||||
);
|
||||
}
|
||||
if(phantom_node_pair.target_phantom.reverse_node_id != SPECIAL_NODEID ) {
|
||||
// SimpleLogger().Write(logDEBUG) << "rev-b insert: " << phantom_node_pair.target_phantom.reverse_node_id << ", w: " << phantom_node_pair.target_phantom.GetReverseWeightPlusOffset();
|
||||
reverse_heap1.Insert(
|
||||
phantom_node_pair.target_phantom.reverse_node_id,
|
||||
phantom_node_pair.target_phantom.GetReverseWeightPlusOffset(),
|
||||
phantom_node_pair.target_phantom.reverse_node_id
|
||||
);
|
||||
}
|
||||
|
||||
//search from s and t till new_min/(1+epsilon) > length_of_shortest_path
|
||||
while(0 < (forward_heap1.Size() + reverse_heap1.Size())){
|
||||
if(0 < forward_heap1.Size()){
|
||||
AlternativeRoutingStep<true>(
|
||||
forward_heap1,
|
||||
reverse_heap1,
|
||||
&middle_node,
|
||||
&upper_bound_to_shortest_path_distance,
|
||||
via_node_candidate_list,
|
||||
forward_search_space
|
||||
);
|
||||
}
|
||||
if(0 < reverse_heap1.Size()){
|
||||
AlternativeRoutingStep<false>(
|
||||
reverse_heap1,
|
||||
forward_heap1,
|
||||
&middle_node,
|
||||
&upper_bound_to_shortest_path_distance,
|
||||
via_node_candidate_list,
|
||||
reverse_search_space
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (INVALID_EDGE_WEIGHT == upper_bound_to_shortest_path_distance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sort_unique_resize( via_node_candidate_list );
|
||||
|
||||
std::vector<NodeID> packed_forward_path;
|
||||
std::vector<NodeID> packed_reverse_path;
|
||||
|
||||
super::RetrievePackedPathFromSingleHeap(
|
||||
forward_heap1,
|
||||
middle_node,
|
||||
packed_forward_path
|
||||
);
|
||||
super::RetrievePackedPathFromSingleHeap(
|
||||
reverse_heap1,
|
||||
middle_node,
|
||||
packed_reverse_path
|
||||
);
|
||||
|
||||
//TODO: leave early when no path found:
|
||||
|
||||
boost::unordered_map<NodeID, int> approximated_forward_sharing;
|
||||
boost::unordered_map<NodeID, int> approximated_reverse_sharing;
|
||||
|
||||
unsigned index_into_forward_path = 0;
|
||||
//sweep over search space, compute forward sharing for each current edge (u,v)
|
||||
BOOST_FOREACH(const SearchSpaceEdge & current_edge, forward_search_space) {
|
||||
const NodeID u = current_edge.first;
|
||||
const NodeID v = current_edge.second;
|
||||
if(
|
||||
( packed_forward_path.size() < index_into_forward_path ) &&
|
||||
( current_edge == forward_search_space[index_into_forward_path] )
|
||||
) {
|
||||
//current_edge is on shortest path => sharing(u):=queue.GetKey(u);
|
||||
++index_into_forward_path;
|
||||
approximated_forward_sharing[v] = forward_heap1.GetKey(u);
|
||||
} else {
|
||||
//sharing (s) = sharing (t)
|
||||
approximated_forward_sharing[v] = approximated_forward_sharing[u];
|
||||
}
|
||||
}
|
||||
|
||||
unsigned index_into_reverse_path = 0;
|
||||
//sweep over search space, compute backward sharing
|
||||
BOOST_FOREACH(const SearchSpaceEdge & current_edge, reverse_search_space) {
|
||||
const NodeID u = current_edge.first;
|
||||
const NodeID v = current_edge.second;
|
||||
if(
|
||||
( packed_reverse_path.size() < index_into_reverse_path ) &&
|
||||
( current_edge == reverse_search_space[index_into_reverse_path] )
|
||||
) {
|
||||
//current_edge is on shortest path => sharing(u):=queue.GetKey(u);
|
||||
++index_into_reverse_path;
|
||||
approximated_reverse_sharing[v] = reverse_heap1.GetKey(u);
|
||||
} else {
|
||||
//sharing (s) = sharing (t)
|
||||
boost::unordered_map<NodeID,int>::const_iterator rev_iterator = approximated_reverse_sharing.find(u);
|
||||
const int rev_sharing = (rev_iterator != approximated_reverse_sharing.end()) ? rev_iterator->second : 0;
|
||||
approximated_reverse_sharing[v] = rev_sharing;
|
||||
}
|
||||
}
|
||||
|
||||
// SimpleLogger().Write(logDEBUG) << "fwd_search_space size: " << forward_search_space.size() << ", marked " << approximated_forward_sharing.size() << " nodes";
|
||||
// SimpleLogger().Write(logDEBUG) << "rev_search_space size: " << reverse_search_space.size() << ", marked " << approximated_reverse_sharing.size() << " nodes";
|
||||
|
||||
std::vector<NodeID> preselected_node_list;
|
||||
BOOST_FOREACH(const NodeID node, via_node_candidate_list) {
|
||||
boost::unordered_map<NodeID, int>::const_iterator fwd_iterator = approximated_forward_sharing.find(node);
|
||||
const int fwd_sharing = (fwd_iterator != approximated_forward_sharing.end()) ? fwd_iterator->second : 0;
|
||||
boost::unordered_map<NodeID, int>::const_iterator rev_iterator = approximated_reverse_sharing.find(node);
|
||||
const int rev_sharing = (rev_iterator != approximated_reverse_sharing.end()) ? rev_iterator->second : 0;
|
||||
|
||||
const int approximated_sharing = fwd_sharing + rev_sharing;
|
||||
const int approximated_length = forward_heap1.GetKey(node) + reverse_heap1.GetKey(node);
|
||||
const bool length_passes = (approximated_length < upper_bound_to_shortest_path_distance*(1+VIAPATH_EPSILON));
|
||||
const bool sharing_passes = (approximated_sharing <= upper_bound_to_shortest_path_distance*VIAPATH_GAMMA);
|
||||
const bool stretch_passes = (approximated_length - approximated_sharing) < ((1.+VIAPATH_ALPHA)*(upper_bound_to_shortest_path_distance-approximated_sharing));
|
||||
|
||||
if( length_passes && sharing_passes && stretch_passes ) {
|
||||
preselected_node_list.push_back(node);
|
||||
}
|
||||
}
|
||||
|
||||
// SimpleLogger().Write() << preselected_node_list.size() << " passed preselection";
|
||||
|
||||
std::vector<NodeID> & packed_shortest_path = packed_forward_path;
|
||||
std::reverse(packed_shortest_path.begin(), packed_shortest_path.end());
|
||||
packed_shortest_path.push_back(middle_node);
|
||||
packed_shortest_path.insert(
|
||||
packed_shortest_path.end(),
|
||||
packed_reverse_path.begin(),
|
||||
packed_reverse_path.end()
|
||||
);
|
||||
std::vector<RankedCandidateNode> ranked_candidates_list;
|
||||
|
||||
//prioritizing via nodes for deep inspection
|
||||
BOOST_FOREACH(const NodeID node, preselected_node_list) {
|
||||
int length_of_via_path = 0, sharing_of_via_path = 0;
|
||||
ComputeLengthAndSharingOfViaPath(node, &length_of_via_path, &sharing_of_via_path, packed_shortest_path);
|
||||
const int maximum_allowed_sharing = upper_bound_to_shortest_path_distance*VIAPATH_GAMMA;
|
||||
if( sharing_of_via_path <= maximum_allowed_sharing && length_of_via_path <= upper_bound_to_shortest_path_distance*(1+VIAPATH_EPSILON)) {
|
||||
ranked_candidates_list.push_back(
|
||||
RankedCandidateNode(
|
||||
node,
|
||||
length_of_via_path,
|
||||
sharing_of_via_path
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
std::sort(
|
||||
ranked_candidates_list.begin(),
|
||||
ranked_candidates_list.end()
|
||||
);
|
||||
|
||||
NodeID selected_via_node = SPECIAL_NODEID;
|
||||
int length_of_via_path = INVALID_EDGE_WEIGHT;
|
||||
NodeID s_v_middle = SPECIAL_NODEID, v_t_middle = SPECIAL_NODEID;
|
||||
BOOST_FOREACH(const RankedCandidateNode & candidate, ranked_candidates_list){
|
||||
if(ViaNodeCandidatePassesTTest(forward_heap1, reverse_heap1, forward_heap2, reverse_heap2, candidate, upper_bound_to_shortest_path_distance, &length_of_via_path, &s_v_middle, &v_t_middle)) {
|
||||
// select first admissable
|
||||
selected_via_node = candidate.node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Unpack shortest path and alternative, if they exist
|
||||
if( INVALID_EDGE_WEIGHT != upper_bound_to_shortest_path_distance )
|
||||
{
|
||||
BOOST_ASSERT(!packed_shortest_path.empty());
|
||||
raw_route_data.unpacked_path_segments.resize(1);
|
||||
raw_route_data.source_traversed_in_reverse = (packed_shortest_path.front() != phantom_node_pair.source_phantom.forward_node_id);
|
||||
raw_route_data.target_traversed_in_reverse = (packed_shortest_path.back() != phantom_node_pair.target_phantom.forward_node_id);
|
||||
|
||||
super::UnpackPath(
|
||||
// -- packed input
|
||||
packed_shortest_path,
|
||||
// -- start of route
|
||||
phantom_node_pair,
|
||||
// -- unpacked output
|
||||
raw_route_data.unpacked_path_segments.front()
|
||||
);
|
||||
raw_route_data.lengthOfShortestPath = upper_bound_to_shortest_path_distance;
|
||||
}
|
||||
|
||||
if( SPECIAL_NODEID != selected_via_node ) {
|
||||
std::vector<NodeID> packed_alternate_path;
|
||||
// retrieve alternate path
|
||||
RetrievePackedAlternatePath(
|
||||
forward_heap1,
|
||||
reverse_heap1,
|
||||
forward_heap2,
|
||||
reverse_heap2,
|
||||
s_v_middle,
|
||||
v_t_middle,
|
||||
packed_alternate_path
|
||||
);
|
||||
|
||||
raw_route_data.source_traversed_in_reverse = (packed_alternate_path.front() != phantom_node_pair.source_phantom.forward_node_id);
|
||||
raw_route_data.target_traversed_in_reverse = (packed_alternate_path.back() != phantom_node_pair.target_phantom.forward_node_id);
|
||||
|
||||
// unpack the alternate path
|
||||
super::UnpackPath(
|
||||
packed_alternate_path,
|
||||
phantom_node_pair,
|
||||
raw_route_data.unpacked_alternative
|
||||
);
|
||||
|
||||
raw_route_data.lengthOfAlternativePath = length_of_via_path;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//unpack alternate <s,..,v,..,t> by exploring search spaces from v
|
||||
inline void RetrievePackedAlternatePath(
|
||||
const QueryHeap & forward_heap1,
|
||||
const QueryHeap & reverse_heap1,
|
||||
const QueryHeap & forward_heap2,
|
||||
const QueryHeap & reverse_heap2,
|
||||
const NodeID s_v_middle,
|
||||
const NodeID v_t_middle,
|
||||
std::vector<NodeID> & packed_path
|
||||
) const {
|
||||
//fetch packed path [s,v)
|
||||
std::vector<NodeID> packed_v_t_path;
|
||||
super::RetrievePackedPathFromHeap(
|
||||
forward_heap1,
|
||||
reverse_heap2,
|
||||
s_v_middle,
|
||||
packed_path
|
||||
);
|
||||
packed_path.pop_back(); //remove middle node. It's in both half-paths
|
||||
|
||||
//fetch patched path [v,t]
|
||||
super::RetrievePackedPathFromHeap(
|
||||
forward_heap2,
|
||||
reverse_heap1,
|
||||
v_t_middle,
|
||||
packed_v_t_path
|
||||
);
|
||||
|
||||
packed_path.insert(
|
||||
packed_path.end(),
|
||||
packed_v_t_path.begin(),
|
||||
packed_v_t_path.end()
|
||||
);
|
||||
}
|
||||
|
||||
//TODO: reorder parameters
|
||||
// compute and unpack <s,..,v> and <v,..,t> by exploring search spaces
|
||||
// from v and intersecting against queues. only half-searches have to be
|
||||
// done at this stage
|
||||
inline void ComputeLengthAndSharingOfViaPath(
|
||||
const NodeID via_node,
|
||||
int *real_length_of_via_path,
|
||||
int *sharing_of_via_path,
|
||||
const std::vector<NodeID> & packed_shortest_path
|
||||
) {
|
||||
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes()
|
||||
);
|
||||
|
||||
QueryHeap & existing_forward_heap = *engine_working_data.forwardHeap;
|
||||
QueryHeap & existing_reverse_heap = *engine_working_data.backwardHeap;
|
||||
QueryHeap & new_forward_heap = *engine_working_data.forwardHeap2;
|
||||
QueryHeap & new_reverse_heap = *engine_working_data.backwardHeap2;
|
||||
|
||||
std::vector<NodeID> packed_s_v_path;
|
||||
std::vector<NodeID> packed_v_t_path;
|
||||
|
||||
std::vector<NodeID> partially_unpacked_shortest_path;
|
||||
std::vector<NodeID> partially_unpacked_via_path;
|
||||
|
||||
NodeID s_v_middle = SPECIAL_NODEID;
|
||||
int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT;
|
||||
new_reverse_heap.Insert(via_node, 0, via_node);
|
||||
//compute path <s,..,v> by reusing forward search from s
|
||||
while( !new_reverse_heap.Empty() ) {
|
||||
super::RoutingStep(
|
||||
new_reverse_heap,
|
||||
existing_forward_heap,
|
||||
&s_v_middle,
|
||||
&upper_bound_s_v_path_length,
|
||||
false
|
||||
);
|
||||
}
|
||||
//compute path <v,..,t> by reusing backward search from node t
|
||||
NodeID v_t_middle = SPECIAL_NODEID;
|
||||
int upper_bound_of_v_t_path_length = INVALID_EDGE_WEIGHT;
|
||||
new_forward_heap.Insert(via_node, 0, via_node);
|
||||
while(!new_forward_heap.Empty() ) {
|
||||
super::RoutingStep(
|
||||
new_forward_heap,
|
||||
existing_reverse_heap,
|
||||
&v_t_middle,
|
||||
&upper_bound_of_v_t_path_length,
|
||||
true
|
||||
);
|
||||
}
|
||||
*real_length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length;
|
||||
|
||||
if( SPECIAL_NODEID == s_v_middle || SPECIAL_NODEID == v_t_middle ) {
|
||||
return;
|
||||
}
|
||||
|
||||
//retrieve packed paths
|
||||
super::RetrievePackedPathFromHeap(
|
||||
existing_forward_heap,
|
||||
new_reverse_heap,
|
||||
s_v_middle,
|
||||
packed_s_v_path
|
||||
);
|
||||
super::RetrievePackedPathFromHeap(
|
||||
new_forward_heap,
|
||||
existing_reverse_heap,
|
||||
v_t_middle,
|
||||
packed_v_t_path
|
||||
);
|
||||
|
||||
//partial unpacking, compute sharing
|
||||
//First partially unpack s-->v until paths deviate, note length of common path.
|
||||
const unsigned s_v_min_path_size = std::min( packed_s_v_path.size(), packed_shortest_path.size()) - 1;
|
||||
for(
|
||||
unsigned i = 0;
|
||||
i < s_v_min_path_size;
|
||||
++i
|
||||
) {
|
||||
if( packed_s_v_path[i] == packed_shortest_path[i] &&
|
||||
packed_s_v_path[i+1] == packed_shortest_path[i+1]
|
||||
) {
|
||||
EdgeID edgeID = facade->FindEdgeInEitherDirection(packed_s_v_path[i], packed_s_v_path[i + 1]);
|
||||
*sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
|
||||
} else {
|
||||
if( packed_s_v_path[i] == packed_shortest_path[i] ) {
|
||||
super::UnpackEdge(
|
||||
packed_s_v_path[i],
|
||||
packed_s_v_path[i+1],
|
||||
partially_unpacked_via_path
|
||||
);
|
||||
super::UnpackEdge(
|
||||
packed_shortest_path[i],
|
||||
packed_shortest_path[i+1],
|
||||
partially_unpacked_shortest_path
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//traverse partially unpacked edge and note common prefix
|
||||
for(
|
||||
int i = 0, packed_path_length = std::min( partially_unpacked_via_path.size(), partially_unpacked_shortest_path.size()) - 1;
|
||||
(i < packed_path_length) && (partially_unpacked_via_path[i] == partially_unpacked_shortest_path[i] && partially_unpacked_via_path[i+1] == partially_unpacked_shortest_path[i+1]);
|
||||
++i
|
||||
) {
|
||||
EdgeID edgeID = facade->FindEdgeInEitherDirection(
|
||||
partially_unpacked_via_path[i],
|
||||
partially_unpacked_via_path[i+1]
|
||||
);
|
||||
*sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
|
||||
}
|
||||
|
||||
//Second, partially unpack v-->t in reverse order until paths deviate and note lengths
|
||||
int via_path_index = packed_v_t_path.size()-1;
|
||||
int shortest_path_index = packed_shortest_path.size()-1;
|
||||
for(;
|
||||
via_path_index > 0 && shortest_path_index > 0;
|
||||
--via_path_index,--shortest_path_index
|
||||
) {
|
||||
if(
|
||||
packed_v_t_path[via_path_index-1] == packed_shortest_path[shortest_path_index-1] &&
|
||||
packed_v_t_path[via_path_index] == packed_shortest_path[shortest_path_index]
|
||||
) {
|
||||
EdgeID edgeID = facade->FindEdgeInEitherDirection(
|
||||
packed_v_t_path[via_path_index-1],
|
||||
packed_v_t_path[via_path_index]
|
||||
);
|
||||
*sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
|
||||
} else {
|
||||
if( packed_v_t_path[via_path_index] == packed_shortest_path[shortest_path_index] ) {
|
||||
super::UnpackEdge(
|
||||
packed_v_t_path[via_path_index-1],
|
||||
packed_v_t_path[via_path_index],
|
||||
partially_unpacked_via_path
|
||||
);
|
||||
super::UnpackEdge(
|
||||
packed_shortest_path[shortest_path_index-1],
|
||||
packed_shortest_path[shortest_path_index],
|
||||
partially_unpacked_shortest_path
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
via_path_index = partially_unpacked_via_path.size()-1;
|
||||
shortest_path_index = partially_unpacked_shortest_path.size()-1;
|
||||
for(;
|
||||
via_path_index > 0 && shortest_path_index > 0;
|
||||
--via_path_index,--shortest_path_index
|
||||
) {
|
||||
if(
|
||||
partially_unpacked_via_path[via_path_index-1] == partially_unpacked_shortest_path[shortest_path_index-1] &&
|
||||
partially_unpacked_via_path[via_path_index] == partially_unpacked_shortest_path[shortest_path_index]
|
||||
) {
|
||||
EdgeID edgeID = facade->FindEdgeInEitherDirection(
|
||||
partially_unpacked_via_path[via_path_index-1],
|
||||
partially_unpacked_via_path[via_path_index]
|
||||
);
|
||||
*sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
//finished partial unpacking spree! Amount of sharing is stored to appropriate pointer variable
|
||||
}
|
||||
|
||||
// inline int approximateAmountOfSharing(
|
||||
// const NodeID alternate_path_middle_node_id,
|
||||
// QueryHeap & forward_heap,
|
||||
// QueryHeap & reverse_heap,
|
||||
// const std::vector<NodeID> & packed_shortest_path
|
||||
// ) const {
|
||||
// std::vector<NodeID> packed_alternate_path;
|
||||
// super::RetrievePackedPathFromHeap(
|
||||
// forward_heap,
|
||||
// reverse_heap,
|
||||
// alternate_path_middle_node_id,
|
||||
// packed_alternate_path
|
||||
// );
|
||||
|
||||
// if(packed_shortest_path.size() < 2 || packed_alternate_path.size() < 2) {
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// int sharing = 0;
|
||||
// int aindex = 0;
|
||||
// //compute forward sharing
|
||||
// while( (packed_alternate_path[aindex] == packed_shortest_path[aindex]) && (packed_alternate_path[aindex+1] == packed_shortest_path[aindex+1]) ) {
|
||||
// // SimpleLogger().Write() << "retrieving edge (" << packed_alternate_path[aindex] << "," << packed_alternate_path[aindex+1] << ")";
|
||||
// EdgeID edgeID = facade->FindEdgeInEitherDirection(packed_alternate_path[aindex], packed_alternate_path[aindex+1]);
|
||||
// sharing += facade->GetEdgeData(edgeID).distance;
|
||||
// ++aindex;
|
||||
// }
|
||||
|
||||
// aindex = packed_alternate_path.size()-1;
|
||||
// int bindex = packed_shortest_path.size()-1;
|
||||
// //compute backward sharing
|
||||
// while( aindex > 0 && bindex > 0 && (packed_alternate_path[aindex] == packed_shortest_path[bindex]) && (packed_alternate_path[aindex-1] == packed_shortest_path[bindex-1]) ) {
|
||||
// EdgeID edgeID = facade->FindEdgeInEitherDirection(packed_alternate_path[aindex], packed_alternate_path[aindex-1]);
|
||||
// sharing += facade->GetEdgeData(edgeID).distance;
|
||||
// --aindex; --bindex;
|
||||
// }
|
||||
// return sharing;
|
||||
// }
|
||||
|
||||
//todo: reorder parameters
|
||||
template<bool is_forward_directed>
|
||||
inline void AlternativeRoutingStep(
|
||||
QueryHeap & forward_heap,
|
||||
QueryHeap & reverse_heap,
|
||||
NodeID * middle_node,
|
||||
int * upper_bound_to_shortest_path_distance,
|
||||
std::vector<NodeID> & search_space_intersection,
|
||||
std::vector<SearchSpaceEdge> & search_space
|
||||
) const {
|
||||
const NodeID node = forward_heap.DeleteMin();
|
||||
const int distance = forward_heap.GetKey(node);
|
||||
const int scaled_distance = distance/(1.+VIAPATH_EPSILON);
|
||||
// SimpleLogger().Write(logDEBUG) << "node: " << node << ", distance: " << distance << ", ub: " << *upper_bound_to_shortest_path_distance << ", scaled_distance: " << scaled_distance;
|
||||
if(
|
||||
(INVALID_EDGE_WEIGHT != *upper_bound_to_shortest_path_distance) &&
|
||||
(scaled_distance > *upper_bound_to_shortest_path_distance)
|
||||
) {
|
||||
// SimpleLogger().Write(logDEBUG) << "removing nodes from heap";
|
||||
forward_heap.DeleteAll();
|
||||
return;
|
||||
}
|
||||
|
||||
search_space.push_back(
|
||||
std::make_pair(forward_heap.GetData( node ).parent, node)
|
||||
);
|
||||
|
||||
if (reverse_heap.WasInserted(node)) {
|
||||
search_space_intersection.push_back(node);
|
||||
|
||||
const int new_distance = reverse_heap.GetKey(node) + distance;
|
||||
if (new_distance < *upper_bound_to_shortest_path_distance)
|
||||
{
|
||||
if (new_distance >= 0)
|
||||
{
|
||||
*middle_node = node;
|
||||
*upper_bound_to_shortest_path_distance = new_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(
|
||||
EdgeID edge = facade->BeginEdges(node);
|
||||
edge < facade->EndEdges(node);
|
||||
++edge
|
||||
) {
|
||||
const EdgeData & data = facade->GetEdgeData(edge);
|
||||
const bool edge_is_forward_directed = (is_forward_directed ? data.forward : data.backward );
|
||||
if( edge_is_forward_directed ) {
|
||||
|
||||
const NodeID to = facade->GetTarget(edge);
|
||||
const int edge_weight = data.distance;
|
||||
|
||||
BOOST_ASSERT( edge_weight > 0 );
|
||||
const int to_distance = distance + edge_weight;
|
||||
|
||||
//New Node discovered -> Add to Heap + Node Info Storage
|
||||
if( !forward_heap.WasInserted( to ) ) {
|
||||
forward_heap.Insert( to, to_distance, node );
|
||||
|
||||
}
|
||||
//Found a shorter Path -> Update distance
|
||||
else if( to_distance < forward_heap.GetKey( to ) ) {
|
||||
// new parent
|
||||
forward_heap.GetData( to ).parent = node;
|
||||
// decreased distance
|
||||
forward_heap.DecreaseKey( to, to_distance );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//conduct T-Test
|
||||
inline bool ViaNodeCandidatePassesTTest(
|
||||
QueryHeap& existing_forward_heap,
|
||||
QueryHeap& existing_reverse_heap,
|
||||
QueryHeap& new_forward_heap,
|
||||
QueryHeap& new_reverse_heap,
|
||||
const RankedCandidateNode& candidate,
|
||||
const int lengthOfShortestPath,
|
||||
int * length_of_via_path,
|
||||
NodeID * s_v_middle,
|
||||
NodeID * v_t_middle
|
||||
) const {
|
||||
new_forward_heap.Clear();
|
||||
new_reverse_heap.Clear();
|
||||
std::vector<NodeID> packed_s_v_path;
|
||||
std::vector<NodeID> packed_v_t_path;
|
||||
|
||||
*s_v_middle = SPECIAL_NODEID;
|
||||
int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT;
|
||||
//compute path <s,..,v> by reusing forward search from s
|
||||
new_reverse_heap.Insert(candidate.node, 0, candidate.node);
|
||||
while (new_reverse_heap.Size() > 0) {
|
||||
super::RoutingStep(new_reverse_heap, existing_forward_heap, s_v_middle, &upper_bound_s_v_path_length, false);
|
||||
}
|
||||
|
||||
if( INVALID_EDGE_WEIGHT == upper_bound_s_v_path_length ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//compute path <v,..,t> by reusing backward search from t
|
||||
*v_t_middle = SPECIAL_NODEID;
|
||||
int upper_bound_of_v_t_path_length = INVALID_EDGE_WEIGHT;
|
||||
new_forward_heap.Insert(candidate.node, 0, candidate.node);
|
||||
while (new_forward_heap.Size() > 0) {
|
||||
super::RoutingStep(new_forward_heap, existing_reverse_heap, v_t_middle, &upper_bound_of_v_t_path_length, true);
|
||||
}
|
||||
|
||||
if( INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_length ){
|
||||
return false;
|
||||
}
|
||||
|
||||
*length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length;
|
||||
|
||||
//retrieve packed paths
|
||||
super::RetrievePackedPathFromHeap(
|
||||
existing_forward_heap,
|
||||
new_reverse_heap,
|
||||
*s_v_middle,
|
||||
packed_s_v_path
|
||||
);
|
||||
|
||||
super::RetrievePackedPathFromHeap(
|
||||
new_forward_heap,
|
||||
existing_reverse_heap,
|
||||
*v_t_middle,
|
||||
packed_v_t_path
|
||||
);
|
||||
|
||||
NodeID s_P = *s_v_middle, t_P = *v_t_middle;
|
||||
if( SPECIAL_NODEID == s_P ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if( SPECIAL_NODEID == t_P ) {
|
||||
return false;
|
||||
}
|
||||
const int T_threshold = VIAPATH_EPSILON * lengthOfShortestPath;
|
||||
int unpacked_until_distance = 0;
|
||||
|
||||
std::stack<SearchSpaceEdge> unpack_stack;
|
||||
//Traverse path s-->v
|
||||
for(
|
||||
unsigned i = packed_s_v_path.size() - 1;
|
||||
(i > 0) && unpack_stack.empty();
|
||||
--i
|
||||
) {
|
||||
const EdgeID current_edge_id = facade->FindEdgeInEitherDirection( packed_s_v_path[i - 1], packed_s_v_path[i]);
|
||||
const int length_of_current_edge = facade->GetEdgeData(current_edge_id).distance;
|
||||
if( (length_of_current_edge + unpacked_until_distance) >= T_threshold ) {
|
||||
unpack_stack.push(
|
||||
std::make_pair(packed_s_v_path[i - 1], packed_s_v_path[i])
|
||||
);
|
||||
} else {
|
||||
unpacked_until_distance += length_of_current_edge;
|
||||
s_P = packed_s_v_path[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
while( !unpack_stack.empty() ) {
|
||||
const SearchSpaceEdge via_path_edge = unpack_stack.top();
|
||||
unpack_stack.pop();
|
||||
EdgeID edge_in_via_path_id = facade->FindEdgeInEitherDirection(
|
||||
via_path_edge.first,
|
||||
via_path_edge.second
|
||||
);
|
||||
|
||||
if( SPECIAL_EDGEID == edge_in_via_path_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const EdgeData & current_edge_data = facade->GetEdgeData(edge_in_via_path_id);
|
||||
const bool current_edge_is_shortcut = current_edge_data.shortcut;
|
||||
if( current_edge_is_shortcut ) {
|
||||
const NodeID via_path_middle_node_id = current_edge_data.id;
|
||||
const EdgeID second_segment_edge_id = facade->FindEdgeInEitherDirection(via_path_middle_node_id, via_path_edge.second);
|
||||
const int second_segment_length = facade->GetEdgeData(second_segment_edge_id).distance;
|
||||
//attention: !unpacking in reverse!
|
||||
//Check if second segment is the one to go over treshold? if yes add second segment to stack, else push first segment to stack and add distance of second one.
|
||||
if (unpacked_until_distance + second_segment_length >= T_threshold) {
|
||||
unpack_stack.push(
|
||||
std::make_pair(
|
||||
via_path_middle_node_id,
|
||||
via_path_edge.second
|
||||
)
|
||||
);
|
||||
} else {
|
||||
unpacked_until_distance += second_segment_length;
|
||||
unpack_stack.push(
|
||||
std::make_pair(
|
||||
via_path_edge.first,
|
||||
via_path_middle_node_id
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// edge is not a shortcut, set the start node for T-Test to end of edge.
|
||||
unpacked_until_distance += current_edge_data.distance;
|
||||
s_P = via_path_edge.first;
|
||||
}
|
||||
}
|
||||
|
||||
int t_test_path_length = unpacked_until_distance;
|
||||
unpacked_until_distance = 0;
|
||||
//Traverse path s-->v
|
||||
for(
|
||||
unsigned i = 0, packed_path_length = packed_v_t_path.size() - 1;
|
||||
(i < packed_path_length) && unpack_stack.empty();
|
||||
++i
|
||||
) {
|
||||
EdgeID edgeID = facade->FindEdgeInEitherDirection( packed_v_t_path[i], packed_v_t_path[i + 1]);
|
||||
int length_of_current_edge = facade->GetEdgeData(edgeID).distance;
|
||||
if (length_of_current_edge + unpacked_until_distance >= T_threshold) {
|
||||
unpack_stack.push( std::make_pair(packed_v_t_path[i], packed_v_t_path[i + 1]));
|
||||
} else {
|
||||
unpacked_until_distance += length_of_current_edge;
|
||||
t_P = packed_v_t_path[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
while (!unpack_stack.empty()) {
|
||||
const SearchSpaceEdge via_path_edge = unpack_stack.top();
|
||||
unpack_stack.pop();
|
||||
EdgeID edge_in_via_path_id = facade->FindEdgeInEitherDirection(via_path_edge.first, via_path_edge.second);
|
||||
if(SPECIAL_EDGEID == edge_in_via_path_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const EdgeData & current_edge_data = facade->GetEdgeData(edge_in_via_path_id);
|
||||
const bool IsViaEdgeShortCut = current_edge_data.shortcut;
|
||||
if (IsViaEdgeShortCut) {
|
||||
const NodeID middleOfViaPath = current_edge_data.id;
|
||||
EdgeID edgeIDOfFirstSegment = facade->FindEdgeInEitherDirection(via_path_edge.first, middleOfViaPath);
|
||||
int lengthOfFirstSegment = facade->GetEdgeData( edgeIDOfFirstSegment).distance;
|
||||
//Check if first segment is the one to go over treshold? if yes first segment to stack, else push second segment to stack and add distance of first one.
|
||||
if (unpacked_until_distance + lengthOfFirstSegment >= T_threshold) {
|
||||
unpack_stack.push( std::make_pair(via_path_edge.first, middleOfViaPath));
|
||||
} else {
|
||||
unpacked_until_distance += lengthOfFirstSegment;
|
||||
unpack_stack.push( std::make_pair(middleOfViaPath, via_path_edge.second));
|
||||
}
|
||||
} else {
|
||||
// edge is not a shortcut, set the start node for T-Test to end of edge.
|
||||
unpacked_until_distance += current_edge_data.distance;
|
||||
t_P = via_path_edge.second;
|
||||
}
|
||||
}
|
||||
|
||||
t_test_path_length += unpacked_until_distance;
|
||||
//Run actual T-Test query and compare if distances equal.
|
||||
engine_working_data.InitializeOrClearThirdThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes()
|
||||
);
|
||||
|
||||
QueryHeap & forward_heap3 = *engine_working_data.forwardHeap3;
|
||||
QueryHeap & reverse_heap3 = *engine_working_data.backwardHeap3;
|
||||
int upper_bound = INVALID_EDGE_WEIGHT;
|
||||
NodeID middle = SPECIAL_NODEID;
|
||||
|
||||
forward_heap3.Insert(s_P, 0, s_P);
|
||||
reverse_heap3.Insert(t_P, 0, t_P);
|
||||
//exploration from s and t until deletemin/(1+epsilon) > _lengthOfShortestPath
|
||||
while( (forward_heap3.Size() + reverse_heap3.Size() ) > 0) {
|
||||
if( !forward_heap3.Empty() ) {
|
||||
super::RoutingStep(
|
||||
forward_heap3,
|
||||
reverse_heap3,
|
||||
&middle,
|
||||
&upper_bound,
|
||||
true
|
||||
);
|
||||
}
|
||||
if( !reverse_heap3.Empty() ) {
|
||||
super::RoutingStep(
|
||||
reverse_heap3,
|
||||
forward_heap3,
|
||||
&middle,
|
||||
&upper_bound,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
return (upper_bound <= t_test_path_length);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* ALTERNATIVE_PATH_ROUTING_H */
|
||||
@@ -1,398 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BASICROUTINGINTERFACE_H_
|
||||
#define BASICROUTINGINTERFACE_H_
|
||||
|
||||
#include "../DataStructures/RawRouteData.h"
|
||||
#include "../DataStructures/SearchEngineData.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../Util/ContainerUtils.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#include <stack>
|
||||
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap2;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap2;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap3;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap3;
|
||||
|
||||
template<class DataFacadeT>
|
||||
class BasicRoutingInterface : boost::noncopyable {
|
||||
private:
|
||||
typedef typename DataFacadeT::EdgeData EdgeData;
|
||||
protected:
|
||||
DataFacadeT * facade;
|
||||
public:
|
||||
explicit BasicRoutingInterface( DataFacadeT * facade ) : facade(facade) { }
|
||||
virtual ~BasicRoutingInterface(){ };
|
||||
|
||||
inline void RoutingStep(
|
||||
SearchEngineData::QueryHeap & forward_heap,
|
||||
SearchEngineData::QueryHeap & reverse_heap,
|
||||
NodeID * middle_node_id,
|
||||
int * upper_bound,
|
||||
const bool forward_direction
|
||||
) const
|
||||
{
|
||||
const NodeID node = forward_heap.DeleteMin();
|
||||
const int distance = forward_heap.GetKey(node);
|
||||
if (reverse_heap.WasInserted(node))
|
||||
{
|
||||
const int new_distance = reverse_heap.GetKey(node) + distance;
|
||||
if(new_distance < *upper_bound )
|
||||
{
|
||||
if (new_distance >= 0)
|
||||
{
|
||||
*middle_node_id = node;
|
||||
*upper_bound = new_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (distance > *upper_bound)
|
||||
{
|
||||
forward_heap.DeleteAll();
|
||||
return;
|
||||
}
|
||||
|
||||
//Stalling
|
||||
for (EdgeID edge = facade->BeginEdges( node ); edge < facade->EndEdges(node); ++edge)
|
||||
{
|
||||
const EdgeData & data = facade->GetEdgeData(edge);
|
||||
const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward);
|
||||
if (reverse_flag)
|
||||
{
|
||||
const NodeID to = facade->GetTarget(edge);
|
||||
const int edge_weight = data.distance;
|
||||
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
|
||||
if (forward_heap.WasInserted(to))
|
||||
{
|
||||
if(forward_heap.GetKey( to ) + edge_weight < distance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (EdgeID edge = facade->BeginEdges(node), end_edge = facade->EndEdges(node); edge < end_edge; ++edge)
|
||||
{
|
||||
const EdgeData & data = facade->GetEdgeData(edge);
|
||||
bool forward_directionFlag = (forward_direction ? data.forward : data.backward);
|
||||
if (forward_directionFlag)
|
||||
{
|
||||
|
||||
const NodeID to = facade->GetTarget(edge);
|
||||
const int edge_weight = data.distance;
|
||||
|
||||
BOOST_ASSERT_MSG( edge_weight > 0, "edge_weight invalid" );
|
||||
const int to_distance = distance + edge_weight;
|
||||
|
||||
//New Node discovered -> Add to Heap + Node Info Storage
|
||||
if ( !forward_heap.WasInserted( to ) ) {
|
||||
forward_heap.Insert( to, to_distance, node );
|
||||
}
|
||||
//Found a shorter Path -> Update distance
|
||||
else if ( to_distance < forward_heap.GetKey( to ) ) {
|
||||
//new parent
|
||||
forward_heap.GetData( to ).parent = node;
|
||||
forward_heap.DecreaseKey( to, to_distance );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void UnpackPath(const std::vector<NodeID> & packed_path, const PhantomNodes & phantom_node_pair, std::vector<PathData> & unpacked_path) const
|
||||
{
|
||||
const bool start_traversed_in_reverse = (packed_path.front() != phantom_node_pair.source_phantom.forward_node_id);
|
||||
const bool target_traversed_in_reverse = (packed_path.back() != phantom_node_pair.target_phantom.forward_node_id);
|
||||
|
||||
const unsigned packed_path_size = packed_path.size();
|
||||
std::stack<std::pair<NodeID, NodeID> > recursion_stack;
|
||||
|
||||
//We have to push the path in reverse order onto the stack because it's LIFO.
|
||||
for(unsigned i = packed_path_size-1; i > 0; --i){
|
||||
recursion_stack.push(
|
||||
std::make_pair(packed_path[i-1], packed_path[i])
|
||||
);
|
||||
}
|
||||
|
||||
std::pair<NodeID, NodeID> edge;
|
||||
while (!recursion_stack.empty())
|
||||
{
|
||||
edge = recursion_stack.top();
|
||||
recursion_stack.pop();
|
||||
|
||||
// facade->FindEdge does not suffice here in case of shortcuts.
|
||||
// The above explanation unclear? Think!
|
||||
EdgeID smaller_edge_id = SPECIAL_EDGEID;
|
||||
int edge_weight = INT_MAX;
|
||||
for (EdgeID edge_id = facade->BeginEdges(edge.first); edge_id < facade->EndEdges(edge.first); ++edge_id)
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.second) &&
|
||||
(weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).forward)
|
||||
{
|
||||
smaller_edge_id = edge_id;
|
||||
edge_weight = weight;
|
||||
}
|
||||
}
|
||||
if (SPECIAL_EDGEID == smaller_edge_id)
|
||||
{
|
||||
for (EdgeID edge_id = facade->BeginEdges(edge.second); edge_id < facade->EndEdges(edge.second); ++edge_id)
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) && facade->GetEdgeData(edge_id).backward)
|
||||
{
|
||||
smaller_edge_id = edge_id;
|
||||
edge_weight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT_MSG(edge_weight != INVALID_EDGE_WEIGHT, "edge id invalid");
|
||||
|
||||
const EdgeData & ed = facade->GetEdgeData(smaller_edge_id);
|
||||
if (ed.shortcut)
|
||||
{//unpack
|
||||
const NodeID middle_node_id = ed.id;
|
||||
//again, we need to this in reversed order
|
||||
recursion_stack.push(std::make_pair(middle_node_id, edge.second));
|
||||
recursion_stack.push(std::make_pair(edge.first, middle_node_id));
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT_MSG(!ed.shortcut, "original edge flagged as shortcut");
|
||||
unsigned name_index = facade->GetNameIndexFromEdgeID(ed.id);
|
||||
const TurnInstruction turn_instruction = facade->GetTurnInstructionForEdgeID(ed.id);
|
||||
|
||||
if (!facade->EdgeIsCompressed(ed.id))
|
||||
{
|
||||
BOOST_ASSERT( !facade->EdgeIsCompressed(ed.id) );
|
||||
unpacked_path.push_back(
|
||||
PathData(
|
||||
facade->GetGeometryIndexForEdgeID(ed.id),
|
||||
name_index,
|
||||
turn_instruction,
|
||||
ed.distance
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<unsigned> id_vector;
|
||||
facade->GetUncompressedGeometry(facade->GetGeometryIndexForEdgeID(ed.id), id_vector);
|
||||
|
||||
const int start_index = ( unpacked_path.empty() ? ( ( start_traversed_in_reverse ) ? id_vector.size() - phantom_node_pair.source_phantom.fwd_segment_position - 1 : phantom_node_pair.source_phantom.fwd_segment_position ) : 0 );
|
||||
const int end_index = id_vector.size();
|
||||
|
||||
BOOST_ASSERT(start_index >= 0);
|
||||
BOOST_ASSERT(start_index <= end_index);
|
||||
for (int i = start_index; i < end_index; ++i)
|
||||
{
|
||||
unpacked_path.push_back(
|
||||
PathData(
|
||||
id_vector[i],
|
||||
name_index,
|
||||
TurnInstructionsClass::NoTurn,
|
||||
0
|
||||
)
|
||||
);
|
||||
}
|
||||
unpacked_path.back().turnInstruction = turn_instruction;
|
||||
unpacked_path.back().durationOfSegment = ed.distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SPECIAL_EDGEID != phantom_node_pair.target_phantom.packed_geometry_id)
|
||||
{
|
||||
std::vector<unsigned> id_vector;
|
||||
facade->GetUncompressedGeometry(phantom_node_pair.target_phantom.packed_geometry_id, id_vector);
|
||||
if (target_traversed_in_reverse)
|
||||
{
|
||||
std::reverse(id_vector.begin(), id_vector.end() );
|
||||
}
|
||||
const bool is_local_path = (phantom_node_pair.source_phantom.packed_geometry_id == phantom_node_pair.target_phantom.packed_geometry_id) && unpacked_path.empty();
|
||||
|
||||
int start_index = 0;
|
||||
int end_index = phantom_node_pair.target_phantom.fwd_segment_position;
|
||||
if (target_traversed_in_reverse)
|
||||
{
|
||||
end_index = id_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position;
|
||||
}
|
||||
if (is_local_path)
|
||||
{
|
||||
start_index = phantom_node_pair.source_phantom.fwd_segment_position;
|
||||
end_index = phantom_node_pair.target_phantom.fwd_segment_position;
|
||||
if (target_traversed_in_reverse)
|
||||
{
|
||||
start_index = id_vector.size() - phantom_node_pair.source_phantom.fwd_segment_position;
|
||||
end_index = id_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASSERT(start_index >= 0);
|
||||
for (int i = start_index; i != end_index; (start_index < end_index ? ++i :--i))
|
||||
{
|
||||
BOOST_ASSERT( i >= -1 );
|
||||
unpacked_path.push_back(
|
||||
PathData(
|
||||
id_vector[i],
|
||||
phantom_node_pair.target_phantom.name_id,
|
||||
TurnInstructionsClass::NoTurn,
|
||||
0
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// there is no equivalent to a node-based node in an edge-expanded graph.
|
||||
// two equivalent routes may start (or end) at different node-based edges
|
||||
// as they are added with the offset how much "distance" on the edge
|
||||
// has already been traversed. Depending on offset one needs to remove
|
||||
// the last node.
|
||||
if (unpacked_path.size() > 1)
|
||||
{
|
||||
const unsigned last_index = unpacked_path.size()-1;
|
||||
const unsigned second_to_last_index = last_index -1;
|
||||
|
||||
//looks like a trivially true check but tests for underflow
|
||||
BOOST_ASSERT(last_index > second_to_last_index);
|
||||
|
||||
if (unpacked_path[last_index].node == unpacked_path[second_to_last_index].node)
|
||||
{
|
||||
unpacked_path.pop_back();
|
||||
}
|
||||
BOOST_ASSERT(!unpacked_path.empty());
|
||||
}
|
||||
}
|
||||
|
||||
inline void UnpackEdge(const NodeID s, const NodeID t, std::vector<NodeID> & unpacked_path) const
|
||||
{
|
||||
std::stack<std::pair<NodeID, NodeID> > recursion_stack;
|
||||
recursion_stack.push(std::make_pair(s,t));
|
||||
|
||||
std::pair<NodeID, NodeID> edge;
|
||||
while (!recursion_stack.empty())
|
||||
{
|
||||
edge = recursion_stack.top();
|
||||
recursion_stack.pop();
|
||||
|
||||
EdgeID smaller_edge_id = SPECIAL_EDGEID;
|
||||
int edge_weight = INT_MAX;
|
||||
for (EdgeID edge_id = facade->BeginEdges(edge.first); edge_id < facade->EndEdges(edge.first); ++edge_id)
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if(
|
||||
(facade->GetTarget(edge_id) == edge.second) &&
|
||||
(weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).forward
|
||||
){
|
||||
smaller_edge_id = edge_id;
|
||||
edge_weight = weight;
|
||||
}
|
||||
}
|
||||
|
||||
if (SPECIAL_EDGEID == smaller_edge_id)
|
||||
{
|
||||
for (EdgeID edge_id = facade->BeginEdges(edge.second); edge_id < facade->EndEdges(edge.second); ++edge_id)
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) && facade->GetEdgeData(edge_id).backward)
|
||||
{
|
||||
smaller_edge_id = edge_id;
|
||||
edge_weight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT_MSG(edge_weight != INT_MAX, "edge weight invalid");
|
||||
|
||||
const EdgeData& ed = facade->GetEdgeData(smaller_edge_id);
|
||||
if (ed.shortcut)
|
||||
{//unpack
|
||||
const NodeID middle_node_id = ed.id;
|
||||
//again, we need to this in reversed order
|
||||
recursion_stack.push(std::make_pair(middle_node_id, edge.second));
|
||||
recursion_stack.push(std::make_pair(edge.first, middle_node_id));
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT_MSG(!ed.shortcut, "edge must be shortcut");
|
||||
unpacked_path.push_back(edge.first );
|
||||
}
|
||||
}
|
||||
unpacked_path.push_back(t);
|
||||
}
|
||||
|
||||
inline void RetrievePackedPathFromHeap(
|
||||
const SearchEngineData::QueryHeap & forward_heap,
|
||||
const SearchEngineData::QueryHeap & reverse_heap,
|
||||
const NodeID middle_node_id,
|
||||
std::vector<NodeID> & packed_path
|
||||
) const
|
||||
{
|
||||
NodeID current_node_id = middle_node_id;
|
||||
while(current_node_id != forward_heap.GetData(current_node_id).parent)
|
||||
{
|
||||
current_node_id = forward_heap.GetData(current_node_id).parent;
|
||||
packed_path.push_back(current_node_id);
|
||||
}
|
||||
std::reverse(packed_path.begin(), packed_path.end());
|
||||
packed_path.push_back(middle_node_id);
|
||||
current_node_id = middle_node_id;
|
||||
while (current_node_id != reverse_heap.GetData(current_node_id).parent)
|
||||
{
|
||||
current_node_id = reverse_heap.GetData(current_node_id).parent;
|
||||
packed_path.push_back(current_node_id);
|
||||
}
|
||||
}
|
||||
|
||||
inline void RetrievePackedPathFromSingleHeap(
|
||||
const SearchEngineData::QueryHeap & search_heap,
|
||||
const NodeID middle_node_id,
|
||||
std::vector<NodeID>& packed_path
|
||||
) const
|
||||
{
|
||||
NodeID current_node_id = middle_node_id;
|
||||
while(current_node_id != search_heap.GetData(current_node_id).parent)
|
||||
{
|
||||
current_node_id = search_heap.GetData(current_node_id).parent;
|
||||
packed_path.push_back(current_node_id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* BASICROUTINGINTERFACE_H_ */
|
||||
@@ -1,404 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SHORTESTPATHROUTING_H_
|
||||
#define SHORTESTPATHROUTING_H_
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "BasicRoutingInterface.h"
|
||||
#include "../DataStructures/SearchEngineData.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
template<class DataFacadeT>
|
||||
class ShortestPathRouting : public BasicRoutingInterface<DataFacadeT>{
|
||||
typedef BasicRoutingInterface<DataFacadeT> super;
|
||||
typedef SearchEngineData::QueryHeap QueryHeap;
|
||||
SearchEngineData & engine_working_data;
|
||||
|
||||
public:
|
||||
ShortestPathRouting(
|
||||
DataFacadeT * facade,
|
||||
SearchEngineData & engine_working_data
|
||||
) :
|
||||
super(facade),
|
||||
engine_working_data(engine_working_data)
|
||||
{ }
|
||||
|
||||
~ShortestPathRouting() { }
|
||||
|
||||
void operator()(
|
||||
const std::vector<PhantomNodes> & phantom_nodes_vector,
|
||||
RawRouteData & raw_route_data
|
||||
) const
|
||||
{
|
||||
BOOST_FOREACH(
|
||||
const PhantomNodes & phantom_node_pair,
|
||||
phantom_nodes_vector
|
||||
){
|
||||
if( phantom_node_pair.AtLeastOnePhantomNodeIsInvalid() ) {
|
||||
// raw_route_data.lengthOfShortestPath = INT_MAX;
|
||||
// raw_route_data.lengthOfAlternativePath = INT_MAX;
|
||||
return;
|
||||
}
|
||||
}
|
||||
int distance1 = 0;
|
||||
int distance2 = 0;
|
||||
bool search_from_1st_node = true;
|
||||
bool search_from_2nd_node = true;
|
||||
NodeID middle1 = UINT_MAX;
|
||||
NodeID middle2 = UINT_MAX;
|
||||
std::vector<std::vector<NodeID> > packed_legs1(phantom_nodes_vector.size());
|
||||
std::vector<std::vector<NodeID> > packed_legs2(phantom_nodes_vector.size());
|
||||
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes()
|
||||
);
|
||||
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes()
|
||||
);
|
||||
engine_working_data.InitializeOrClearThirdThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes()
|
||||
);
|
||||
|
||||
QueryHeap & forward_heap1 = *(engine_working_data.forwardHeap);
|
||||
QueryHeap & reverse_heap1 = *(engine_working_data.backwardHeap);
|
||||
QueryHeap & forward_heap2 = *(engine_working_data.forwardHeap2);
|
||||
QueryHeap & reverse_heap2 = *(engine_working_data.backwardHeap2);
|
||||
|
||||
int current_leg = 0;
|
||||
//Get distance to next pair of target nodes.
|
||||
BOOST_FOREACH(
|
||||
const PhantomNodes & phantom_node_pair, phantom_nodes_vector
|
||||
){
|
||||
forward_heap1.Clear(); forward_heap2.Clear();
|
||||
reverse_heap1.Clear(); reverse_heap2.Clear();
|
||||
int local_upper_bound1 = INT_MAX;
|
||||
int local_upper_bound2 = INT_MAX;
|
||||
|
||||
middle1 = UINT_MAX;
|
||||
middle2 = UINT_MAX;
|
||||
|
||||
//insert new starting nodes into forward heap, adjusted by previous distances.
|
||||
if(
|
||||
search_from_1st_node &&
|
||||
phantom_node_pair.source_phantom.forward_node_id != SPECIAL_NODEID
|
||||
) {
|
||||
// SimpleLogger().Write(logDEBUG) << "fwd1 insert: " << phantom_node_pair.source_phantom.forward_node_id << ", w: " << -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset();
|
||||
forward_heap1.Insert(
|
||||
phantom_node_pair.source_phantom.forward_node_id,
|
||||
distance1-phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
|
||||
phantom_node_pair.source_phantom.forward_node_id
|
||||
);
|
||||
forward_heap2.Insert(
|
||||
phantom_node_pair.source_phantom.forward_node_id,
|
||||
distance1-phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
|
||||
phantom_node_pair.source_phantom.forward_node_id
|
||||
);
|
||||
}
|
||||
if(
|
||||
search_from_2nd_node &&
|
||||
phantom_node_pair.source_phantom.reverse_node_id != SPECIAL_NODEID
|
||||
) {
|
||||
// SimpleLogger().Write(logDEBUG) << "fwd1 insert: " << phantom_node_pair.source_phantom.reverse_node_id << ", w: " << -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset();
|
||||
forward_heap1.Insert(
|
||||
phantom_node_pair.source_phantom.reverse_node_id,
|
||||
distance2-phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
|
||||
phantom_node_pair.source_phantom.reverse_node_id
|
||||
);
|
||||
forward_heap2.Insert(
|
||||
phantom_node_pair.source_phantom.reverse_node_id,
|
||||
distance2-phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
|
||||
phantom_node_pair.source_phantom.reverse_node_id
|
||||
);
|
||||
}
|
||||
|
||||
//insert new backward nodes into backward heap, unadjusted.
|
||||
if( phantom_node_pair.target_phantom.forward_node_id != SPECIAL_NODEID ) {
|
||||
// SimpleLogger().Write(logDEBUG) << "rev insert: " << phantom_node_pair.target_phantom.forward_node_id << ", w: " << phantom_node_pair.target_phantom.GetForwardWeightPlusOffset();
|
||||
reverse_heap1.Insert(
|
||||
phantom_node_pair.target_phantom.forward_node_id,
|
||||
phantom_node_pair.target_phantom.GetForwardWeightPlusOffset(),
|
||||
phantom_node_pair.target_phantom.forward_node_id
|
||||
);
|
||||
}
|
||||
|
||||
if( phantom_node_pair.target_phantom.reverse_node_id != SPECIAL_NODEID ) {
|
||||
// SimpleLogger().Write(logDEBUG) << "rev insert: " << phantom_node_pair.target_phantom.reverse_node_id << ", w: " << phantom_node_pair.target_phantom.GetReverseWeightPlusOffset();
|
||||
reverse_heap2.Insert(
|
||||
phantom_node_pair.target_phantom.reverse_node_id,
|
||||
phantom_node_pair.target_phantom.GetReverseWeightPlusOffset(),
|
||||
phantom_node_pair.target_phantom.reverse_node_id
|
||||
);
|
||||
}
|
||||
|
||||
// const int forward_offset = phantom_node_pair.ComputeForwardQueueOffset();
|
||||
// const int forward_offset = super::ComputeForwardOffset(
|
||||
// phantom_node_pair.source_phantom
|
||||
// );
|
||||
// const int reverse_offset = -phantom_node_pair.ComputeReverseQueueOffset();
|
||||
// const int reverse_offset = super::ComputeReverseOffset(
|
||||
// phantom_node_pair.target_phantom
|
||||
// );
|
||||
|
||||
//run two-Target Dijkstra routing step.
|
||||
while(0 < (forward_heap1.Size() + reverse_heap1.Size() )){
|
||||
if( 0 < forward_heap1.Size() ){
|
||||
super::RoutingStep(
|
||||
forward_heap1,
|
||||
reverse_heap1,
|
||||
&middle1,
|
||||
&local_upper_bound1,
|
||||
true
|
||||
);
|
||||
}
|
||||
if( 0 < reverse_heap1.Size() ){
|
||||
super::RoutingStep(
|
||||
reverse_heap1,
|
||||
forward_heap1,
|
||||
&middle1,
|
||||
&local_upper_bound1,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if( !reverse_heap2.Empty() ) {
|
||||
while(0 < (forward_heap2.Size() + reverse_heap2.Size() )){
|
||||
if( 0 < forward_heap2.Size() ){
|
||||
super::RoutingStep(
|
||||
forward_heap2,
|
||||
reverse_heap2,
|
||||
&middle2,
|
||||
&local_upper_bound2,
|
||||
true
|
||||
);
|
||||
}
|
||||
if( 0 < reverse_heap2.Size() ){
|
||||
super::RoutingStep(
|
||||
reverse_heap2,
|
||||
forward_heap2,
|
||||
&middle2,
|
||||
&local_upper_bound2,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//No path found for both target nodes?
|
||||
if(
|
||||
(INVALID_EDGE_WEIGHT == local_upper_bound1) &&
|
||||
(INVALID_EDGE_WEIGHT == local_upper_bound2)
|
||||
) {
|
||||
raw_route_data.lengthOfShortestPath = INVALID_EDGE_WEIGHT;
|
||||
raw_route_data.lengthOfAlternativePath = INVALID_EDGE_WEIGHT;
|
||||
return;
|
||||
}
|
||||
if( SPECIAL_NODEID == middle1 ) {
|
||||
search_from_1st_node = false;
|
||||
}
|
||||
if( SPECIAL_NODEID == middle2 ) {
|
||||
search_from_2nd_node = false;
|
||||
}
|
||||
|
||||
//Was at most one of the two paths not found?
|
||||
BOOST_ASSERT_MSG(
|
||||
(INT_MAX != distance1 || INT_MAX != distance2),
|
||||
"no path found"
|
||||
);
|
||||
|
||||
//Unpack paths if they exist
|
||||
std::vector<NodeID> temporary_packed_leg1;
|
||||
std::vector<NodeID> temporary_packed_leg2;
|
||||
|
||||
BOOST_ASSERT( (unsigned)current_leg < packed_legs1.size() );
|
||||
BOOST_ASSERT( (unsigned)current_leg < packed_legs2.size() );
|
||||
|
||||
if( INVALID_EDGE_WEIGHT != local_upper_bound1 ) {
|
||||
super::RetrievePackedPathFromHeap(
|
||||
forward_heap1,
|
||||
reverse_heap1,
|
||||
middle1,
|
||||
temporary_packed_leg1
|
||||
);
|
||||
}
|
||||
|
||||
if( INVALID_EDGE_WEIGHT != local_upper_bound2 ) {
|
||||
super::RetrievePackedPathFromHeap(
|
||||
forward_heap2,
|
||||
reverse_heap2,
|
||||
middle2,
|
||||
temporary_packed_leg2
|
||||
);
|
||||
}
|
||||
|
||||
//if one of the paths was not found, replace it with the other one.
|
||||
if( temporary_packed_leg1.empty() ) {
|
||||
temporary_packed_leg1.insert(
|
||||
temporary_packed_leg1.end(),
|
||||
temporary_packed_leg2.begin(),
|
||||
temporary_packed_leg2.end()
|
||||
);
|
||||
local_upper_bound1 = local_upper_bound2;
|
||||
}
|
||||
if( temporary_packed_leg2.empty() ) {
|
||||
temporary_packed_leg2.insert(
|
||||
temporary_packed_leg2.end(),
|
||||
temporary_packed_leg1.begin(),
|
||||
temporary_packed_leg1.end()
|
||||
);
|
||||
local_upper_bound2 = local_upper_bound1;
|
||||
}
|
||||
|
||||
BOOST_ASSERT_MSG(
|
||||
!temporary_packed_leg1.empty() ||
|
||||
!temporary_packed_leg2.empty(),
|
||||
"tempory packed paths empty"
|
||||
);
|
||||
|
||||
BOOST_ASSERT(
|
||||
(0 == current_leg) || !packed_legs1[current_leg-1].empty()
|
||||
);
|
||||
BOOST_ASSERT(
|
||||
(0 == current_leg) || !packed_legs2[current_leg-1].empty()
|
||||
);
|
||||
|
||||
if( 0 < current_leg ) {
|
||||
const NodeID end_id_of_segment1 = packed_legs1[current_leg-1].back();
|
||||
const NodeID end_id_of_segment2 = packed_legs2[current_leg-1].back();
|
||||
BOOST_ASSERT( !temporary_packed_leg1.empty() );
|
||||
const NodeID start_id_of_leg1 = temporary_packed_leg1.front();
|
||||
const NodeID start_id_of_leg2 = temporary_packed_leg2.front();
|
||||
if( ( end_id_of_segment1 != start_id_of_leg1 ) &&
|
||||
( end_id_of_segment2 != start_id_of_leg2 )
|
||||
) {
|
||||
std::swap(temporary_packed_leg1, temporary_packed_leg2);
|
||||
std::swap(local_upper_bound1, local_upper_bound2);
|
||||
}
|
||||
}
|
||||
|
||||
// remove one path if both legs end at the same segment
|
||||
if( 0 < current_leg ) {
|
||||
const NodeID start_id_of_leg1 = temporary_packed_leg1.front();
|
||||
const NodeID start_id_of_leg2 = temporary_packed_leg2.front();
|
||||
if(
|
||||
start_id_of_leg1 == start_id_of_leg2
|
||||
) {
|
||||
const NodeID last_id_of_packed_legs1 = packed_legs1[current_leg-1].back();
|
||||
const NodeID last_id_of_packed_legs2 = packed_legs2[current_leg-1].back();
|
||||
if( start_id_of_leg1 != last_id_of_packed_legs1 ) {
|
||||
packed_legs1 = packed_legs2;
|
||||
BOOST_ASSERT(
|
||||
start_id_of_leg1 == temporary_packed_leg1.front()
|
||||
);
|
||||
} else
|
||||
if( start_id_of_leg2 != last_id_of_packed_legs2 ) {
|
||||
packed_legs2 = packed_legs1;
|
||||
BOOST_ASSERT(
|
||||
start_id_of_leg2 == temporary_packed_leg2.front()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT(
|
||||
packed_legs1.size() == packed_legs2.size()
|
||||
);
|
||||
|
||||
packed_legs1[current_leg].insert(
|
||||
packed_legs1[current_leg].end(),
|
||||
temporary_packed_leg1.begin(),
|
||||
temporary_packed_leg1.end()
|
||||
);
|
||||
BOOST_ASSERT(packed_legs1[current_leg].size() == temporary_packed_leg1.size() );
|
||||
packed_legs2[current_leg].insert(
|
||||
packed_legs2[current_leg].end(),
|
||||
temporary_packed_leg2.begin(),
|
||||
temporary_packed_leg2.end()
|
||||
);
|
||||
BOOST_ASSERT(packed_legs2[current_leg].size() == temporary_packed_leg2.size() );
|
||||
|
||||
if(
|
||||
(packed_legs1[current_leg].back() == packed_legs2[current_leg].back()) &&
|
||||
phantom_node_pair.target_phantom.isBidirected()
|
||||
) {
|
||||
const NodeID last_node_id = packed_legs2[current_leg].back();
|
||||
search_from_1st_node &= !(last_node_id == phantom_node_pair.target_phantom.reverse_node_id);
|
||||
search_from_2nd_node &= !(last_node_id == phantom_node_pair.target_phantom.forward_node_id);
|
||||
BOOST_ASSERT( search_from_1st_node != search_from_2nd_node );
|
||||
}
|
||||
|
||||
distance1 = local_upper_bound1;
|
||||
distance2 = local_upper_bound2;
|
||||
++current_leg;
|
||||
}
|
||||
|
||||
if (distance1 > distance2)
|
||||
{
|
||||
std::swap( packed_legs1, packed_legs2 );
|
||||
}
|
||||
raw_route_data.unpacked_path_segments.resize( packed_legs1.size() );
|
||||
// const int start_offset = ( packed_legs1[0].front() == phantom_nodes_vector.front().source_phantom.forward_node_id ? 1 : -1 )*phantom_nodes_vector.front().source_phantom.fwd_segment_position;
|
||||
|
||||
raw_route_data.source_traversed_in_reverse = (packed_legs1.front().front() != phantom_nodes_vector.front().source_phantom.forward_node_id);
|
||||
raw_route_data.target_traversed_in_reverse = (packed_legs1.back().back() != phantom_nodes_vector.back().target_phantom.forward_node_id);
|
||||
|
||||
for (unsigned i = 0; i < packed_legs1.size(); ++i)
|
||||
{
|
||||
BOOST_ASSERT(!phantom_nodes_vector.empty());
|
||||
// const bool at_beginning = (packed_legs1[i] == packed_legs1.front());
|
||||
// const bool at_end = (packed_legs1[i] == packed_legs1.back());
|
||||
BOOST_ASSERT(packed_legs1.size() == raw_route_data.unpacked_path_segments.size());
|
||||
|
||||
PhantomNodes unpack_phantom_node_pair = phantom_nodes_vector[i];
|
||||
// if (!at_beginning)
|
||||
// {
|
||||
// unpack_phantom_node_pair.source_phantom.packed_geometry_id = SPECIAL_EDGEID;
|
||||
// unpack_phantom_node_pair.source_phantom.fwd_segment_position = 0;
|
||||
// }
|
||||
|
||||
// if (!at_end)
|
||||
// {
|
||||
// unpack_phantom_node_pair.target_phantom.packed_geometry_id = SPECIAL_EDGEID;
|
||||
// unpack_phantom_node_pair.target_phantom.fwd_segment_position = 0;
|
||||
// }
|
||||
|
||||
super::UnpackPath(
|
||||
// -- packed input
|
||||
packed_legs1[i],
|
||||
// -- start and end of (sub-)route
|
||||
unpack_phantom_node_pair,
|
||||
// -- unpacked output
|
||||
raw_route_data.unpacked_path_segments[i]
|
||||
);
|
||||
}
|
||||
raw_route_data.lengthOfShortestPath = std::min(distance1, distance2);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SHORTESTPATHROUTING_H_ */
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef APIGRAMMAR_H_
|
||||
#define APIGRAMMAR_H_
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
#include <boost/spirit/include/qi_action.hpp>
|
||||
|
||||
namespace qi = boost::spirit::qi;
|
||||
|
||||
template <typename Iterator, class HandlerT>
|
||||
struct APIGrammar : qi::grammar<Iterator> {
|
||||
explicit APIGrammar(HandlerT * h) : APIGrammar::base_type(api_call), handler(h) {
|
||||
api_call = qi::lit('/') >> string[boost::bind(&HandlerT::setService, handler, ::_1)] >> *(query);
|
||||
query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | cmp | language | instruction | geometry | alt_route | old_API) ) ;
|
||||
|
||||
zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >> qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)];
|
||||
output = (-qi::lit('&')) >> qi::lit("output") >> '=' >> string[boost::bind(&HandlerT::setOutputFormat, handler, ::_1)];
|
||||
jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >> stringwithPercent[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)];
|
||||
checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >> qi::int_[boost::bind(&HandlerT::setChecksum, handler, ::_1)];
|
||||
instruction = (-qi::lit('&')) >> qi::lit("instructions") >> '=' >> qi::bool_[boost::bind(&HandlerT::setInstructionFlag, handler, ::_1)];
|
||||
geometry = (-qi::lit('&')) >> qi::lit("geometry") >> '=' >> qi::bool_[boost::bind(&HandlerT::setGeometryFlag, handler, ::_1)];
|
||||
cmp = (-qi::lit('&')) >> qi::lit("compression") >> '=' >> qi::bool_[boost::bind(&HandlerT::setCompressionFlag, handler, ::_1)];
|
||||
location = (-qi::lit('&')) >> qi::lit("loc") >> '=' >> (qi::double_ >> qi::lit(',') >> qi::double_)[boost::bind(&HandlerT::addCoordinate, handler, ::_1)];
|
||||
hint = (-qi::lit('&')) >> qi::lit("hint") >> '=' >> stringwithDot[boost::bind(&HandlerT::addHint, handler, ::_1)];
|
||||
language = (-qi::lit('&')) >> qi::lit("hl") >> '=' >> string[boost::bind(&HandlerT::setLanguage, handler, ::_1)];
|
||||
alt_route = (-qi::lit('&')) >> qi::lit("alt") >> '=' >> qi::bool_[boost::bind(&HandlerT::setAlternateRouteFlag, handler, ::_1)];
|
||||
old_API = (-qi::lit('&')) >> qi::lit("geomformat") >> '=' >> string[boost::bind(&HandlerT::setDeprecatedAPIFlag, handler, ::_1)];
|
||||
|
||||
string = +(qi::char_("a-zA-Z"));
|
||||
stringwithDot = +(qi::char_("a-zA-Z0-9_.-"));
|
||||
stringwithPercent = +(qi::char_("a-zA-Z0-9_.-") | qi::char_('[') | qi::char_(']') | (qi::char_('%') >> qi::char_("0-9A-Z") >> qi::char_("0-9A-Z") ));
|
||||
}
|
||||
|
||||
qi::rule<Iterator> api_call, query;
|
||||
qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location, hint,
|
||||
stringwithDot, stringwithPercent, language, instruction, geometry,
|
||||
cmp, alt_route, old_API;
|
||||
|
||||
HandlerT * handler;
|
||||
};
|
||||
|
||||
#endif /* APIGRAMMAR_H_ */
|
||||
@@ -1,240 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "Connection.h"
|
||||
#include "RequestHandler.h"
|
||||
#include "RequestParser.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/iostreams/filtering_stream.hpp>
|
||||
#include <boost/iostreams/filter/gzip.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace http {
|
||||
|
||||
Connection::Connection(
|
||||
boost::asio::io_service& io_service,
|
||||
RequestHandler& handler
|
||||
) :
|
||||
strand(io_service),
|
||||
TCP_socket(io_service),
|
||||
request_handler(handler),
|
||||
request_parser(new RequestParser())
|
||||
{ }
|
||||
|
||||
Connection::~Connection() {
|
||||
delete request_parser;
|
||||
}
|
||||
|
||||
boost::asio::ip::tcp::socket& Connection::socket() {
|
||||
return TCP_socket;
|
||||
}
|
||||
|
||||
/// Start the first asynchronous operation for the connection.
|
||||
void Connection::start() {
|
||||
TCP_socket.async_read_some(
|
||||
boost::asio::buffer(incoming_data_buffer),
|
||||
strand.wrap( boost::bind(
|
||||
&Connection::handle_read,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void Connection::handle_read(
|
||||
const boost::system::error_code& e,
|
||||
std::size_t bytes_transferred
|
||||
) {
|
||||
if( !e ) {
|
||||
CompressionType compression_type(noCompression);
|
||||
boost::tribool result;
|
||||
boost::tie(result, boost::tuples::ignore) = request_parser->Parse(
|
||||
request,
|
||||
incoming_data_buffer.data(),
|
||||
incoming_data_buffer.data() + bytes_transferred,
|
||||
&compression_type
|
||||
);
|
||||
|
||||
if( result ) {
|
||||
request.endpoint = TCP_socket.remote_endpoint().address();
|
||||
request_handler.handle_request(request, reply);
|
||||
|
||||
Header compression_header;
|
||||
std::vector<char> compressed_output;
|
||||
std::vector<boost::asio::const_buffer> output_buffer;
|
||||
switch(compression_type) {
|
||||
case deflateRFC1951:
|
||||
compression_header.name = "Content-Encoding";
|
||||
compression_header.value = "deflate";
|
||||
reply.headers.insert(
|
||||
reply.headers.begin(),
|
||||
compression_header
|
||||
);
|
||||
compressBufferCollection(
|
||||
reply.content,
|
||||
compression_type,
|
||||
compressed_output
|
||||
);
|
||||
reply.setSize(compressed_output.size());
|
||||
output_buffer = reply.HeaderstoBuffers();
|
||||
output_buffer.push_back(
|
||||
boost::asio::buffer(compressed_output)
|
||||
);
|
||||
boost::asio::async_write(
|
||||
TCP_socket,
|
||||
output_buffer,
|
||||
strand.wrap(
|
||||
boost::bind(
|
||||
&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error
|
||||
)
|
||||
)
|
||||
);
|
||||
break;
|
||||
case gzipRFC1952:
|
||||
compression_header.name = "Content-Encoding";
|
||||
compression_header.value = "gzip";
|
||||
reply.headers.insert(
|
||||
reply.headers.begin(),
|
||||
compression_header
|
||||
);
|
||||
compressBufferCollection(
|
||||
reply.content,
|
||||
compression_type,
|
||||
compressed_output
|
||||
);
|
||||
reply.setSize(compressed_output.size());
|
||||
output_buffer = reply.HeaderstoBuffers();
|
||||
output_buffer.push_back(
|
||||
boost::asio::buffer(compressed_output)
|
||||
);
|
||||
boost::asio::async_write(
|
||||
TCP_socket,
|
||||
output_buffer,
|
||||
strand.wrap(
|
||||
boost::bind(
|
||||
&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error
|
||||
)
|
||||
)
|
||||
);
|
||||
break;
|
||||
case noCompression:
|
||||
reply.SetUncompressedSize();
|
||||
output_buffer = reply.toBuffers();
|
||||
boost::asio::async_write(
|
||||
TCP_socket,
|
||||
output_buffer,
|
||||
strand.wrap(
|
||||
boost::bind(
|
||||
&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error
|
||||
)
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
} else if (!result) {
|
||||
reply = Reply::StockReply(Reply::badRequest);
|
||||
|
||||
boost::asio::async_write(
|
||||
TCP_socket,
|
||||
reply.toBuffers(),
|
||||
strand.wrap(
|
||||
boost::bind(
|
||||
&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error
|
||||
)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
TCP_socket.async_read_some(
|
||||
boost::asio::buffer(incoming_data_buffer),
|
||||
strand.wrap(
|
||||
boost::bind(
|
||||
&Connection::handle_read,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle completion of a write operation.
|
||||
void Connection::handle_write(const boost::system::error_code& e) {
|
||||
if (!e) {
|
||||
// Initiate graceful connection closure.
|
||||
boost::system::error_code ignoredEC;
|
||||
TCP_socket.shutdown(
|
||||
boost::asio::ip::tcp::socket::shutdown_both,
|
||||
ignoredEC
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void Connection::compressBufferCollection(
|
||||
std::vector<std::string> uncompressed_data,
|
||||
CompressionType compression_type,
|
||||
std::vector<char> & compressed_data
|
||||
) {
|
||||
boost::iostreams::gzip_params compression_parameters;
|
||||
|
||||
compression_parameters.level = boost::iostreams::zlib::best_speed;
|
||||
if ( deflateRFC1951 == compression_type ) {
|
||||
compression_parameters.noheader = true;
|
||||
}
|
||||
|
||||
BOOST_ASSERT( compressed_data.empty() );
|
||||
boost::iostreams::filtering_ostream compressing_stream;
|
||||
|
||||
compressing_stream.push(
|
||||
boost::iostreams::gzip_compressor(compression_parameters)
|
||||
);
|
||||
compressing_stream.push(
|
||||
boost::iostreams::back_inserter(compressed_data)
|
||||
);
|
||||
|
||||
BOOST_FOREACH( const std::string & line, uncompressed_data) {
|
||||
compressing_stream << line;
|
||||
}
|
||||
|
||||
compressing_stream.reset();
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CONNECTION_H
|
||||
#define CONNECTION_H
|
||||
|
||||
#include "Http/CompressionType.h"
|
||||
#include "Http/Request.h"
|
||||
|
||||
#include <osrm/Reply.h>
|
||||
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class RequestHandler;
|
||||
|
||||
namespace http {
|
||||
|
||||
class RequestParser;
|
||||
|
||||
/// Represents a single connection from a client.
|
||||
class Connection : public boost::enable_shared_from_this<Connection>,
|
||||
private boost::noncopyable {
|
||||
public:
|
||||
explicit Connection(
|
||||
boost::asio::io_service& io_service,
|
||||
RequestHandler& handler
|
||||
);
|
||||
|
||||
~Connection();
|
||||
|
||||
boost::asio::ip::tcp::socket& socket();
|
||||
|
||||
/// Start the first asynchronous operation for the connection.
|
||||
void start();
|
||||
|
||||
private:
|
||||
void handle_read(
|
||||
const boost::system::error_code& e,
|
||||
std::size_t bytes_transferred
|
||||
);
|
||||
|
||||
/// Handle completion of a write operation.
|
||||
void handle_write(const boost::system::error_code& e);
|
||||
|
||||
void compressBufferCollection(
|
||||
std::vector<std::string> uncompressed_data,
|
||||
CompressionType compression_type,
|
||||
std::vector<char> & compressed_data
|
||||
);
|
||||
|
||||
boost::asio::io_service::strand strand;
|
||||
boost::asio::ip::tcp::socket TCP_socket;
|
||||
RequestHandler& request_handler;
|
||||
boost::array<char, 8192> incoming_data_buffer;
|
||||
Request request;
|
||||
RequestParser * request_parser;
|
||||
Reply reply;
|
||||
};
|
||||
|
||||
} // namespace http
|
||||
|
||||
#endif // CONNECTION_H
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef QUERY_DATA_FACADE_H
|
||||
#define QUERY_DATA_FACADE_H
|
||||
|
||||
//Exposes all data access interfaces to the algorithms via base class ptr
|
||||
|
||||
#include "../../DataStructures/EdgeBasedNode.h"
|
||||
#include "../../DataStructures/ImportNode.h"
|
||||
#include "../../DataStructures/PhantomNodes.h"
|
||||
#include "../../DataStructures/TurnInstructions.h"
|
||||
#include "../../Util/OSRMException.h"
|
||||
#include "../../Util/StringUtil.h"
|
||||
#include "../../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
template<class EdgeDataT>
|
||||
class BaseDataFacade {
|
||||
public:
|
||||
typedef EdgeBasedNode RTreeLeaf;
|
||||
typedef EdgeDataT EdgeData;
|
||||
BaseDataFacade( ) { }
|
||||
virtual ~BaseDataFacade() { }
|
||||
|
||||
//search graph access
|
||||
virtual unsigned GetNumberOfNodes() const = 0;
|
||||
|
||||
virtual unsigned GetNumberOfEdges() const = 0;
|
||||
|
||||
virtual unsigned GetOutDegree( const NodeID n ) const = 0;
|
||||
|
||||
virtual NodeID GetTarget( const EdgeID e ) const = 0;
|
||||
|
||||
virtual EdgeDataT &GetEdgeData( const EdgeID e ) = 0;
|
||||
|
||||
// virtual const EdgeDataT &GetEdgeData( const EdgeID e ) const = 0;
|
||||
|
||||
virtual EdgeID BeginEdges( const NodeID n ) const = 0;
|
||||
|
||||
virtual EdgeID EndEdges( const NodeID n ) const = 0;
|
||||
|
||||
//searches for a specific edge
|
||||
virtual EdgeID FindEdge( const NodeID from, const NodeID to ) const = 0;
|
||||
|
||||
virtual EdgeID FindEdgeInEitherDirection(
|
||||
const NodeID from,
|
||||
const NodeID to
|
||||
) const = 0;
|
||||
|
||||
virtual EdgeID FindEdgeIndicateIfReverse(
|
||||
const NodeID from,
|
||||
const NodeID to,
|
||||
bool & result
|
||||
) const = 0;
|
||||
|
||||
//node and edge information access
|
||||
virtual FixedPointCoordinate GetCoordinateOfNode(
|
||||
const unsigned id
|
||||
) const = 0;
|
||||
|
||||
virtual bool EdgeIsCompressed( const unsigned id ) const = 0;
|
||||
|
||||
virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const = 0;
|
||||
|
||||
virtual void GetUncompressedGeometry(
|
||||
const unsigned id,
|
||||
std::vector<unsigned> & result_nodes
|
||||
) const = 0;
|
||||
|
||||
virtual TurnInstruction GetTurnInstructionForEdgeID(
|
||||
const unsigned id
|
||||
) const = 0;
|
||||
|
||||
virtual bool LocateClosestEndPointForCoordinate(
|
||||
const FixedPointCoordinate& input_coordinate,
|
||||
FixedPointCoordinate& result,
|
||||
const unsigned zoom_level = 18
|
||||
) const = 0;
|
||||
|
||||
virtual bool FindPhantomNodeForCoordinate(
|
||||
const FixedPointCoordinate & input_coordinate,
|
||||
PhantomNode & resulting_phantom_node,
|
||||
const unsigned zoom_level
|
||||
) const = 0;
|
||||
|
||||
virtual unsigned GetCheckSum() const = 0;
|
||||
|
||||
virtual unsigned GetNameIndexFromEdgeID(const unsigned id) const = 0;
|
||||
|
||||
virtual void GetName(
|
||||
const unsigned name_id,
|
||||
std::string & result
|
||||
) const = 0;
|
||||
|
||||
std::string GetEscapedNameForNameID(const unsigned name_id) const {
|
||||
std::string temporary_string;
|
||||
GetName(name_id, temporary_string);
|
||||
return EscapeJSONString(temporary_string);
|
||||
}
|
||||
|
||||
virtual std::string GetTimestamp() const = 0;
|
||||
};
|
||||
|
||||
#endif // QUERY_DATA_FACADE_H
|
||||
@@ -1,485 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INTERNAL_DATA_FACADE
|
||||
#define INTERNAL_DATA_FACADE
|
||||
|
||||
//implements all data storage when shared memory is _NOT_ used
|
||||
|
||||
#include "BaseDataFacade.h"
|
||||
|
||||
#include "../../DataStructures/OriginalEdgeData.h"
|
||||
#include "../../DataStructures/QueryNode.h"
|
||||
#include "../../DataStructures/QueryEdge.h"
|
||||
#include "../../DataStructures/SharedMemoryVectorWrapper.h"
|
||||
#include "../../DataStructures/StaticGraph.h"
|
||||
#include "../../DataStructures/StaticRTree.h"
|
||||
#include "../../Util/BoostFileSystemFix.h"
|
||||
#include "../../Util/GraphLoader.h"
|
||||
#include "../../Util/ProgramOptions.h"
|
||||
#include "../../Util/SimpleLogger.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
template<class EdgeDataT>
|
||||
class InternalDataFacade : public BaseDataFacade<EdgeDataT> {
|
||||
|
||||
private:
|
||||
typedef BaseDataFacade<EdgeDataT> super;
|
||||
typedef StaticGraph<typename super::EdgeData> QueryGraph;
|
||||
typedef typename QueryGraph::InputEdge InputEdge;
|
||||
typedef typename super::RTreeLeaf RTreeLeaf;
|
||||
|
||||
InternalDataFacade() { }
|
||||
|
||||
unsigned m_check_sum;
|
||||
unsigned m_number_of_nodes;
|
||||
QueryGraph * m_query_graph;
|
||||
std::string m_timestamp;
|
||||
|
||||
boost::shared_ptr<ShM<FixedPointCoordinate, false>::vector> m_coordinate_list;
|
||||
ShM<NodeID, false>::vector m_via_node_list;
|
||||
ShM<unsigned, false>::vector m_name_ID_list;
|
||||
ShM<TurnInstruction, false>::vector m_turn_instruction_list;
|
||||
ShM<char, false>::vector m_names_char_list;
|
||||
ShM<unsigned, false>::vector m_name_begin_indices;
|
||||
ShM<bool, false>::vector m_egde_is_compressed;
|
||||
ShM<unsigned, false>::vector m_geometry_indices;
|
||||
ShM<unsigned, false>::vector m_geometry_list;
|
||||
|
||||
boost::shared_ptr<
|
||||
StaticRTree<
|
||||
RTreeLeaf,
|
||||
ShM<FixedPointCoordinate, false>::vector,
|
||||
false
|
||||
>
|
||||
> m_static_rtree;
|
||||
|
||||
|
||||
void LoadTimestamp(const boost::filesystem::path & timestamp_path) {
|
||||
if( boost::filesystem::exists(timestamp_path) ) {
|
||||
SimpleLogger().Write() << "Loading Timestamp";
|
||||
boost::filesystem::ifstream timestampInStream( timestamp_path );
|
||||
if(!timestampInStream) {
|
||||
SimpleLogger().Write(logWARNING) << timestamp_path << " not found";
|
||||
}
|
||||
getline(timestampInStream, m_timestamp);
|
||||
timestampInStream.close();
|
||||
}
|
||||
if(m_timestamp.empty()) {
|
||||
m_timestamp = "n/a";
|
||||
}
|
||||
if(25 < m_timestamp.length()) {
|
||||
m_timestamp.resize(25);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadGraph(const boost::filesystem::path & hsgr_path) {
|
||||
typename ShM<typename QueryGraph::_StrNode, false>::vector node_list;
|
||||
typename ShM<typename QueryGraph::_StrEdge, false>::vector edge_list;
|
||||
|
||||
SimpleLogger().Write() << "loading graph from " << hsgr_path.string();
|
||||
|
||||
m_number_of_nodes = readHSGRFromStream(
|
||||
hsgr_path,
|
||||
node_list,
|
||||
edge_list,
|
||||
&m_check_sum
|
||||
);
|
||||
|
||||
BOOST_ASSERT_MSG(0 != node_list.size(), "node list empty");
|
||||
// BOOST_ASSERT_MSG(0 != edge_list.size(), "edge list empty");
|
||||
SimpleLogger().Write() << "loaded " << node_list.size() << " nodes and " << edge_list.size() << " edges";
|
||||
m_query_graph = new QueryGraph(node_list, edge_list);
|
||||
|
||||
BOOST_ASSERT_MSG(0 == node_list.size(), "node list not flushed");
|
||||
BOOST_ASSERT_MSG(0 == edge_list.size(), "edge list not flushed");
|
||||
SimpleLogger().Write() << "Data checksum is " << m_check_sum;
|
||||
}
|
||||
|
||||
void LoadNodeAndEdgeInformation(
|
||||
const boost::filesystem::path & nodes_file,
|
||||
const boost::filesystem::path & edges_file
|
||||
) {
|
||||
boost::filesystem::ifstream nodes_input_stream(
|
||||
nodes_file,
|
||||
std::ios::binary
|
||||
);
|
||||
|
||||
NodeInfo current_node;
|
||||
unsigned number_of_coordinates = 0;
|
||||
nodes_input_stream.read(
|
||||
(char *)&number_of_coordinates,
|
||||
sizeof(unsigned)
|
||||
);
|
||||
m_coordinate_list = boost::make_shared<std::vector<FixedPointCoordinate> >(number_of_coordinates);
|
||||
for(unsigned i = 0; i < number_of_coordinates; ++i) {
|
||||
nodes_input_stream.read((char *)¤t_node, sizeof(NodeInfo));
|
||||
m_coordinate_list->at(i) = FixedPointCoordinate(
|
||||
current_node.lat,
|
||||
current_node.lon
|
||||
);
|
||||
BOOST_ASSERT( ( std::abs(m_coordinate_list->at(i).lat) >> 30) == 0 );
|
||||
BOOST_ASSERT( ( std::abs(m_coordinate_list->at(i).lon) >> 30) == 0 );
|
||||
}
|
||||
nodes_input_stream.close();
|
||||
|
||||
boost::filesystem::ifstream edges_input_stream(
|
||||
edges_file,
|
||||
std::ios::binary
|
||||
);
|
||||
unsigned number_of_edges = 0;
|
||||
edges_input_stream.read((char*)&number_of_edges, sizeof(unsigned));
|
||||
m_via_node_list.resize (number_of_edges);
|
||||
m_name_ID_list.resize (number_of_edges);
|
||||
m_turn_instruction_list.resize(number_of_edges);
|
||||
m_egde_is_compressed.resize (number_of_edges);
|
||||
|
||||
unsigned compressed = 0;
|
||||
|
||||
OriginalEdgeData current_edge_data;
|
||||
for(unsigned i = 0; i < number_of_edges; ++i) {
|
||||
edges_input_stream.read(
|
||||
(char*)&(current_edge_data),
|
||||
sizeof(OriginalEdgeData)
|
||||
);
|
||||
m_via_node_list[i] = current_edge_data.via_node;
|
||||
m_name_ID_list[i] = current_edge_data.name_id;
|
||||
m_turn_instruction_list[i] = current_edge_data.turn_instruction;
|
||||
m_egde_is_compressed[i] = current_edge_data.compressed_geometry;
|
||||
if(m_egde_is_compressed[i]) {
|
||||
++compressed;
|
||||
}
|
||||
}
|
||||
|
||||
edges_input_stream.close();
|
||||
}
|
||||
|
||||
void LoadGeometries(const boost::filesystem::path & geometry_file)
|
||||
{
|
||||
std::ifstream geometry_stream(
|
||||
geometry_file.c_str(),
|
||||
std::ios::binary
|
||||
);
|
||||
unsigned number_of_indices = 0;
|
||||
unsigned number_of_compressed_geometries = 0;
|
||||
|
||||
geometry_stream.read(
|
||||
(char *)&number_of_indices,
|
||||
sizeof(unsigned)
|
||||
);
|
||||
|
||||
m_geometry_indices.resize(number_of_indices);
|
||||
geometry_stream.read(
|
||||
(char *)&(m_geometry_indices[0]),
|
||||
number_of_indices*sizeof(unsigned)
|
||||
);
|
||||
|
||||
geometry_stream.read(
|
||||
(char *)&number_of_compressed_geometries,
|
||||
sizeof(unsigned)
|
||||
);
|
||||
|
||||
BOOST_ASSERT( m_geometry_indices.back() == number_of_compressed_geometries );
|
||||
m_geometry_list.resize( number_of_compressed_geometries );
|
||||
|
||||
geometry_stream.read(
|
||||
(char *)&(m_geometry_list[0]),
|
||||
number_of_compressed_geometries*sizeof(unsigned)
|
||||
);
|
||||
geometry_stream.close();
|
||||
}
|
||||
|
||||
void LoadRTree(
|
||||
const boost::filesystem::path & ram_index_path,
|
||||
const boost::filesystem::path & file_index_path
|
||||
) {
|
||||
BOOST_ASSERT_MSG(
|
||||
!m_coordinate_list->empty(),
|
||||
"coordinates must be loaded before r-tree"
|
||||
);
|
||||
|
||||
m_static_rtree = boost::make_shared<StaticRTree<RTreeLeaf> >(
|
||||
ram_index_path,
|
||||
file_index_path,
|
||||
m_coordinate_list
|
||||
);
|
||||
}
|
||||
|
||||
void LoadStreetNames(
|
||||
const boost::filesystem::path & names_file
|
||||
) {
|
||||
boost::filesystem::ifstream name_stream(names_file, std::ios::binary);
|
||||
unsigned number_of_names = 0;
|
||||
unsigned number_of_chars = 0;
|
||||
name_stream.read((char *)&number_of_names, sizeof(unsigned));
|
||||
name_stream.read((char *)&number_of_chars, sizeof(unsigned));
|
||||
BOOST_ASSERT_MSG(0 != number_of_names, "name file broken");
|
||||
BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
|
||||
|
||||
m_name_begin_indices.resize(number_of_names);
|
||||
name_stream.read(
|
||||
(char*)&m_name_begin_indices[0],
|
||||
number_of_names*sizeof(unsigned)
|
||||
);
|
||||
|
||||
m_names_char_list.resize(number_of_chars+1); //+1 gives sentinel element
|
||||
name_stream.read(
|
||||
(char *)&m_names_char_list[0],
|
||||
number_of_chars*sizeof(char)
|
||||
);
|
||||
BOOST_ASSERT_MSG(
|
||||
0 != m_names_char_list.size(),
|
||||
"could not load any names"
|
||||
);
|
||||
name_stream.close();
|
||||
}
|
||||
public:
|
||||
~InternalDataFacade() {
|
||||
delete m_query_graph;
|
||||
m_static_rtree.reset();
|
||||
}
|
||||
|
||||
explicit InternalDataFacade( const ServerPaths & server_paths ) {
|
||||
//generate paths of data files
|
||||
if( server_paths.find("hsgrdata") == server_paths.end() ) {
|
||||
throw OSRMException("no hsgr file given in ini file");
|
||||
}
|
||||
if( server_paths.find("ramindex") == server_paths.end() ) {
|
||||
throw OSRMException("no ram index file given in ini file");
|
||||
}
|
||||
if( server_paths.find("fileindex") == server_paths.end() ) {
|
||||
throw OSRMException("no leaf index file given in ini file");
|
||||
}
|
||||
if( server_paths.find("geometries") == server_paths.end() ) {
|
||||
throw OSRMException("no geometries file given in ini file");
|
||||
}
|
||||
if( server_paths.find("nodesdata") == server_paths.end() ) {
|
||||
throw OSRMException("no nodes file given in ini file");
|
||||
}
|
||||
if( server_paths.find("edgesdata") == server_paths.end() ) {
|
||||
throw OSRMException("no edges file given in ini file");
|
||||
}
|
||||
if( server_paths.find("namesdata") == server_paths.end() ) {
|
||||
throw OSRMException("no names file given in ini file");
|
||||
}
|
||||
|
||||
ServerPaths::const_iterator paths_iterator = server_paths.find("hsgrdata");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path & hsgr_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("timestamp");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path & timestamp_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("ramindex");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path & ram_index_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("fileindex");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path & file_index_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("nodesdata");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path & nodes_data_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("edgesdata");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path & edges_data_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("namesdata");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path & names_data_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("geometries");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path & geometries_path = paths_iterator->second;
|
||||
|
||||
//load data
|
||||
SimpleLogger().Write() << "loading graph data";
|
||||
LoadGraph(hsgr_path);
|
||||
SimpleLogger().Write() << "loading egde information";
|
||||
LoadNodeAndEdgeInformation(nodes_data_path, edges_data_path);
|
||||
SimpleLogger().Write() << "loading geometries";
|
||||
LoadGeometries( geometries_path );
|
||||
SimpleLogger().Write() << "loading r-tree";
|
||||
LoadRTree(ram_index_path, file_index_path);
|
||||
SimpleLogger().Write() << "loading timestamp";
|
||||
LoadTimestamp(timestamp_path);
|
||||
SimpleLogger().Write() << "loading street names";
|
||||
LoadStreetNames(names_data_path);
|
||||
}
|
||||
|
||||
//search graph access
|
||||
unsigned GetNumberOfNodes() const {
|
||||
return m_query_graph->GetNumberOfNodes();
|
||||
}
|
||||
|
||||
unsigned GetNumberOfEdges() const {
|
||||
return m_query_graph->GetNumberOfEdges();
|
||||
}
|
||||
|
||||
unsigned GetOutDegree( const NodeID n ) const {
|
||||
return m_query_graph->GetOutDegree(n);
|
||||
}
|
||||
|
||||
NodeID GetTarget( const EdgeID e ) const {
|
||||
return m_query_graph->GetTarget(e); }
|
||||
|
||||
EdgeDataT &GetEdgeData( const EdgeID e ) {
|
||||
return m_query_graph->GetEdgeData(e);
|
||||
}
|
||||
|
||||
const EdgeDataT &GetEdgeData( const EdgeID e ) const {
|
||||
return m_query_graph->GetEdgeData(e);
|
||||
}
|
||||
|
||||
EdgeID BeginEdges( const NodeID n ) const {
|
||||
return m_query_graph->BeginEdges(n);
|
||||
}
|
||||
|
||||
EdgeID EndEdges( const NodeID n ) const {
|
||||
return m_query_graph->EndEdges(n);
|
||||
}
|
||||
|
||||
//searches for a specific edge
|
||||
EdgeID FindEdge( const NodeID from, const NodeID to ) const {
|
||||
return m_query_graph->FindEdge(from, to);
|
||||
}
|
||||
|
||||
EdgeID FindEdgeInEitherDirection(
|
||||
const NodeID from,
|
||||
const NodeID to
|
||||
) const {
|
||||
return m_query_graph->FindEdgeInEitherDirection(from, to);
|
||||
}
|
||||
|
||||
EdgeID FindEdgeIndicateIfReverse(
|
||||
const NodeID from,
|
||||
const NodeID to,
|
||||
bool & result
|
||||
) const {
|
||||
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
|
||||
}
|
||||
|
||||
//node and edge information access
|
||||
FixedPointCoordinate GetCoordinateOfNode(
|
||||
const unsigned id
|
||||
) const {
|
||||
return m_coordinate_list->at(id);
|
||||
};
|
||||
|
||||
bool EdgeIsCompressed( const unsigned id ) const {
|
||||
return m_egde_is_compressed.at(id);
|
||||
}
|
||||
|
||||
TurnInstruction GetTurnInstructionForEdgeID(
|
||||
const unsigned id
|
||||
) const {
|
||||
return m_turn_instruction_list.at(id);
|
||||
}
|
||||
|
||||
bool LocateClosestEndPointForCoordinate(
|
||||
const FixedPointCoordinate& input_coordinate,
|
||||
FixedPointCoordinate& result,
|
||||
const unsigned zoom_level = 18
|
||||
) const {
|
||||
return m_static_rtree->LocateClosestEndPointForCoordinate(
|
||||
input_coordinate,
|
||||
result,
|
||||
zoom_level
|
||||
);
|
||||
}
|
||||
|
||||
bool FindPhantomNodeForCoordinate(
|
||||
const FixedPointCoordinate & input_coordinate,
|
||||
PhantomNode & resulting_phantom_node,
|
||||
const unsigned zoom_level
|
||||
) const {
|
||||
const bool found = m_static_rtree->FindPhantomNodeForCoordinate(
|
||||
input_coordinate,
|
||||
resulting_phantom_node,
|
||||
zoom_level
|
||||
);
|
||||
return found;
|
||||
}
|
||||
|
||||
unsigned GetCheckSum() const { return m_check_sum; }
|
||||
|
||||
unsigned GetNameIndexFromEdgeID(const unsigned id) const {
|
||||
return m_name_ID_list.at(id);
|
||||
};
|
||||
|
||||
void GetName( const unsigned name_id, std::string & result ) const {
|
||||
if(UINT_MAX == name_id) {
|
||||
result = "";
|
||||
return;
|
||||
}
|
||||
BOOST_ASSERT_MSG(
|
||||
name_id < m_name_begin_indices.size(),
|
||||
"name id too high"
|
||||
);
|
||||
const unsigned begin_index = m_name_begin_indices[name_id];
|
||||
const unsigned end_index = m_name_begin_indices[name_id+1];
|
||||
BOOST_ASSERT_MSG(
|
||||
begin_index < m_names_char_list.size(),
|
||||
"begin index of name too high"
|
||||
);
|
||||
BOOST_ASSERT_MSG(
|
||||
end_index < m_names_char_list.size(),
|
||||
"end index of name too high"
|
||||
);
|
||||
|
||||
BOOST_ASSERT_MSG(begin_index <= end_index, "string ends before begin");
|
||||
result.clear();
|
||||
result.resize(end_index - begin_index);
|
||||
std::copy(
|
||||
m_names_char_list.begin() + begin_index,
|
||||
m_names_char_list.begin() + end_index,
|
||||
result.begin()
|
||||
);
|
||||
}
|
||||
|
||||
virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const {
|
||||
return m_via_node_list.at(id);
|
||||
}
|
||||
|
||||
virtual void GetUncompressedGeometry(
|
||||
const unsigned id, std::vector<unsigned> & result_nodes
|
||||
) const {
|
||||
const unsigned begin = m_geometry_indices.at(id);
|
||||
const unsigned end = m_geometry_indices.at(id+1);
|
||||
|
||||
result_nodes.clear();
|
||||
result_nodes.insert(result_nodes.begin(),
|
||||
m_geometry_list.begin() + begin,
|
||||
m_geometry_list.begin() + end);
|
||||
}
|
||||
|
||||
std::string GetTimestamp() const {
|
||||
return m_timestamp;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // INTERNAL_DATA_FACADE
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SHARED_BARRIER_H
|
||||
#define SHARED_BARRIER_H
|
||||
|
||||
#include <boost/interprocess/sync/named_mutex.hpp>
|
||||
#include <boost/interprocess/sync/named_condition.hpp>
|
||||
|
||||
struct SharedBarriers {
|
||||
|
||||
SharedBarriers ()
|
||||
:
|
||||
pending_update_mutex(
|
||||
boost::interprocess::open_or_create,
|
||||
"pending_update"
|
||||
),
|
||||
update_mutex(
|
||||
boost::interprocess::open_or_create,
|
||||
"update"
|
||||
),
|
||||
query_mutex(
|
||||
boost::interprocess::open_or_create,
|
||||
"query"
|
||||
),
|
||||
no_running_queries_condition(
|
||||
boost::interprocess::open_or_create,
|
||||
"no_running_queries"
|
||||
),
|
||||
update_ongoing(false),
|
||||
number_of_queries(0)
|
||||
{ }
|
||||
|
||||
// Mutex to protect access to the boolean variable
|
||||
boost::interprocess::named_mutex pending_update_mutex;
|
||||
boost::interprocess::named_mutex update_mutex;
|
||||
boost::interprocess::named_mutex query_mutex;
|
||||
|
||||
// Condition that no update is running
|
||||
boost::interprocess::named_condition no_running_queries_condition;
|
||||
|
||||
// Is there an ongoing update?
|
||||
bool update_ongoing;
|
||||
// Is there any query?
|
||||
int number_of_queries;
|
||||
};
|
||||
|
||||
#endif //SHARED_BARRIER_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user