Compare commits
2371 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4db1b7bea5 | |||
| 32c5f14ed3 | |||
| cbd88c63b9 | |||
| 621e302a38 | |||
| 1db794b2cb | |||
| a1ccedb5bf | |||
| 189f8c3265 | |||
| 12238ebb52 | |||
| b033ac9f0b | |||
| a411589092 | |||
| 45673581ea | |||
| f9ecdca5d5 | |||
| accdbe92f0 | |||
| 644d082cb9 | |||
| f948fb081b | |||
| 42445dc10c | |||
| c1041e5a64 | |||
| b2bc169547 | |||
| 5713460331 | |||
| cc2e26fd52 | |||
| c0bd9da645 | |||
| 7348e7ca55 | |||
| 519dc986f9 | |||
| 1ae2964b0f | |||
| 237e8e02fd | |||
| 865052352e | |||
| 2064d6b2ce | |||
| 6c9227d4d0 | |||
| ef66e271c1 | |||
| 7c3b587028 | |||
| d399014633 | |||
| e27ce0e518 | |||
| 1a1e16c5b4 | |||
| 01e7232add | |||
| c69f99f282 | |||
| 391163cba0 | |||
| 4cddec298f | |||
| c306a59854 | |||
| dcc1b5ab2b | |||
| 938dff011f | |||
| 9123c93a90 | |||
| a551286a8f | |||
| 86fd04e556 | |||
| b6dbf81206 | |||
| af47252efe | |||
| 3b81b39998 | |||
| 802b93fa9a | |||
| 7899444135 | |||
| 1ab2b87cc0 | |||
| 97c66c6c82 | |||
| 733207d4a1 | |||
| a0ed70f0a2 | |||
| d3a6b5a77e | |||
| 7a523713c7 | |||
| f7265892ed | |||
| be266c7c2b | |||
| b1b41435b6 | |||
| 8f32a80778 | |||
| 5d79e0ac2f | |||
| 47a6cd5462 | |||
| 7528b27f99 | |||
| a4f9499305 | |||
| bb244e28bb | |||
| 6fac14dbd8 | |||
| 8b144f22c9 | |||
| 146eb3a20e | |||
| d8e444e620 | |||
| da9d63a384 | |||
| c5e85f3d6d | |||
| e05750547c | |||
| 315823cce1 | |||
| 6ff07f4e82 | |||
| 41b54cf25d | |||
| 5ee15ee339 | |||
| 01b0bce2d5 | |||
| cb57ccacef | |||
| 7e0d14b113 | |||
| d06eec5e42 | |||
| 9648821a79 | |||
| 21fb18fe5e | |||
| 6a2518c0df | |||
| 7886d06839 | |||
| 5a9eb6ef72 | |||
| b6c3d1d5bf | |||
| 9b2f6585fb | |||
| 46fd17a9ff | |||
| da73bae9c6 | |||
| 766e2713ab | |||
| 9957254a5a | |||
| 9f6859561c | |||
| 88573a66cd | |||
| 3ccbe9842c | |||
| 5971822f82 | |||
| cdf6baba1d | |||
| 4b7ddb6826 | |||
| 06b74c1f08 | |||
| 3a0eed2ee5 | |||
| 2557bdcf39 | |||
| 12d478784b | |||
| 38fef77d70 | |||
| e8bae78749 | |||
| e14bc30428 | |||
| 9485c97738 | |||
| 11aed6c93e | |||
| d53c267129 | |||
| 2f6de614c1 | |||
| 087080a6c3 | |||
| 41b22916f3 | |||
| 89f1071947 | |||
| 464de785cb | |||
| 8986777c58 | |||
| 65def1a9e2 | |||
| 176c2244ad | |||
| b161e10b73 | |||
| 5bef5dcb04 | |||
| 46a4c27582 | |||
| acc6da86de | |||
| 4d84bc0f01 | |||
| c737635a3b | |||
| b7eeafb183 | |||
| 677306eeee | |||
| 2284ebaacb | |||
| 6b4975b2e4 | |||
| 94c38d115a | |||
| b1e309b4eb | |||
| e8ce119972 | |||
| 8b7cd2931b | |||
| 8bee57b0b0 | |||
| 6bfe3a2d41 | |||
| 7f71f0ed12 | |||
| 583aaff286 | |||
| b24f5c7c1a | |||
| 026f71934b | |||
| 1353d55880 | |||
| b09f637d02 | |||
| 979f9cab20 | |||
| eb6083daf5 | |||
| c4718495a0 | |||
| 0d36d472c9 | |||
| 35422a0fb5 | |||
| d012b44b7f | |||
| eda6d9dc7c | |||
| 63c86198a3 | |||
| 33bdfe9cf9 | |||
| a87c5998a1 | |||
| c918a7957b | |||
| 61e6afdef0 | |||
| 95dc36e908 | |||
| 951a4dc112 | |||
| c09b9b4c99 | |||
| b0873e2aa4 | |||
| 2bdb8fce63 | |||
| d8a692740a | |||
| 14797c421e | |||
| 280b000f07 | |||
| fb4834458e | |||
| c7a1576100 | |||
| aebf6fa0b1 | |||
| f76e3d4522 | |||
| eaf42ba437 | |||
| e83905b783 | |||
| 0b868969be | |||
| b4710633b1 | |||
| 7d076e9344 | |||
| 71d64e8cd9 | |||
| 748fd3efa9 | |||
| 1fc63e1e72 | |||
| fd6bb5ec1f | |||
| 261dbf3edd | |||
| 9e323d2d42 | |||
| 1309dd2a0f | |||
| 9b737230d6 | |||
| ecbd709535 | |||
| 060ec99678 | |||
| 3601d1d262 | |||
| 41ba20ca9a | |||
| 57e3f173d3 | |||
| 92c298c7cf | |||
| b25011ee60 | |||
| 0e017a6ce5 | |||
| 2431e15ffa | |||
| 396add1e9d | |||
| 86241a2793 | |||
| ee47afbe17 | |||
| 8831ca2f32 | |||
| abde215bc3 | |||
| 130d5298fc | |||
| 50cbba1620 | |||
| 2cc293ad16 | |||
| 6ac65a922f | |||
| 3d80f989d0 | |||
| 4fcb5d28a4 | |||
| 3ebdacf369 | |||
| 2ddc00c21e | |||
| e76e39a398 | |||
| 04667f1ed8 | |||
| 2091c3443b | |||
| 2b466b2fb2 | |||
| e17b306265 | |||
| b00b15ab98 | |||
| f4db79fe9b | |||
| 0e4061f858 | |||
| 043a1446e1 | |||
| 49221995e8 | |||
| 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 |
+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"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# Issue
|
||||
|
||||
What issue is this PR targeting? Is there no issue that covers the problem addressed here? Please open a corresponding issue and link it from here.
|
||||
|
||||
## Tasklist
|
||||
- [ ] ADD OWN TASKS HERE
|
||||
- [ ] add regression / cucumber cases (see docs/testing.md)
|
||||
- [ ] review
|
||||
- [ ] adjust for for comments
|
||||
|
||||
## Requirements / Relations
|
||||
Link any requirements here. Other pull requests this PR is based on?
|
||||
+17
-20
@@ -1,3 +1,7 @@
|
||||
# pre compiled dependencies #
|
||||
#############################
|
||||
osrm-deps
|
||||
|
||||
# Compiled source #
|
||||
###################
|
||||
*.com
|
||||
@@ -36,8 +40,8 @@ Thumbs.db
|
||||
# build related files #
|
||||
#######################
|
||||
/build/
|
||||
/Util/FingerPrint.cpp
|
||||
/Util/GitDescription.cpp
|
||||
/example/build/
|
||||
/test/data/monaco*
|
||||
/cmake/postinst
|
||||
|
||||
# Eclipse related files #
|
||||
@@ -53,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
|
||||
@@ -81,14 +68,24 @@ stxxl.errlog
|
||||
/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
|
||||
|
||||
+172
-52
@@ -1,57 +1,177 @@
|
||||
language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
# - clang
|
||||
# Make sure CMake is installed
|
||||
install:
|
||||
- sudo apt-add-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- sudo add-apt-repository -y ppa:boost-latest/ppa
|
||||
- sudo apt-get update >/dev/null
|
||||
- sudo apt-get -q install protobuf-compiler libprotoc-dev libprotobuf7 libprotobuf-dev libosmpbf-dev libbz2-dev libstxxl-dev libstxxl1 libxml2-dev libzip-dev lua5.1 liblua5.1-0-dev rubygems libtbb-dev
|
||||
- sudo apt-get -q install g++-4.8
|
||||
- sudo apt-get install libboost1.54-all-dev
|
||||
#luabind
|
||||
- curl https://gist.githubusercontent.com/DennisOSRM/f2eb7b948e6fe1ae319e/raw/install-luabind.sh | sudo bash
|
||||
#osmosis
|
||||
- curl -s https://gist.githubusercontent.com/DennisOSRM/803a64a9178ec375069f/raw/ | sudo bash
|
||||
#cmake
|
||||
- curl -s https://gist.githubusercontent.com/DennisOSRM/5fad9bee5c7f09fd7fc9/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
|
||||
- make -j 2 tests
|
||||
- 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 -DCMAKE_CXX_COMPILER=g++-4.8" OSRM_PORT=5000 OSRM_TIMEOUT=60
|
||||
- CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=g++-4.8" 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
|
||||
- 5.4
|
||||
|
||||
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
|
||||
- CASHER_TIME_OUT=599 # one second less than 10m to avoid 10m timeout error: https://github.com/Project-OSRM/osrm-backend/issues/2742
|
||||
- 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: "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'
|
||||
|
||||
# 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=ON -DBUILD_COMPONENTS=ON -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,147 +0,0 @@
|
||||
#ifndef BFS_COMPONENT_EXPLORER_H_
|
||||
#define BFS_COMPONENT_EXPLORER_H_
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../DataStructures/RestrictionMap.h"
|
||||
|
||||
#include <queue>
|
||||
#include <unordered_set>
|
||||
|
||||
// Explores the components of the given graph while respecting turn restrictions
|
||||
// and barriers.
|
||||
template <typename GraphT> class BFSComponentExplorer
|
||||
{
|
||||
public:
|
||||
BFSComponentExplorer(const GraphT &dynamic_graph,
|
||||
const RestrictionMap &restrictions,
|
||||
const std::unordered_set<NodeID> &barrier_nodes)
|
||||
: m_graph(dynamic_graph), m_restriction_map(restrictions), m_barrier_nodes(barrier_nodes)
|
||||
{
|
||||
BOOST_ASSERT(m_graph.GetNumberOfNodes() > 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Returns the size of the component that the node belongs to.
|
||||
*/
|
||||
unsigned int GetComponentSize(const NodeID node) const
|
||||
{
|
||||
BOOST_ASSERT(node < m_component_index_list.size());
|
||||
|
||||
return m_component_index_size[m_component_index_list[node]];
|
||||
}
|
||||
|
||||
unsigned int GetNumberOfComponents() { return m_component_index_size.size(); }
|
||||
|
||||
/*!
|
||||
* Computes the component sizes.
|
||||
*/
|
||||
void run()
|
||||
{
|
||||
std::queue<std::pair<NodeID, NodeID>> bfs_queue;
|
||||
unsigned current_component = 0;
|
||||
|
||||
BOOST_ASSERT(m_component_index_list.empty());
|
||||
BOOST_ASSERT(m_component_index_size.empty());
|
||||
|
||||
unsigned num_nodes = m_graph.GetNumberOfNodes();
|
||||
|
||||
m_component_index_list.resize(num_nodes, std::numeric_limits<unsigned>::max());
|
||||
|
||||
BOOST_ASSERT(num_nodes > 0);
|
||||
|
||||
// put unexplorered node with parent pointer into queue
|
||||
for (NodeID node = 0; node < num_nodes; ++node)
|
||||
{
|
||||
if (std::numeric_limits<unsigned>::max() == m_component_index_list[node])
|
||||
{
|
||||
unsigned size = ExploreComponent(bfs_queue, node, current_component);
|
||||
|
||||
// push size into vector
|
||||
m_component_index_size.emplace_back(size);
|
||||
++current_component;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/*!
|
||||
* Explores the current component that starts at node using BFS.
|
||||
*/
|
||||
unsigned ExploreComponent(std::queue<std::pair<NodeID, NodeID>> &bfs_queue,
|
||||
NodeID node,
|
||||
unsigned current_component)
|
||||
{
|
||||
/*
|
||||
Graphical representation of variables:
|
||||
|
||||
u v w
|
||||
*---------->*---------->*
|
||||
e2
|
||||
*/
|
||||
|
||||
bfs_queue.emplace(node, node);
|
||||
// mark node as read
|
||||
m_component_index_list[node] = current_component;
|
||||
|
||||
unsigned current_component_size = 1;
|
||||
|
||||
while (!bfs_queue.empty())
|
||||
{
|
||||
// fetch element from BFS queue
|
||||
std::pair<NodeID, NodeID> current_queue_item = bfs_queue.front();
|
||||
bfs_queue.pop();
|
||||
|
||||
const NodeID v = current_queue_item.first; // current node
|
||||
const NodeID u = current_queue_item.second; // parent
|
||||
// increment size counter of current component
|
||||
++current_component_size;
|
||||
const bool is_barrier_node = (m_barrier_nodes.find(v) != m_barrier_nodes.end());
|
||||
if (!is_barrier_node)
|
||||
{
|
||||
const NodeID to_node_of_only_restriction =
|
||||
m_restriction_map.CheckForEmanatingIsOnlyTurn(u, v);
|
||||
|
||||
for (auto e2 : m_graph.GetAdjacentEdgeRange(v))
|
||||
{
|
||||
const NodeID w = m_graph.GetTarget(e2);
|
||||
|
||||
if (to_node_of_only_restriction != std::numeric_limits<unsigned>::max() &&
|
||||
w != to_node_of_only_restriction)
|
||||
{
|
||||
// At an only_-restriction but not at the right turn
|
||||
continue;
|
||||
}
|
||||
|
||||
if (u != w)
|
||||
{
|
||||
// only add an edge if turn is not a U-turn except
|
||||
// when it is at the end of a dead-end street.
|
||||
if (!m_restriction_map.CheckIfTurnIsRestricted(u, v, w))
|
||||
{
|
||||
// only add an edge if turn is not prohibited
|
||||
if (std::numeric_limits<unsigned>::max() == m_component_index_list[w])
|
||||
{
|
||||
// insert next (node, parent) only if w has
|
||||
// not yet been explored
|
||||
// mark node as read
|
||||
m_component_index_list[w] = current_component;
|
||||
bfs_queue.emplace(w, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return current_component_size;
|
||||
}
|
||||
|
||||
std::vector<unsigned> m_component_index_list;
|
||||
std::vector<NodeID> m_component_index_size;
|
||||
|
||||
const GraphT &m_graph;
|
||||
const RestrictionMap &m_restriction_map;
|
||||
const std::unordered_set<NodeID> &m_barrier_nodes;
|
||||
};
|
||||
|
||||
#endif // BFS_COMPONENT_EXPLORER_H_
|
||||
@@ -1,186 +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/Range.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
struct CoordinatePairCalculator
|
||||
{
|
||||
CoordinatePairCalculator() = delete;
|
||||
CoordinatePairCalculator(const FixedPointCoordinate &coordinate_a,
|
||||
const FixedPointCoordinate &coordinate_b)
|
||||
{
|
||||
// initialize distance calculator with two fixed coordinates a, b
|
||||
const float RAD = 0.017453292519943295769236907684886f;
|
||||
first_lat = (coordinate_a.lat / COORDINATE_PRECISION) * RAD;
|
||||
first_lon = (coordinate_a.lon / COORDINATE_PRECISION) * RAD;
|
||||
second_lat = (coordinate_b.lat / COORDINATE_PRECISION) * RAD;
|
||||
second_lon = (coordinate_b.lon / COORDINATE_PRECISION) * RAD;
|
||||
}
|
||||
|
||||
int operator()(FixedPointCoordinate &other) const
|
||||
{
|
||||
// set third coordinate c
|
||||
const float RAD = 0.017453292519943295769236907684886f;
|
||||
const float earth_radius = 6372797.560856f;
|
||||
const float float_lat1 = (other.lat / COORDINATE_PRECISION) * RAD;
|
||||
const float float_lon1 = (other.lon / COORDINATE_PRECISION) * RAD;
|
||||
|
||||
// compute distance (a,c)
|
||||
const float x_value_1 = (first_lon - float_lon1) * cos((float_lat1 + first_lat) / 2.f);
|
||||
const float y_value_1 = first_lat - float_lat1;
|
||||
const float dist1 = sqrt(std::pow(x_value_1, 2) + std::pow(y_value_1, 2)) * earth_radius;
|
||||
|
||||
// compute distance (b,c)
|
||||
const float x_value_2 = (second_lon - float_lon1) * cos((float_lat1 + second_lat) / 2.f);
|
||||
const float y_value_2 = second_lat - float_lat1;
|
||||
const float dist2 = sqrt(std::pow(x_value_2, 2) + std::pow(y_value_2, 2)) * earth_radius;
|
||||
|
||||
// return the minimum
|
||||
return static_cast<int>(std::min(dist1, dist2));
|
||||
}
|
||||
|
||||
float first_lat;
|
||||
float first_lon;
|
||||
float second_lat;
|
||||
float second_lon;
|
||||
};
|
||||
}
|
||||
|
||||
DouglasPeucker::DouglasPeucker()
|
||||
: douglas_peucker_thresholds({512440, // z0
|
||||
256720, // z1
|
||||
122560, // z2
|
||||
56780, // z3
|
||||
28800, // z4
|
||||
14400, // z5
|
||||
7200, // z6
|
||||
3200, // z7
|
||||
2400, // z8
|
||||
1000, // z9
|
||||
600, // z10
|
||||
120, // z11
|
||||
60, // z12
|
||||
45, // z13
|
||||
36, // z14
|
||||
20, // z15
|
||||
8, // z16
|
||||
6, // z17
|
||||
4 // z18
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level)
|
||||
{
|
||||
// check if input data is invalid
|
||||
BOOST_ASSERT_MSG(!input_geometry.empty(), "geometry invalid");
|
||||
|
||||
if (input_geometry.size() < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
input_geometry.front().necessary = true;
|
||||
input_geometry.back().necessary = true;
|
||||
|
||||
{
|
||||
BOOST_ASSERT_MSG(zoom_level < 19, "unsupported zoom level");
|
||||
unsigned left_border = 0;
|
||||
unsigned right_border = 1;
|
||||
// Sweep over array and identify those ranges that need to be checked
|
||||
do
|
||||
{
|
||||
// traverse list until new border element found
|
||||
if (input_geometry[right_border].necessary)
|
||||
{
|
||||
// sanity checks
|
||||
BOOST_ASSERT(input_geometry[left_border].necessary);
|
||||
BOOST_ASSERT(input_geometry[right_border].necessary);
|
||||
recursion_stack.emplace(left_border, right_border);
|
||||
left_border = right_border;
|
||||
}
|
||||
++right_border;
|
||||
} while (right_border < input_geometry.size());
|
||||
}
|
||||
|
||||
// mark locations as 'necessary' by divide-and-conquer
|
||||
while (!recursion_stack.empty())
|
||||
{
|
||||
// pop next element
|
||||
const GeometryRange pair = recursion_stack.top();
|
||||
recursion_stack.pop();
|
||||
// sanity checks
|
||||
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");
|
||||
|
||||
int max_int_distance = 0;
|
||||
unsigned farthest_entry_index = pair.second;
|
||||
const CoordinatePairCalculator dist_calc(input_geometry[pair.first].location,
|
||||
input_geometry[pair.second].location);
|
||||
|
||||
// sweep over range to find the maximum
|
||||
for (const auto i : osrm::irange(pair.first + 1, pair.second))
|
||||
{
|
||||
const int distance = dist_calc(input_geometry[i].location);
|
||||
// found new feasible maximum?
|
||||
if (distance > max_int_distance && distance > douglas_peucker_thresholds[zoom_level])
|
||||
{
|
||||
farthest_entry_index = i;
|
||||
max_int_distance = distance;
|
||||
}
|
||||
}
|
||||
|
||||
// check if maximum violates a zoom level dependent threshold
|
||||
if (max_int_distance > douglas_peucker_thresholds[zoom_level])
|
||||
{
|
||||
// mark idx as necessary
|
||||
input_geometry[farthest_entry_index].necessary = true;
|
||||
if (1 < (farthest_entry_index - pair.first))
|
||||
{
|
||||
recursion_stack.emplace(pair.first, farthest_entry_index);
|
||||
}
|
||||
if (1 < (pair.second - farthest_entry_index))
|
||||
{
|
||||
recursion_stack.emplace(farthest_entry_index, pair.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +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 <stack>
|
||||
#include <utility>
|
||||
#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:
|
||||
std::vector<int> douglas_peucker_thresholds;
|
||||
|
||||
using GeometryRange = std::pair<unsigned, unsigned>;
|
||||
// Stack to simulate the recursion
|
||||
std::stack<GeometryRange> recursion_stack;
|
||||
|
||||
public:
|
||||
DouglasPeucker();
|
||||
void Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level);
|
||||
};
|
||||
|
||||
#endif /* DOUGLASPEUCKER_H_ */
|
||||
@@ -1,169 +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 EXTRACT_ROUTE_NAMES_H
|
||||
#define EXTRACT_ROUTE_NAMES_H
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct RouteNames
|
||||
{
|
||||
std::string shortest_path_name_1;
|
||||
std::string shortest_path_name_2;
|
||||
std::string alternative_path_name_1;
|
||||
std::string alternative_path_name_2;
|
||||
};
|
||||
|
||||
// construct routes names
|
||||
template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
|
||||
{
|
||||
private:
|
||||
SegmentT PickNextLongestSegment(const std::vector<SegmentT> &segment_list,
|
||||
const unsigned blocked_name_id) const
|
||||
{
|
||||
SegmentT result_segment;
|
||||
result_segment.length = 0;
|
||||
|
||||
for (const SegmentT &segment : segment_list)
|
||||
{
|
||||
if (segment.name_id != blocked_name_id && segment.length > result_segment.length && segment.name_id != 0)
|
||||
{
|
||||
result_segment = segment;
|
||||
}
|
||||
}
|
||||
return result_segment;
|
||||
}
|
||||
|
||||
public:
|
||||
RouteNames operator()(std::vector<SegmentT> &shortest_path_segments,
|
||||
std::vector<SegmentT> &alternative_path_segments,
|
||||
const DataFacadeT *facade) const
|
||||
{
|
||||
RouteNames route_names;
|
||||
|
||||
SegmentT shortest_segment_1, shortest_segment_2;
|
||||
SegmentT alternative_segment_1, alternative_segment_2;
|
||||
|
||||
auto length_comperator = [](const SegmentT &a, const SegmentT &b)
|
||||
{ return a.length > b.length; };
|
||||
auto name_id_comperator = [](const SegmentT &a, const SegmentT &b)
|
||||
{ return a.name_id < b.name_id; };
|
||||
|
||||
if (shortest_path_segments.empty())
|
||||
{
|
||||
return route_names;
|
||||
}
|
||||
|
||||
// pick the longest segment for the shortest path.
|
||||
std::sort(shortest_path_segments.begin(), shortest_path_segments.end(), length_comperator);
|
||||
shortest_segment_1 = shortest_path_segments[0];
|
||||
if (!alternative_path_segments.empty())
|
||||
{
|
||||
std::sort(alternative_path_segments.begin(),
|
||||
alternative_path_segments.end(),
|
||||
length_comperator);
|
||||
|
||||
// also pick the longest segment for the alternative path
|
||||
alternative_segment_1 = alternative_path_segments[0];
|
||||
}
|
||||
|
||||
// compute the set difference (for shortest path) depending on names between shortest and
|
||||
// alternative
|
||||
std::vector<SegmentT> shortest_path_set_difference(shortest_path_segments.size());
|
||||
std::sort(shortest_path_segments.begin(), shortest_path_segments.end(), name_id_comperator);
|
||||
std::sort(alternative_path_segments.begin(), alternative_path_segments.end(), name_id_comperator);
|
||||
std::set_difference(shortest_path_segments.begin(),
|
||||
shortest_path_segments.end(),
|
||||
alternative_path_segments.begin(),
|
||||
alternative_path_segments.end(),
|
||||
shortest_path_set_difference.begin(),
|
||||
name_id_comperator);
|
||||
|
||||
std::sort(shortest_path_set_difference.begin(),
|
||||
shortest_path_set_difference.end(),
|
||||
length_comperator);
|
||||
shortest_segment_2 =
|
||||
PickNextLongestSegment(shortest_path_set_difference, shortest_segment_1.name_id);
|
||||
|
||||
// compute the set difference (for alternative path) depending on names between shortest and
|
||||
// alternative
|
||||
// vectors are still sorted, no need to do again
|
||||
BOOST_ASSERT(std::is_sorted(shortest_path_segments.begin(),
|
||||
shortest_path_segments.end(),
|
||||
name_id_comperator));
|
||||
BOOST_ASSERT(std::is_sorted(alternative_path_segments.begin(),
|
||||
alternative_path_segments.end(),
|
||||
name_id_comperator));
|
||||
|
||||
std::vector<SegmentT> alternative_path_set_difference(alternative_path_segments.size());
|
||||
std::set_difference(alternative_path_segments.begin(),
|
||||
alternative_path_segments.end(),
|
||||
shortest_path_segments.begin(),
|
||||
shortest_path_segments.end(),
|
||||
alternative_path_set_difference.begin(),
|
||||
name_id_comperator);
|
||||
|
||||
std::sort(alternative_path_set_difference.begin(),
|
||||
alternative_path_set_difference.end(),
|
||||
length_comperator);
|
||||
|
||||
if (!alternative_path_segments.empty())
|
||||
{
|
||||
alternative_segment_2 = PickNextLongestSegment(alternative_path_set_difference,
|
||||
alternative_segment_1.name_id);
|
||||
}
|
||||
|
||||
// move the segments into the order in which they occur.
|
||||
if (shortest_segment_1.position > shortest_segment_2.position)
|
||||
{
|
||||
std::swap(shortest_segment_1, shortest_segment_2);
|
||||
}
|
||||
if (alternative_segment_1.position > alternative_segment_2.position)
|
||||
{
|
||||
std::swap(alternative_segment_1, alternative_segment_2);
|
||||
}
|
||||
|
||||
// fetching names for the selected segments
|
||||
route_names.shortest_path_name_1 =
|
||||
facade->GetEscapedNameForNameID(shortest_segment_1.name_id);
|
||||
route_names.shortest_path_name_2 =
|
||||
facade->GetEscapedNameForNameID(shortest_segment_2.name_id);
|
||||
|
||||
route_names.alternative_path_name_1 =
|
||||
facade->GetEscapedNameForNameID(alternative_segment_1.name_id);
|
||||
route_names.alternative_path_name_2 =
|
||||
facade->GetEscapedNameForNameID(alternative_segment_2.name_id);
|
||||
|
||||
return route_names;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // EXTRACT_ROUTE_NAMES_H
|
||||
@@ -1,94 +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 OBJECT_TO_BASE64_H_
|
||||
#define OBJECT_TO_BASE64_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 <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct ObjectEncoder
|
||||
{
|
||||
using base64_t = boost::archive::iterators::base64_from_binary<
|
||||
boost::archive::iterators::transform_width<const char *, 6, 8>>;
|
||||
|
||||
using binary_t = boost::archive::iterators::transform_width<
|
||||
boost::archive::iterators::binary_from_base64<std::string::const_iterator>,
|
||||
8,
|
||||
6>;
|
||||
|
||||
template <class ObjectT>
|
||||
static void EncodeToBase64(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 DecodeFromBase64(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 /* OBJECT_TO_BASE64_H_ */
|
||||
@@ -1,112 +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"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
void PolylineCompressor::encodeVectorSignedNumber(std::vector<int> &numbers,
|
||||
std::string &output) const
|
||||
{
|
||||
const unsigned end = static_cast<unsigned>(numbers.size());
|
||||
for (unsigned i = 0; i < end; ++i)
|
||||
{
|
||||
numbers[i] <<= 1;
|
||||
if (numbers[i] < 0)
|
||||
{
|
||||
numbers[i] = ~(numbers[i]);
|
||||
}
|
||||
}
|
||||
for (const int number : numbers)
|
||||
{
|
||||
encodeNumber(number, output);
|
||||
}
|
||||
}
|
||||
|
||||
void PolylineCompressor::encodeNumber(int number_to_encode, std::string &output) const
|
||||
{
|
||||
while (number_to_encode >= 0x20)
|
||||
{
|
||||
const int next_value = (0x20 | (number_to_encode & 0x1f)) + 63;
|
||||
output += static_cast<char>(next_value);
|
||||
if (92 == next_value)
|
||||
{
|
||||
output += static_cast<char>(next_value);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
JSON::String
|
||||
PolylineCompressor::printEncodedString(const std::vector<SegmentInformation> &polyline) const
|
||||
{
|
||||
std::string output;
|
||||
std::vector<int> delta_numbers;
|
||||
if (!polyline.empty())
|
||||
{
|
||||
FixedPointCoordinate last_coordinate = {0, 0};
|
||||
for (const auto &segment : polyline)
|
||||
{
|
||||
if (segment.necessary)
|
||||
{
|
||||
const int lat_diff = segment.location.lat - last_coordinate.lat;
|
||||
const int lon_diff = segment.location.lon - last_coordinate.lon;
|
||||
delta_numbers.emplace_back(lat_diff);
|
||||
delta_numbers.emplace_back(lon_diff);
|
||||
last_coordinate = segment.location;
|
||||
}
|
||||
}
|
||||
encodeVectorSignedNumber(delta_numbers, output);
|
||||
}
|
||||
JSON::String return_value(output);
|
||||
return return_value;
|
||||
}
|
||||
|
||||
JSON::Array
|
||||
PolylineCompressor::printUnencodedString(const std::vector<SegmentInformation> &polyline) const
|
||||
{
|
||||
JSON::Array json_geometry_array;
|
||||
for (const auto &segment : polyline)
|
||||
{
|
||||
if (segment.necessary)
|
||||
{
|
||||
JSON::Array json_coordinate;
|
||||
json_coordinate.values.push_back(segment.location.lat / COORDINATE_PRECISION);
|
||||
json_coordinate.values.push_back(segment.location.lon / COORDINATE_PRECISION);
|
||||
json_geometry_array.values.push_back(json_coordinate);
|
||||
}
|
||||
}
|
||||
return json_geometry_array;
|
||||
}
|
||||
@@ -1,51 +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_
|
||||
|
||||
struct SegmentInformation;
|
||||
|
||||
#include "../DataStructures/JSONContainer.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:
|
||||
JSON::String printEncodedString(const std::vector<SegmentInformation> &polyline) const;
|
||||
|
||||
JSON::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const;
|
||||
};
|
||||
|
||||
#endif /* POLYLINECOMPRESSOR_H_ */
|
||||
@@ -1,459 +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 "../typedefs.h"
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
#include "../DataStructures/DynamicGraph.h"
|
||||
#include "../DataStructures/ImportEdge.h"
|
||||
#include "../DataStructures/QueryNode.h"
|
||||
#include "../DataStructures/Percent.h"
|
||||
#include "../DataStructures/Range.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/simple_logger.hpp"
|
||||
#include "../Util/StdHashExtensions.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <tbb/parallel_sort.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <gdal.h>
|
||||
#include <ogrsf_frmts.h>
|
||||
#else
|
||||
#include <gdal/gdal.h>
|
||||
#include <gdal/ogrsf_frmts.h>
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
class TarjanSCC
|
||||
{
|
||||
private:
|
||||
struct TarjanNode
|
||||
{
|
||||
TarjanNode() : index(SPECIAL_NODEID), low_link(SPECIAL_NODEID), on_stack(false) {}
|
||||
unsigned index;
|
||||
unsigned low_link;
|
||||
bool on_stack;
|
||||
};
|
||||
|
||||
struct TarjanEdgeData
|
||||
{
|
||||
TarjanEdgeData() : distance(INVALID_EDGE_WEIGHT), name_id(INVALID_NAMEID) {}
|
||||
TarjanEdgeData(int distance, unsigned name_id) : distance(distance), name_id(name_id) {}
|
||||
int distance;
|
||||
unsigned name_id;
|
||||
};
|
||||
|
||||
struct TarjanStackFrame
|
||||
{
|
||||
explicit TarjanStackFrame(NodeID v, NodeID parent) : v(v), parent(parent) {}
|
||||
NodeID v;
|
||||
NodeID parent;
|
||||
};
|
||||
|
||||
using TarjanDynamicGraph = DynamicGraph<TarjanEdgeData>;
|
||||
using TarjanEdge = TarjanDynamicGraph::InputEdge;
|
||||
using RestrictionSource = std::pair<NodeID, NodeID>;
|
||||
using RestrictionTarget = std::pair<NodeID, bool>;
|
||||
using EmanatingRestrictionsVector = std::vector<RestrictionTarget>;
|
||||
using RestrictionMap = std::unordered_map<RestrictionSource, unsigned>;
|
||||
|
||||
std::vector<NodeInfo> m_coordinate_list;
|
||||
std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list;
|
||||
std::shared_ptr<TarjanDynamicGraph> m_node_based_graph;
|
||||
std::unordered_set<NodeID> barrier_node_list;
|
||||
std::unordered_set<NodeID> traffic_light_list;
|
||||
unsigned m_restriction_counter;
|
||||
RestrictionMap m_restriction_map;
|
||||
|
||||
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())
|
||||
{
|
||||
TIMER_START(SCC_LOAD);
|
||||
for (const TurnRestriction &restriction : irs)
|
||||
{
|
||||
std::pair<NodeID, NodeID> restriction_source = {restriction.fromNode,
|
||||
restriction.viaNode};
|
||||
unsigned index = 0;
|
||||
const auto restriction_iterator = m_restriction_map.find(restriction_source);
|
||||
if (restriction_iterator == m_restriction_map.end())
|
||||
{
|
||||
index = m_restriction_bucket_list.size();
|
||||
m_restriction_bucket_list.resize(index + 1);
|
||||
m_restriction_map.emplace(restriction_source, 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)
|
||||
.emplace_back(restriction.toNode, restriction.flags.isOnly);
|
||||
}
|
||||
|
||||
barrier_node_list.insert(bn.begin(), bn.end());
|
||||
traffic_light_list.insert(tl.begin(), tl.end());
|
||||
|
||||
DeallocatingVector<TarjanEdge> edge_list;
|
||||
for (const NodeBasedEdge &input_edge : input_edges)
|
||||
{
|
||||
if (input_edge.source == input_edge.target)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (input_edge.forward)
|
||||
{
|
||||
edge_list.emplace_back(input_edge.source,
|
||||
input_edge.target,
|
||||
(std::max)((int)input_edge.weight, 1),
|
||||
input_edge.name_id);
|
||||
}
|
||||
if (input_edge.backward)
|
||||
{
|
||||
edge_list.emplace_back(input_edge.target,
|
||||
input_edge.source,
|
||||
(std::max)((int)input_edge.weight, 1),
|
||||
input_edge.name_id);
|
||||
}
|
||||
}
|
||||
input_edges.clear();
|
||||
input_edges.shrink_to_fit();
|
||||
BOOST_ASSERT_MSG(0 == input_edges.size() && 0 == input_edges.capacity(),
|
||||
"input edge vector not properly deallocated");
|
||||
|
||||
tbb::parallel_sort(edge_list.begin(), edge_list.end());
|
||||
m_node_based_graph = std::make_shared<TarjanDynamicGraph>(number_of_nodes, edge_list);
|
||||
TIMER_STOP(SCC_LOAD);
|
||||
SimpleLogger().Write() << "Loading data into SCC took " << TIMER_MSEC(SCC_LOAD)/1000. << "s";
|
||||
}
|
||||
|
||||
~TarjanSCC() { m_node_based_graph.reset(); }
|
||||
|
||||
void Run()
|
||||
{
|
||||
TIMER_START(SCC_RUN_SETUP);
|
||||
// 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 (nullptr == poDriver)
|
||||
{
|
||||
throw OSRMException("ESRI Shapefile driver not available");
|
||||
}
|
||||
OGRDataSource *poDS = poDriver->CreateDataSource("component.shp", nullptr);
|
||||
|
||||
if (nullptr == poDS)
|
||||
{
|
||||
throw OSRMException("Creation of output file failed");
|
||||
}
|
||||
|
||||
OGRSpatialReference *poSRS = new OGRSpatialReference();
|
||||
poSRS->importFromEPSG(4326);
|
||||
|
||||
OGRLayer *poLayer = poDS->CreateLayer("component", poSRS, wkbLineString, nullptr);
|
||||
|
||||
if (nullptr == poLayer)
|
||||
{
|
||||
throw OSRMException("Layer creation failed.");
|
||||
}
|
||||
TIMER_STOP(SCC_RUN_SETUP);
|
||||
SimpleLogger().Write() << "shapefile setup took " << TIMER_MSEC(SCC_RUN_SETUP)/1000. << "s";
|
||||
|
||||
TIMER_START(SCC_RUN);
|
||||
// The following is a hack to distinguish between stuff that happens
|
||||
// before the recursive call and stuff that happens after
|
||||
std::stack<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(),
|
||||
SPECIAL_NODEID);
|
||||
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;
|
||||
const NodeID last_node = m_node_based_graph->GetNumberOfNodes();
|
||||
std::vector<bool> processing_node_before_recursion(m_node_based_graph->GetNumberOfNodes(), true);
|
||||
for(const NodeID node : osrm::irange(0u, last_node))
|
||||
{
|
||||
if (SPECIAL_NODEID == components_index[node])
|
||||
{
|
||||
recursion_stack.emplace(TarjanStackFrame(node, node));
|
||||
}
|
||||
|
||||
while (!recursion_stack.empty())
|
||||
{
|
||||
TarjanStackFrame currentFrame = recursion_stack.top();
|
||||
const NodeID v = currentFrame.v;
|
||||
recursion_stack.pop();
|
||||
const bool before_recursion = processing_node_before_recursion[v];
|
||||
|
||||
if (before_recursion && tarjan_node_list[v].index != UINT_MAX)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (before_recursion)
|
||||
{
|
||||
// Mark frame to handle tail of recursion
|
||||
recursion_stack.emplace(currentFrame);
|
||||
processing_node_before_recursion[v] = false;
|
||||
|
||||
// Mark essential information for SCC
|
||||
tarjan_node_list[v].index = index;
|
||||
tarjan_node_list[v].low_link = index;
|
||||
tarjan_stack.push(v);
|
||||
tarjan_node_list[v].on_stack = true;
|
||||
++index;
|
||||
|
||||
// Traverse outgoing edges
|
||||
for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(v))
|
||||
{
|
||||
const TarjanDynamicGraph::NodeIterator vprime =
|
||||
m_node_based_graph->GetTarget(current_edge);
|
||||
if (SPECIAL_NODEID == tarjan_node_list[vprime].index)
|
||||
{
|
||||
recursion_stack.emplace(TarjanStackFrame(vprime, v));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tarjan_node_list[vprime].on_stack &&
|
||||
tarjan_node_list[vprime].index < tarjan_node_list[v].low_link)
|
||||
{
|
||||
tarjan_node_list[v].low_link = tarjan_node_list[vprime].index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
processing_node_before_recursion[v] = true;
|
||||
tarjan_node_list[currentFrame.parent].low_link =
|
||||
std::min(tarjan_node_list[currentFrame.parent].low_link,
|
||||
tarjan_node_list[v].low_link);
|
||||
// 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].low_link == tarjan_node_list[v].index)
|
||||
{
|
||||
NodeID vprime;
|
||||
do
|
||||
{
|
||||
vprime = tarjan_stack.top();
|
||||
tarjan_stack.pop();
|
||||
tarjan_node_list[vprime].on_stack = false;
|
||||
components_index[vprime] = component_index;
|
||||
++size_of_current_component;
|
||||
} while (v != vprime);
|
||||
|
||||
component_size_vector.emplace_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TIMER_STOP(SCC_RUN);
|
||||
SimpleLogger().Write() << "SCC run took: " << TIMER_MSEC(SCC_RUN)/1000. << "s";
|
||||
SimpleLogger().Write() << "identified: " << component_size_vector.size()
|
||||
<< " many components, marking small components";
|
||||
|
||||
TIMER_START(SCC_OUTPUT);
|
||||
|
||||
const unsigned size_one_counter = std::count_if(component_size_vector.begin(),
|
||||
component_size_vector.end(),
|
||||
[](unsigned value)
|
||||
{
|
||||
return 1 == value;
|
||||
});
|
||||
|
||||
SimpleLogger().Write() << "identified " << size_one_counter << " SCCs of size 1";
|
||||
|
||||
uint64_t total_network_distance = 0;
|
||||
p.reinit(m_node_based_graph->GetNumberOfNodes());
|
||||
// const NodeID last_u_node = m_node_based_graph->GetNumberOfNodes();
|
||||
for (const NodeID source : osrm::irange(0u, last_node))
|
||||
{
|
||||
p.printIncrement();
|
||||
for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(source))
|
||||
{
|
||||
const TarjanDynamicGraph::NodeIterator target =
|
||||
m_node_based_graph->GetTarget(current_edge);
|
||||
|
||||
if (source < target ||
|
||||
m_node_based_graph->EndEdges(target) ==
|
||||
m_node_based_graph->FindEdge(target, source))
|
||||
{
|
||||
total_network_distance +=
|
||||
100 * FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
m_coordinate_list[source].lat,
|
||||
m_coordinate_list[source].lon,
|
||||
m_coordinate_list[target].lat,
|
||||
m_coordinate_list[target].lon);
|
||||
|
||||
BOOST_ASSERT(current_edge != SPECIAL_EDGEID);
|
||||
BOOST_ASSERT(source != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(target != SPECIAL_NODEID);
|
||||
|
||||
const unsigned size_of_containing_component =
|
||||
std::min(component_size_vector[components_index[source]],
|
||||
component_size_vector[components_index[target]]);
|
||||
|
||||
// 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[source].lon / COORDINATE_PRECISION,
|
||||
m_coordinate_list[source].lat / COORDINATE_PRECISION);
|
||||
lineString.addPoint(m_coordinate_list[target].lon / COORDINATE_PRECISION,
|
||||
m_coordinate_list[target].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);
|
||||
component_size_vector.clear();
|
||||
component_size_vector.shrink_to_fit();
|
||||
BOOST_ASSERT_MSG(0 == component_size_vector.size() && 0 == component_size_vector.capacity(),
|
||||
"component_size_vector not properly deallocated");
|
||||
|
||||
components_index.clear();
|
||||
components_index.shrink_to_fit();
|
||||
BOOST_ASSERT_MSG(0 == components_index.size() && 0 == components_index.capacity(),
|
||||
"components_index not properly deallocated");
|
||||
TIMER_STOP(SCC_OUTPUT);
|
||||
SimpleLogger().Write() << "generating output took: " << TIMER_MSEC(SCC_OUTPUT)/1000. << "s";
|
||||
|
||||
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 = {u, v};
|
||||
const auto restriction_iterator = m_restriction_map.find(restriction_source);
|
||||
if (restriction_iterator != m_restriction_map.end())
|
||||
{
|
||||
const unsigned index = restriction_iterator->second;
|
||||
for (const RestrictionSource &restriction_target : m_restriction_bucket_list.at(index))
|
||||
{
|
||||
if (restriction_target.second)
|
||||
{
|
||||
return restriction_target.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SPECIAL_NODEID;
|
||||
}
|
||||
|
||||
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 = {u, v};
|
||||
const auto restriction_iterator = m_restriction_map.find(restriction_source);
|
||||
if (restriction_iterator != m_restriction_map.end())
|
||||
{
|
||||
const unsigned index = restriction_iterator->second;
|
||||
for (const RestrictionTarget &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_ */
|
||||
@@ -1,130 +0,0 @@
|
||||
#include "../DataStructures/OriginalEdgeData.h"
|
||||
#include "../DataStructures/QueryNode.h"
|
||||
#include "../DataStructures/SharedMemoryVectorWrapper.h"
|
||||
#include "../DataStructures/StaticRTree.h"
|
||||
#include "../Util/BoostFileSystemFix.h"
|
||||
#include "../DataStructures/EdgeBasedNode.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <random>
|
||||
|
||||
// Choosen by a fair W20 dice roll (this value is completely arbitrary)
|
||||
constexpr unsigned RANDOM_SEED = 13;
|
||||
constexpr int32_t WORLD_MIN_LAT = -90 * COORDINATE_PRECISION;
|
||||
constexpr int32_t WORLD_MAX_LAT = 90 * COORDINATE_PRECISION;
|
||||
constexpr int32_t WORLD_MIN_LON = -180 * COORDINATE_PRECISION;
|
||||
constexpr int32_t WORLD_MAX_LON = 180 * COORDINATE_PRECISION;
|
||||
|
||||
using RTreeLeaf = EdgeBasedNode;
|
||||
using FixedPointCoordinateListPtr = std::shared_ptr<std::vector<FixedPointCoordinate>>;
|
||||
using BenchStaticRTree = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false>;
|
||||
|
||||
FixedPointCoordinateListPtr LoadCoordinates(const boost::filesystem::path &nodes_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));
|
||||
auto coords = std::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));
|
||||
coords->at(i) = FixedPointCoordinate(current_node.lat, current_node.lon);
|
||||
BOOST_ASSERT((std::abs(coords->at(i).lat) >> 30) == 0);
|
||||
BOOST_ASSERT((std::abs(coords->at(i).lon) >> 30) == 0);
|
||||
}
|
||||
nodes_input_stream.close();
|
||||
return coords;
|
||||
}
|
||||
|
||||
void Benchmark(BenchStaticRTree &rtree, unsigned num_queries)
|
||||
{
|
||||
std::mt19937 mt_rand(RANDOM_SEED);
|
||||
std::uniform_int_distribution<> lat_udist(WORLD_MIN_LAT, WORLD_MAX_LAT);
|
||||
std::uniform_int_distribution<> lon_udist(WORLD_MIN_LON, WORLD_MAX_LON);
|
||||
std::vector<FixedPointCoordinate> queries;
|
||||
for (unsigned i = 0; i < num_queries; i++)
|
||||
{
|
||||
queries.emplace_back(FixedPointCoordinate(lat_udist(mt_rand), lon_udist(mt_rand)));
|
||||
}
|
||||
|
||||
const unsigned num_results = 5;
|
||||
std::cout << "#### IncrementalFindPhantomNodeForCoordinate : " << num_results
|
||||
<< " phantom nodes"
|
||||
<< "\n";
|
||||
|
||||
TIMER_START(query_phantom);
|
||||
std::vector<PhantomNode> resulting_phantom_node_vector;
|
||||
for (const auto &q : queries)
|
||||
{
|
||||
resulting_phantom_node_vector.clear();
|
||||
rtree.IncrementalFindPhantomNodeForCoordinate(
|
||||
q, resulting_phantom_node_vector, 3, num_results);
|
||||
resulting_phantom_node_vector.clear();
|
||||
rtree.IncrementalFindPhantomNodeForCoordinate(
|
||||
q, resulting_phantom_node_vector, 17, num_results);
|
||||
}
|
||||
TIMER_STOP(query_phantom);
|
||||
|
||||
std::cout << "Took " << TIMER_MSEC(query_phantom) << " msec for " << num_queries << " queries."
|
||||
<< "\n";
|
||||
std::cout << TIMER_MSEC(query_phantom) / ((double)num_queries) << " msec/query."
|
||||
<< "\n";
|
||||
|
||||
std::cout << "#### LocateClosestEndPointForCoordinate"
|
||||
<< "\n";
|
||||
|
||||
TIMER_START(query_endpoint);
|
||||
FixedPointCoordinate result;
|
||||
for (const auto &q : queries)
|
||||
{
|
||||
rtree.LocateClosestEndPointForCoordinate(q, result, 3);
|
||||
}
|
||||
TIMER_STOP(query_endpoint);
|
||||
|
||||
std::cout << "Took " << TIMER_MSEC(query_endpoint) << " msec for " << num_queries << " queries."
|
||||
<< "\n";
|
||||
std::cout << TIMER_MSEC(query_endpoint) / ((double)num_queries) << " msec/query."
|
||||
<< "\n";
|
||||
|
||||
std::cout << "#### FindPhantomNodeForCoordinate"
|
||||
<< "\n";
|
||||
|
||||
TIMER_START(query_phantomnode);
|
||||
for (const auto &q : queries)
|
||||
{
|
||||
PhantomNode phantom;
|
||||
rtree.FindPhantomNodeForCoordinate(q, phantom, 3);
|
||||
}
|
||||
TIMER_STOP(query_phantomnode);
|
||||
|
||||
std::cout << "Took " << TIMER_MSEC(query_phantomnode) << " msec for " << num_queries
|
||||
<< " queries."
|
||||
<< "\n";
|
||||
std::cout << TIMER_MSEC(query_phantomnode) / ((double)num_queries) << " msec/query."
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 4)
|
||||
{
|
||||
std::cout << "./rtree-bench file.ramIndex file.fileIndx file.nodes"
|
||||
<< "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *ramPath = argv[1];
|
||||
const char *filePath = argv[2];
|
||||
const char *nodesPath = argv[3];
|
||||
|
||||
auto coords = LoadCoordinates(nodesPath);
|
||||
|
||||
BenchStaticRTree rtree(ramPath, filePath, coords);
|
||||
|
||||
Benchmark(rtree, 10000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+353
@@ -0,0 +1,353 @@
|
||||
# 5.4.0-rc.7
|
||||
- Chages from 5.4.0-rc.6
|
||||
- Bugfixes re-introduce space between two entries in summaries
|
||||
|
||||
# 5.4.0-rc.6
|
||||
- Changes from 5.4.0-rc.5
|
||||
- Bugfixes
|
||||
- fixed a bug where polyline decoding on a defective polyline could end up in out-of-bound access on a vector
|
||||
- Guidance
|
||||
- Summaries have been improved to consider references as well
|
||||
|
||||
# 5.4.0-rc.5
|
||||
- Changes from 5.4.0-rc.4
|
||||
- Guidance
|
||||
- Improved detection of obvious name changes
|
||||
- Profiles
|
||||
- The default profile for car now excludes HOV-only routes in navigation by default
|
||||
- Bugfixes
|
||||
- Fixed a bug that could result in endless loops in combination with sliproads
|
||||
|
||||
# 5.4.0-rc.4
|
||||
- Changes from 5.4.0-rc.3
|
||||
- Bugfixes
|
||||
- Fixed a bug where roundabout intersections could result in breaking assertions when immediately exited
|
||||
|
||||
# 5.4.0-rc.3
|
||||
- Changes from 5.4.0-rc.2
|
||||
- Bugfixes
|
||||
- BREAKING: Fixed a bug where some roads could be falsly identified as sliproadsi This change requires reprocessing datasets with osrm-extract and osrm-contract
|
||||
- BREAKING: Fixed a bug that resulted in false names/ref/destination/pronunciation This change requires reprocessing datasets with osrm-extract and osrm-contract
|
||||
- `restrictions` is now used for namespaced restrictions and restriction exceptions (e.g. `restriction:motorcar=` as well as `except=motorcar`)
|
||||
- replaced lhs/rhs profiles by using test defined profiles
|
||||
- Trip Plugin
|
||||
- changed internal behaviour to prefer the smallest lexicographic result over the largest one
|
||||
|
||||
# 5.4.0
|
||||
- Changes from 5.3.0
|
||||
- Profiles
|
||||
- includes library guidance.lua that offers preliminary configuration on guidance.
|
||||
- added left_hand_driving flag in global profile properties
|
||||
- modified turn penalty function for car profile - better fit to real data
|
||||
- return `ref` and `name` as separate fields. Do no use ref or destination as fallback for name value
|
||||
- Guidance
|
||||
- Handle Access tags for lanes, only considering valid lanes in lane-guidance (think car | car | bike | car)
|
||||
- API:
|
||||
- `annotations=true` now returns the data source id for each segment as `datasources`
|
||||
- Reduced semantic of merge to refer only to merges from a lane onto a motorway-like road
|
||||
- new `ref` field in the `RouteStep` object. It contains the reference code or name of a way. Previously merged into the `name` property like `name (ref)` and are now separate fields.
|
||||
- Bugfixes
|
||||
- Fixed an issue that would result in segfaults for viaroutes with an invalid intermediate segment when u-turns were allowed at the via-location
|
||||
- Invalid only_* restrictions could result in loss of connectivity. As a fallback, we assume all turns allowed when the restriction is not valid
|
||||
- Fixed a bug that could result in an infinite loop when finding information about an upcoming intersection
|
||||
- Fixed a bug that led to not discovering if a road simply looses a considered prefix
|
||||
- BREAKING: Fixed a bug that could crash postprocessing of instructions on invalid roundabout taggings. This change requires reprocessing datasets with osrm-extract and osrm-contract
|
||||
- Fixed an issue that could emit `invalid` as instruction when ending on a sliproad after a traffic-light
|
||||
- Fixed an issue that would detect turning circles as sliproads
|
||||
- Fixed a bug where post-processing instructions (e.g. left + left -> uturn) could result in false pronunciations
|
||||
- Fixes a bug where a bearing range of zero would cause exhaustive graph traversals
|
||||
- Fixes a bug where certain looped geometries could cause an infinite loop during extraction
|
||||
|
||||
- Infrastructure:
|
||||
- Adds a feature to limit results in nearest service with a default of 100 in `osrm-routed`
|
||||
|
||||
# 5.3.0
|
||||
- Changes from 5.3.0-rc.3
|
||||
- Guidance
|
||||
- Only announce `use lane` on required turns (not using all lanes to go straight)
|
||||
- Moved `lanes` to the intersection objects. This is BREAKING in relation to other Release Candidates but not with respect to other releases.
|
||||
- Bugfixes
|
||||
- Fix BREAKING: bug that could result in failure to load 'osrm.icd' files. This breaks the dataformat
|
||||
- Fix: bug that results in segfaults when `use lane` instructions are suppressed
|
||||
|
||||
- Changes form 5.2.7
|
||||
- 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 `Intersection` object. The lane data contains both the markings at the intersection and a flag indicating if they can be chosen for the next turn
|
||||
- Removed unused `-s` from `osrm-datastore`
|
||||
- Guidance
|
||||
- Only announce `use lane` on required turns (not using all lanes to go straight)
|
||||
- Improved detection of obvious turns
|
||||
- Improved turn lane detection
|
||||
- Reduce the number of end-of-road instructions in obvious cases
|
||||
- Profile:
|
||||
- bicycle.lua: Surface speeds never increase the actual speed
|
||||
- Infrastructure
|
||||
- Add 32bit support
|
||||
- Add ARM NEON/VFP support
|
||||
- Fix Windows builds
|
||||
- Optimize speed file updates using mmap
|
||||
- Add option to disable LTO for older compilers
|
||||
- BREAKING: The new turn type changes the turn-type order. This breaks the **data format**.
|
||||
- BREAKING: Turn lane data introduces two new files (osrm.tld,osrm.tls). This breaks the fileformat for older versions.
|
||||
- Bugfixes:
|
||||
- Fix devide by zero on updating speed data using osrm-contract
|
||||
|
||||
# 5.3.0 RC3
|
||||
- Changes from 5.3.0-rc.2
|
||||
- Guidance
|
||||
- Improved detection of obvious turns
|
||||
- Improved turn lane detection
|
||||
- Bugfixes
|
||||
- Fix bug that didn't chose minimal weights on overlapping edges
|
||||
|
||||
# 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 two new files (osrm.tld,osrm.tls). 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`
|
||||
|
||||
|
||||
+400
-195
@@ -1,100 +1,104 @@
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
# we depend on 2.8.11 introducing target_include_directories
|
||||
|
||||
if( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR AND NOT MSVC_IDE )
|
||||
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)
|
||||
project(OSRM C CXX)
|
||||
set(OSRM_VERSION_MAJOR 5)
|
||||
set(OSRM_VERSION_MINOR 4)
|
||||
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)
|
||||
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()
|
||||
|
||||
if (WIN32 AND MSVC_VERSION LESS 1800)
|
||||
message(FATAL_ERROR "Building with Microsoft compiler needs Visual Studio 2013 or later (Express version works too)")
|
||||
if(WIN32 AND MSVC_VERSION LESS 1900)
|
||||
message(FATAL_ERROR "Building with Microsoft compiler needs Latest Visual Studio 2015 (Community or better)")
|
||||
endif()
|
||||
|
||||
OPTION(WITH_TOOLS "Build OSRM tools" OFF)
|
||||
OPTION(BUILD_TOOLS "Build OSRM tools" OFF)
|
||||
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)
|
||||
option(ENABLE_FUZZING "Fuzz testing using LLVM's libFuzzer" OFF)
|
||||
option(ENABLE_GOLD_LINKER "Use GNU gold linker if available" ON)
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/Include/)
|
||||
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_command(OUTPUT ${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp FingerPrint.cpp.alwaysbuild
|
||||
COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR}
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FingerPrint-Config.cmake
|
||||
DEPENDS
|
||||
${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp.in
|
||||
COMMENT "Configuring FingerPrint.cpp"
|
||||
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(FingerPrintConfigure DEPENDS ${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp)
|
||||
add_custom_target(tests DEPENDS datastructure-tests)
|
||||
add_custom_target(benchmarks DEPENDS rtree-bench)
|
||||
|
||||
set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread unit_test_framework)
|
||||
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)
|
||||
file(GLOB ImporterGlob DataStructures/Import*.cpp)
|
||||
add_library(IMPORT OBJECT ${ImporterGlob})
|
||||
add_library(LOGGER OBJECT Util/simple_logger.cpp)
|
||||
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)
|
||||
|
||||
set(ExtractorSources extractor.cpp ${ExtractorGlob})
|
||||
add_executable(osrm-extract ${ExtractorSources} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:LOGGER>)
|
||||
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 PrepareGlob Contractor/*.cpp DataStructures/HilbertValue.cpp DataStructures/RestrictionMap.cpp Util/compute_angle.cpp)
|
||||
set(PrepareSources prepare.cpp ${PrepareGlob})
|
||||
add_executable(osrm-prepare ${PrepareSources} $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:LOGGER>)
|
||||
add_dependencies(UTIL FingerPrintConfigure)
|
||||
set_target_properties(UTIL PROPERTIES LINKER_LANGUAGE CXX)
|
||||
|
||||
file(GLOB ServerGlob Server/*.cpp)
|
||||
file(GLOB DescriptorGlob Descriptors/*.cpp)
|
||||
file(GLOB DatastructureGlob DataStructures/SearchEngineData.cpp DataStructures/RouteParameters.cpp)
|
||||
list(REMOVE_ITEM DatastructureGlob DataStructures/Coordinate.cpp)
|
||||
file(GLOB CoordinateGlob DataStructures/Coordinate.cpp)
|
||||
file(GLOB AlgorithmGlob Algorithms/*.cpp)
|
||||
file(GLOB HttpGlob Server/Http/*.cpp)
|
||||
file(GLOB LibOSRMGlob Library/*.cpp)
|
||||
file(GLOB DataStructureTestsGlob UnitTests/DataStructures/*.cpp DataStructures/HilbertValue.cpp)
|
||||
|
||||
set(
|
||||
OSRMSources
|
||||
${LibOSRMGlob}
|
||||
${DescriptorGlob}
|
||||
${DatastructureGlob}
|
||||
${CoordinateGlob}
|
||||
${AlgorithmGlob}
|
||||
${HttpGlob}
|
||||
)
|
||||
add_library(COORDINATE OBJECT ${CoordinateGlob})
|
||||
add_library(FINGERPRINT OBJECT Util/FingerPrint.cpp)
|
||||
add_library(GITDESCRIPTION OBJECT Util/GitDescription.cpp)
|
||||
add_library(OSRM ${OSRMSources} $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER>)
|
||||
add_dependencies(FINGERPRINT FingerPrintConfigure)
|
||||
|
||||
add_executable(osrm-routed routed.cpp ${ServerGlob})
|
||||
add_executable(osrm-datastore datastore.cpp $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:LOGGER>)
|
||||
|
||||
# Unit tests
|
||||
add_executable(datastructure-tests EXCLUDE_FROM_ALL UnitTests/datastructure_tests.cpp ${DataStructureTestsGlob} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER>)
|
||||
|
||||
# Benchmarks
|
||||
add_executable(rtree-bench EXCLUDE_FROM_ALL Benchmarks/StaticRTreeBench.cpp $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER>)
|
||||
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)
|
||||
@@ -102,61 +106,145 @@ 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(ENABLE_GOLD_LINKER)
|
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -fuse-ld=gold -Wl,--version ERROR_QUIET OUTPUT_VARIABLE LD_VERSION)
|
||||
if("${LD_VERSION}" MATCHES "GNU gold")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold -Wl,--disable-new-dtags")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold -Wl,--disable-new-dtags")
|
||||
message(STATUS "Using GNU gold as linker.")
|
||||
|
||||
# Issue 2785: check gold binutils version and don't use gc-sections for versions prior 2.25
|
||||
string(REGEX REPLACE ".*\\(GNU Binutils[^\\)0-9]+([0-9]+\\.[0-9]+)[^\\)]*\\).*" "\\1" GOLD_BINUTILS_VERSION "${LD_VERSION}")
|
||||
if ("${GOLD_BINUTILS_VERSION}" VERSION_LESS "2.26")
|
||||
message(STATUS "Disabling gc-sections on gold binutils < 2.26, see: https://sourceware.org/bugzilla/show_bug.cgi?id=17639")
|
||||
set(LD_AVOID_GC_SECTIONS TRUE)
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "GNU gold linker isn't available.")
|
||||
set(ENABLE_GOLD_LINKER OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES Release)
|
||||
message(STATUS "Configuring OSRM in release mode")
|
||||
# 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")
|
||||
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
|
||||
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()
|
||||
endif (HAS_LTO_FLAG)
|
||||
|
||||
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()
|
||||
|
||||
if (NOT WIN32)
|
||||
add_definitions(-DBOOST_TEST_DYN_LINK)
|
||||
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 -pedantic -fPIC")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
# using GCC
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -fPIC")
|
||||
if (WIN32) # using mingw
|
||||
add_definitions(-D_USE_MATH_DEFINES) # define M_PI, M_1_PI etc.
|
||||
add_definitions(-DWIN32)
|
||||
SET(OPTIONAL_SOCKET_LIBS ws2_32 wsock32)
|
||||
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()
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
|
||||
# using GCC
|
||||
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 -ipo -fPIC")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
|
||||
# using Visual Studio C++
|
||||
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} date_time chrono zlib)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-DNOMINMAX) # avoid min and max macros that can break compilation
|
||||
add_definitions(-D_USE_MATH_DEFINES) # define M_PI
|
||||
add_definitions(-D_WIN32_WINNT=0x0501)
|
||||
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()
|
||||
|
||||
# Activate C++11
|
||||
if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
ADD_DEFINITIONS(-std=c++11)
|
||||
# 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" OR "${LD_AVOID_GC_SECTIONS}"))
|
||||
# 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}")
|
||||
|
||||
# Activate C++1y
|
||||
if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y")
|
||||
endif()
|
||||
|
||||
# Configuring other platform dependencies
|
||||
@@ -175,157 +263,274 @@ if(APPLE)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(osrm-prepare rt)
|
||||
target_link_libraries(osrm-datastore rt)
|
||||
target_link_libraries(OSRM rt)
|
||||
set(MAYBE_RT_LIBRARY rt)
|
||||
endif()
|
||||
|
||||
#Check Boost
|
||||
set(BOOST_MIN_VERSION "1.49.0")
|
||||
find_package(Boost ${BOOST_MIN_VERSION} COMPONENTS ${BOOST_COMPONENTS} REQUIRED)
|
||||
if(NOT Boost_FOUND)
|
||||
message(FATAL_ERROR "Fatal error: Boost (version >= 1.49.0) required.\n")
|
||||
endif()
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
|
||||
target_link_libraries(OSRM ${Boost_LIBRARIES})
|
||||
target_link_libraries(osrm-extract ${Boost_LIBRARIES})
|
||||
target_link_libraries(osrm-prepare ${Boost_LIBRARIES})
|
||||
target_link_libraries(osrm-routed ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM)
|
||||
target_link_libraries(osrm-datastore ${Boost_LIBRARIES})
|
||||
target_link_libraries(datastructure-tests ${Boost_LIBRARIES})
|
||||
target_link_libraries(rtree-bench ${Boost_LIBRARIES})
|
||||
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})
|
||||
|
||||
|
||||
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})
|
||||
target_link_libraries(osrm-datastore ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(osrm-prepare ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(OSRM ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(datastructure-tests ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(rtree-bench ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
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()
|
||||
target_link_libraries(osrm-datastore ${TBB_LIBRARIES})
|
||||
target_link_libraries(osrm-extract ${TBB_LIBRARIES})
|
||||
target_link_libraries(osrm-prepare ${TBB_LIBRARIES})
|
||||
target_link_libraries(osrm-routed ${TBB_LIBRARIES})
|
||||
target_link_libraries(datastructure-tests ${TBB_LIBRARIES})
|
||||
target_link_libraries(rtree-bench ${TBB_LIBRARIES})
|
||||
include_directories(${TBB_INCLUDE_DIR})
|
||||
|
||||
find_package( Luabind REQUIRED )
|
||||
find_package(Luabind REQUIRED)
|
||||
include(check_luabind)
|
||||
add_dependency_includes(${LUABIND_INCLUDE_DIR})
|
||||
|
||||
include_directories(${LUABIND_INCLUDE_DIR})
|
||||
target_link_libraries(osrm-extract ${LUABIND_LIBRARY})
|
||||
target_link_libraries(osrm-prepare ${LUABIND_LIBRARY})
|
||||
|
||||
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})
|
||||
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( 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(STXXL REQUIRED)
|
||||
add_dependency_includes(${STXXL_INCLUDE_DIR})
|
||||
|
||||
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 OR BUILD_TOOLS)
|
||||
message(STATUS "Activating OSRM internal tools")
|
||||
if (ENABLE_JSON_LOGGING)
|
||||
message(STATUS "Enabling json logging")
|
||||
add_dependency_defines(-DENABLE_JSON_LOGGING)
|
||||
endif()
|
||||
|
||||
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 Tools/components.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER>)
|
||||
add_executable(osrm-components src/tools/components.cpp $<TARGET_OBJECTS:UTIL>)
|
||||
target_link_libraries(osrm-components ${TBB_LIBRARIES})
|
||||
include_directories(${GDAL_INCLUDE_DIR})
|
||||
target_link_libraries(
|
||||
osrm-components
|
||||
${GDAL_LIBRARIES} ${Boost_LIBRARIES})
|
||||
include_directories(SYSTEM ${GDAL_INCLUDE_DIR})
|
||||
target_link_libraries(osrm-components ${GDAL_LIBRARIES} ${Boost_LIBRARIES})
|
||||
install(TARGETS osrm-components DESTINATION bin)
|
||||
else()
|
||||
message(FATAL_ERROR "libgdal and/or development headers not found")
|
||||
message(WARNING "libgdal and/or development headers not found")
|
||||
endif()
|
||||
add_executable(osrm-cli Tools/simpleclient.cpp $<TARGET_OBJECTS:LOGGER>)
|
||||
target_link_libraries(osrm-cli ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM)
|
||||
target_link_libraries(osrm-cli ${TBB_LIBRARIES})
|
||||
add_executable(osrm-io-benchmark Tools/io-benchmark.cpp $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:LOGGER>)
|
||||
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 Tools/unlock_all_mutexes.cpp $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:LOGGER>)
|
||||
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-check-hsgr Tools/check-hsgr.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER>)
|
||||
target_link_libraries(osrm-check-hsgr ${Boost_LIBRARIES})
|
||||
add_executable(osrm-springclean Tools/springclean.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:GITDESCRIPTION>)
|
||||
add_executable(osrm-springclean src/tools/springclean.cpp $<TARGET_OBJECTS:UTIL>)
|
||||
target_link_libraries(osrm-springclean ${Boost_LIBRARIES})
|
||||
|
||||
install(TARGETS osrm-cli DESTINATION bin)
|
||||
install(TARGETS osrm-io-benchmark DESTINATION bin)
|
||||
install(TARGETS osrm-unlock-all DESTINATION bin)
|
||||
install(TARGETS osrm-check-hsgr DESTINATION bin)
|
||||
install(TARGETS osrm-springclean DESTINATION bin)
|
||||
endif()
|
||||
|
||||
file(GLOB InstallGlob Include/osrm/*.h Library/OSRM.h)
|
||||
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 include/util/exception.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)
|
||||
install(FILES ${PROJECT_BINARY_DIR}/libosrm.pc DESTINATION lib/pkgconfig)
|
||||
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)
|
||||
|
||||
if (ENABLE_FUZZING)
|
||||
# Requires libosrm being built with sanitizers; make configurable and default to ubsan
|
||||
set(FUZZ_SANITIZER "undefined" CACHE STRING "Sanitizer to be used for Fuzz testing")
|
||||
set_property(CACHE FUZZ_SANITIZER PROPERTY STRINGS "undefined" "integer" "address" "memory" "thread" "leak")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize-coverage=edge,indirect-calls,8bit-counters -fsanitize=address")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
|
||||
|
||||
message(STATUS "Using -fsanitize=${FUZZ_SANITIZER} for Fuzz testing")
|
||||
|
||||
add_subdirectory(fuzz)
|
||||
endif ()
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# User
|
||||
|
||||
Before you open a new issue, please search for older ones that cover the same issue.
|
||||
In general "me too" comments/issues are frowned upon.
|
||||
You can add a :+1: emoji to the issue if you want to express interest in this.
|
||||
|
||||
# Developer
|
||||
|
||||
We use `clang-format` version `3.8` to consistently format the code base. There is a helper script under `scripts/format.sh`.
|
||||
|
||||
In general changes that affect the API and/or increase the memory consumption need to be discussed first.
|
||||
Often we don't include changes that would increase the memory consumption a lot if they are not generally usable (e.g. elevation data is a good example).
|
||||
|
||||
## Pull Request
|
||||
|
||||
Every pull-request that changes the API needs to update the docs in `docs/http.md` and add an entry to `CHANGELOG.md`.
|
||||
Breaking changes need to have a BREAKING prefix. See the [releasing documentation](docs/releasing.md) on how this affects the version.
|
||||
|
||||
Early feedback is also important.
|
||||
You will see that a lot of the PR have tags like `[not ready]` or `[wip]`.
|
||||
We like to open PRs as soon as we are starting to work on something to make it visible to the rest of the team.
|
||||
If your work is going in entirely the wrong direction, there is a good chance someone will pick up on this before it is too late.
|
||||
Everyone is encouraged to read PRs of other people and give feedback.
|
||||
|
||||
For every significant code change we require a pull request review before it is merged.
|
||||
If your pull request modifies the API this need to be signed of by a team discussion.
|
||||
This means you will need to find another member of the team with commit access and request a review of your pull request.
|
||||
|
||||
Once your pull request is reviewed you can merge it! If you don't have commit access, ping someone that has commit access.
|
||||
If you do have commit access there are in general two accepted styles to merging:
|
||||
|
||||
1. Make sure the branch is up to date with `master`. Run `git rebase master` to find out.
|
||||
2. Once that is ensured you can either:
|
||||
- Click the nice green merge button (for a non-fast-forward merge)
|
||||
- Merge by hand using a fast-forward merge
|
||||
|
||||
Which merge you prefer is up to personal preference. In general it is recommended to use fast-forward merges because it creates a history that is sequential and easier to understand.
|
||||
|
||||
# Maintainer
|
||||
|
||||
## Doing a release
|
||||
|
||||
There is an in-depth guide around how to push out a release once it is ready [here](docs/releasing.md).
|
||||
|
||||
## The API
|
||||
|
||||
Changes to the API need to be discussed and signed off by the team. Breaking changes even more so than additive changes.
|
||||
|
||||
## Milestones
|
||||
|
||||
If a pull request or an issue is applicable for the current or next milestone, depends on the target version number.
|
||||
Since we use semantic versioning we restrict breaking changes to major releases.
|
||||
After a Release Candidate is released we usually don't change the API anymore if it is not critical.
|
||||
Bigger code changes after a RC was released should also be avoided.
|
||||
|
||||
@@ -1,973 +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
|
||||
#define CONTRACTOR_H
|
||||
|
||||
#include "../DataStructures/BinaryHeap.h"
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
#include "../DataStructures/DynamicGraph.h"
|
||||
#include "../DataStructures/Percent.h"
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "../DataStructures/Range.h"
|
||||
#include "../DataStructures/XORFastHash.h"
|
||||
#include "../DataStructures/XORFastHashStorage.h"
|
||||
#include "../Util/simple_logger.hpp"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <stxxl/vector>
|
||||
|
||||
#include <tbb/enumerable_thread_specific.h>
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/parallel_sort.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
class Contractor
|
||||
{
|
||||
|
||||
private:
|
||||
struct ContractorEdgeData
|
||||
{
|
||||
ContractorEdgeData()
|
||||
: distance(0), id(0), originalEdges(0), shortcut(0), forward(0), backward(0),
|
||||
is_original_via_node_ID(false)
|
||||
{
|
||||
}
|
||||
ContractorEdgeData(unsigned distance,
|
||||
unsigned original_edges,
|
||||
unsigned id,
|
||||
bool shortcut,
|
||||
bool forward,
|
||||
bool backward)
|
||||
: distance(distance), id(id),
|
||||
originalEdges(std::min((unsigned)1 << 28, original_edges)), shortcut(shortcut),
|
||||
forward(forward), backward(backward), is_original_via_node_ID(false)
|
||||
{
|
||||
}
|
||||
unsigned distance;
|
||||
unsigned id;
|
||||
unsigned originalEdges : 28;
|
||||
bool shortcut : 1;
|
||||
bool forward : 1;
|
||||
bool backward : 1;
|
||||
bool is_original_via_node_ID : 1;
|
||||
} data;
|
||||
|
||||
struct ContractorHeapData
|
||||
{
|
||||
short hop;
|
||||
bool target;
|
||||
ContractorHeapData() : hop(0), target(false) {}
|
||||
ContractorHeapData(short h, bool t) : hop(h), target(t) {}
|
||||
};
|
||||
|
||||
using ContractorGraph = DynamicGraph<ContractorEdgeData>;
|
||||
// using ContractorHeap = BinaryHeap<NodeID, NodeID, int, ContractorHeapData, ArrayStorage<NodeID, NodeID>
|
||||
// >;
|
||||
using ContractorHeap = BinaryHeap<NodeID, NodeID, int, ContractorHeapData, XORFastHashStorage<NodeID, NodeID>>;
|
||||
using ContractorEdge = ContractorGraph::InputEdge;
|
||||
|
||||
struct ContractorThreadData
|
||||
{
|
||||
ContractorHeap heap;
|
||||
std::vector<ContractorEdge> inserted_edges;
|
||||
std::vector<NodeID> neighbours;
|
||||
explicit ContractorThreadData(NodeID nodes) : heap(nodes) {}
|
||||
};
|
||||
|
||||
struct NodePriorityData
|
||||
{
|
||||
int depth;
|
||||
NodePriorityData() : depth(0) {}
|
||||
};
|
||||
|
||||
struct ContractionStats
|
||||
{
|
||||
int edges_deleted_count;
|
||||
int edges_added_count;
|
||||
int original_edges_deleted_count;
|
||||
int original_edges_added_count;
|
||||
ContractionStats()
|
||||
: edges_deleted_count(0), edges_added_count(0), original_edges_deleted_count(0),
|
||||
original_edges_added_count(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct RemainingNodeData
|
||||
{
|
||||
RemainingNodeData() : id(0), is_independent(false) {}
|
||||
NodeID id : 31;
|
||||
bool is_independent : 1;
|
||||
};
|
||||
|
||||
|
||||
struct ThreadDataContainer
|
||||
{
|
||||
explicit ThreadDataContainer(int number_of_nodes) : number_of_nodes(number_of_nodes) {}
|
||||
|
||||
inline ContractorThreadData* getThreadData()
|
||||
{
|
||||
bool exists = false;
|
||||
auto& ref = data.local(exists);
|
||||
if (!exists)
|
||||
{
|
||||
ref = std::make_shared<ContractorThreadData>(number_of_nodes);
|
||||
}
|
||||
|
||||
return ref.get();
|
||||
}
|
||||
|
||||
int number_of_nodes;
|
||||
using EnumerableThreadData = tbb::enumerable_thread_specific<std::shared_ptr<ContractorThreadData>>;
|
||||
EnumerableThreadData data;
|
||||
};
|
||||
|
||||
public:
|
||||
template <class ContainerT> Contractor(int nodes, ContainerT &input_edge_list)
|
||||
{
|
||||
std::vector<ContractorEdge> edges;
|
||||
edges.reserve(input_edge_list.size() * 2);
|
||||
|
||||
const auto dend = input_edge_list.dend();
|
||||
for (auto diter = input_edge_list.dbegin(); diter != dend; ++diter)
|
||||
{
|
||||
BOOST_ASSERT_MSG(static_cast<unsigned int>(std::max(diter->weight, 1)) > 0, "edge distance < 1");
|
||||
#ifndef NDEBUG
|
||||
if (static_cast<unsigned int>(std::max(diter->weight, 1)) > 24 * 60 * 60 * 10)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "Edge weight large -> "
|
||||
<< static_cast<unsigned int>(std::max(diter->weight, 1));
|
||||
}
|
||||
#endif
|
||||
edges.emplace_back(diter->source, diter->target,
|
||||
static_cast<unsigned int>(std::max(diter->weight, 1)),
|
||||
1,
|
||||
diter->edge_id,
|
||||
false,
|
||||
diter->forward ? true : false,
|
||||
diter->backward ? true : false);
|
||||
|
||||
edges.emplace_back(diter->target, diter->source,
|
||||
static_cast<unsigned int>(std::max(diter->weight, 1)),
|
||||
1,
|
||||
diter->edge_id,
|
||||
false,
|
||||
diter->backward ? true : false,
|
||||
diter->forward ? true : false);
|
||||
}
|
||||
// clear input vector
|
||||
input_edge_list.clear();
|
||||
edges.shrink_to_fit();
|
||||
|
||||
tbb::parallel_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 forward_edge;
|
||||
ContractorEdge reverse_edge;
|
||||
forward_edge.source = reverse_edge.source = source;
|
||||
forward_edge.target = reverse_edge.target = target;
|
||||
forward_edge.data.forward = reverse_edge.data.backward = true;
|
||||
forward_edge.data.backward = reverse_edge.data.forward = false;
|
||||
forward_edge.data.shortcut = reverse_edge.data.shortcut = false;
|
||||
forward_edge.data.id = reverse_edge.data.id = id;
|
||||
forward_edge.data.originalEdges = reverse_edge.data.originalEdges = 1;
|
||||
forward_edge.data.distance = reverse_edge.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)
|
||||
{
|
||||
forward_edge.data.distance =
|
||||
std::min(edges[i].data.distance, forward_edge.data.distance);
|
||||
}
|
||||
if (edges[i].data.backward)
|
||||
{
|
||||
reverse_edge.data.distance =
|
||||
std::min(edges[i].data.distance, reverse_edge.data.distance);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
// merge edges (s,t) and (t,s) into bidirectional edge
|
||||
if (forward_edge.data.distance == reverse_edge.data.distance)
|
||||
{
|
||||
if ((int)forward_edge.data.distance != std::numeric_limits<int>::max())
|
||||
{
|
||||
forward_edge.data.backward = true;
|
||||
edges[edge++] = forward_edge;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // insert seperate edges
|
||||
if (((int)forward_edge.data.distance) != std::numeric_limits<int>::max())
|
||||
{
|
||||
edges[edge++] = forward_edge;
|
||||
}
|
||||
if ((int)reverse_edge.data.distance != std::numeric_limits<int>::max())
|
||||
{
|
||||
edges[edge++] = reverse_edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << "merged " << edges.size() - edge << " edges out of " << edges.size()
|
||||
<< std::endl;
|
||||
edges.resize(edge);
|
||||
contractor_graph = std::make_shared<ContractorGraph>(nodes, edges);
|
||||
edges.clear();
|
||||
edges.shrink_to_fit();
|
||||
|
||||
BOOST_ASSERT(0 == edges.capacity());
|
||||
// unsigned maxdegree = 0;
|
||||
// NodeID highestNode = 0;
|
||||
//
|
||||
// for(unsigned i = 0; i < contractor_graph->GetNumberOfNodes(); ++i) {
|
||||
// unsigned degree = contractor_graph->EndEdges(i) -
|
||||
// contractor_graph->BeginEdges(i);
|
||||
// if(degree > maxdegree) {
|
||||
// maxdegree = degree;
|
||||
// highestNode = i;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// SimpleLogger().Write() << "edges at node with id " << highestNode << " has degree
|
||||
// " << maxdegree;
|
||||
// for(unsigned i = contractor_graph->BeginEdges(highestNode); i <
|
||||
// contractor_graph->EndEdges(highestNode); ++i) {
|
||||
// SimpleLogger().Write() << " ->(" << highestNode << "," <<
|
||||
// contractor_graph->GetTarget(i)
|
||||
// << "); via: " << contractor_graph->GetEdgeData(i).via;
|
||||
// }
|
||||
|
||||
std::cout << "contractor finished initalization" << std::endl;
|
||||
}
|
||||
|
||||
~Contractor() { }
|
||||
|
||||
void Run()
|
||||
{
|
||||
// for the preperation we can use a big grain size, which is much faster (probably cache)
|
||||
constexpr size_t InitGrainSize = 100000;
|
||||
constexpr size_t PQGrainSize = 100000;
|
||||
// auto_partitioner will automatically increase the blocksize if we have
|
||||
// a lot of data. It is *important* for the last loop iterations
|
||||
// (which have a very small dataset) that it is devisible.
|
||||
constexpr size_t IndependentGrainSize = 1;
|
||||
constexpr size_t ContractGrainSize = 1;
|
||||
constexpr size_t NeighboursGrainSize = 1;
|
||||
constexpr size_t DeleteGrainSize = 1;
|
||||
|
||||
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
|
||||
Percent p(number_of_nodes);
|
||||
|
||||
ThreadDataContainer thread_data_list(number_of_nodes);
|
||||
|
||||
NodeID number_of_contracted_nodes = 0;
|
||||
std::vector<RemainingNodeData> remaining_nodes(number_of_nodes);
|
||||
std::vector<float> node_priorities(number_of_nodes);
|
||||
std::vector<NodePriorityData> node_data(number_of_nodes);
|
||||
|
||||
|
||||
// initialize priorities in parallel
|
||||
tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, InitGrainSize),
|
||||
[&remaining_nodes](const tbb::blocked_range<int>& range)
|
||||
{
|
||||
for (int x = range.begin(); x != range.end(); ++x)
|
||||
{
|
||||
remaining_nodes[x].id = x;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
std::cout << "initializing elimination PQ ..." << std::flush;
|
||||
tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, PQGrainSize),
|
||||
[this, &node_priorities, &node_data, &thread_data_list](const tbb::blocked_range<int>& range)
|
||||
{
|
||||
ContractorThreadData *data = thread_data_list.getThreadData();
|
||||
for (int x = range.begin(); x != range.end(); ++x)
|
||||
{
|
||||
node_priorities[x] = this->EvaluateNodePriority(data, &node_data[x], x);
|
||||
}
|
||||
}
|
||||
);
|
||||
std::cout << "ok" << std::endl << "preprocessing " << number_of_nodes << " nodes ..."
|
||||
<< std::flush;
|
||||
|
||||
bool flushed_contractor = false;
|
||||
while (number_of_nodes > 2 && number_of_contracted_nodes < number_of_nodes)
|
||||
{
|
||||
if (!flushed_contractor && (number_of_contracted_nodes > (number_of_nodes * 0.65)))
|
||||
{
|
||||
DeallocatingVector<ContractorEdge> new_edge_set; // this one is not explicitely
|
||||
// cleared since it goes out of
|
||||
// scope anywa
|
||||
std::cout << " [flush " << number_of_contracted_nodes << " nodes] " << std::flush;
|
||||
|
||||
// Delete old heap data to free memory that we need for the coming operations
|
||||
thread_data_list.data.clear();
|
||||
|
||||
// Create new priority array
|
||||
std::vector<float> new_node_priority(remaining_nodes.size());
|
||||
// this map gives the old IDs from the new ones, necessary to get a consistent graph
|
||||
// at the end of contraction
|
||||
orig_node_id_to_new_id_map.resize(remaining_nodes.size());
|
||||
// this map gives the new IDs from the old ones, necessary to remap targets from the
|
||||
// remaining graph
|
||||
std::vector<NodeID> new_node_id_from_orig_id_map(number_of_nodes, UINT_MAX);
|
||||
|
||||
// build forward and backward renumbering map and remap ids in remaining_nodes and
|
||||
// Priorities.
|
||||
for (const auto new_node_id : osrm::irange<std::size_t>(0, remaining_nodes.size()))
|
||||
{
|
||||
// create renumbering maps in both directions
|
||||
orig_node_id_to_new_id_map[new_node_id] = remaining_nodes[new_node_id].id;
|
||||
new_node_id_from_orig_id_map[remaining_nodes[new_node_id].id] = new_node_id;
|
||||
new_node_priority[new_node_id] =
|
||||
node_priorities[remaining_nodes[new_node_id].id];
|
||||
remaining_nodes[new_node_id].id = new_node_id;
|
||||
}
|
||||
// walk over all nodes
|
||||
for (const auto i : osrm::irange<std::size_t>(0, contractor_graph->GetNumberOfNodes()))
|
||||
{
|
||||
const NodeID source = i;
|
||||
for (auto current_edge : contractor_graph->GetAdjacentEdgeRange(source))
|
||||
{
|
||||
ContractorGraph::EdgeData &data =
|
||||
contractor_graph->GetEdgeData(current_edge);
|
||||
const NodeID target = contractor_graph->GetTarget(current_edge);
|
||||
if (SPECIAL_NODEID == new_node_id_from_orig_id_map[i])
|
||||
{
|
||||
external_edge_list.push_back({source, target, data});
|
||||
}
|
||||
else
|
||||
{
|
||||
// node is not yet contracted.
|
||||
// add (renumbered) outgoing edges to new DynamicGraph.
|
||||
ContractorEdge new_edge = {
|
||||
new_node_id_from_orig_id_map[source],
|
||||
new_node_id_from_orig_id_map[target],
|
||||
data
|
||||
};
|
||||
|
||||
new_edge.data.is_original_via_node_ID = true;
|
||||
BOOST_ASSERT_MSG(UINT_MAX != new_node_id_from_orig_id_map[source],
|
||||
"new source id not resolveable");
|
||||
BOOST_ASSERT_MSG(UINT_MAX != new_node_id_from_orig_id_map[target],
|
||||
"new target id not resolveable");
|
||||
new_edge_set.push_back(new_edge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete map from old NodeIDs to new ones.
|
||||
new_node_id_from_orig_id_map.clear();
|
||||
new_node_id_from_orig_id_map.shrink_to_fit();
|
||||
|
||||
// Replace old priorities array by new one
|
||||
node_priorities.swap(new_node_priority);
|
||||
// Delete old node_priorities vector
|
||||
new_node_priority.clear();
|
||||
new_node_priority.shrink_to_fit();
|
||||
// old Graph is removed
|
||||
contractor_graph.reset();
|
||||
|
||||
// create new graph
|
||||
std::sort(new_edge_set.begin(), new_edge_set.end());
|
||||
contractor_graph =
|
||||
std::make_shared<ContractorGraph>(remaining_nodes.size(), new_edge_set);
|
||||
|
||||
new_edge_set.clear();
|
||||
flushed_contractor = true;
|
||||
|
||||
// INFO: MAKE SURE THIS IS THE LAST OPERATION OF THE FLUSH!
|
||||
// reinitialize heaps and ThreadData objects with appropriate size
|
||||
thread_data_list.number_of_nodes = contractor_graph->GetNumberOfNodes();
|
||||
}
|
||||
|
||||
const int last = (int)remaining_nodes.size();
|
||||
tbb::parallel_for(tbb::blocked_range<int>(0, last, IndependentGrainSize),
|
||||
[this, &node_priorities, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int>& range)
|
||||
{
|
||||
ContractorThreadData *data = thread_data_list.getThreadData();
|
||||
// determine independent node set
|
||||
for (int i = range.begin(); i != range.end(); ++i)
|
||||
{
|
||||
const NodeID node = remaining_nodes[i].id;
|
||||
remaining_nodes[i].is_independent =
|
||||
this->IsNodeIndependent(node_priorities, data, node);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const auto first = stable_partition(remaining_nodes.begin(),
|
||||
remaining_nodes.end(),
|
||||
[](RemainingNodeData node_data)
|
||||
{ return !node_data.is_independent; });
|
||||
const int first_independent_node = static_cast<int>(first - remaining_nodes.begin());
|
||||
|
||||
// contract independent nodes
|
||||
tbb::parallel_for(tbb::blocked_range<int>(first_independent_node, last, ContractGrainSize),
|
||||
[this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int>& range)
|
||||
{
|
||||
ContractorThreadData *data = thread_data_list.getThreadData();
|
||||
for (int position = range.begin(); position != range.end(); ++position)
|
||||
{
|
||||
const NodeID x = remaining_nodes[position].id;
|
||||
this->ContractNode<false>(data, x);
|
||||
}
|
||||
}
|
||||
);
|
||||
// make sure we really sort each block
|
||||
tbb::parallel_for(thread_data_list.data.range(),
|
||||
[&](const ThreadDataContainer::EnumerableThreadData::range_type& range)
|
||||
{
|
||||
for (auto& data : range)
|
||||
std::sort(data->inserted_edges.begin(),
|
||||
data->inserted_edges.end());
|
||||
}
|
||||
);
|
||||
tbb::parallel_for(tbb::blocked_range<int>(first_independent_node, last, DeleteGrainSize),
|
||||
[this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int>& range)
|
||||
{
|
||||
ContractorThreadData *data = thread_data_list.getThreadData();
|
||||
for (int position = range.begin(); position != range.end(); ++position)
|
||||
{
|
||||
const NodeID x = remaining_nodes[position].id;
|
||||
this->DeleteIncomingEdges(data, x);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// insert new edges
|
||||
for (auto& data : thread_data_list.data)
|
||||
{
|
||||
for (const ContractorEdge &edge : data->inserted_edges)
|
||||
{
|
||||
const EdgeID current_edge_ID = contractor_graph->FindEdge(edge.source, edge.target);
|
||||
if (current_edge_ID < contractor_graph->EndEdges(edge.source))
|
||||
{
|
||||
ContractorGraph::EdgeData ¤t_data =
|
||||
contractor_graph->GetEdgeData(current_edge_ID);
|
||||
if (current_data.shortcut && edge.data.forward == current_data.forward &&
|
||||
edge.data.backward == current_data.backward &&
|
||||
edge.data.distance < current_data.distance)
|
||||
{
|
||||
// found a duplicate edge with smaller weight, update it.
|
||||
current_data = edge.data;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
contractor_graph->InsertEdge(edge.source, edge.target, edge.data);
|
||||
}
|
||||
data->inserted_edges.clear();
|
||||
}
|
||||
|
||||
tbb::parallel_for(tbb::blocked_range<int>(first_independent_node, last, NeighboursGrainSize),
|
||||
[this, &remaining_nodes, &node_priorities, &node_data, &thread_data_list](const tbb::blocked_range<int>& range)
|
||||
{
|
||||
ContractorThreadData *data = thread_data_list.getThreadData();
|
||||
for (int position = range.begin(); position != range.end(); ++position)
|
||||
{
|
||||
NodeID x = remaining_nodes[position].id;
|
||||
this->UpdateNodeNeighbours(node_priorities, node_data, data, x);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// remove contracted nodes from the pool
|
||||
number_of_contracted_nodes += last - first_independent_node;
|
||||
remaining_nodes.resize(first_independent_node);
|
||||
remaining_nodes.shrink_to_fit();
|
||||
// unsigned maxdegree = 0;
|
||||
// unsigned avgdegree = 0;
|
||||
// unsigned mindegree = UINT_MAX;
|
||||
// unsigned quaddegree = 0;
|
||||
//
|
||||
// for(unsigned i = 0; i < remaining_nodes.size(); ++i) {
|
||||
// unsigned degree = contractor_graph->EndEdges(remaining_nodes[i].first)
|
||||
// -
|
||||
// contractor_graph->BeginEdges(remaining_nodes[i].first);
|
||||
// if(degree > maxdegree)
|
||||
// maxdegree = degree;
|
||||
// if(degree < mindegree)
|
||||
// mindegree = degree;
|
||||
//
|
||||
// avgdegree += degree;
|
||||
// quaddegree += (degree*degree);
|
||||
// }
|
||||
//
|
||||
// avgdegree /= std::max((unsigned)1,(unsigned)remaining_nodes.size() );
|
||||
// quaddegree /= std::max((unsigned)1,(unsigned)remaining_nodes.size() );
|
||||
//
|
||||
// SimpleLogger().Write() << "rest: " << remaining_nodes.size() << ", max: "
|
||||
// << maxdegree << ", min: " << mindegree << ", avg: " << avgdegree << ",
|
||||
// quad: " << quaddegree;
|
||||
|
||||
p.printStatus(number_of_contracted_nodes);
|
||||
}
|
||||
|
||||
thread_data_list.data.clear();
|
||||
}
|
||||
|
||||
template <class Edge> inline void GetEdges(DeallocatingVector<Edge> &edges)
|
||||
{
|
||||
Percent p(contractor_graph->GetNumberOfNodes());
|
||||
SimpleLogger().Write() << "Getting edges of minimized graph";
|
||||
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
|
||||
if (contractor_graph->GetNumberOfNodes())
|
||||
{
|
||||
Edge new_edge;
|
||||
for (const auto node : osrm::irange(0u, number_of_nodes))
|
||||
{
|
||||
p.printStatus(node);
|
||||
for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const NodeID target = contractor_graph->GetTarget(edge);
|
||||
const ContractorGraph::EdgeData &data = contractor_graph->GetEdgeData(edge);
|
||||
if (!orig_node_id_to_new_id_map.empty())
|
||||
{
|
||||
new_edge.source = orig_node_id_to_new_id_map[node];
|
||||
new_edge.target = orig_node_id_to_new_id_map[target];
|
||||
}
|
||||
else
|
||||
{
|
||||
new_edge.source = node;
|
||||
new_edge.target = target;
|
||||
}
|
||||
BOOST_ASSERT_MSG(UINT_MAX != new_edge.source, "Source id invalid");
|
||||
BOOST_ASSERT_MSG(UINT_MAX != new_edge.target, "Target id invalid");
|
||||
new_edge.data.distance = data.distance;
|
||||
new_edge.data.shortcut = data.shortcut;
|
||||
if (!data.is_original_via_node_ID && !orig_node_id_to_new_id_map.empty())
|
||||
{
|
||||
new_edge.data.id = orig_node_id_to_new_id_map[data.id];
|
||||
}
|
||||
else
|
||||
{
|
||||
new_edge.data.id = data.id;
|
||||
}
|
||||
BOOST_ASSERT_MSG(new_edge.data.id != INT_MAX, // 2^31
|
||||
"edge id invalid");
|
||||
new_edge.data.forward = data.forward;
|
||||
new_edge.data.backward = data.backward;
|
||||
edges.push_back(new_edge);
|
||||
}
|
||||
}
|
||||
}
|
||||
contractor_graph.reset();
|
||||
orig_node_id_to_new_id_map.clear();
|
||||
orig_node_id_to_new_id_map.shrink_to_fit();
|
||||
|
||||
BOOST_ASSERT(0 == orig_node_id_to_new_id_map.capacity());
|
||||
|
||||
edges.append(external_edge_list.begin(), external_edge_list.end());
|
||||
external_edge_list.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
inline void Dijkstra(const int max_distance,
|
||||
const unsigned number_of_targets,
|
||||
const int maxNodes,
|
||||
ContractorThreadData *const data,
|
||||
const NodeID middleNode)
|
||||
{
|
||||
|
||||
ContractorHeap &heap = data->heap;
|
||||
|
||||
int nodes = 0;
|
||||
unsigned number_of_targets_found = 0;
|
||||
while (!heap.Empty())
|
||||
{
|
||||
const NodeID node = heap.DeleteMin();
|
||||
const int distance = heap.GetKey(node);
|
||||
const short current_hop = heap.GetData(node).hop + 1;
|
||||
|
||||
if (++nodes > maxNodes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (distance > max_distance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Destination settled?
|
||||
if (heap.GetData(node).target)
|
||||
{
|
||||
++number_of_targets_found;
|
||||
if (number_of_targets_found >= number_of_targets)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// iterate over all edges of node
|
||||
for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const ContractorEdgeData &data = contractor_graph->GetEdgeData(edge);
|
||||
if (!data.forward)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const NodeID to = contractor_graph->GetTarget(edge);
|
||||
if (middleNode == to)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const int to_distance = distance + data.distance;
|
||||
|
||||
// New Node discovered -> Add to Heap + Node Info Storage
|
||||
if (!heap.WasInserted(to))
|
||||
{
|
||||
heap.Insert(to, to_distance, ContractorHeapData(current_hop, false));
|
||||
}
|
||||
// Found a shorter Path -> Update distance
|
||||
else if (to_distance < heap.GetKey(to))
|
||||
{
|
||||
heap.DecreaseKey(to, to_distance);
|
||||
heap.GetData(to).hop = current_hop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline float EvaluateNodePriority(ContractorThreadData *const data,
|
||||
NodePriorityData *const node_data,
|
||||
const NodeID node)
|
||||
{
|
||||
ContractionStats stats;
|
||||
|
||||
// perform simulated contraction
|
||||
ContractNode<true>(data, node, &stats);
|
||||
|
||||
// Result will contain the priority
|
||||
float result;
|
||||
if (0 == (stats.edges_deleted_count * stats.original_edges_deleted_count))
|
||||
{
|
||||
result = 1.f * node_data->depth;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 2.f * (((float)stats.edges_added_count) / stats.edges_deleted_count) +
|
||||
4.f * (((float)stats.original_edges_added_count) /
|
||||
stats.original_edges_deleted_count) +
|
||||
1.f * node_data->depth;
|
||||
}
|
||||
BOOST_ASSERT(result >= 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <bool RUNSIMULATION>
|
||||
inline bool
|
||||
ContractNode(ContractorThreadData *data, const NodeID node, ContractionStats *stats = nullptr)
|
||||
{
|
||||
ContractorHeap &heap = data->heap;
|
||||
int inserted_edges_size = data->inserted_edges.size();
|
||||
std::vector<ContractorEdge> &inserted_edges = data->inserted_edges;
|
||||
|
||||
for (auto in_edge : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const ContractorEdgeData &in_data = contractor_graph->GetEdgeData(in_edge);
|
||||
const NodeID source = contractor_graph->GetTarget(in_edge);
|
||||
if (RUNSIMULATION)
|
||||
{
|
||||
BOOST_ASSERT(stats != nullptr);
|
||||
++stats->edges_deleted_count;
|
||||
stats->original_edges_deleted_count += in_data.originalEdges;
|
||||
}
|
||||
if (!in_data.backward)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
heap.Clear();
|
||||
heap.Insert(source, 0, ContractorHeapData());
|
||||
int max_distance = 0;
|
||||
unsigned number_of_targets = 0;
|
||||
|
||||
for (auto out_edge : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const ContractorEdgeData &out_data = contractor_graph->GetEdgeData(out_edge);
|
||||
if (!out_data.forward)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const NodeID target = contractor_graph->GetTarget(out_edge);
|
||||
const int path_distance = in_data.distance + out_data.distance;
|
||||
max_distance = std::max(max_distance, path_distance);
|
||||
if (!heap.WasInserted(target))
|
||||
{
|
||||
heap.Insert(target, INT_MAX, ContractorHeapData(0, true));
|
||||
++number_of_targets;
|
||||
}
|
||||
}
|
||||
|
||||
if (RUNSIMULATION)
|
||||
{
|
||||
Dijkstra(max_distance, number_of_targets, 1000, data, node);
|
||||
}
|
||||
else
|
||||
{
|
||||
Dijkstra(max_distance, number_of_targets, 2000, data, node);
|
||||
}
|
||||
for (auto out_edge : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const ContractorEdgeData &out_data = contractor_graph->GetEdgeData(out_edge);
|
||||
if (!out_data.forward)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const NodeID target = contractor_graph->GetTarget(out_edge);
|
||||
const int path_distance = in_data.distance + out_data.distance;
|
||||
const int distance = heap.GetKey(target);
|
||||
if (path_distance < distance)
|
||||
{
|
||||
if (RUNSIMULATION)
|
||||
{
|
||||
BOOST_ASSERT(stats != nullptr);
|
||||
stats->edges_added_count += 2;
|
||||
stats->original_edges_added_count +=
|
||||
2 * (out_data.originalEdges + in_data.originalEdges);
|
||||
}
|
||||
else
|
||||
{
|
||||
inserted_edges.emplace_back(source, target, path_distance,
|
||||
out_data.originalEdges + in_data.originalEdges,
|
||||
node,
|
||||
true,
|
||||
true,
|
||||
false);
|
||||
|
||||
inserted_edges.emplace_back(target, source, path_distance,
|
||||
out_data.originalEdges + in_data.originalEdges,
|
||||
node,
|
||||
true,
|
||||
false,
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!RUNSIMULATION)
|
||||
{
|
||||
int iend = inserted_edges.size();
|
||||
for (int i = inserted_edges_size; i < iend; ++i)
|
||||
{
|
||||
bool found = false;
|
||||
for (int other = i + 1; other < iend; ++other)
|
||||
{
|
||||
if (inserted_edges[other].source != inserted_edges[i].source)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (inserted_edges[other].target != inserted_edges[i].target)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (inserted_edges[other].data.distance != inserted_edges[i].data.distance)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (inserted_edges[other].data.shortcut != inserted_edges[i].data.shortcut)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
inserted_edges[other].data.forward |= inserted_edges[i].data.forward;
|
||||
inserted_edges[other].data.backward |= inserted_edges[i].data.backward;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
inserted_edges[inserted_edges_size++] = inserted_edges[i];
|
||||
}
|
||||
}
|
||||
inserted_edges.resize(inserted_edges_size);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void DeleteIncomingEdges(ContractorThreadData *data, const NodeID node)
|
||||
{
|
||||
std::vector<NodeID> &neighbours = data->neighbours;
|
||||
neighbours.clear();
|
||||
|
||||
// find all neighbours
|
||||
for (auto e : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const NodeID u = contractor_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 (const auto i : osrm::irange<std::size_t>(0, neighbours.size()))
|
||||
{
|
||||
contractor_graph->DeleteEdgesTo(neighbours[i], node);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool UpdateNodeNeighbours(std::vector<float> &priorities,
|
||||
std::vector<NodePriorityData> &node_data,
|
||||
ContractorThreadData *const data,
|
||||
const NodeID node)
|
||||
{
|
||||
std::vector<NodeID> &neighbours = data->neighbours;
|
||||
neighbours.clear();
|
||||
|
||||
// find all neighbours
|
||||
for (auto e : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const NodeID u = contractor_graph->GetTarget(e);
|
||||
if (u == node)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
neighbours.push_back(u);
|
||||
node_data[u].depth = (std::max)(node_data[node].depth + 1, node_data[u].depth);
|
||||
}
|
||||
// eliminate duplicate entries ( forward + backward edges )
|
||||
std::sort(neighbours.begin(), neighbours.end());
|
||||
neighbours.resize(std::unique(neighbours.begin(), neighbours.end()) - neighbours.begin());
|
||||
|
||||
// re-evaluate priorities of neighboring nodes
|
||||
for (const NodeID u : neighbours)
|
||||
{
|
||||
priorities[u] = EvaluateNodePriority(data, &(node_data)[u], u);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool IsNodeIndependent(
|
||||
const std::vector<float> &priorities,
|
||||
ContractorThreadData *const data,
|
||||
NodeID node) const
|
||||
{
|
||||
const float priority = priorities[node];
|
||||
|
||||
std::vector<NodeID> &neighbours = data->neighbours;
|
||||
neighbours.clear();
|
||||
|
||||
for (auto e : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const NodeID target = contractor_graph->GetTarget(e);
|
||||
if (node == target)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const float target_priority = priorities[target];
|
||||
BOOST_ASSERT(target_priority >= 0);
|
||||
// found a neighbour with lower priority?
|
||||
if (priority > target_priority)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// tie breaking
|
||||
if (std::abs(priority - target_priority) < std::numeric_limits<float>::epsilon() &&
|
||||
bias(node, target))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
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
|
||||
for (const NodeID u : neighbours)
|
||||
{
|
||||
for (auto e : contractor_graph->GetAdjacentEdgeRange(u))
|
||||
{
|
||||
const NodeID target = contractor_graph->GetTarget(e);
|
||||
if (node == target)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const float target_priority = priorities[target];
|
||||
BOOST_ASSERT(target_priority >= 0);
|
||||
// found a neighbour with lower priority?
|
||||
if (priority > target_priority)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// tie breaking
|
||||
if (std::abs(priority - target_priority) < std::numeric_limits<float>::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
|
||||
{
|
||||
const unsigned short hasha = fast_hash(a);
|
||||
const unsigned short hashb = fast_hash(b);
|
||||
|
||||
// The compiler optimizes that to conditional register flags but without branching
|
||||
// statements!
|
||||
if (hasha != hashb)
|
||||
{
|
||||
return hasha < hashb;
|
||||
}
|
||||
return a < b;
|
||||
}
|
||||
|
||||
std::shared_ptr<ContractorGraph> contractor_graph;
|
||||
std::vector<ContractorGraph::InputEdge> contracted_edge_list;
|
||||
stxxl::vector<QueryEdge> external_edge_list;
|
||||
std::vector<NodeID> orig_node_id_to_new_id_map;
|
||||
XORFastHash fast_hash;
|
||||
};
|
||||
|
||||
#endif // CONTRACTOR_H
|
||||
@@ -1,782 +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 "EdgeBasedGraphFactory.h"
|
||||
#include "../Algorithms/BFSComponentExplorer.h"
|
||||
#include "../DataStructures/Percent.h"
|
||||
#include "../DataStructures/Range.h"
|
||||
#include "../Util/compute_angle.hpp"
|
||||
#include "../Util/LuaUtil.h"
|
||||
#include "../Util/simple_logger.hpp"
|
||||
#include "../Util/TimingUtil.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
|
||||
EdgeBasedGraphFactory::EdgeBasedGraphFactory(
|
||||
const std::shared_ptr<NodeBasedDynamicGraph> &node_based_graph,
|
||||
std::unique_ptr<RestrictionMap> restriction_map,
|
||||
std::vector<NodeID> &barrier_node_list,
|
||||
std::vector<NodeID> &traffic_light_node_list,
|
||||
std::vector<NodeInfo> &node_info_list,
|
||||
SpeedProfileProperties &speed_profile)
|
||||
: speed_profile(speed_profile),
|
||||
m_number_of_edge_based_nodes(std::numeric_limits<unsigned>::max()),
|
||||
m_node_info_list(node_info_list), m_node_based_graph(node_based_graph),
|
||||
m_restriction_map(std::move(restriction_map)), max_id(0)
|
||||
{
|
||||
|
||||
// insert into unordered sets for fast lookup
|
||||
m_barrier_nodes.insert(barrier_node_list.begin(), barrier_node_list.end());
|
||||
m_traffic_lights.insert(traffic_light_node_list.begin(), traffic_light_node_list.end());
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::GetEdgeBasedEdges(DeallocatingVector<EdgeBasedEdge> &output_edge_list)
|
||||
{
|
||||
BOOST_ASSERT_MSG(0 == output_edge_list.size(), "Vector is not empty");
|
||||
m_edge_based_edge_list.swap(output_edge_list);
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
for (const EdgeBasedNode &node : m_edge_based_node_list)
|
||||
{
|
||||
BOOST_ASSERT(m_node_info_list.at(node.u).lat != INT_MAX);
|
||||
BOOST_ASSERT(m_node_info_list.at(node.u).lon != INT_MAX);
|
||||
BOOST_ASSERT(m_node_info_list.at(node.v).lon != INT_MAX);
|
||||
BOOST_ASSERT(m_node_info_list.at(node.v).lat != INT_MAX);
|
||||
}
|
||||
#endif
|
||||
nodes.swap(m_edge_based_node_list);
|
||||
}
|
||||
|
||||
void
|
||||
EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const NodeID node_v, const bool belongs_to_tiny_cc)
|
||||
{
|
||||
// merge edges together into one EdgeBasedNode
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
||||
|
||||
// find forward edge id and
|
||||
const EdgeID e1 = m_node_based_graph->FindEdge(node_u, node_v);
|
||||
BOOST_ASSERT(e1 != SPECIAL_EDGEID);
|
||||
|
||||
const EdgeData &forward_data = m_node_based_graph->GetEdgeData(e1);
|
||||
|
||||
// find reverse edge id and
|
||||
const EdgeID e2 = m_node_based_graph->FindEdge(node_v, node_u);
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (e2 == m_node_based_graph->EndEdges(node_v))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "Did not find edge (" << node_v << "," << node_u << ")";
|
||||
}
|
||||
#endif
|
||||
BOOST_ASSERT(e2 != SPECIAL_EDGEID);
|
||||
BOOST_ASSERT(e2 < m_node_based_graph->EndEdges(node_v));
|
||||
const EdgeData &reverse_data = m_node_based_graph->GetEdgeData(e2);
|
||||
|
||||
if (forward_data.edgeBasedNodeID == SPECIAL_NODEID &&
|
||||
reverse_data.edgeBasedNodeID == SPECIAL_NODEID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(m_geometry_compressor.HasEntryForID(e1) ==
|
||||
m_geometry_compressor.HasEntryForID(e2));
|
||||
if (m_geometry_compressor.HasEntryForID(e1))
|
||||
{
|
||||
BOOST_ASSERT(m_geometry_compressor.HasEntryForID(e2));
|
||||
|
||||
// reconstruct geometry and put in each individual edge with its offset
|
||||
const std::vector<GeometryCompressor::CompressedNode> &forward_geometry =
|
||||
m_geometry_compressor.GetBucketReference(e1);
|
||||
const std::vector<GeometryCompressor::CompressedNode> &reverse_geometry =
|
||||
m_geometry_compressor.GetBucketReference(e2);
|
||||
BOOST_ASSERT(forward_geometry.size() == reverse_geometry.size());
|
||||
BOOST_ASSERT(0 != forward_geometry.size());
|
||||
const unsigned geometry_size = forward_geometry.size();
|
||||
BOOST_ASSERT(geometry_size > 1);
|
||||
|
||||
// reconstruct bidirectional edge with individual weights and put each into the NN index
|
||||
|
||||
std::vector<int> forward_dist_prefix_sum(forward_geometry.size(), 0);
|
||||
std::vector<int> reverse_dist_prefix_sum(reverse_geometry.size(), 0);
|
||||
|
||||
// quick'n'dirty prefix sum as std::partial_sum needs addtional casts
|
||||
// TODO: move to lambda function with C++11
|
||||
int temp_sum = 0;
|
||||
|
||||
for (const auto i : osrm::irange(0u, geometry_size))
|
||||
{
|
||||
forward_dist_prefix_sum[i] = temp_sum;
|
||||
temp_sum += forward_geometry[i].second;
|
||||
|
||||
BOOST_ASSERT(forward_data.distance >= temp_sum);
|
||||
}
|
||||
|
||||
temp_sum = 0;
|
||||
for (const auto i : osrm::irange(0u, geometry_size))
|
||||
{
|
||||
temp_sum += reverse_geometry[reverse_geometry.size() - 1 - i].second;
|
||||
reverse_dist_prefix_sum[i] = reverse_data.distance - temp_sum;
|
||||
// BOOST_ASSERT(reverse_data.distance >= temp_sum);
|
||||
}
|
||||
|
||||
NodeID current_edge_source_coordinate_id = node_u;
|
||||
|
||||
if (SPECIAL_NODEID != forward_data.edgeBasedNodeID)
|
||||
{
|
||||
max_id = std::max(forward_data.edgeBasedNodeID, max_id);
|
||||
}
|
||||
if (SPECIAL_NODEID != reverse_data.edgeBasedNodeID)
|
||||
{
|
||||
max_id = std::max(reverse_data.edgeBasedNodeID, max_id);
|
||||
}
|
||||
|
||||
// traverse arrays from start and end respectively
|
||||
for (const auto i : osrm::irange(0u, geometry_size))
|
||||
{
|
||||
BOOST_ASSERT(current_edge_source_coordinate_id ==
|
||||
reverse_geometry[geometry_size - 1 - i].first);
|
||||
const NodeID current_edge_target_coordinate_id = forward_geometry[i].first;
|
||||
BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id);
|
||||
|
||||
// build edges
|
||||
m_edge_based_node_list.emplace_back(forward_data.edgeBasedNodeID,
|
||||
reverse_data.edgeBasedNodeID,
|
||||
current_edge_source_coordinate_id,
|
||||
current_edge_target_coordinate_id,
|
||||
forward_data.nameID,
|
||||
forward_geometry[i].second,
|
||||
reverse_geometry[geometry_size - 1 - i].second,
|
||||
forward_dist_prefix_sum[i],
|
||||
reverse_dist_prefix_sum[i],
|
||||
m_geometry_compressor.GetPositionForID(e1),
|
||||
i,
|
||||
belongs_to_tiny_cc,
|
||||
forward_data.travel_mode,
|
||||
reverse_data.travel_mode);
|
||||
current_edge_source_coordinate_id = current_edge_target_coordinate_id;
|
||||
|
||||
BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
|
||||
|
||||
BOOST_ASSERT(node_u != m_edge_based_node_list.back().u ||
|
||||
node_v != m_edge_based_node_list.back().v);
|
||||
|
||||
BOOST_ASSERT(node_u != m_edge_based_node_list.back().v ||
|
||||
node_v != m_edge_based_node_list.back().u);
|
||||
}
|
||||
|
||||
BOOST_ASSERT(current_edge_source_coordinate_id == node_v);
|
||||
BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(!m_geometry_compressor.HasEntryForID(e2));
|
||||
|
||||
if (forward_data.edgeBasedNodeID != SPECIAL_NODEID)
|
||||
{
|
||||
BOOST_ASSERT(forward_data.forward);
|
||||
}
|
||||
if (reverse_data.edgeBasedNodeID != SPECIAL_NODEID)
|
||||
{
|
||||
BOOST_ASSERT(reverse_data.forward);
|
||||
}
|
||||
if (forward_data.edgeBasedNodeID == SPECIAL_NODEID)
|
||||
{
|
||||
BOOST_ASSERT(!forward_data.forward);
|
||||
}
|
||||
if (reverse_data.edgeBasedNodeID == SPECIAL_NODEID)
|
||||
{
|
||||
BOOST_ASSERT(!reverse_data.forward);
|
||||
}
|
||||
|
||||
BOOST_ASSERT(forward_data.edgeBasedNodeID != SPECIAL_NODEID ||
|
||||
reverse_data.edgeBasedNodeID != SPECIAL_NODEID);
|
||||
|
||||
m_edge_based_node_list.emplace_back(forward_data.edgeBasedNodeID,
|
||||
reverse_data.edgeBasedNodeID,
|
||||
node_u,
|
||||
node_v,
|
||||
forward_data.nameID,
|
||||
forward_data.distance,
|
||||
reverse_data.distance,
|
||||
0,
|
||||
0,
|
||||
SPECIAL_EDGEID,
|
||||
0,
|
||||
belongs_to_tiny_cc,
|
||||
forward_data.travel_mode,
|
||||
reverse_data.travel_mode);
|
||||
BOOST_ASSERT(!m_edge_based_node_list.back().IsCompressed());
|
||||
}
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::FlushVectorToStream(
|
||||
std::ofstream &edge_data_file, std::vector<OriginalEdgeData> &original_edge_data_vector) const
|
||||
{
|
||||
if (original_edge_data_vector.empty()) {
|
||||
return;
|
||||
}
|
||||
edge_data_file.write((char *)&(original_edge_data_vector[0]),
|
||||
original_edge_data_vector.size() * sizeof(OriginalEdgeData));
|
||||
original_edge_data_vector.clear();
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::Run(const std::string &original_edge_data_filename,
|
||||
const std::string &geometry_filename,
|
||||
lua_State *lua_state)
|
||||
{
|
||||
|
||||
TIMER_START(geometry);
|
||||
CompressGeometry();
|
||||
TIMER_STOP(geometry);
|
||||
|
||||
TIMER_START(renumber);
|
||||
RenumberEdges();
|
||||
TIMER_STOP(renumber);
|
||||
|
||||
TIMER_START(generate_nodes);
|
||||
GenerateEdgeExpandedNodes();
|
||||
TIMER_STOP(generate_nodes);
|
||||
|
||||
TIMER_START(generate_edges);
|
||||
GenerateEdgeExpandedEdges(original_edge_data_filename, lua_state);
|
||||
TIMER_STOP(generate_edges);
|
||||
|
||||
m_geometry_compressor.SerializeInternalVector(geometry_filename);
|
||||
|
||||
SimpleLogger().Write() << "Timing statistics for edge-expanded graph:";
|
||||
SimpleLogger().Write() << "Geometry compression: " << TIMER_SEC(geometry) << "s";
|
||||
SimpleLogger().Write() << "Renumbering edges: " << TIMER_SEC(renumber) << "s";
|
||||
SimpleLogger().Write() << "Generating nodes: " << TIMER_SEC(generate_nodes) << "s";
|
||||
SimpleLogger().Write() << "Generating edges: " << TIMER_SEC(generate_edges) << "s";
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::CompressGeometry()
|
||||
{
|
||||
SimpleLogger().Write() << "Removing graph geometry while preserving topology";
|
||||
|
||||
const unsigned original_number_of_nodes = m_node_based_graph->GetNumberOfNodes();
|
||||
const unsigned original_number_of_edges = m_node_based_graph->GetNumberOfEdges();
|
||||
|
||||
Percent progress(original_number_of_nodes);
|
||||
unsigned removed_node_count = 0;
|
||||
|
||||
for (const NodeID node_v : osrm::irange(0u, original_number_of_nodes))
|
||||
{
|
||||
progress.printStatus(node_v);
|
||||
|
||||
// only contract degree 2 vertices
|
||||
if (2 != m_node_based_graph->GetOutDegree(node_v))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// don't contract barrier node
|
||||
if (m_barrier_nodes.end() != m_barrier_nodes.find(node_v))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if v is a via node for a turn restriction, i.e. a 'directed' barrier node
|
||||
if (m_restriction_map->IsViaNode(node_v))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool reverse_edge_order =
|
||||
!(m_node_based_graph->GetEdgeData(m_node_based_graph->BeginEdges(node_v)).forward);
|
||||
const EdgeID forward_e2 = m_node_based_graph->BeginEdges(node_v) + reverse_edge_order;
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != forward_e2);
|
||||
const EdgeID reverse_e2 = m_node_based_graph->BeginEdges(node_v) + 1 - reverse_edge_order;
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != reverse_e2);
|
||||
|
||||
const EdgeData &fwd_edge_data2 = m_node_based_graph->GetEdgeData(forward_e2);
|
||||
const EdgeData &rev_edge_data2 = m_node_based_graph->GetEdgeData(reverse_e2);
|
||||
|
||||
const NodeID node_w = m_node_based_graph->GetTarget(forward_e2);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != node_w);
|
||||
BOOST_ASSERT(node_v != node_w);
|
||||
const NodeID node_u = m_node_based_graph->GetTarget(reverse_e2);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != node_u);
|
||||
BOOST_ASSERT(node_u != node_v);
|
||||
|
||||
const EdgeID forward_e1 = m_node_based_graph->FindEdge(node_u, node_v);
|
||||
BOOST_ASSERT(m_node_based_graph->EndEdges(node_u) != forward_e1);
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != forward_e1);
|
||||
BOOST_ASSERT(node_v == m_node_based_graph->GetTarget(forward_e1));
|
||||
const EdgeID reverse_e1 = m_node_based_graph->FindEdge(node_w, node_v);
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != reverse_e1);
|
||||
BOOST_ASSERT(node_v == m_node_based_graph->GetTarget(reverse_e1));
|
||||
|
||||
const EdgeData &fwd_edge_data1 = m_node_based_graph->GetEdgeData(forward_e1);
|
||||
const EdgeData &rev_edge_data1 = m_node_based_graph->GetEdgeData(reverse_e1);
|
||||
|
||||
if ((m_node_based_graph->FindEdge(node_u, node_w) != m_node_based_graph->EndEdges(node_u)) ||
|
||||
(m_node_based_graph->FindEdge(node_w, node_u) != m_node_based_graph->EndEdges(node_w)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( // TODO: rename to IsCompatibleTo
|
||||
fwd_edge_data1.IsEqualTo(fwd_edge_data2) &&
|
||||
rev_edge_data1.IsEqualTo(rev_edge_data2))
|
||||
{
|
||||
// Get distances before graph is modified
|
||||
const int forward_weight1 = m_node_based_graph->GetEdgeData(forward_e1).distance;
|
||||
const int forward_weight2 = m_node_based_graph->GetEdgeData(forward_e2).distance;
|
||||
|
||||
BOOST_ASSERT(0 != forward_weight1);
|
||||
BOOST_ASSERT(0 != forward_weight2);
|
||||
|
||||
const int reverse_weight1 = m_node_based_graph->GetEdgeData(reverse_e1).distance;
|
||||
const int reverse_weight2 = m_node_based_graph->GetEdgeData(reverse_e2).distance;
|
||||
|
||||
BOOST_ASSERT(0 != reverse_weight1);
|
||||
BOOST_ASSERT(0 != forward_weight2);
|
||||
|
||||
const bool add_traffic_signal_penalty =
|
||||
(m_traffic_lights.find(node_v) != m_traffic_lights.end());
|
||||
|
||||
// add weight of e2's to e1
|
||||
m_node_based_graph->GetEdgeData(forward_e1).distance += fwd_edge_data2.distance;
|
||||
m_node_based_graph->GetEdgeData(reverse_e1).distance += rev_edge_data2.distance;
|
||||
if (add_traffic_signal_penalty)
|
||||
{
|
||||
m_node_based_graph->GetEdgeData(forward_e1).distance +=
|
||||
speed_profile.traffic_signal_penalty;
|
||||
m_node_based_graph->GetEdgeData(reverse_e1).distance +=
|
||||
speed_profile.traffic_signal_penalty;
|
||||
}
|
||||
|
||||
// extend e1's to targets of e2's
|
||||
m_node_based_graph->SetTarget(forward_e1, node_w);
|
||||
m_node_based_graph->SetTarget(reverse_e1, node_u);
|
||||
|
||||
// remove e2's (if bidir, otherwise only one)
|
||||
m_node_based_graph->DeleteEdge(node_v, forward_e2);
|
||||
m_node_based_graph->DeleteEdge(node_v, reverse_e2);
|
||||
|
||||
// update any involved turn restrictions
|
||||
m_restriction_map->FixupStartingTurnRestriction(node_u, node_v, node_w);
|
||||
m_restriction_map->FixupArrivingTurnRestriction(node_u, node_v, node_w);
|
||||
|
||||
m_restriction_map->FixupStartingTurnRestriction(node_w, node_v, node_u);
|
||||
m_restriction_map->FixupArrivingTurnRestriction(node_w, node_v, node_u);
|
||||
|
||||
// store compressed geometry in container
|
||||
m_geometry_compressor.CompressEdge(
|
||||
forward_e1,
|
||||
forward_e2,
|
||||
node_v,
|
||||
node_w,
|
||||
forward_weight1 +
|
||||
(add_traffic_signal_penalty ? speed_profile.traffic_signal_penalty : 0),
|
||||
forward_weight2);
|
||||
m_geometry_compressor.CompressEdge(
|
||||
reverse_e1,
|
||||
reverse_e2,
|
||||
node_v,
|
||||
node_u,
|
||||
reverse_weight1,
|
||||
reverse_weight2 +
|
||||
(add_traffic_signal_penalty ? speed_profile.traffic_signal_penalty : 0));
|
||||
++removed_node_count;
|
||||
|
||||
BOOST_ASSERT(m_node_based_graph->GetEdgeData(forward_e1).nameID ==
|
||||
m_node_based_graph->GetEdgeData(reverse_e1).nameID);
|
||||
}
|
||||
}
|
||||
SimpleLogger().Write() << "removed " << removed_node_count << " nodes";
|
||||
m_geometry_compressor.PrintStatistics();
|
||||
|
||||
unsigned new_node_count = 0;
|
||||
unsigned new_edge_count = 0;
|
||||
|
||||
for(const auto i : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
|
||||
{
|
||||
if (m_node_based_graph->GetOutDegree(i) > 0)
|
||||
{
|
||||
++new_node_count;
|
||||
new_edge_count += (m_node_based_graph->EndEdges(i) - m_node_based_graph->BeginEdges(i));
|
||||
}
|
||||
}
|
||||
SimpleLogger().Write() << "new nodes: " << new_node_count << ", edges " << new_edge_count;
|
||||
SimpleLogger().Write() << "Node compression ratio: " << new_node_count /
|
||||
(double)original_number_of_nodes;
|
||||
SimpleLogger().Write() << "Edge compression ratio: " << new_edge_count /
|
||||
(double)original_number_of_edges;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the id of the edge in the edge expanded graph (into the edge in the node based graph)
|
||||
*/
|
||||
void EdgeBasedGraphFactory::RenumberEdges()
|
||||
{
|
||||
// renumber edge based node IDs
|
||||
unsigned numbered_edges_count = 0;
|
||||
for (NodeID current_node = 0; current_node < m_node_based_graph->GetNumberOfNodes();
|
||||
++current_node)
|
||||
{
|
||||
for (EdgeID current_edge : m_node_based_graph->GetAdjacentEdgeRange(current_node))
|
||||
{
|
||||
EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge);
|
||||
if (!edge_data.forward)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(numbered_edges_count < m_node_based_graph->GetNumberOfEdges());
|
||||
edge_data.edgeBasedNodeID = numbered_edges_count;
|
||||
++numbered_edges_count;
|
||||
|
||||
BOOST_ASSERT(SPECIAL_NODEID != edge_data.edgeBasedNodeID);
|
||||
}
|
||||
}
|
||||
m_number_of_edge_based_nodes = numbered_edges_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the nodes in the edge expanded graph from edges in the node-based graph.
|
||||
*/
|
||||
void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
|
||||
{
|
||||
SimpleLogger().Write() << "Identifying components of the road network";
|
||||
|
||||
// Run a BFS on the undirected graph and identify small components
|
||||
BFSComponentExplorer<NodeBasedDynamicGraph> component_explorer(
|
||||
*m_node_based_graph, *m_restriction_map, m_barrier_nodes);
|
||||
|
||||
component_explorer.run();
|
||||
|
||||
SimpleLogger().Write() << "identified: " << component_explorer.GetNumberOfComponents()
|
||||
<< " many components";
|
||||
SimpleLogger().Write() << "generating edge-expanded nodes";
|
||||
|
||||
Percent progress(m_node_based_graph->GetNumberOfNodes());
|
||||
|
||||
// loop over all edges and generate new set of nodes
|
||||
for (NodeID u = 0, end = m_node_based_graph->GetNumberOfNodes(); u < end; ++u)
|
||||
{
|
||||
BOOST_ASSERT(u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(u < m_node_based_graph->GetNumberOfNodes());
|
||||
progress.printStatus(u);
|
||||
for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
|
||||
{
|
||||
const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
|
||||
BOOST_ASSERT(e1 != SPECIAL_EDGEID);
|
||||
const NodeID v = m_node_based_graph->GetTarget(e1);
|
||||
|
||||
BOOST_ASSERT(SPECIAL_NODEID != v);
|
||||
// pick only every other edge
|
||||
if (u > v)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(u < v);
|
||||
|
||||
// Note: edges that end on barrier nodes or on a turn restriction
|
||||
// may actually be in two distinct components. We choose the smallest
|
||||
const unsigned size_of_component = std::min(component_explorer.GetComponentSize(u),
|
||||
component_explorer.GetComponentSize(v));
|
||||
|
||||
const bool component_is_tiny = (size_of_component < 1000);
|
||||
if (edge_data.edgeBasedNodeID == SPECIAL_NODEID)
|
||||
{
|
||||
InsertEdgeBasedNode(v, u, component_is_tiny);
|
||||
}
|
||||
else
|
||||
{
|
||||
InsertEdgeBasedNode(u, v, component_is_tiny);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size()
|
||||
<< " nodes in edge-expanded graph";
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually it also generates OriginalEdgeData and serializes them...
|
||||
*/
|
||||
void
|
||||
EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edge_data_filename,
|
||||
lua_State *lua_state)
|
||||
{
|
||||
SimpleLogger().Write() << "generating edge-expanded edges";
|
||||
|
||||
unsigned node_based_edge_counter = 0;
|
||||
unsigned original_edges_counter = 0;
|
||||
|
||||
std::ofstream edge_data_file(original_edge_data_filename.c_str(), std::ios::binary);
|
||||
|
||||
// writes a dummy value that is updated later
|
||||
edge_data_file.write((char *)&original_edges_counter, sizeof(unsigned));
|
||||
|
||||
std::vector<OriginalEdgeData> original_edge_data_vector;
|
||||
original_edge_data_vector.reserve(1024 * 1024);
|
||||
|
||||
// Loop over all turns and generate new set of edges.
|
||||
// Three nested loop look super-linear, but we are dealing with a (kind of)
|
||||
// linear number of turns only.
|
||||
unsigned restricted_turns_counter = 0;
|
||||
unsigned skipped_uturns_counter = 0;
|
||||
unsigned skipped_barrier_turns_counter = 0;
|
||||
unsigned compressed = 0;
|
||||
|
||||
Percent progress(m_node_based_graph->GetNumberOfNodes());
|
||||
|
||||
for (NodeID u = 0, end = m_node_based_graph->GetNumberOfNodes(); u < end; ++u)
|
||||
{
|
||||
progress.printStatus(u);
|
||||
for (const EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
|
||||
{
|
||||
if (!m_node_based_graph->GetEdgeData(e1).forward)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
++node_based_edge_counter;
|
||||
const NodeID v = m_node_based_graph->GetTarget(e1);
|
||||
const NodeID to_node_of_only_restriction =
|
||||
m_restriction_map->CheckForEmanatingIsOnlyTurn(u, v);
|
||||
const bool is_barrier_node = (m_barrier_nodes.find(v) != m_barrier_nodes.end());
|
||||
|
||||
for (EdgeID e2 : m_node_based_graph->GetAdjacentEdgeRange(v))
|
||||
{
|
||||
if (!m_node_based_graph->GetEdgeData(e2).forward)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const NodeID w = m_node_based_graph->GetTarget(e2);
|
||||
|
||||
if ((to_node_of_only_restriction != SPECIAL_NODEID) &&
|
||||
(w != to_node_of_only_restriction))
|
||||
{
|
||||
// We are at an only_-restriction but not at the right turn.
|
||||
++restricted_turns_counter;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_barrier_node)
|
||||
{
|
||||
if (u != w)
|
||||
{
|
||||
++skipped_barrier_turns_counter;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((u == w) && (m_node_based_graph->GetOutDegree(v) > 1))
|
||||
{
|
||||
++skipped_uturns_counter;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// only add an edge if turn is not a U-turn except when it is
|
||||
// at the end of a dead-end street
|
||||
if (m_restriction_map->CheckIfTurnIsRestricted(u, v, w) &&
|
||||
(to_node_of_only_restriction == SPECIAL_NODEID) &&
|
||||
(w != to_node_of_only_restriction))
|
||||
{
|
||||
// We are at an only_-restriction but not at the right turn.
|
||||
++restricted_turns_counter;
|
||||
continue;
|
||||
}
|
||||
|
||||
// only add an edge if turn is not prohibited
|
||||
const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(e1);
|
||||
const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(e2);
|
||||
|
||||
BOOST_ASSERT(edge_data1.edgeBasedNodeID != edge_data2.edgeBasedNodeID);
|
||||
BOOST_ASSERT(edge_data1.forward);
|
||||
BOOST_ASSERT(edge_data2.forward);
|
||||
|
||||
// the following is the core of the loop.
|
||||
unsigned distance = edge_data1.distance;
|
||||
if (m_traffic_lights.find(v) != m_traffic_lights.end())
|
||||
{
|
||||
distance += speed_profile.traffic_signal_penalty;
|
||||
}
|
||||
|
||||
// unpack last node of first segment if packed
|
||||
const auto first_coordinate = m_node_info_list[(m_geometry_compressor.HasEntryForID(e1) ?
|
||||
m_geometry_compressor.GetLastNodeIDOfBucket(e1) :
|
||||
u)];
|
||||
|
||||
// unpack first node of second segment if packed
|
||||
const auto third_coordinate = m_node_info_list[(m_geometry_compressor.HasEntryForID(e2) ?
|
||||
m_geometry_compressor.GetFirstNodeIDOfBucket(e2) :
|
||||
w)];
|
||||
|
||||
const double turn_angle = ComputeAngle::OfThreeFixedPointCoordinates(
|
||||
first_coordinate, m_node_info_list[v], third_coordinate);
|
||||
|
||||
const int turn_penalty = GetTurnPenalty(turn_angle, lua_state);
|
||||
TurnInstruction turn_instruction = AnalyzeTurn(u, v, w, turn_angle);
|
||||
if (turn_instruction == TurnInstruction::UTurn)
|
||||
{
|
||||
distance += speed_profile.u_turn_penalty;
|
||||
}
|
||||
distance += turn_penalty;
|
||||
|
||||
const bool edge_is_compressed = m_geometry_compressor.HasEntryForID(e1);
|
||||
|
||||
if (edge_is_compressed)
|
||||
{
|
||||
++compressed;
|
||||
}
|
||||
|
||||
original_edge_data_vector.emplace_back(
|
||||
(edge_is_compressed ? m_geometry_compressor.GetPositionForID(e1) : v),
|
||||
edge_data1.nameID,
|
||||
turn_instruction,
|
||||
edge_is_compressed,
|
||||
edge_data2.travel_mode);
|
||||
|
||||
++original_edges_counter;
|
||||
|
||||
if (original_edge_data_vector.size() > 1024 * 1024 * 10)
|
||||
{
|
||||
FlushVectorToStream(edge_data_file, original_edge_data_vector);
|
||||
}
|
||||
|
||||
BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edgeBasedNodeID);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edgeBasedNodeID);
|
||||
|
||||
m_edge_based_edge_list.emplace_back(EdgeBasedEdge(edge_data1.edgeBasedNodeID,
|
||||
edge_data2.edgeBasedNodeID,
|
||||
m_edge_based_edge_list.size(),
|
||||
distance,
|
||||
true,
|
||||
false));
|
||||
}
|
||||
}
|
||||
}
|
||||
FlushVectorToStream(edge_data_file, original_edge_data_vector);
|
||||
|
||||
edge_data_file.seekp(std::ios::beg);
|
||||
edge_data_file.write((char *)&original_edges_counter, sizeof(unsigned));
|
||||
edge_data_file.close();
|
||||
|
||||
SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size() << " edge based nodes";
|
||||
SimpleLogger().Write() << "Node-based graph contains " << node_based_edge_counter << " edges";
|
||||
SimpleLogger().Write() << "Edge-expanded graph ...";
|
||||
SimpleLogger().Write() << " contains " << m_edge_based_edge_list.size() << " edges";
|
||||
SimpleLogger().Write() << " skips " << restricted_turns_counter << " turns, "
|
||||
"defined by "
|
||||
<< m_restriction_map->size() << " restrictions";
|
||||
SimpleLogger().Write() << " skips " << skipped_uturns_counter << " U turns";
|
||||
SimpleLogger().Write() << " skips " << skipped_barrier_turns_counter << " turns over barriers";
|
||||
}
|
||||
|
||||
int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) const
|
||||
{
|
||||
|
||||
if (speed_profile.has_turn_penalty_function)
|
||||
{
|
||||
try
|
||||
{
|
||||
// call lua profile to compute turn penalty
|
||||
return luabind::call_function<int>(lua_state, "turn_function", 180. - angle);
|
||||
}
|
||||
catch (const luabind::error &er) { SimpleLogger().Write(logWARNING) << er.what(); }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID node_u,
|
||||
const NodeID node_v,
|
||||
const NodeID node_w,
|
||||
const double angle)
|
||||
const
|
||||
{
|
||||
if (node_u == node_w)
|
||||
{
|
||||
return TurnInstruction::UTurn;
|
||||
}
|
||||
|
||||
const EdgeID edge1 = m_node_based_graph->FindEdge(node_u, node_v);
|
||||
const EdgeID edge2 = m_node_based_graph->FindEdge(node_v, node_w);
|
||||
|
||||
const EdgeData &data1 = m_node_based_graph->GetEdgeData(edge1);
|
||||
const EdgeData &data2 = m_node_based_graph->GetEdgeData(edge2);
|
||||
|
||||
// roundabouts need to be handled explicitely
|
||||
if (data1.roundabout && data2.roundabout)
|
||||
{
|
||||
// Is a turn possible? If yes, we stay on the roundabout!
|
||||
if (1 == m_node_based_graph->GetDirectedOutDegree(node_v))
|
||||
{
|
||||
// No turn possible.
|
||||
return TurnInstruction::NoTurn;
|
||||
}
|
||||
return TurnInstruction::StayOnRoundAbout;
|
||||
}
|
||||
// Does turn start or end on roundabout?
|
||||
if (data1.roundabout || data2.roundabout)
|
||||
{
|
||||
// We are entering the roundabout
|
||||
if ((!data1.roundabout) && data2.roundabout)
|
||||
{
|
||||
return TurnInstruction::EnterRoundAbout;
|
||||
}
|
||||
// We are leaving the roundabout
|
||||
if (data1.roundabout && (!data2.roundabout))
|
||||
{
|
||||
return TurnInstruction::LeaveRoundAbout;
|
||||
}
|
||||
}
|
||||
|
||||
// If street names stay the same and if we are certain that it is not a
|
||||
// a segment of a roundabout, we skip it.
|
||||
if (data1.nameID == data2.nameID)
|
||||
{
|
||||
// TODO: Here we should also do a small graph exploration to check for
|
||||
// more complex situations
|
||||
if (0 != data1.nameID || m_node_based_graph->GetOutDegree(node_v) <= 2)
|
||||
{
|
||||
return TurnInstruction::NoTurn;
|
||||
}
|
||||
}
|
||||
|
||||
return TurnInstructionsClass::GetTurnDirectionOfInstruction(angle);
|
||||
}
|
||||
|
||||
unsigned EdgeBasedGraphFactory::GetNumberOfEdgeBasedNodes() const
|
||||
{
|
||||
return m_number_of_edge_based_nodes;
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
*/
|
||||
|
||||
// This class constructs the edge-expanded routing graph
|
||||
|
||||
#ifndef EDGEBASEDGRAPHFACTORY_H_
|
||||
#define EDGEBASEDGRAPHFACTORY_H_
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
#include "../DataStructures/EdgeBasedNode.h"
|
||||
#include "../DataStructures/OriginalEdgeData.h"
|
||||
#include "../DataStructures/QueryNode.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../DataStructures/NodeBasedGraph.h"
|
||||
#include "../DataStructures/RestrictionMap.h"
|
||||
#include "GeometryCompressor.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
struct lua_State;
|
||||
|
||||
class EdgeBasedGraphFactory
|
||||
{
|
||||
public:
|
||||
EdgeBasedGraphFactory() = delete;
|
||||
EdgeBasedGraphFactory(const EdgeBasedGraphFactory &) = delete;
|
||||
|
||||
struct SpeedProfileProperties;
|
||||
|
||||
explicit EdgeBasedGraphFactory(const std::shared_ptr<NodeBasedDynamicGraph> &node_based_graph,
|
||||
std::unique_ptr<RestrictionMap> restricion_map,
|
||||
std::vector<NodeID> &barrier_node_list,
|
||||
std::vector<NodeID> &traffic_light_node_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 *lua_state);
|
||||
|
||||
void GetEdgeBasedEdges(DeallocatingVector<EdgeBasedEdge> &edges);
|
||||
|
||||
void GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes);
|
||||
|
||||
TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, const double angle) const;
|
||||
|
||||
int GetTurnPenalty(double angle, lua_State *lua_state) const;
|
||||
|
||||
unsigned GetNumberOfEdgeBasedNodes() const;
|
||||
|
||||
struct SpeedProfileProperties
|
||||
{
|
||||
SpeedProfileProperties()
|
||||
: traffic_signal_penalty(0), u_turn_penalty(0), has_turn_penalty_function(false)
|
||||
{
|
||||
}
|
||||
|
||||
int traffic_signal_penalty;
|
||||
int u_turn_penalty;
|
||||
bool has_turn_penalty_function;
|
||||
} speed_profile;
|
||||
|
||||
private:
|
||||
using EdgeData = NodeBasedDynamicGraph::EdgeData;
|
||||
|
||||
unsigned m_number_of_edge_based_nodes;
|
||||
|
||||
std::vector<NodeInfo> m_node_info_list;
|
||||
std::vector<EdgeBasedNode> m_edge_based_node_list;
|
||||
DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list;
|
||||
|
||||
std::shared_ptr<NodeBasedDynamicGraph> m_node_based_graph;
|
||||
std::unordered_set<NodeID> m_barrier_nodes;
|
||||
std::unordered_set<NodeID> m_traffic_lights;
|
||||
|
||||
std::unique_ptr<RestrictionMap> m_restriction_map;
|
||||
|
||||
GeometryCompressor m_geometry_compressor;
|
||||
|
||||
void CompressGeometry();
|
||||
void RenumberEdges();
|
||||
void GenerateEdgeExpandedNodes();
|
||||
void GenerateEdgeExpandedEdges(const std::string &original_edge_data_filename,
|
||||
lua_State *lua_state);
|
||||
|
||||
void InsertEdgeBasedNode(const NodeID u, const NodeID v, const bool belongsToTinyComponent);
|
||||
|
||||
void FlushVectorToStream(std::ofstream &edge_data_file,
|
||||
std::vector<OriginalEdgeData> &original_edge_data_vector) const;
|
||||
|
||||
NodeID max_id;
|
||||
};
|
||||
|
||||
#endif /* EDGEBASEDGRAPHFACTORY_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 GEOMETRY_COMPRESSOR_H
|
||||
#define GEOMETRY_COMPRESSOR_H
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class GeometryCompressor
|
||||
{
|
||||
public:
|
||||
using CompressedNode = std::pair<NodeID, EdgeWeight>;
|
||||
|
||||
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;
|
||||
NodeID GetFirstNodeIDOfBucket(const EdgeID edge_id) const;
|
||||
NodeID GetLastNodeIDOfBucket(const EdgeID edge_id) const;
|
||||
|
||||
private:
|
||||
void IncreaseFreeList();
|
||||
std::vector<std::vector<CompressedNode>> m_compressed_geometries;
|
||||
std::vector<unsigned> m_free_list;
|
||||
std::unordered_map<EdgeID, unsigned> m_edge_id_to_list_index_map;
|
||||
};
|
||||
|
||||
#endif // GEOMETRY_COMPRESSOR_H
|
||||
@@ -1,575 +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 "Prepare.h"
|
||||
|
||||
#include "Contractor.h"
|
||||
|
||||
#include "../Algorithms/IteratorBasedCRC32.h"
|
||||
#include "../DataStructures/BinaryHeap.h"
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
#include "../DataStructures/Range.h"
|
||||
#include "../DataStructures/StaticRTree.h"
|
||||
#include "../DataStructures/RestrictionMap.h"
|
||||
|
||||
#include "../Util/GitDescription.h"
|
||||
#include "../Util/LuaUtil.h"
|
||||
#include "../Util/make_unique.hpp"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/simple_logger.hpp"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <tbb/task_scheduler_init.h>
|
||||
#include <tbb/parallel_sort.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
Prepare::Prepare() : requested_num_threads(1) {}
|
||||
|
||||
Prepare::~Prepare() {}
|
||||
|
||||
int Prepare::Process(int argc, char *argv[])
|
||||
{
|
||||
LogPolicy::GetInstance().Unmute();
|
||||
TIMER_START(preparing);
|
||||
TIMER_START(expansion);
|
||||
|
||||
if (!ParseArguments(argc, argv))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (!boost::filesystem::is_regular_file(input_path))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "Input file " << input_path.string() << " not found!";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!boost::filesystem::is_regular_file(profile_path))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "Profile " << profile_path.string() << " not found!";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (1 > requested_num_threads)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
|
||||
return 1;
|
||||
}
|
||||
|
||||
const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
|
||||
|
||||
SimpleLogger().Write() << "Input file: " << input_path.filename().string();
|
||||
SimpleLogger().Write() << "Restrictions file: " << restrictions_path.filename().string();
|
||||
SimpleLogger().Write() << "Profile: " << profile_path.filename().string();
|
||||
SimpleLogger().Write() << "Threads: " << requested_num_threads;
|
||||
if (recommended_num_threads != requested_num_threads)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "The recommended number of threads is "
|
||||
<< recommended_num_threads
|
||||
<< "! This setting may have performance side-effects.";
|
||||
}
|
||||
|
||||
tbb::task_scheduler_init init(requested_num_threads);
|
||||
|
||||
LogPolicy::GetInstance().Unmute();
|
||||
|
||||
FingerPrint fingerprint_orig;
|
||||
CheckRestrictionsFile(fingerprint_orig);
|
||||
|
||||
boost::filesystem::ifstream input_stream(input_path, std::ios::in | std::ios::binary);
|
||||
|
||||
node_filename = input_path.string() + ".nodes";
|
||||
edge_out = input_path.string() + ".edges";
|
||||
geometry_filename = input_path.string() + ".geometry";
|
||||
graph_out = input_path.string() + ".hsgr";
|
||||
rtree_nodes_path = input_path.string() + ".ramIndex";
|
||||
rtree_leafs_path = input_path.string() + ".fileIndex";
|
||||
|
||||
/*** Setup Scripting Environment ***/
|
||||
// Create a new lua state
|
||||
lua_State *lua_state = luaL_newstate();
|
||||
|
||||
// Connect LuaBind to this lua state
|
||||
luabind::open(lua_state);
|
||||
|
||||
EdgeBasedGraphFactory::SpeedProfileProperties speed_profile;
|
||||
|
||||
if (!SetupScriptingEnvironment(lua_state, speed_profile))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma message("Memory consumption on Windows can be higher due to different bit packing")
|
||||
#else
|
||||
static_assert(sizeof(ImportEdge) == 20,
|
||||
"changing ImportEdge type has influence on memory consumption!");
|
||||
#endif
|
||||
NodeID number_of_node_based_nodes =
|
||||
readBinaryOSRMGraphFromStream(input_stream,
|
||||
edge_list,
|
||||
barrier_node_list,
|
||||
traffic_light_list,
|
||||
&internal_to_external_node_map,
|
||||
restriction_list);
|
||||
input_stream.close();
|
||||
|
||||
if (edge_list.empty())
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
|
||||
return 1;
|
||||
}
|
||||
|
||||
SimpleLogger().Write() << restriction_list.size() << " restrictions, "
|
||||
<< barrier_node_list.size() << " bollard nodes, "
|
||||
<< traffic_light_list.size() << " traffic lights";
|
||||
|
||||
std::vector<EdgeBasedNode> node_based_edge_list;
|
||||
unsigned number_of_edge_based_nodes = 0;
|
||||
DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
|
||||
|
||||
// init node_based_edge_list, edge_based_edge_list by edgeList
|
||||
number_of_edge_based_nodes = BuildEdgeExpandedGraph(lua_state,
|
||||
number_of_node_based_nodes,
|
||||
node_based_edge_list,
|
||||
edge_based_edge_list,
|
||||
speed_profile);
|
||||
lua_close(lua_state);
|
||||
|
||||
TIMER_STOP(expansion);
|
||||
|
||||
BuildRTree(node_based_edge_list);
|
||||
|
||||
RangebasedCRC32 crc32;
|
||||
if (crc32.using_hardware())
|
||||
{
|
||||
SimpleLogger().Write() << "using hardware based CRC32 computation";
|
||||
}
|
||||
else
|
||||
{
|
||||
SimpleLogger().Write() << "using software based CRC32 computation";
|
||||
}
|
||||
|
||||
const unsigned crc32_value = crc32(node_based_edge_list);
|
||||
node_based_edge_list.clear();
|
||||
node_based_edge_list.shrink_to_fit();
|
||||
SimpleLogger().Write() << "CRC32: " << crc32_value;
|
||||
|
||||
WriteNodeMapping();
|
||||
|
||||
/***
|
||||
* Contracting the edge-expanded graph
|
||||
*/
|
||||
|
||||
SimpleLogger().Write() << "initializing contractor";
|
||||
auto contractor =
|
||||
osrm::make_unique<Contractor>(number_of_edge_based_nodes, edge_based_edge_list);
|
||||
|
||||
TIMER_START(contraction);
|
||||
contractor->Run();
|
||||
TIMER_STOP(contraction);
|
||||
|
||||
SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
|
||||
|
||||
DeallocatingVector<QueryEdge> contracted_edge_list;
|
||||
contractor->GetEdges(contracted_edge_list);
|
||||
contractor.reset();
|
||||
|
||||
/***
|
||||
* Sorting contracted edges in a way that the static query graph can read some in in-place.
|
||||
*/
|
||||
|
||||
tbb::parallel_sort(contracted_edge_list.begin(), contracted_edge_list.end());
|
||||
const unsigned contracted_edge_count = contracted_edge_list.size();
|
||||
SimpleLogger().Write() << "Serializing compacted graph of " << contracted_edge_count
|
||||
<< " edges";
|
||||
|
||||
boost::filesystem::ofstream hsgr_output_stream(graph_out, std::ios::binary);
|
||||
hsgr_output_stream.write((char *)&fingerprint_orig, sizeof(FingerPrint));
|
||||
const unsigned max_used_node_id = 1 + [&contracted_edge_list]
|
||||
{
|
||||
unsigned tmp_max = 0;
|
||||
for (const QueryEdge &edge : contracted_edge_list)
|
||||
{
|
||||
BOOST_ASSERT(SPECIAL_NODEID != edge.source);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != edge.target);
|
||||
tmp_max = std::max(tmp_max, edge.source);
|
||||
tmp_max = std::max(tmp_max, edge.target);
|
||||
}
|
||||
return tmp_max;
|
||||
}();
|
||||
|
||||
SimpleLogger().Write(logDEBUG) << "input graph has " << number_of_edge_based_nodes << " nodes";
|
||||
SimpleLogger().Write(logDEBUG) << "contracted graph has " << max_used_node_id << " nodes";
|
||||
|
||||
std::vector<StaticGraph<EdgeData>::NodeArrayEntry> node_array;
|
||||
node_array.resize(number_of_edge_based_nodes + 1);
|
||||
|
||||
SimpleLogger().Write() << "Building node array";
|
||||
StaticGraph<EdgeData>::EdgeIterator edge = 0;
|
||||
StaticGraph<EdgeData>::EdgeIterator position = 0;
|
||||
StaticGraph<EdgeData>::EdgeIterator last_edge = edge;
|
||||
|
||||
// initializing 'first_edge'-field of nodes:
|
||||
for (const auto node : osrm::irange(0u, max_used_node_id))
|
||||
{
|
||||
last_edge = edge;
|
||||
while ((edge < contracted_edge_count) && (contracted_edge_list[edge].source == node))
|
||||
{
|
||||
++edge;
|
||||
}
|
||||
node_array[node].first_edge = position; //=edge
|
||||
position += edge - last_edge; // remove
|
||||
}
|
||||
|
||||
for (const auto sentinel_counter : osrm::irange<unsigned>(max_used_node_id, node_array.size()))
|
||||
{
|
||||
// sentinel element, guarded against underflow
|
||||
node_array[sentinel_counter].first_edge = contracted_edge_count;
|
||||
}
|
||||
|
||||
SimpleLogger().Write() << "Serializing node array";
|
||||
|
||||
const unsigned node_array_size = node_array.size();
|
||||
// serialize crc32, aka checksum
|
||||
hsgr_output_stream.write((char *)&crc32_value, sizeof(unsigned));
|
||||
// serialize number of nodes
|
||||
hsgr_output_stream.write((char *)&node_array_size, sizeof(unsigned));
|
||||
// serialize number of edges
|
||||
hsgr_output_stream.write((char *)&contracted_edge_count, sizeof(unsigned));
|
||||
// serialize all nodes
|
||||
if (node_array_size > 0)
|
||||
{
|
||||
hsgr_output_stream.write((char *)&node_array[0],
|
||||
sizeof(StaticGraph<EdgeData>::NodeArrayEntry) * node_array_size);
|
||||
}
|
||||
// serialize all edges
|
||||
|
||||
SimpleLogger().Write() << "Building edge array";
|
||||
edge = 0;
|
||||
int number_of_used_edges = 0;
|
||||
|
||||
StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
|
||||
for (const auto edge : osrm::irange<std::size_t>(0, contracted_edge_list.size()))
|
||||
{
|
||||
// no eigen loops
|
||||
BOOST_ASSERT(contracted_edge_list[edge].source != contracted_edge_list[edge].target);
|
||||
current_edge.target = contracted_edge_list[edge].target;
|
||||
current_edge.data = contracted_edge_list[edge].data;
|
||||
|
||||
// every target needs to be valid
|
||||
BOOST_ASSERT(current_edge.target < max_used_node_id);
|
||||
#ifndef NDEBUG
|
||||
if (current_edge.data.distance <= 0)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "Edge: " << edge
|
||||
<< ",source: " << contracted_edge_list[edge].source
|
||||
<< ", target: " << contracted_edge_list[edge].target
|
||||
<< ", dist: " << current_edge.data.distance;
|
||||
|
||||
SimpleLogger().Write(logWARNING) << "Failed at adjacency list of node "
|
||||
<< contracted_edge_list[edge].source << "/"
|
||||
<< node_array.size() - 1;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
hsgr_output_stream.write((char *)¤t_edge,
|
||||
sizeof(StaticGraph<EdgeData>::EdgeArrayEntry));
|
||||
|
||||
++number_of_used_edges;
|
||||
}
|
||||
hsgr_output_stream.close();
|
||||
|
||||
TIMER_STOP(preparing);
|
||||
|
||||
SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
|
||||
SimpleLogger().Write() << "Expansion : " << (number_of_node_based_nodes / TIMER_SEC(expansion))
|
||||
<< " nodes/sec and "
|
||||
<< (number_of_edge_based_nodes / TIMER_SEC(expansion)) << " edges/sec";
|
||||
|
||||
SimpleLogger().Write() << "Contraction: "
|
||||
<< (number_of_edge_based_nodes / TIMER_SEC(contraction))
|
||||
<< " nodes/sec and " << number_of_used_edges / TIMER_SEC(contraction)
|
||||
<< " edges/sec";
|
||||
|
||||
node_array.clear();
|
||||
SimpleLogger().Write() << "finished preprocessing";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Parses command line arguments
|
||||
\param argc count of arguments
|
||||
\param argv array of arguments
|
||||
\param result [out] value for exit return value
|
||||
\return true if everything is ok, false if need to terminate execution
|
||||
*/
|
||||
bool Prepare::ParseArguments(int argc, char *argv[])
|
||||
{
|
||||
// declare a group of options that will be allowed only on command line
|
||||
boost::program_options::options_description generic_options("Options");
|
||||
generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
|
||||
"config,c",
|
||||
boost::program_options::value<boost::filesystem::path>(&config_file_path)
|
||||
->default_value("contractor.ini"),
|
||||
"Path to a configuration file.");
|
||||
|
||||
// declare a group of options that will be allowed both on command line and in config file
|
||||
boost::program_options::options_description config_options("Configuration");
|
||||
config_options.add_options()(
|
||||
"restrictions,r",
|
||||
boost::program_options::value<boost::filesystem::path>(&restrictions_path),
|
||||
"Restrictions file in .osrm.restrictions format")(
|
||||
"profile,p",
|
||||
boost::program_options::value<boost::filesystem::path>(&profile_path)
|
||||
->default_value("profile.lua"),
|
||||
"Path to LUA routing profile")(
|
||||
"threads,t",
|
||||
boost::program_options::value<unsigned int>(&requested_num_threads)
|
||||
->default_value(tbb::task_scheduler_init::default_num_threads()),
|
||||
"Number of threads to use");
|
||||
|
||||
// hidden options, will be allowed both on command line and in config file, but will not be
|
||||
// shown to the user
|
||||
boost::program_options::options_description hidden_options("Hidden options");
|
||||
hidden_options.add_options()(
|
||||
"input,i",
|
||||
boost::program_options::value<boost::filesystem::path>(&input_path),
|
||||
"Input file in .osm, .osm.bz2 or .osm.pbf format");
|
||||
|
||||
// positional option
|
||||
boost::program_options::positional_options_description positional_options;
|
||||
positional_options.add("input", 1);
|
||||
|
||||
// combine above options for parsing
|
||||
boost::program_options::options_description cmdline_options;
|
||||
cmdline_options.add(generic_options).add(config_options).add(hidden_options);
|
||||
|
||||
boost::program_options::options_description config_file_options;
|
||||
config_file_options.add(config_options).add(hidden_options);
|
||||
|
||||
boost::program_options::options_description visible_options(
|
||||
"Usage: " + boost::filesystem::basename(argv[0]) + " <input.osrm> [options]");
|
||||
visible_options.add(generic_options).add(config_options);
|
||||
|
||||
// parse command line options
|
||||
boost::program_options::variables_map option_variables;
|
||||
boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
|
||||
.options(cmdline_options)
|
||||
.positional(positional_options)
|
||||
.run(),
|
||||
option_variables);
|
||||
|
||||
if (option_variables.count("version"))
|
||||
{
|
||||
SimpleLogger().Write() << g_GIT_DESCRIPTION;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (option_variables.count("help"))
|
||||
{
|
||||
SimpleLogger().Write() << "\n" << visible_options;
|
||||
return false;
|
||||
}
|
||||
|
||||
boost::program_options::notify(option_variables);
|
||||
|
||||
if (!option_variables.count("restrictions"))
|
||||
{
|
||||
restrictions_path = std::string(input_path.string() + ".restrictions");
|
||||
}
|
||||
|
||||
if (!option_variables.count("input"))
|
||||
{
|
||||
SimpleLogger().Write() << "\n" << visible_options;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Loads and checks file UUIDs
|
||||
*/
|
||||
void Prepare::CheckRestrictionsFile(FingerPrint &fingerprint_orig)
|
||||
{
|
||||
boost::filesystem::ifstream restriction_stream(restrictions_path, std::ios::binary);
|
||||
FingerPrint fingerprint_loaded;
|
||||
unsigned number_of_usable_restrictions = 0;
|
||||
restriction_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
|
||||
if (!fingerprint_loaded.TestPrepare(fingerprint_orig))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << ".restrictions was prepared with different build.\n"
|
||||
"Reprocess to get rid of this warning.";
|
||||
}
|
||||
|
||||
restriction_stream.read((char *)&number_of_usable_restrictions, sizeof(unsigned));
|
||||
restriction_list.resize(number_of_usable_restrictions);
|
||||
if (number_of_usable_restrictions > 0)
|
||||
{
|
||||
restriction_stream.read((char *)&(restriction_list[0]),
|
||||
number_of_usable_restrictions * sizeof(TurnRestriction));
|
||||
}
|
||||
restriction_stream.close();
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Setups scripting environment (lua-scripting)
|
||||
Also initializes speed profile.
|
||||
*/
|
||||
bool
|
||||
Prepare::SetupScriptingEnvironment(lua_State *lua_state,
|
||||
EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile)
|
||||
{
|
||||
// open utility libraries string library;
|
||||
luaL_openlibs(lua_state);
|
||||
|
||||
// adjust lua load path
|
||||
luaAddScriptFolderToLoadPath(lua_state, profile_path.string().c_str());
|
||||
|
||||
// Now call our function in a lua script
|
||||
if (0 != luaL_dofile(lua_state, profile_path.string().c_str()))
|
||||
{
|
||||
std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 != luaL_dostring(lua_state, "return traffic_signal_penalty\n"))
|
||||
{
|
||||
std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
|
||||
return false;
|
||||
}
|
||||
speed_profile.traffic_signal_penalty = 10 * lua_tointeger(lua_state, -1);
|
||||
SimpleLogger().Write(logDEBUG)
|
||||
<< "traffic_signal_penalty: " << speed_profile.traffic_signal_penalty;
|
||||
|
||||
if (0 != luaL_dostring(lua_state, "return u_turn_penalty\n"))
|
||||
{
|
||||
std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
speed_profile.u_turn_penalty = 10 * lua_tointeger(lua_state, -1);
|
||||
speed_profile.has_turn_penalty_function = lua_function_exists(lua_state, "turn_function");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Building an edge-expanded graph from node-based input and turn restrictions
|
||||
*/
|
||||
std::size_t
|
||||
Prepare::BuildEdgeExpandedGraph(lua_State *lua_state,
|
||||
NodeID number_of_node_based_nodes,
|
||||
std::vector<EdgeBasedNode> &node_based_edge_list,
|
||||
DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
||||
EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile)
|
||||
{
|
||||
SimpleLogger().Write() << "Generating edge-expanded graph representation";
|
||||
std::shared_ptr<NodeBasedDynamicGraph> node_based_graph =
|
||||
NodeBasedDynamicGraphFromImportEdges(number_of_node_based_nodes, edge_list);
|
||||
std::unique_ptr<RestrictionMap> restriction_map =
|
||||
std::unique_ptr<RestrictionMap>(new RestrictionMap(node_based_graph, restriction_list));
|
||||
std::shared_ptr<EdgeBasedGraphFactory> edge_based_graph_factory =
|
||||
std::make_shared<EdgeBasedGraphFactory>(node_based_graph,
|
||||
std::move(restriction_map),
|
||||
barrier_node_list,
|
||||
traffic_light_list,
|
||||
internal_to_external_node_map,
|
||||
speed_profile);
|
||||
edge_list.clear();
|
||||
edge_list.shrink_to_fit();
|
||||
|
||||
edge_based_graph_factory->Run(edge_out, geometry_filename, lua_state);
|
||||
|
||||
restriction_list.clear();
|
||||
restriction_list.shrink_to_fit();
|
||||
barrier_node_list.clear();
|
||||
barrier_node_list.shrink_to_fit();
|
||||
traffic_light_list.clear();
|
||||
traffic_light_list.shrink_to_fit();
|
||||
|
||||
const std::size_t number_of_edge_based_nodes =
|
||||
edge_based_graph_factory->GetNumberOfEdgeBasedNodes();
|
||||
|
||||
BOOST_ASSERT(number_of_edge_based_nodes != std::numeric_limits<unsigned>::max());
|
||||
#ifndef WIN32
|
||||
static_assert(sizeof(EdgeBasedEdge) == 16,
|
||||
"changing ImportEdge type has influence on memory consumption!");
|
||||
#endif
|
||||
|
||||
edge_based_graph_factory->GetEdgeBasedEdges(edge_based_edge_list);
|
||||
edge_based_graph_factory->GetEdgeBasedNodes(node_based_edge_list);
|
||||
|
||||
edge_based_graph_factory.reset();
|
||||
node_based_graph.reset();
|
||||
|
||||
return number_of_edge_based_nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Writing info on original (node-based) nodes
|
||||
*/
|
||||
void Prepare::WriteNodeMapping()
|
||||
{
|
||||
SimpleLogger().Write() << "writing node map ...";
|
||||
boost::filesystem::ofstream node_stream(node_filename, std::ios::binary);
|
||||
const unsigned size_of_mapping = internal_to_external_node_map.size();
|
||||
node_stream.write((char *)&size_of_mapping, sizeof(unsigned));
|
||||
if (size_of_mapping > 0)
|
||||
{
|
||||
node_stream.write((char *)&(internal_to_external_node_map[0]),
|
||||
size_of_mapping * sizeof(NodeInfo));
|
||||
}
|
||||
node_stream.close();
|
||||
internal_to_external_node_map.clear();
|
||||
internal_to_external_node_map.shrink_to_fit();
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Building rtree-based nearest-neighbor data structure
|
||||
|
||||
Saves info to files: '.ramIndex' and '.fileIndex'.
|
||||
*/
|
||||
void Prepare::BuildRTree(std::vector<EdgeBasedNode> &node_based_edge_list)
|
||||
{
|
||||
SimpleLogger().Write() << "building r-tree ...";
|
||||
StaticRTree<EdgeBasedNode>(node_based_edge_list,
|
||||
rtree_nodes_path.c_str(),
|
||||
rtree_leafs_path.c_str(),
|
||||
internal_to_external_node_map);
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
#ifndef PREPARE_H
|
||||
#define PREPARE_H
|
||||
|
||||
#include "EdgeBasedGraphFactory.h"
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "../DataStructures/StaticGraph.h"
|
||||
#include "../Util/GraphLoader.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <luabind/luabind.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
\brief class of 'prepare' utility.
|
||||
*/
|
||||
class Prepare
|
||||
{
|
||||
public:
|
||||
using EdgeData = QueryEdge::EdgeData;
|
||||
using InputEdge = DynamicGraph<EdgeData>::InputEdge;
|
||||
using StaticEdge = StaticGraph<EdgeData>::InputEdge;
|
||||
|
||||
explicit Prepare();
|
||||
Prepare(const Prepare &) = delete;
|
||||
~Prepare();
|
||||
|
||||
int Process(int argc, char *argv[]);
|
||||
|
||||
protected:
|
||||
bool ParseArguments(int argc, char *argv[]);
|
||||
void CheckRestrictionsFile(FingerPrint &fingerprint_orig);
|
||||
bool SetupScriptingEnvironment(lua_State *myLuaState,
|
||||
EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile);
|
||||
std::size_t BuildEdgeExpandedGraph(lua_State *myLuaState,
|
||||
NodeID nodeBasedNodeNumber,
|
||||
std::vector<EdgeBasedNode> &nodeBasedEdgeList,
|
||||
DeallocatingVector<EdgeBasedEdge> &edgeBasedEdgeList,
|
||||
EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile);
|
||||
void WriteNodeMapping();
|
||||
void BuildRTree(std::vector<EdgeBasedNode> &node_based_edge_list);
|
||||
|
||||
private:
|
||||
std::vector<NodeInfo> internal_to_external_node_map;
|
||||
std::vector<TurnRestriction> restriction_list;
|
||||
std::vector<NodeID> barrier_node_list;
|
||||
std::vector<NodeID> traffic_light_list;
|
||||
std::vector<ImportEdge> edge_list;
|
||||
|
||||
unsigned requested_num_threads;
|
||||
boost::filesystem::path config_file_path;
|
||||
boost::filesystem::path input_path;
|
||||
boost::filesystem::path restrictions_path;
|
||||
boost::filesystem::path preinfo_path;
|
||||
boost::filesystem::path profile_path;
|
||||
|
||||
std::string node_filename;
|
||||
std::string edge_out;
|
||||
std::string info_out;
|
||||
std::string geometry_filename;
|
||||
std::string graph_out;
|
||||
std::string rtree_nodes_path;
|
||||
std::string rtree_leafs_path;
|
||||
};
|
||||
|
||||
#endif // PREPARE_H
|
||||
@@ -1,83 +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 CONCURRENT_QUEUE_H
|
||||
#define CONCURRENT_QUEUE_H
|
||||
|
||||
#include <boost/circular_buffer.hpp>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
template <typename Data> class ConcurrentQueue
|
||||
{
|
||||
public:
|
||||
explicit ConcurrentQueue(const size_t max_size) : m_internal_queue(max_size) {}
|
||||
|
||||
inline void push(const Data &data)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_not_full.wait(lock,
|
||||
[this]
|
||||
{ return m_internal_queue.size() < m_internal_queue.capacity(); });
|
||||
m_internal_queue.push_back(data);
|
||||
m_not_empty.notify_one();
|
||||
}
|
||||
|
||||
inline bool empty() const { return m_internal_queue.empty(); }
|
||||
|
||||
inline void wait_and_pop(Data &popped_value)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_not_empty.wait(lock,
|
||||
[this]
|
||||
{ return !m_internal_queue.empty(); });
|
||||
popped_value = m_internal_queue.front();
|
||||
m_internal_queue.pop_front();
|
||||
m_not_full.notify_one();
|
||||
}
|
||||
|
||||
inline bool try_pop(Data &popped_value)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
if (m_internal_queue.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
popped_value = m_internal_queue.front();
|
||||
m_internal_queue.pop_front();
|
||||
m_not_full.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::circular_buffer<Data> m_internal_queue;
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_not_empty;
|
||||
std::condition_variable m_not_full;
|
||||
};
|
||||
|
||||
#endif // CONCURRENT_QUEUE_H
|
||||
@@ -1,483 +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/MercatorUtil.h"
|
||||
#ifndef NDEBUG
|
||||
#include "../Util/simple_logger.hpp"
|
||||
#endif
|
||||
#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_coordinate_vector(lat);
|
||||
SimpleLogger().Write(logDEBUG) << "broken lat: " << lat
|
||||
<< ", bits: " << y_coordinate_vector;
|
||||
}
|
||||
if (0 != (std::abs(lon) >> 30))
|
||||
{
|
||||
std::bitset<32> x_coordinate_vector(lon);
|
||||
SimpleLogger().Write(logDEBUG) << "broken lon: " << lon
|
||||
<< ", bits: " << x_coordinate_vector;
|
||||
}
|
||||
#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 &coordinate_1,
|
||||
const FixedPointCoordinate &coordinate_2)
|
||||
{
|
||||
return ApproximateDistance(
|
||||
coordinate_1.lat, coordinate_1.lon, coordinate_2.lat, coordinate_2.lon);
|
||||
}
|
||||
|
||||
float FixedPointCoordinate::ApproximateEuclideanDistance(const FixedPointCoordinate &coordinate_1,
|
||||
const FixedPointCoordinate &coordinate_2)
|
||||
{
|
||||
return ApproximateEuclideanDistance(
|
||||
coordinate_1.lat, coordinate_1.lon, coordinate_2.lat, coordinate_2.lon);
|
||||
}
|
||||
|
||||
float FixedPointCoordinate::ApproximateEuclideanDistance(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());
|
||||
|
||||
const float RAD = 0.017453292519943295769236907684886f;
|
||||
const float float_lat1 = (lat1 / COORDINATE_PRECISION) * RAD;
|
||||
const float float_lon1 = (lon1 / COORDINATE_PRECISION) * RAD;
|
||||
const float float_lat2 = (lat2 / COORDINATE_PRECISION) * RAD;
|
||||
const float float_lon2 = (lon2 / COORDINATE_PRECISION) * RAD;
|
||||
|
||||
const float x_value = (float_lon2 - float_lon1) * cos((float_lat1 + float_lat2) / 2.f);
|
||||
const float y_value = float_lat2 - float_lat1;
|
||||
const float earth_radius = 6372797.560856f;
|
||||
return sqrt(x_value * x_value + y_value * y_value) * earth_radius;
|
||||
}
|
||||
|
||||
float
|
||||
FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &source_coordinate,
|
||||
const FixedPointCoordinate &target_coordinate,
|
||||
const FixedPointCoordinate &point)
|
||||
{
|
||||
// initialize values
|
||||
const float x_value = static_cast<float>(lat2y(point.lat / COORDINATE_PRECISION));
|
||||
const float y_value = point.lon / COORDINATE_PRECISION;
|
||||
float a = static_cast<float>(lat2y(source_coordinate.lat / COORDINATE_PRECISION));
|
||||
float b = source_coordinate.lon / COORDINATE_PRECISION;
|
||||
float c = static_cast<float>(lat2y(target_coordinate.lat / COORDINATE_PRECISION));
|
||||
float d = target_coordinate.lon / COORDINATE_PRECISION;
|
||||
float p, q;
|
||||
if (std::abs(a - c) > std::numeric_limits<float>::epsilon())
|
||||
{
|
||||
const float slope = (d - b) / (c - a); // slope
|
||||
// Projection of (x,y) on line joining (a,b) and (c,d)
|
||||
p = ((x_value + (slope * y_value)) + (slope * slope * a - slope * b)) /
|
||||
(1.f + slope * slope);
|
||||
q = b + slope * (p - a);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = c;
|
||||
q = y_value;
|
||||
}
|
||||
|
||||
float ratio;
|
||||
bool inverse_ratio = false;
|
||||
|
||||
// straight line segment on equator
|
||||
if (std::abs(c) < std::numeric_limits<float>::epsilon() &&
|
||||
std::abs(a) < std::numeric_limits<float>::epsilon())
|
||||
{
|
||||
ratio = (q - b) / (d - b);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (std::abs(c) < std::numeric_limits<float>::epsilon())
|
||||
{
|
||||
// swap start/end
|
||||
std::swap(a, c);
|
||||
std::swap(b, d);
|
||||
inverse_ratio = true;
|
||||
}
|
||||
|
||||
float nY = (d * p - c * q) / (a * d - b * c);
|
||||
// discretize the result to coordinate precision. it's a hack!
|
||||
if (std::abs(nY) < (1.f / COORDINATE_PRECISION))
|
||||
{
|
||||
nY = 0.f;
|
||||
}
|
||||
|
||||
// compute ratio
|
||||
ratio = (p - nY * a) / c;
|
||||
}
|
||||
|
||||
if (std::isnan(ratio))
|
||||
{
|
||||
ratio = (target_coordinate == point ? 1.f : 0.f);
|
||||
}
|
||||
else if (std::abs(ratio) <= std::numeric_limits<float>::epsilon())
|
||||
{
|
||||
ratio = 0.f;
|
||||
}
|
||||
else if (std::abs(ratio - 1.f) <= std::numeric_limits<float>::epsilon())
|
||||
{
|
||||
ratio = 1.f;
|
||||
}
|
||||
|
||||
// we need to do this, if we switched start/end coordinates
|
||||
if (inverse_ratio)
|
||||
{
|
||||
ratio = 1.0f - ratio;
|
||||
}
|
||||
|
||||
// compute the nearest location
|
||||
FixedPointCoordinate nearest_location;
|
||||
BOOST_ASSERT(!std::isnan(ratio));
|
||||
if (ratio <= 0.f)
|
||||
{ // point is "left" of edge
|
||||
nearest_location = source_coordinate;
|
||||
}
|
||||
else if (ratio >= 1.f)
|
||||
{ // point is "right" of edge
|
||||
nearest_location = target_coordinate;
|
||||
}
|
||||
else
|
||||
{ // point lies in between
|
||||
nearest_location.lat = static_cast<int>(y2lat(p) * COORDINATE_PRECISION);
|
||||
nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
|
||||
}
|
||||
|
||||
BOOST_ASSERT(nearest_location.isValid());
|
||||
return FixedPointCoordinate::ApproximateEuclideanDistance(point, nearest_location);
|
||||
}
|
||||
|
||||
float FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location,
|
||||
FixedPointCoordinate &nearest_location,
|
||||
float &ratio)
|
||||
{
|
||||
BOOST_ASSERT(query_location.isValid());
|
||||
|
||||
// initialize values
|
||||
const double x = lat2y(query_location.lat / COORDINATE_PRECISION);
|
||||
const double y = query_location.lon / COORDINATE_PRECISION;
|
||||
const double a = lat2y(segment_source.lat / COORDINATE_PRECISION);
|
||||
const double b = segment_source.lon / COORDINATE_PRECISION;
|
||||
const double c = lat2y(segment_target.lat / COORDINATE_PRECISION);
|
||||
const double d = segment_target.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.f + 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.f / COORDINATE_PRECISION))
|
||||
{
|
||||
nY = 0.f;
|
||||
}
|
||||
|
||||
// compute ratio
|
||||
ratio = (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(ratio))
|
||||
{
|
||||
ratio = (segment_target == query_location ? 1.f : 0.f);
|
||||
}
|
||||
else if (std::abs(ratio) <= std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
ratio = 0.f;
|
||||
}
|
||||
else if (std::abs(ratio - 1.f) <= std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
ratio = 1.f;
|
||||
}
|
||||
|
||||
// compute nearest location
|
||||
BOOST_ASSERT(!std::isnan(ratio));
|
||||
if (ratio <= 0.f)
|
||||
{
|
||||
nearest_location = segment_source;
|
||||
}
|
||||
else if (ratio >= 1.f)
|
||||
{
|
||||
nearest_location = segment_target;
|
||||
}
|
||||
else
|
||||
{
|
||||
// point lies in between
|
||||
nearest_location.lat = static_cast<int>(y2lat(p) * COORDINATE_PRECISION);
|
||||
nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
|
||||
}
|
||||
BOOST_ASSERT(nearest_location.isValid());
|
||||
|
||||
const float approximate_distance =
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(query_location, nearest_location);
|
||||
BOOST_ASSERT(0. <= approximate_distance);
|
||||
return approximate_distance;
|
||||
}
|
||||
|
||||
void FixedPointCoordinate::convertInternalLatLonToString(const int value, std::string &output)
|
||||
{
|
||||
char buffer[12];
|
||||
buffer[11] = 0; // zero termination
|
||||
output = printInt<11, 6>(buffer, value);
|
||||
}
|
||||
|
||||
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 << ")";
|
||||
}
|
||||
|
||||
float FixedPointCoordinate::GetBearing(const FixedPointCoordinate &first_coordinate,
|
||||
const FixedPointCoordinate &second_coordinate)
|
||||
{
|
||||
const float lon_diff =
|
||||
second_coordinate.lon / COORDINATE_PRECISION - first_coordinate.lon / COORDINATE_PRECISION;
|
||||
const float lon_delta = DegreeToRadian(lon_diff);
|
||||
const float lat1 = DegreeToRadian(first_coordinate.lat / COORDINATE_PRECISION);
|
||||
const float lat2 = DegreeToRadian(second_coordinate.lat / COORDINATE_PRECISION);
|
||||
const float y = sin(lon_delta) * cos(lat2);
|
||||
const float x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lon_delta);
|
||||
float result = RadianToDegree(std::atan2(y, x));
|
||||
while (result < 0.f)
|
||||
{
|
||||
result += 360.f;
|
||||
}
|
||||
|
||||
while (result >= 360.f)
|
||||
{
|
||||
result -= 360.f;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
float FixedPointCoordinate::GetBearing(const FixedPointCoordinate &other) const
|
||||
{
|
||||
const float lon_delta =
|
||||
DegreeToRadian(lon / COORDINATE_PRECISION - other.lon / COORDINATE_PRECISION);
|
||||
const float lat1 = DegreeToRadian(other.lat / COORDINATE_PRECISION);
|
||||
const float lat2 = DegreeToRadian(lat / COORDINATE_PRECISION);
|
||||
const float y_value = std::sin(lon_delta) * std::cos(lat2);
|
||||
const float x_value =
|
||||
std::cos(lat1) * std::sin(lat2) - std::sin(lat1) * std::cos(lat2) * std::cos(lon_delta);
|
||||
float result = RadianToDegree(std::atan2(y_value, x_value));
|
||||
|
||||
while (result < 0.f)
|
||||
{
|
||||
result += 360.f;
|
||||
}
|
||||
|
||||
while (result >= 360.f)
|
||||
{
|
||||
result -= 360.f;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
float FixedPointCoordinate::DegreeToRadian(const float degree)
|
||||
{
|
||||
return degree * (static_cast<float>(M_PI) / 180.f);
|
||||
}
|
||||
|
||||
float FixedPointCoordinate::RadianToDegree(const float radian)
|
||||
{
|
||||
return radian * (180.f * static_cast<float>(M_1_PI));
|
||||
}
|
||||
|
||||
// This distance computation does integer arithmetic only and is a lot faster than
|
||||
// the other distance function which are numerically correct('ish).
|
||||
// It preserves some order among the elements that make it useful for certain purposes
|
||||
int FixedPointCoordinate::OrderedPerpendicularDistanceApproximation(
|
||||
const FixedPointCoordinate &input_point,
|
||||
const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target)
|
||||
{
|
||||
// initialize values
|
||||
const float x = static_cast<float>(lat2y(input_point.lat / COORDINATE_PRECISION));
|
||||
const float y = input_point.lon / COORDINATE_PRECISION;
|
||||
const float a = static_cast<float>(lat2y(segment_source.lat / COORDINATE_PRECISION));
|
||||
const float b = segment_source.lon / COORDINATE_PRECISION;
|
||||
const float c = static_cast<float>(lat2y(segment_target.lat / COORDINATE_PRECISION));
|
||||
const float d = segment_target.lon / COORDINATE_PRECISION;
|
||||
|
||||
float p, q;
|
||||
if (a == c)
|
||||
{
|
||||
p = c;
|
||||
q = y;
|
||||
}
|
||||
else
|
||||
{
|
||||
const float 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.f + m * m);
|
||||
q = b + m * (p - a);
|
||||
}
|
||||
|
||||
const float nY = (d * p - c * q) / (a * d - b * c);
|
||||
float ratio = (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(ratio))
|
||||
{
|
||||
ratio = (segment_target == input_point) ? 1.f : 0.f;
|
||||
}
|
||||
|
||||
// compute target quasi-location
|
||||
int dx, dy;
|
||||
if (ratio < 0.f)
|
||||
{
|
||||
dx = input_point.lon - segment_source.lon;
|
||||
dy = input_point.lat - segment_source.lat;
|
||||
}
|
||||
else if (ratio > 1.f)
|
||||
{
|
||||
dx = input_point.lon - segment_target.lon;
|
||||
dy = input_point.lat - segment_target.lat;
|
||||
}
|
||||
else
|
||||
{
|
||||
// point lies in between
|
||||
dx = input_point.lon - static_cast<int>(q * COORDINATE_PRECISION);
|
||||
dy = input_point.lat - static_cast<int>(y2lat(p) * COORDINATE_PRECISION);
|
||||
}
|
||||
|
||||
// return an approximation in the plane
|
||||
return static_cast<int>(sqrt(dx * dx + dy * dy));
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
#ifndef EDGE_BASED_NODE_H
|
||||
#define EDGE_BASED_NODE_H
|
||||
|
||||
#include "../DataStructures/TravelMode.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() ),
|
||||
is_in_tiny_cc(false),
|
||||
forward_travel_mode(TRAVEL_MODE_INACCESSIBLE),
|
||||
backward_travel_mode(TRAVEL_MODE_INACCESSIBLE)
|
||||
{ }
|
||||
|
||||
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,
|
||||
TravelMode forward_travel_mode,
|
||||
TravelMode backward_travel_mode
|
||||
) :
|
||||
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),
|
||||
is_in_tiny_cc(belongs_to_tiny_component),
|
||||
forward_travel_mode(forward_travel_mode),
|
||||
backward_travel_mode(backward_travel_mode)
|
||||
{
|
||||
BOOST_ASSERT((forward_edge_based_node_id != SPECIAL_NODEID) ||
|
||||
(reverse_edge_based_node_id != SPECIAL_NODEID));
|
||||
}
|
||||
|
||||
static inline FixedPointCoordinate Centroid(const FixedPointCoordinate & a, const FixedPointCoordinate & b)
|
||||
{
|
||||
FixedPointCoordinate centroid;
|
||||
//The coordinates of the midpoint are given by:
|
||||
centroid.lat = (a.lat + b.lat)/2;
|
||||
centroid.lon = (a.lon + b.lon)/2;
|
||||
return centroid;
|
||||
}
|
||||
|
||||
bool IsCompressed() const
|
||||
{
|
||||
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 is_in_tiny_cc;
|
||||
TravelMode forward_travel_mode : 4;
|
||||
TravelMode backward_travel_mode : 4;
|
||||
};
|
||||
|
||||
#endif //EDGE_BASED_NODE_H
|
||||
@@ -1,216 +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_FIXED_POINT_NUMBER_H
|
||||
#define OSRM_FIXED_POINT_NUMBER_H
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
|
||||
// implements an binary based fixed point number type
|
||||
template <unsigned FractionalBitSize,
|
||||
bool use_64_bits = false,
|
||||
bool is_unsigned = false,
|
||||
bool truncate_results = false>
|
||||
class FixedPointNumber
|
||||
{
|
||||
static_assert(FractionalBitSize > 0, "FractionalBitSize must be greater than 0");
|
||||
static_assert(FractionalBitSize <= 32, "FractionalBitSize must at most 32");
|
||||
|
||||
typename std::conditional<use_64_bits, int64_t, int32_t>::type m_fixed_point_state;
|
||||
constexpr static const decltype(m_fixed_point_state) PRECISION = 1 << FractionalBitSize;
|
||||
|
||||
// state signage encapsulates whether the state should either represent a
|
||||
// signed or an unsigned floating point number
|
||||
using state_signage =
|
||||
typename std::conditional<is_unsigned,
|
||||
typename std::make_unsigned<decltype(m_fixed_point_state)>::type,
|
||||
decltype(m_fixed_point_state)>::type;
|
||||
|
||||
public:
|
||||
FixedPointNumber() : m_fixed_point_state(0) {}
|
||||
|
||||
// the type is either initialized with a floating point value or an
|
||||
// integral state. Anything else will throw at compile-time.
|
||||
template <class T>
|
||||
constexpr FixedPointNumber(const T &&input) noexcept
|
||||
: m_fixed_point_state(static_cast<decltype(m_fixed_point_state)>(
|
||||
std::round(std::forward<const T>(input) * PRECISION)))
|
||||
{
|
||||
static_assert(
|
||||
std::is_floating_point<T>::value || std::is_integral<T>::value,
|
||||
"FixedPointNumber needs to be initialized with floating point or integral value");
|
||||
}
|
||||
|
||||
// get max value
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
|
||||
constexpr static auto max() noexcept -> T
|
||||
{
|
||||
return static_cast<T>(std::numeric_limits<state_signage>::max()) / PRECISION;
|
||||
}
|
||||
|
||||
// get min value
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
|
||||
constexpr static auto min() noexcept -> T
|
||||
{
|
||||
return static_cast<T>(1) / PRECISION;
|
||||
}
|
||||
|
||||
// get lowest value
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
|
||||
constexpr static auto lowest() noexcept -> T
|
||||
{
|
||||
return static_cast<T>(std::numeric_limits<state_signage>::min()) / PRECISION;
|
||||
}
|
||||
|
||||
// cast to floating point type T, return value
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
|
||||
explicit operator const T() const noexcept
|
||||
{
|
||||
// casts to external type (signed or unsigned) and then to float
|
||||
return static_cast<T>(static_cast<state_signage>(m_fixed_point_state)) / PRECISION;
|
||||
}
|
||||
|
||||
// warn about cast to integral type T, its disabled for good reason
|
||||
template <typename T, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
|
||||
explicit operator T() const
|
||||
{
|
||||
static_assert(std::is_integral<T>::value,
|
||||
"casts to integral types have been disabled on purpose");
|
||||
}
|
||||
|
||||
// compare, ie. sort fixed-point numbers
|
||||
bool operator<(const FixedPointNumber &other) const noexcept
|
||||
{
|
||||
return m_fixed_point_state < other.m_fixed_point_state;
|
||||
}
|
||||
|
||||
// equality, ie. sort fixed-point numbers
|
||||
bool operator==(const FixedPointNumber &other) const noexcept
|
||||
{
|
||||
return m_fixed_point_state == other.m_fixed_point_state;
|
||||
}
|
||||
|
||||
bool operator!=(const FixedPointNumber &other) const { return !(*this == other); }
|
||||
bool operator>(const FixedPointNumber &other) const { return other < *this; }
|
||||
bool operator<=(const FixedPointNumber &other) const { return !(other < *this); }
|
||||
bool operator>=(const FixedPointNumber &other) const { return !(*this < other); }
|
||||
|
||||
// arithmetic operators
|
||||
FixedPointNumber operator+(const FixedPointNumber &other) const noexcept
|
||||
{
|
||||
FixedPointNumber tmp = *this;
|
||||
tmp.m_fixed_point_state += other.m_fixed_point_state;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
FixedPointNumber &operator+=(const FixedPointNumber &other) noexcept
|
||||
{
|
||||
this->m_fixed_point_state += other.m_fixed_point_state;
|
||||
return *this;
|
||||
}
|
||||
|
||||
FixedPointNumber operator-(const FixedPointNumber &other) const noexcept
|
||||
{
|
||||
FixedPointNumber tmp = *this;
|
||||
tmp.m_fixed_point_state -= other.m_fixed_point_state;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
FixedPointNumber &operator-=(const FixedPointNumber &other) noexcept
|
||||
{
|
||||
this->m_fixed_point_state -= other.m_fixed_point_state;
|
||||
return *this;
|
||||
}
|
||||
|
||||
FixedPointNumber operator*(const FixedPointNumber &other) const noexcept
|
||||
{
|
||||
int64_t temp = this->m_fixed_point_state;
|
||||
temp *= other.m_fixed_point_state;
|
||||
|
||||
// rounding!
|
||||
if (!truncate_results)
|
||||
{
|
||||
temp = temp + ((temp & 1 << (FractionalBitSize - 1)) << 1);
|
||||
}
|
||||
temp >>= FractionalBitSize;
|
||||
FixedPointNumber tmp;
|
||||
tmp.m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
FixedPointNumber &operator*=(const FixedPointNumber &other) noexcept
|
||||
{
|
||||
int64_t temp = this->m_fixed_point_state;
|
||||
temp *= other.m_fixed_point_state;
|
||||
|
||||
// rounding!
|
||||
if (!truncate_results)
|
||||
{
|
||||
temp = temp + ((temp & 1 << (FractionalBitSize - 1)) << 1);
|
||||
}
|
||||
temp >>= FractionalBitSize;
|
||||
this->m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FixedPointNumber operator/(const FixedPointNumber &other) const noexcept
|
||||
{
|
||||
int64_t temp = this->m_fixed_point_state;
|
||||
temp <<= FractionalBitSize;
|
||||
temp /= static_cast<int64_t>(other.m_fixed_point_state);
|
||||
FixedPointNumber tmp;
|
||||
tmp.m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
FixedPointNumber &operator/=(const FixedPointNumber &other) noexcept
|
||||
{
|
||||
int64_t temp = this->m_fixed_point_state;
|
||||
temp <<= FractionalBitSize;
|
||||
temp /= static_cast<int64_t>(other.m_fixed_point_state);
|
||||
FixedPointNumber tmp;
|
||||
this->m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(4 == sizeof(FixedPointNumber<1>), "FP19 has wrong size != 4");
|
||||
}
|
||||
#endif // OSRM_FIXED_POINT_NUMBER_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 HASH_TABLE_H
|
||||
#define HASH_TABLE_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
template <typename Key, typename Value>
|
||||
class HashTable
|
||||
{
|
||||
private:
|
||||
using KeyValPair = std::pair<Key, Value>;
|
||||
std::vector<KeyValPair> table;
|
||||
|
||||
public:
|
||||
HashTable() {}
|
||||
|
||||
inline void Add(Key const &key, Value const &value)
|
||||
{
|
||||
table.emplace_back(std::move(key), std::move(value));
|
||||
}
|
||||
|
||||
inline void Clear()
|
||||
{
|
||||
table.clear();
|
||||
}
|
||||
|
||||
inline const Value Find(Key const &key) const
|
||||
{
|
||||
for (const auto &key_val_pair : table)
|
||||
{
|
||||
if (key_val_pair.first == key)
|
||||
{
|
||||
return key_val_pair.second;
|
||||
}
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
|
||||
inline const bool Holds(Key const &key) const
|
||||
{
|
||||
for (const auto &key_val_pair : table)
|
||||
{
|
||||
if (key_val_pair.first == key)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* HASH_TABLE_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.
|
||||
|
||||
*/
|
||||
|
||||
#include "HilbertValue.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
uint64_t HilbertCode::operator()(const FixedPointCoordinate ¤t_coordinate) const
|
||||
{
|
||||
unsigned location[2];
|
||||
location[0] = current_coordinate.lat + static_cast<int>(90 * COORDINATE_PRECISION);
|
||||
location[1] = current_coordinate.lon + static_cast<int>(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,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 HILBERTVALUE_H_
|
||||
#define HILBERTVALUE_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// computes a 64 bit value that corresponds to the hilbert space filling curve
|
||||
|
||||
struct FixedPointCoordinate;
|
||||
|
||||
class HilbertCode
|
||||
{
|
||||
public:
|
||||
uint64_t operator()(const FixedPointCoordinate ¤t_coordinate) const;
|
||||
HilbertCode() {}
|
||||
HilbertCode(const HilbertCode &) = delete;
|
||||
|
||||
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,105 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, 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 "ImportEdge.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
bool NodeBasedEdge::operator<(const NodeBasedEdge &other) const
|
||||
{
|
||||
if (source == other.source)
|
||||
{
|
||||
if (target == other.target)
|
||||
{
|
||||
if (weight == other.weight)
|
||||
{
|
||||
return forward && backward && ((!other.forward) || (!other.backward));
|
||||
}
|
||||
return weight < other.weight;
|
||||
}
|
||||
return target < other.target;
|
||||
}
|
||||
return source < other.source;
|
||||
}
|
||||
|
||||
NodeBasedEdge::NodeBasedEdge(NodeID source,
|
||||
NodeID target,
|
||||
NodeID name_id,
|
||||
EdgeWeight weight,
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool in_tiny_cc,
|
||||
bool access_restricted,
|
||||
TravelMode travel_mode,
|
||||
bool is_split)
|
||||
: source(source), target(target), name_id(name_id), weight(weight),
|
||||
forward(forward), backward(backward), roundabout(roundabout), in_tiny_cc(in_tiny_cc),
|
||||
access_restricted(access_restricted), is_split(is_split), travel_mode(travel_mode)
|
||||
{
|
||||
}
|
||||
|
||||
bool EdgeBasedEdge::operator<(const EdgeBasedEdge &other) const
|
||||
{
|
||||
if (source == other.source)
|
||||
{
|
||||
if (target == other.target)
|
||||
{
|
||||
if (weight == other.weight)
|
||||
{
|
||||
return forward && backward && ((!other.forward) || (!other.backward));
|
||||
}
|
||||
return weight < other.weight;
|
||||
}
|
||||
return target < other.target;
|
||||
}
|
||||
return source < other.source;
|
||||
}
|
||||
|
||||
template <class EdgeT>
|
||||
EdgeBasedEdge::EdgeBasedEdge(const EdgeT &other)
|
||||
: source(other.source), target(other.target), edge_id(other.data.via),
|
||||
weight(other.data.distance), forward(other.data.forward), backward(other.data.backward)
|
||||
{
|
||||
}
|
||||
|
||||
/** Default constructor. target and weight are set to 0.*/
|
||||
EdgeBasedEdge::EdgeBasedEdge()
|
||||
: source(0), target(0), edge_id(0), weight(0), forward(false), backward(false)
|
||||
{
|
||||
}
|
||||
|
||||
EdgeBasedEdge::EdgeBasedEdge(const NodeID source,
|
||||
const NodeID target,
|
||||
const NodeID edge_id,
|
||||
const EdgeWeight weight,
|
||||
const bool forward,
|
||||
const bool backward)
|
||||
: source(source), target(target), edge_id(edge_id), weight(weight), forward(forward),
|
||||
backward(backward)
|
||||
{
|
||||
}
|
||||
@@ -1,91 +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 "../DataStructures/TravelMode.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
struct NodeBasedEdge
|
||||
{
|
||||
bool operator<(const NodeBasedEdge &e) const;
|
||||
|
||||
explicit NodeBasedEdge(NodeID source,
|
||||
NodeID target,
|
||||
NodeID name_id,
|
||||
EdgeWeight weight,
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool in_tiny_cc,
|
||||
bool access_restricted,
|
||||
TravelMode travel_mode,
|
||||
bool is_split);
|
||||
|
||||
NodeID source;
|
||||
NodeID target;
|
||||
NodeID name_id;
|
||||
EdgeWeight weight;
|
||||
bool forward : 1;
|
||||
bool backward : 1;
|
||||
bool roundabout : 1;
|
||||
bool in_tiny_cc : 1;
|
||||
bool access_restricted : 1;
|
||||
bool is_split : 1;
|
||||
TravelMode travel_mode : 4;
|
||||
|
||||
NodeBasedEdge() = delete;
|
||||
};
|
||||
|
||||
struct EdgeBasedEdge
|
||||
{
|
||||
|
||||
public:
|
||||
bool operator<(const EdgeBasedEdge &e) const;
|
||||
|
||||
template <class EdgeT> explicit EdgeBasedEdge(const EdgeT &myEdge);
|
||||
|
||||
EdgeBasedEdge();
|
||||
|
||||
explicit EdgeBasedEdge(const NodeID source,
|
||||
const NodeID target,
|
||||
const NodeID edge_id,
|
||||
const EdgeWeight weight,
|
||||
const bool forward,
|
||||
const bool backward);
|
||||
NodeID source;
|
||||
NodeID target;
|
||||
NodeID edge_id;
|
||||
EdgeWeight weight : 30;
|
||||
bool forward : 1;
|
||||
bool backward : 1;
|
||||
};
|
||||
|
||||
using ImportEdge = NodeBasedEdge;
|
||||
|
||||
#endif /* IMPORT_EDGE_H */
|
||||
@@ -1,123 +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 INPUT_READER_FACTORY_H
|
||||
#define INPUT_READER_FACTORY_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 = nullptr;
|
||||
char *unusedTmp = nullptr;
|
||||
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(nullptr != 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 == nullptr || context->file == nullptr)
|
||||
{
|
||||
delete context;
|
||||
return nullptr;
|
||||
}
|
||||
return xmlReaderForIO(readFromBz2Stream, closeBz2Stream, (void *)context, nullptr, nullptr, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return xmlNewTextReaderFilename(name);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // INPUT_READER_FACTORY_H
|
||||
@@ -1,236 +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.
|
||||
|
||||
*/
|
||||
|
||||
// based on
|
||||
// https://svn.apache.org/repos/asf/mesos/tags/release-0.9.0-incubating-RC0/src/common/json.hpp
|
||||
|
||||
#ifndef JSON_CONTAINER_H
|
||||
#define JSON_CONTAINER_H
|
||||
|
||||
#include "../ThirdParty/variant/variant.hpp"
|
||||
#include "../Util/cast.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace JSON
|
||||
{
|
||||
|
||||
struct Object;
|
||||
struct Array;
|
||||
|
||||
struct String
|
||||
{
|
||||
String() {}
|
||||
String(const char *value) : value(value) {}
|
||||
String(const std::string &value) : value(value) {}
|
||||
std::string value;
|
||||
};
|
||||
|
||||
struct Number
|
||||
{
|
||||
Number() {}
|
||||
Number(double value) : value(value) {}
|
||||
double value;
|
||||
};
|
||||
|
||||
struct True
|
||||
{
|
||||
};
|
||||
|
||||
struct False
|
||||
{
|
||||
};
|
||||
|
||||
struct Null
|
||||
{
|
||||
};
|
||||
|
||||
using Value = mapbox::util::variant<String,
|
||||
Number,
|
||||
mapbox::util::recursive_wrapper<Object>,
|
||||
mapbox::util::recursive_wrapper<Array>,
|
||||
True,
|
||||
False,
|
||||
Null>;
|
||||
|
||||
struct Object
|
||||
{
|
||||
std::unordered_map<std::string, Value> values;
|
||||
};
|
||||
|
||||
struct Array
|
||||
{
|
||||
std::vector<Value> values;
|
||||
};
|
||||
|
||||
struct Renderer : mapbox::util::static_visitor<>
|
||||
{
|
||||
explicit Renderer(std::ostream &_out) : out(_out) {}
|
||||
|
||||
void operator()(const String &string) const { out << "\"" << string.value << "\""; }
|
||||
|
||||
void operator()(const Number &number) const
|
||||
{
|
||||
out.precision(10);
|
||||
out << number.value;
|
||||
}
|
||||
|
||||
void operator()(const Object &object) const
|
||||
{
|
||||
out << "{";
|
||||
auto iterator = object.values.begin();
|
||||
while (iterator != object.values.end())
|
||||
{
|
||||
out << "\"" << (*iterator).first << "\":";
|
||||
mapbox::util::apply_visitor(Renderer(out), (*iterator).second);
|
||||
if (++iterator != object.values.end())
|
||||
{
|
||||
out << ",";
|
||||
}
|
||||
}
|
||||
out << "}";
|
||||
}
|
||||
|
||||
void operator()(const Array &array) const
|
||||
{
|
||||
out << "[";
|
||||
std::vector<Value>::const_iterator iterator;
|
||||
iterator = array.values.begin();
|
||||
while (iterator != array.values.end())
|
||||
{
|
||||
mapbox::util::apply_visitor(Renderer(out), *iterator);
|
||||
if (++iterator != array.values.end())
|
||||
{
|
||||
out << ",";
|
||||
}
|
||||
}
|
||||
out << "]";
|
||||
}
|
||||
|
||||
void operator()(const True &) const { out << "true"; }
|
||||
|
||||
void operator()(const False &) const { out << "false"; }
|
||||
|
||||
void operator()(const Null &) const { out << "null"; }
|
||||
|
||||
private:
|
||||
std::ostream &out;
|
||||
};
|
||||
|
||||
struct ArrayRenderer : mapbox::util::static_visitor<>
|
||||
{
|
||||
explicit ArrayRenderer(std::vector<char> &_out) : out(_out) {}
|
||||
|
||||
void operator()(const String &string) const
|
||||
{
|
||||
out.push_back('\"');
|
||||
out.insert(out.end(), string.value.begin(), string.value.end());
|
||||
out.push_back('\"');
|
||||
}
|
||||
|
||||
void operator()(const Number &number) const
|
||||
{
|
||||
const std::string number_string = cast::double_fixed_to_string(number.value);
|
||||
out.insert(out.end(), number_string.begin(), number_string.end());
|
||||
}
|
||||
|
||||
void operator()(const Object &object) const
|
||||
{
|
||||
out.push_back('{');
|
||||
auto iterator = object.values.begin();
|
||||
while (iterator != object.values.end())
|
||||
{
|
||||
out.push_back('\"');
|
||||
out.insert(out.end(), (*iterator).first.begin(), (*iterator).first.end());
|
||||
out.push_back('\"');
|
||||
out.push_back(':');
|
||||
|
||||
mapbox::util::apply_visitor(ArrayRenderer(out), (*iterator).second);
|
||||
if (++iterator != object.values.end())
|
||||
{
|
||||
out.push_back(',');
|
||||
}
|
||||
}
|
||||
out.push_back('}');
|
||||
}
|
||||
|
||||
void operator()(const Array &array) const
|
||||
{
|
||||
out.push_back('[');
|
||||
std::vector<Value>::const_iterator iterator;
|
||||
iterator = array.values.begin();
|
||||
while (iterator != array.values.end())
|
||||
{
|
||||
mapbox::util::apply_visitor(ArrayRenderer(out), *iterator);
|
||||
if (++iterator != array.values.end())
|
||||
{
|
||||
out.push_back(',');
|
||||
}
|
||||
}
|
||||
out.push_back(']');
|
||||
}
|
||||
|
||||
void operator()(const True &) const
|
||||
{
|
||||
const std::string temp("true");
|
||||
out.insert(out.end(), temp.begin(), temp.end());
|
||||
}
|
||||
|
||||
void operator()(const False &) const
|
||||
{
|
||||
const std::string temp("false");
|
||||
out.insert(out.end(), temp.begin(), temp.end());
|
||||
}
|
||||
|
||||
void operator()(const Null &) const
|
||||
{
|
||||
const std::string temp("null");
|
||||
out.insert(out.end(), temp.begin(), temp.end());
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<char> &out;
|
||||
};
|
||||
|
||||
inline void render(std::ostream &out, const Object &object)
|
||||
{
|
||||
Value value = object;
|
||||
mapbox::util::apply_visitor(Renderer(out), value);
|
||||
}
|
||||
|
||||
inline void render(std::vector<char> &out, const Object &object)
|
||||
{
|
||||
Value value = object;
|
||||
mapbox::util::apply_visitor(ArrayRenderer(out), value);
|
||||
}
|
||||
|
||||
} // namespace JSON
|
||||
|
||||
#endif // JSON_CONTAINER_H
|
||||
@@ -1,97 +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 <unordered_map>
|
||||
|
||||
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;
|
||||
std::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,244 +0,0 @@
|
||||
#ifndef NODE_BASED_GRAPH_H_
|
||||
#define NODE_BASED_GRAPH_H_
|
||||
|
||||
#include "DynamicGraph.h"
|
||||
#include "ImportEdge.h"
|
||||
#include "../Util/simple_logger.hpp"
|
||||
|
||||
#include <tbb/parallel_sort.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
struct NodeBasedEdgeData
|
||||
{
|
||||
NodeBasedEdgeData()
|
||||
: distance(INVALID_EDGE_WEIGHT), edgeBasedNodeID(SPECIAL_NODEID),
|
||||
nameID(std::numeric_limits<unsigned>::max()),
|
||||
isAccessRestricted(false), shortcut(false), forward(false), backward(false),
|
||||
roundabout(false), ignore_in_grid(false), travel_mode(TRAVEL_MODE_INACCESSIBLE)
|
||||
{
|
||||
}
|
||||
|
||||
int distance;
|
||||
unsigned edgeBasedNodeID;
|
||||
unsigned nameID;
|
||||
bool isAccessRestricted : 1;
|
||||
bool shortcut : 1;
|
||||
bool forward : 1;
|
||||
bool backward : 1;
|
||||
bool roundabout : 1;
|
||||
bool ignore_in_grid : 1;
|
||||
TravelMode travel_mode : 4;
|
||||
|
||||
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) &&
|
||||
(travel_mode == other.travel_mode);
|
||||
}
|
||||
};
|
||||
|
||||
struct SimpleEdgeData
|
||||
{
|
||||
SimpleEdgeData() : capacity(0) {}
|
||||
EdgeWeight capacity;
|
||||
};
|
||||
|
||||
using NodeBasedDynamicGraph = DynamicGraph<NodeBasedEdgeData>;
|
||||
using SimpleNodeBasedDynamicGraph = DynamicGraph<SimpleEdgeData>;
|
||||
|
||||
// Factory method to create NodeBasedDynamicGraph from ImportEdges
|
||||
inline std::shared_ptr<NodeBasedDynamicGraph>
|
||||
NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge> &input_edge_list)
|
||||
{
|
||||
static_assert(sizeof(NodeBasedEdgeData) == 16, "changing node based edge data size changes memory consumption");
|
||||
|
||||
DeallocatingVector<NodeBasedDynamicGraph::InputEdge> edges_list;
|
||||
NodeBasedDynamicGraph::InputEdge edge;
|
||||
for (const ImportEdge &import_edge : input_edge_list)
|
||||
{
|
||||
if (import_edge.forward)
|
||||
{
|
||||
edge.source = import_edge.source;
|
||||
edge.target = import_edge.target;
|
||||
edge.data.forward = import_edge.forward;
|
||||
edge.data.backward = import_edge.backward;
|
||||
}
|
||||
else
|
||||
{
|
||||
edge.source = import_edge.target;
|
||||
edge.target = import_edge.source;
|
||||
edge.data.backward = import_edge.forward;
|
||||
edge.data.forward = import_edge.backward;
|
||||
}
|
||||
|
||||
if (edge.source == edge.target)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
edge.data.distance = (std::max)((int)import_edge.weight, 1);
|
||||
BOOST_ASSERT(edge.data.distance > 0);
|
||||
edge.data.shortcut = false;
|
||||
edge.data.roundabout = import_edge.roundabout;
|
||||
edge.data.ignore_in_grid = import_edge.in_tiny_cc;
|
||||
edge.data.nameID = import_edge.name_id;
|
||||
edge.data.isAccessRestricted = import_edge.access_restricted;
|
||||
edge.data.travel_mode = import_edge.travel_mode;
|
||||
|
||||
edges_list.push_back(edge);
|
||||
|
||||
if (!import_edge.is_split)
|
||||
{
|
||||
using std::swap; // enable ADL
|
||||
swap(edge.source, edge.target);
|
||||
edge.data.SwapDirectionFlags();
|
||||
edges_list.push_back(edge);
|
||||
}
|
||||
}
|
||||
|
||||
// remove duplicate edges
|
||||
tbb::parallel_sort(edges_list.begin(), edges_list.end());
|
||||
NodeID edge_count = 0;
|
||||
for (NodeID i = 0; i < edges_list.size(); )
|
||||
{
|
||||
const NodeID source = edges_list[i].source;
|
||||
const NodeID target = edges_list[i].target;
|
||||
// remove eigenloops
|
||||
if (source == target)
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
NodeBasedDynamicGraph::InputEdge forward_edge;
|
||||
NodeBasedDynamicGraph::InputEdge reverse_edge;
|
||||
forward_edge = reverse_edge = edges_list[i];
|
||||
forward_edge.data.forward = reverse_edge.data.backward = true;
|
||||
forward_edge.data.backward = reverse_edge.data.forward = false;
|
||||
forward_edge.data.shortcut = reverse_edge.data.shortcut = false;
|
||||
forward_edge.data.distance = reverse_edge.data.distance =
|
||||
std::numeric_limits<int>::max();
|
||||
// remove parallel edges
|
||||
while (i < edges_list.size() && edges_list[i].source == source && edges_list[i].target == target)
|
||||
{
|
||||
if (edges_list[i].data.forward)
|
||||
{
|
||||
forward_edge.data.distance =
|
||||
std::min(edges_list[i].data.distance, forward_edge.data.distance);
|
||||
}
|
||||
if (edges_list[i].data.backward)
|
||||
{
|
||||
reverse_edge.data.distance =
|
||||
std::min(edges_list[i].data.distance, reverse_edge.data.distance);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
// merge edges (s,t) and (t,s) into bidirectional edge
|
||||
if (forward_edge.data.distance == reverse_edge.data.distance)
|
||||
{
|
||||
if ((int)forward_edge.data.distance != std::numeric_limits<int>::max())
|
||||
{
|
||||
forward_edge.data.backward = true;
|
||||
edges_list[edge_count++] = forward_edge;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // insert seperate edges
|
||||
if (((int)forward_edge.data.distance) != std::numeric_limits<int>::max())
|
||||
{
|
||||
edges_list[edge_count++] = forward_edge;
|
||||
}
|
||||
if ((int)reverse_edge.data.distance != std::numeric_limits<int>::max())
|
||||
{
|
||||
edges_list[edge_count++] = reverse_edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
edges_list.resize(edge_count);
|
||||
SimpleLogger().Write() << "merged " << edges_list.size() - edge_count << " edges out of " << edges_list.size();
|
||||
|
||||
auto graph = std::make_shared<NodeBasedDynamicGraph>(static_cast<NodeBasedDynamicGraph::NodeIterator>(number_of_nodes), edges_list);
|
||||
return graph;
|
||||
}
|
||||
|
||||
template<class SimpleEdgeT>
|
||||
inline std::shared_ptr<SimpleNodeBasedDynamicGraph>
|
||||
SimpleNodeBasedDynamicGraphFromEdges(int number_of_nodes, std::vector<SimpleEdgeT> &input_edge_list)
|
||||
{
|
||||
static_assert(sizeof(NodeBasedEdgeData) == 16, "changing node based edge data size changes memory consumption");
|
||||
tbb::parallel_sort(input_edge_list.begin(), input_edge_list.end());
|
||||
|
||||
DeallocatingVector<SimpleNodeBasedDynamicGraph::InputEdge> edges_list;
|
||||
SimpleNodeBasedDynamicGraph::InputEdge edge;
|
||||
edge.data.capacity = 1;
|
||||
for (const SimpleEdgeT &import_edge : input_edge_list)
|
||||
{
|
||||
if (import_edge.source == import_edge.target)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
edge.source = import_edge.source;
|
||||
edge.target = import_edge.target;
|
||||
edges_list.push_back(edge);
|
||||
std::swap(edge.source, edge.target);
|
||||
edges_list.push_back(edge);
|
||||
}
|
||||
|
||||
// remove duplicate edges
|
||||
tbb::parallel_sort(edges_list.begin(), edges_list.end());
|
||||
NodeID edge_count = 0;
|
||||
for (NodeID i = 0; i < edges_list.size(); )
|
||||
{
|
||||
const NodeID source = edges_list[i].source;
|
||||
const NodeID target = edges_list[i].target;
|
||||
// remove eigenloops
|
||||
if (source == target)
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
SimpleNodeBasedDynamicGraph::InputEdge forward_edge;
|
||||
SimpleNodeBasedDynamicGraph::InputEdge reverse_edge;
|
||||
forward_edge = reverse_edge = edges_list[i];
|
||||
forward_edge.data.capacity = reverse_edge.data.capacity = INVALID_EDGE_WEIGHT;
|
||||
// remove parallel edges
|
||||
while (i < edges_list.size() && edges_list[i].source == source && edges_list[i].target == target)
|
||||
{
|
||||
forward_edge.data.capacity = std::min(edges_list[i].data.capacity, forward_edge.data.capacity);
|
||||
reverse_edge.data.capacity = std::min(edges_list[i].data.capacity, reverse_edge.data.capacity);
|
||||
++i;
|
||||
}
|
||||
// merge edges (s,t) and (t,s) into bidirectional edge
|
||||
if (forward_edge.data.capacity == reverse_edge.data.capacity)
|
||||
{
|
||||
if ((int)forward_edge.data.capacity != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
edges_list[edge_count++] = forward_edge;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // insert seperate edges
|
||||
if (((int)forward_edge.data.capacity) != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
edges_list[edge_count++] = forward_edge;
|
||||
}
|
||||
if ((int)reverse_edge.data.capacity != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
edges_list[edge_count++] = reverse_edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
SimpleLogger().Write() << "merged " << edges_list.size() - edge_count << " edges out of " << edges_list.size();
|
||||
|
||||
auto graph = std::make_shared<SimpleNodeBasedDynamicGraph>(number_of_nodes, edges_list);
|
||||
return graph;
|
||||
}
|
||||
|
||||
#endif // NODE_BASED_GRAPH_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 ORIGINAL_EDGE_DATA_H
|
||||
#define ORIGINAL_EDGE_DATA_H
|
||||
|
||||
#include "TurnInstructions.h"
|
||||
#include "../DataStructures/TravelMode.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
struct OriginalEdgeData
|
||||
{
|
||||
explicit OriginalEdgeData(NodeID via_node,
|
||||
unsigned name_id,
|
||||
TurnInstruction turn_instruction,
|
||||
bool compressed_geometry,
|
||||
TravelMode travel_mode)
|
||||
: via_node(via_node), name_id(name_id), turn_instruction(turn_instruction),
|
||||
compressed_geometry(compressed_geometry), travel_mode(travel_mode)
|
||||
{
|
||||
}
|
||||
|
||||
OriginalEdgeData()
|
||||
: via_node(std::numeric_limits<unsigned>::max()),
|
||||
name_id(std::numeric_limits<unsigned>::max()),
|
||||
turn_instruction(TurnInstruction::NoTurn), compressed_geometry(false),
|
||||
travel_mode(TRAVEL_MODE_INACCESSIBLE)
|
||||
{
|
||||
}
|
||||
|
||||
NodeID via_node;
|
||||
unsigned name_id;
|
||||
TurnInstruction turn_instruction;
|
||||
bool compressed_geometry;
|
||||
TravelMode travel_mode;
|
||||
};
|
||||
|
||||
#endif // ORIGINAL_EDGE_DATA_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 PERCENT_H
|
||||
#define PERCENT_H
|
||||
|
||||
#include <iostream>
|
||||
#include <atomic>
|
||||
|
||||
class Percent
|
||||
{
|
||||
public:
|
||||
explicit Percent(unsigned max_value, unsigned step = 5) { reinit(max_value, step); }
|
||||
|
||||
// Reinitializes
|
||||
void reinit(unsigned max_value, unsigned step = 5)
|
||||
{
|
||||
m_max_value = max_value;
|
||||
m_current_value = 0;
|
||||
m_percent_interval = m_max_value / 100;
|
||||
m_next_threshold = m_percent_interval;
|
||||
m_last_percent = 0;
|
||||
m_step = step;
|
||||
}
|
||||
|
||||
// If there has been significant progress, display it.
|
||||
void printStatus(unsigned current_value)
|
||||
{
|
||||
if (current_value >= m_next_threshold)
|
||||
{
|
||||
m_next_threshold += m_percent_interval;
|
||||
printPercent(current_value / (double)m_max_value * 100);
|
||||
}
|
||||
if (current_value + 1 == m_max_value)
|
||||
std::cout << " 100%" << std::endl;
|
||||
}
|
||||
|
||||
void printIncrement()
|
||||
{
|
||||
++m_current_value;
|
||||
printStatus(m_current_value);
|
||||
}
|
||||
|
||||
void printAddition(const unsigned addition)
|
||||
{
|
||||
m_current_value += addition;
|
||||
printStatus(m_current_value);
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic_uint m_current_value;
|
||||
unsigned m_max_value;
|
||||
unsigned m_percent_interval;
|
||||
unsigned m_next_threshold;
|
||||
unsigned m_last_percent;
|
||||
unsigned m_step;
|
||||
|
||||
// Displays progress.
|
||||
void printPercent(double percent)
|
||||
{
|
||||
while (percent >= m_last_percent + m_step)
|
||||
{
|
||||
m_last_percent += m_step;
|
||||
if (m_last_percent % 10 == 0)
|
||||
{
|
||||
std::cout << " " << m_last_percent << "% ";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << ".";
|
||||
}
|
||||
std::cout.flush();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // PERCENT_H
|
||||
@@ -1,181 +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 PHANTOM_NODES_H
|
||||
#define PHANTOM_NODES_H
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
#include "../DataStructures/TravelMode.h"
|
||||
#include "../Util/simple_logger.hpp"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct PhantomNode
|
||||
{
|
||||
PhantomNode(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,
|
||||
TravelMode forward_travel_mode, TravelMode backward_travel_mode) :
|
||||
forward_node_id(forward_node_id),
|
||||
reverse_node_id(reverse_node_id),
|
||||
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),
|
||||
location(location),
|
||||
fwd_segment_position(fwd_segment_position),
|
||||
forward_travel_mode(forward_travel_mode),
|
||||
backward_travel_mode(backward_travel_mode)
|
||||
{ }
|
||||
|
||||
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),
|
||||
forward_travel_mode(TRAVEL_MODE_INACCESSIBLE),
|
||||
backward_travel_mode(TRAVEL_MODE_INACCESSIBLE)
|
||||
{ }
|
||||
|
||||
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;
|
||||
TravelMode forward_travel_mode : 4;
|
||||
TravelMode backward_travel_mode : 4;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 isValid() const
|
||||
{
|
||||
return location.isValid() &&
|
||||
(name_id != std::numeric_limits<unsigned>::max());
|
||||
}
|
||||
|
||||
bool operator==(const PhantomNode & other) const
|
||||
{
|
||||
return location == other.location;
|
||||
}
|
||||
};
|
||||
|
||||
using PhantomNodeArray = std::vector<std::vector<PhantomNode>>;
|
||||
|
||||
struct PhantomNodeLists
|
||||
{
|
||||
std::vector<PhantomNode> source_phantom_list;
|
||||
std::vector<PhantomNode> target_phantom_list;
|
||||
};
|
||||
|
||||
struct PhantomNodes
|
||||
{
|
||||
PhantomNode source_phantom;
|
||||
PhantomNode 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 // PHANTOM_NODES_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 QUERYEDGE_H_
|
||||
#define QUERYEDGE_H_
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
struct QueryEdge
|
||||
{
|
||||
NodeID source;
|
||||
NodeID target;
|
||||
struct EdgeData
|
||||
{
|
||||
EdgeData() : id(0), shortcut(false), distance(0), forward(false), backward(false) {}
|
||||
|
||||
template <class OtherT> EdgeData(const OtherT &other)
|
||||
{
|
||||
distance = other.distance;
|
||||
shortcut = other.shortcut;
|
||||
id = other.id;
|
||||
forward = other.forward;
|
||||
backward = other.backward;
|
||||
}
|
||||
NodeID id : 31;
|
||||
bool shortcut : 1;
|
||||
int distance : 30;
|
||||
bool forward : 1;
|
||||
bool backward : 1;
|
||||
} data;
|
||||
|
||||
QueryEdge() : source(SPECIAL_NODEID), target(SPECIAL_NODEID) {}
|
||||
|
||||
QueryEdge(NodeID source, NodeID target, EdgeData data)
|
||||
: source(source), target(target), data(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,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 QUERY_NODE_H
|
||||
#define QUERY_NODE_H
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <limits>
|
||||
|
||||
struct NodeInfo
|
||||
{
|
||||
using key_type = NodeID; // type of NodeID
|
||||
using value_type = int; // type of lat,lons
|
||||
|
||||
explicit NodeInfo(int lat, int lon, NodeID node_id) : lat(lat), lon(lon), node_id(node_id) {}
|
||||
NodeInfo()
|
||||
: lat(std::numeric_limits<int>::max()), lon(std::numeric_limits<int>::max()),
|
||||
node_id(std::numeric_limits<unsigned>::max())
|
||||
{
|
||||
}
|
||||
|
||||
int lat;
|
||||
int lon;
|
||||
NodeID node_id;
|
||||
|
||||
static NodeInfo min_value()
|
||||
{
|
||||
return NodeInfo(static_cast<int>(-90 * COORDINATE_PRECISION),
|
||||
static_cast<int>(-180 * COORDINATE_PRECISION),
|
||||
std::numeric_limits<NodeID>::min());
|
||||
}
|
||||
|
||||
static NodeInfo max_value()
|
||||
{
|
||||
return NodeInfo(static_cast<int>(90 * COORDINATE_PRECISION),
|
||||
static_cast<int>(180 * COORDINATE_PRECISION),
|
||||
std::numeric_limits<NodeID>::max());
|
||||
}
|
||||
|
||||
value_type operator[](const std::size_t n) const
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case 1:
|
||||
return lat;
|
||||
case 0:
|
||||
return lon;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
BOOST_ASSERT_MSG(false, "should not happen");
|
||||
return std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // QUERY_NODE_H
|
||||
@@ -1,93 +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 RAW_ROUTE_DATA_H
|
||||
#define RAW_ROUTE_DATA_H
|
||||
|
||||
#include "../DataStructures/PhantomNodes.h"
|
||||
#include "../DataStructures/TravelMode.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct PathData
|
||||
{
|
||||
PathData()
|
||||
: node(SPECIAL_NODEID), name_id(INVALID_EDGE_WEIGHT),
|
||||
segment_duration(INVALID_EDGE_WEIGHT),
|
||||
turn_instruction(TurnInstruction::NoTurn),
|
||||
travel_mode(TRAVEL_MODE_INACCESSIBLE)
|
||||
{
|
||||
}
|
||||
|
||||
PathData(NodeID node,
|
||||
unsigned name_id,
|
||||
TurnInstruction turn_instruction,
|
||||
EdgeWeight segment_duration,
|
||||
TravelMode travel_mode)
|
||||
: node(node), name_id(name_id), segment_duration(segment_duration), turn_instruction(turn_instruction),
|
||||
travel_mode(travel_mode)
|
||||
{
|
||||
}
|
||||
NodeID node;
|
||||
unsigned name_id;
|
||||
EdgeWeight segment_duration;
|
||||
TurnInstruction turn_instruction;
|
||||
TravelMode travel_mode : 4;
|
||||
};
|
||||
|
||||
struct RawRouteData
|
||||
{
|
||||
std::vector<std::vector<PathData>> unpacked_path_segments;
|
||||
std::vector<PathData> unpacked_alternative;
|
||||
std::vector<PhantomNodes> segment_end_coordinates;
|
||||
std::vector<FixedPointCoordinate> raw_via_node_coordinates;
|
||||
std::vector<bool> source_traversed_in_reverse;
|
||||
std::vector<bool> target_traversed_in_reverse;
|
||||
std::vector<bool> alt_source_traversed_in_reverse;
|
||||
std::vector<bool> alt_target_traversed_in_reverse;
|
||||
unsigned check_sum;
|
||||
int shortest_path_length;
|
||||
int alternative_path_length;
|
||||
|
||||
bool is_via_leg(const std::size_t leg) const
|
||||
{
|
||||
return (leg != unpacked_path_segments.size() - 1);
|
||||
}
|
||||
|
||||
RawRouteData()
|
||||
: check_sum(SPECIAL_NODEID),
|
||||
shortest_path_length(INVALID_EDGE_WEIGHT),
|
||||
alternative_path_length(INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif // RAW_ROUTE_DATA_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.
|
||||
|
||||
*/
|
||||
|
||||
#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(std::numeric_limits<unsigned>::max()),
|
||||
fromNode(std::numeric_limits<unsigned>::max()),
|
||||
toNode(std::numeric_limits<unsigned>::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
|
||||
{
|
||||
using value_type = InputRestrictionContainer;
|
||||
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
|
||||
{
|
||||
using value_type = InputRestrictionContainer;
|
||||
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,219 +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 "RestrictionMap.h"
|
||||
#include "NodeBasedGraph.h"
|
||||
|
||||
bool RestrictionMap::IsViaNode(const NodeID node) const
|
||||
{
|
||||
return m_no_turn_via_node_set.find(node) != m_no_turn_via_node_set.end();
|
||||
}
|
||||
|
||||
RestrictionMap::RestrictionMap(const std::shared_ptr<NodeBasedDynamicGraph> &graph,
|
||||
const std::vector<TurnRestriction> &restriction_list)
|
||||
: m_count(0), m_graph(graph)
|
||||
{
|
||||
// decompose restriction consisting of a start, via and end node into a
|
||||
// a pair of starting edge and a list of all end nodes
|
||||
for (auto &restriction : restriction_list)
|
||||
{
|
||||
m_restriction_start_nodes.insert(restriction.fromNode);
|
||||
m_no_turn_via_node_set.insert(restriction.viaNode);
|
||||
|
||||
RestrictionSource restriction_source = {restriction.fromNode, restriction.viaNode};
|
||||
|
||||
unsigned index;
|
||||
auto restriction_iter = m_restriction_map.find(restriction_source);
|
||||
if (restriction_iter == m_restriction_map.end())
|
||||
{
|
||||
index = m_restriction_bucket_list.size();
|
||||
m_restriction_bucket_list.resize(index + 1);
|
||||
m_restriction_map.emplace(restriction_source, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
index = restriction_iter->second;
|
||||
// Map already contains an is_only_*-restriction
|
||||
if (m_restriction_bucket_list.at(index).begin()->is_only)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (restriction.flags.isOnly)
|
||||
{
|
||||
// We are going to insert an is_only_*-restriction. There can be only one.
|
||||
m_count -= m_restriction_bucket_list.at(index).size();
|
||||
m_restriction_bucket_list.at(index).clear();
|
||||
}
|
||||
}
|
||||
++m_count;
|
||||
m_restriction_bucket_list.at(index)
|
||||
.emplace_back(restriction.toNode, restriction.flags.isOnly);
|
||||
}
|
||||
}
|
||||
|
||||
// Replace end v with w in each turn restriction containing u as via node
|
||||
void RestrictionMap::FixupArrivingTurnRestriction(const NodeID node_u,
|
||||
const NodeID node_v,
|
||||
const NodeID node_w)
|
||||
{
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_w != SPECIAL_NODEID);
|
||||
|
||||
if (!IsViaNode(node_u))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// find all potential start edges. It is more efficent to get a (small) list
|
||||
// of potential start edges than iterating over all buckets
|
||||
std::vector<NodeID> predecessors;
|
||||
for (const EdgeID current_edge_id : m_graph->GetAdjacentEdgeRange(node_u))
|
||||
{
|
||||
const NodeID target = m_graph->GetTarget(current_edge_id);
|
||||
if (node_v != target)
|
||||
{
|
||||
predecessors.push_back(target);
|
||||
}
|
||||
}
|
||||
|
||||
for (const NodeID node_x : predecessors)
|
||||
{
|
||||
const auto restriction_iterator = m_restriction_map.find({node_x, node_u});
|
||||
if (restriction_iterator == m_restriction_map.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const unsigned index = restriction_iterator->second;
|
||||
auto &bucket = m_restriction_bucket_list.at(index);
|
||||
for (RestrictionTarget &restriction_target : bucket)
|
||||
{
|
||||
if (node_v == restriction_target.target_node)
|
||||
{
|
||||
restriction_target.target_node = node_w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Replaces start edge (v, w) with (u, w). Only start node changes.
|
||||
void RestrictionMap::FixupStartingTurnRestriction(const NodeID node_u,
|
||||
const NodeID node_v,
|
||||
const NodeID node_w)
|
||||
{
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_w != SPECIAL_NODEID);
|
||||
|
||||
if (!IsSourceNode(node_v))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto restriction_iterator = m_restriction_map.find({node_v, node_w});
|
||||
if (restriction_iterator != m_restriction_map.end())
|
||||
{
|
||||
const unsigned index = restriction_iterator->second;
|
||||
// remove old restriction start (v,w)
|
||||
m_restriction_map.erase(restriction_iterator);
|
||||
m_restriction_start_nodes.emplace(node_u);
|
||||
// insert new restriction start (u,w) (pointing to index)
|
||||
RestrictionSource new_source = {node_u, node_w};
|
||||
m_restriction_map.emplace(new_source, index);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if edge (u, v) is the start of any turn restriction.
|
||||
// If so returns id of first target node.
|
||||
NodeID RestrictionMap::CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const
|
||||
{
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
||||
|
||||
if (!IsSourceNode(node_u))
|
||||
{
|
||||
return SPECIAL_NODEID;
|
||||
}
|
||||
|
||||
const auto restriction_iter = m_restriction_map.find({node_u, node_v});
|
||||
if (restriction_iter != m_restriction_map.end())
|
||||
{
|
||||
const unsigned index = restriction_iter->second;
|
||||
const auto &bucket = m_restriction_bucket_list.at(index);
|
||||
for (const RestrictionTarget &restriction_target : bucket)
|
||||
{
|
||||
if (restriction_target.is_only)
|
||||
{
|
||||
return restriction_target.target_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SPECIAL_NODEID;
|
||||
}
|
||||
|
||||
// Checks if turn <u,v,w> is actually a turn restriction.
|
||||
bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID node_u,
|
||||
const NodeID node_v,
|
||||
const NodeID node_w) const
|
||||
{
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_w != SPECIAL_NODEID);
|
||||
|
||||
if (!IsSourceNode(node_u))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto restriction_iter = m_restriction_map.find({node_u, node_v});
|
||||
if (restriction_iter != m_restriction_map.end())
|
||||
{
|
||||
const unsigned index = restriction_iter->second;
|
||||
const auto &bucket = m_restriction_bucket_list.at(index);
|
||||
for (const RestrictionTarget &restriction_target : bucket)
|
||||
{
|
||||
if ((node_w == restriction_target.target_node) && // target found
|
||||
(!restriction_target.is_only) // and not an only_-restr.
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// check of node is the start of any restriction
|
||||
bool RestrictionMap::IsSourceNode(const NodeID node) const
|
||||
{
|
||||
if (m_restriction_start_nodes.find(node) == m_restriction_start_nodes.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef RESTRICTION_MAP_H_
|
||||
#define RESTRICTION_MAP_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "DynamicGraph.h"
|
||||
#include "Restriction.h"
|
||||
#include "NodeBasedGraph.h"
|
||||
#include "../Util/StdHashExtensions.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
struct RestrictionSource
|
||||
{
|
||||
NodeID start_node;
|
||||
NodeID via_node;
|
||||
|
||||
RestrictionSource(NodeID start, NodeID via) : start_node(start), via_node(via)
|
||||
{
|
||||
}
|
||||
|
||||
friend inline bool operator==(const RestrictionSource &lhs, const RestrictionSource &rhs)
|
||||
{
|
||||
return (lhs.start_node == rhs.start_node && lhs.via_node == rhs.via_node);
|
||||
}
|
||||
};
|
||||
|
||||
struct RestrictionTarget
|
||||
{
|
||||
NodeID target_node;
|
||||
bool is_only;
|
||||
|
||||
explicit RestrictionTarget(NodeID target, bool only) : target_node(target), is_only(only)
|
||||
{
|
||||
}
|
||||
|
||||
friend inline bool operator==(const RestrictionTarget &lhs, const RestrictionTarget &rhs)
|
||||
{
|
||||
return (lhs.target_node == rhs.target_node && lhs.is_only == rhs.is_only);
|
||||
}
|
||||
};
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <> struct hash<RestrictionSource>
|
||||
{
|
||||
size_t operator()(const RestrictionSource &r_source) const
|
||||
{
|
||||
return hash_val(r_source.start_node, r_source.via_node);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct hash<RestrictionTarget>
|
||||
{
|
||||
size_t operator()(const RestrictionTarget &r_target) const
|
||||
{
|
||||
return hash_val(r_target.target_node, r_target.is_only);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Efficent look up if an edge is the start + via node of a TurnRestriction
|
||||
EdgeBasedEdgeFactory decides by it if edges are inserted or geometry is compressed
|
||||
*/
|
||||
class RestrictionMap
|
||||
{
|
||||
public:
|
||||
RestrictionMap(const std::shared_ptr<NodeBasedDynamicGraph> &graph,
|
||||
const std::vector<TurnRestriction> &input_restrictions_list);
|
||||
|
||||
void FixupArrivingTurnRestriction(const NodeID u, const NodeID v, const NodeID w);
|
||||
void FixupStartingTurnRestriction(const NodeID u, const NodeID v, const NodeID w);
|
||||
NodeID CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const;
|
||||
bool CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const;
|
||||
bool IsViaNode(const NodeID node) const;
|
||||
std::size_t size()
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
private:
|
||||
bool IsSourceNode(const NodeID node) const;
|
||||
using EmanatingRestrictionsVector = std::vector<RestrictionTarget>;
|
||||
using EdgeData = NodeBasedDynamicGraph::EdgeData;
|
||||
|
||||
std::size_t m_count;
|
||||
std::shared_ptr<NodeBasedDynamicGraph> m_graph;
|
||||
//! index -> list of (target, isOnly)
|
||||
std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list;
|
||||
//! maps (start, via) -> bucket index
|
||||
std::unordered_map<RestrictionSource, unsigned> m_restriction_map;
|
||||
std::unordered_set<NodeID> m_restriction_start_nodes;
|
||||
std::unordered_set<NodeID> m_no_turn_via_node_set;
|
||||
};
|
||||
|
||||
#endif //RESTRICTION_MAP_H_
|
||||
@@ -1,117 +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/RouteParameters.h>
|
||||
|
||||
#include <boost/fusion/container/vector.hpp>
|
||||
#include <boost/fusion/sequence/intrinsic.hpp>
|
||||
#include <boost/fusion/include/at_c.hpp>
|
||||
|
||||
RouteParameters::RouteParameters()
|
||||
: zoom_level(18), print_instructions(false), alternate_route(true), geometry(true),
|
||||
compression(true), deprecatedAPI(false), uturn_default(false), check_sum(-1), num_results(1)
|
||||
{
|
||||
}
|
||||
|
||||
void RouteParameters::setZoomLevel(const short level)
|
||||
{
|
||||
if (18 >= level && 0 <= level)
|
||||
{
|
||||
zoom_level = level;
|
||||
}
|
||||
}
|
||||
|
||||
void RouteParameters::setNumberOfResults(const short number)
|
||||
{
|
||||
if (number > 0 && number <= 100)
|
||||
{
|
||||
num_results = number;
|
||||
}
|
||||
}
|
||||
|
||||
void RouteParameters::setAlternateRouteFlag(const bool flag) { alternate_route = flag; }
|
||||
|
||||
void RouteParameters::setUTurn(const bool flag)
|
||||
{
|
||||
uturns.resize(coordinates.size(), uturn_default);
|
||||
if (!uturns.empty())
|
||||
{
|
||||
uturns.back() = flag;
|
||||
}
|
||||
}
|
||||
|
||||
void RouteParameters::setAllUTurns(const bool flag)
|
||||
{
|
||||
// if the flag flips the default, then we erase everything.
|
||||
if (flag)
|
||||
{
|
||||
uturn_default = flag;
|
||||
uturns.clear();
|
||||
uturns.resize(coordinates.size(), uturn_default);
|
||||
}
|
||||
}
|
||||
|
||||
void RouteParameters::setDeprecatedAPIFlag(const std::string &) { deprecatedAPI = true; }
|
||||
|
||||
void RouteParameters::setChecksum(const unsigned sum) { check_sum = sum; }
|
||||
|
||||
void RouteParameters::setInstructionFlag(const bool flag) { print_instructions = flag; }
|
||||
|
||||
void RouteParameters::setService(const std::string &service_string) { service = service_string; }
|
||||
|
||||
void RouteParameters::setOutputFormat(const std::string &format) { output_format = format; }
|
||||
|
||||
void RouteParameters::setJSONpParameter(const std::string ¶meter)
|
||||
{
|
||||
jsonp_parameter = parameter;
|
||||
}
|
||||
|
||||
void RouteParameters::addHint(const std::string &hint)
|
||||
{
|
||||
hints.resize(coordinates.size());
|
||||
if (!hints.empty())
|
||||
{
|
||||
hints.back() = hint;
|
||||
}
|
||||
}
|
||||
|
||||
void RouteParameters::setLanguage(const std::string &language_string)
|
||||
{
|
||||
language = language_string;
|
||||
}
|
||||
|
||||
void RouteParameters::setGeometryFlag(const bool flag) { geometry = flag; }
|
||||
|
||||
void RouteParameters::setCompressionFlag(const bool flag) { compression = flag; }
|
||||
|
||||
void
|
||||
RouteParameters::addCoordinate(const boost::fusion::vector<double, double> &transmitted_coordinates)
|
||||
{
|
||||
coordinates.emplace_back(
|
||||
static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<0>(transmitted_coordinates)),
|
||||
static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<1>(transmitted_coordinates)));
|
||||
}
|
||||
@@ -1,60 +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 "../RoutingAlgorithms/AlternativePathRouting.h"
|
||||
#include "../RoutingAlgorithms/ManyToManyRouting.h"
|
||||
#include "../RoutingAlgorithms/ShortestPathRouting.h"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
template <class DataFacadeT> class SearchEngine
|
||||
{
|
||||
private:
|
||||
DataFacadeT *facade;
|
||||
SearchEngineData engine_working_data;
|
||||
|
||||
public:
|
||||
ShortestPathRouting<DataFacadeT> shortest_path;
|
||||
AlternativeRouting<DataFacadeT> alternative_path;
|
||||
ManyToManyRouting<DataFacadeT> distance_table;
|
||||
|
||||
explicit SearchEngine(DataFacadeT *facade)
|
||||
: facade(facade), shortest_path(facade, engine_working_data),
|
||||
alternative_path(facade, engine_working_data), distance_table(facade, engine_working_data)
|
||||
{
|
||||
static_assert(!std::is_pointer<DataFacadeT>::value, "don't instantiate with ptr type");
|
||||
static_assert(std::is_object<DataFacadeT>::value, "don't instantiate with void, function, or reference");
|
||||
}
|
||||
|
||||
~SearchEngine() {}
|
||||
};
|
||||
|
||||
#endif // SEARCHENGINE_H
|
||||
@@ -1,93 +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 "SearchEngineData.h"
|
||||
|
||||
#include "BinaryHeap.h"
|
||||
|
||||
void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes)
|
||||
{
|
||||
if (forwardHeap.get())
|
||||
{
|
||||
forwardHeap->Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
forwardHeap.reset(new QueryHeap(number_of_nodes));
|
||||
}
|
||||
|
||||
if (backwardHeap.get())
|
||||
{
|
||||
backwardHeap->Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
backwardHeap.reset(new QueryHeap(number_of_nodes));
|
||||
}
|
||||
}
|
||||
|
||||
void SearchEngineData::InitializeOrClearSecondThreadLocalStorage(const unsigned number_of_nodes)
|
||||
{
|
||||
if (forwardHeap2.get())
|
||||
{
|
||||
forwardHeap2->Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
forwardHeap2.reset(new QueryHeap(number_of_nodes));
|
||||
}
|
||||
|
||||
if (backwardHeap2.get())
|
||||
{
|
||||
backwardHeap2->Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
backwardHeap2.reset(new QueryHeap(number_of_nodes));
|
||||
}
|
||||
}
|
||||
|
||||
void SearchEngineData::InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes)
|
||||
{
|
||||
if (forwardHeap3.get())
|
||||
{
|
||||
forwardHeap3->Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
forwardHeap3.reset(new QueryHeap(number_of_nodes));
|
||||
}
|
||||
|
||||
if (backwardHeap3.get())
|
||||
{
|
||||
backwardHeap3->Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
backwardHeap3.reset(new QueryHeap(number_of_nodes));
|
||||
}
|
||||
}
|
||||
@@ -1,61 +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 <boost/thread/tss.hpp>
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "BinaryHeap.h"
|
||||
|
||||
struct HeapData
|
||||
{
|
||||
NodeID parent;
|
||||
/* explicit */ HeapData(NodeID p) : parent(p) {}
|
||||
};
|
||||
|
||||
struct SearchEngineData
|
||||
{
|
||||
using QueryHeap = BinaryHeap<NodeID, NodeID, int, HeapData, UnorderedMapStorage<NodeID, int>>;
|
||||
using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
|
||||
|
||||
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,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 SEGMENT_INFORMATION_H
|
||||
#define SEGMENT_INFORMATION_H
|
||||
|
||||
#include "TurnInstructions.h"
|
||||
|
||||
#include "../DataStructures/TravelMode.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
// Struct fits everything in one cache line
|
||||
struct SegmentInformation
|
||||
{
|
||||
FixedPointCoordinate location;
|
||||
NodeID name_id;
|
||||
EdgeWeight duration;
|
||||
float length;
|
||||
short bearing; // more than enough [0..3600] fits into 12 bits
|
||||
TurnInstruction turn_instruction;
|
||||
TravelMode travel_mode;
|
||||
bool necessary;
|
||||
bool is_via_location;
|
||||
|
||||
explicit SegmentInformation(const FixedPointCoordinate &location,
|
||||
const NodeID name_id,
|
||||
const EdgeWeight duration,
|
||||
const float length,
|
||||
const TurnInstruction turn_instruction,
|
||||
const bool necessary,
|
||||
const bool is_via_location,
|
||||
const TravelMode travel_mode)
|
||||
: location(location), name_id(name_id), duration(duration), length(length), bearing(0),
|
||||
turn_instruction(turn_instruction), travel_mode(travel_mode), necessary(necessary),
|
||||
is_via_location(is_via_location)
|
||||
{
|
||||
}
|
||||
|
||||
explicit SegmentInformation(const FixedPointCoordinate &location,
|
||||
const NodeID name_id,
|
||||
const EdgeWeight duration,
|
||||
const float length,
|
||||
const TurnInstruction turn_instruction,
|
||||
const TravelMode travel_mode)
|
||||
: location(location), name_id(name_id), duration(duration), length(length), bearing(0),
|
||||
turn_instruction(turn_instruction), travel_mode(travel_mode),
|
||||
necessary(turn_instruction != TurnInstruction::NoTurn), is_via_location(false)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SEGMENT_INFORMATION_H */
|
||||
@@ -1,260 +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:
|
||||
using Iterator = unsigned;
|
||||
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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,90 +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 TURN_INSTRUCTIONS_H
|
||||
#define TURN_INSTRUCTIONS_H
|
||||
|
||||
enum class TurnInstruction : unsigned char
|
||||
{
|
||||
NoTurn = 0, GoStraight, TurnSlightRight, TurnRight, TurnSharpRight, UTurn,
|
||||
TurnSharpLeft, TurnLeft, TurnSlightLeft, ReachViaLocation, HeadOn, EnterRoundAbout,
|
||||
LeaveRoundAbout, StayOnRoundAbout, StartAtEndOfStreet, ReachedYourDestination,
|
||||
EnterAgainstAllowedDirection, LeaveAgainstAllowedDirection,
|
||||
InverseAccessRestrictionFlag = 127,
|
||||
AccessRestrictionFlag = 128,
|
||||
AccessRestrictionPenalty = 129
|
||||
};
|
||||
|
||||
struct TurnInstructionsClass
|
||||
{
|
||||
TurnInstructionsClass() = delete;
|
||||
TurnInstructionsClass(const TurnInstructionsClass&) = delete;
|
||||
|
||||
static inline TurnInstruction GetTurnDirectionOfInstruction(const double angle)
|
||||
{
|
||||
if (angle >= 23 && angle < 67)
|
||||
{
|
||||
return TurnInstruction::TurnSharpRight;
|
||||
}
|
||||
if (angle >= 67 && angle < 113)
|
||||
{
|
||||
return TurnInstruction::TurnRight;
|
||||
}
|
||||
if (angle >= 113 && angle < 158)
|
||||
{
|
||||
return TurnInstruction::TurnSlightRight;
|
||||
}
|
||||
if (angle >= 158 && angle < 202)
|
||||
{
|
||||
return TurnInstruction::GoStraight;
|
||||
}
|
||||
if (angle >= 202 && angle < 248)
|
||||
{
|
||||
return TurnInstruction::TurnSlightLeft;
|
||||
}
|
||||
if (angle >= 248 && angle < 292)
|
||||
{
|
||||
return TurnInstruction::TurnLeft;
|
||||
}
|
||||
if (angle >= 292 && angle < 336)
|
||||
{
|
||||
return TurnInstruction::TurnSharpLeft;
|
||||
}
|
||||
return TurnInstruction::UTurn;
|
||||
}
|
||||
|
||||
static inline bool TurnIsNecessary(const TurnInstruction turn_instruction)
|
||||
{
|
||||
if (TurnInstruction::NoTurn == turn_instruction || TurnInstruction::StayOnRoundAbout == turn_instruction)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* TURN_INSTRUCTIONS_H */
|
||||
@@ -1,115 +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 XOR_FAST_HASH_H
|
||||
#define XOR_FAST_HASH_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 // XOR_FAST_HASH_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 XOR_FAST_HASH_STORAGE_H
|
||||
#define XOR_FAST_HASH_STORAGE_H
|
||||
|
||||
#include "XORFastHash.h"
|
||||
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
template <typename NodeID, typename Key> class XORFastHashStorage
|
||||
{
|
||||
public:
|
||||
struct HashCell
|
||||
{
|
||||
Key key;
|
||||
NodeID id;
|
||||
unsigned time;
|
||||
HashCell()
|
||||
: key(std::numeric_limits<unsigned>::max()), id(std::numeric_limits<unsigned>::max()),
|
||||
time(std::numeric_limits<unsigned>::max())
|
||||
{
|
||||
}
|
||||
|
||||
HashCell(const HashCell &other) : key(other.key), id(other.id), time(other.time) {}
|
||||
|
||||
operator Key() const { return key; }
|
||||
|
||||
void operator=(const Key &key_to_insert) { key = key_to_insert; }
|
||||
};
|
||||
|
||||
explicit XORFastHashStorage(size_t) : positions(2 << 16), current_timestamp(0) {}
|
||||
|
||||
HashCell &operator[](const NodeID node)
|
||||
{
|
||||
unsigned short position = fast_hasher(node);
|
||||
while ((positions[position].time == current_timestamp) && (positions[position].id != node))
|
||||
{
|
||||
++position %= (2 << 16);
|
||||
}
|
||||
|
||||
positions[position].id = node;
|
||||
positions[position].time = current_timestamp;
|
||||
return positions[position];
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
++current_timestamp;
|
||||
if (std::numeric_limits<unsigned>::max() == current_timestamp)
|
||||
{
|
||||
positions.clear();
|
||||
positions.resize((2 << 16));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
XORFastHashStorage() : positions(2 << 16), current_timestamp(0) {}
|
||||
std::vector<HashCell> positions;
|
||||
XORFastHash fast_hasher;
|
||||
unsigned current_timestamp;
|
||||
};
|
||||
|
||||
#endif // XOR_FAST_HASH_STORAGE_H
|
||||
@@ -1,61 +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 &raw_route, http::Reply &reply) = 0;
|
||||
virtual void SetConfig(const DescriptorConfig &config) = 0;
|
||||
};
|
||||
|
||||
#endif // BASE_DESCRIPTOR_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 "DescriptionFactory.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../Algorithms/PolylineCompressor.h"
|
||||
#include "../DataStructures/PhantomNodes.h"
|
||||
#include "../DataStructures/RawRouteData.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
|
||||
DescriptionFactory::DescriptionFactory() : entireLength(0) { via_indices.push_back(0); }
|
||||
|
||||
std::vector<unsigned> const &DescriptionFactory::GetViaIndices() const { return via_indices; }
|
||||
|
||||
void DescriptionFactory::SetStartSegment(const PhantomNode &source, const bool traversed_in_reverse)
|
||||
{
|
||||
start_phantom = source;
|
||||
const EdgeWeight segment_duration =
|
||||
(traversed_in_reverse ? source.reverse_weight : source.forward_weight);
|
||||
const TravelMode travel_mode =
|
||||
(traversed_in_reverse ? source.backward_travel_mode : source.forward_travel_mode);
|
||||
AppendSegment(
|
||||
source.location,
|
||||
PathData(0, source.name_id, TurnInstruction::HeadOn, segment_duration, travel_mode));
|
||||
BOOST_ASSERT(path_description.back().duration == segment_duration);
|
||||
}
|
||||
|
||||
void DescriptionFactory::SetEndSegment(const PhantomNode &target,
|
||||
const bool traversed_in_reverse,
|
||||
const bool is_via_location)
|
||||
{
|
||||
target_phantom = target;
|
||||
const EdgeWeight segment_duration =
|
||||
(traversed_in_reverse ? target.reverse_weight : target.forward_weight);
|
||||
const TravelMode travel_mode =
|
||||
(traversed_in_reverse ? target.backward_travel_mode : target.forward_travel_mode);
|
||||
path_description.emplace_back(target.location,
|
||||
target.name_id,
|
||||
segment_duration,
|
||||
0.f,
|
||||
is_via_location ? TurnInstruction::ReachViaLocation
|
||||
: TurnInstruction::NoTurn,
|
||||
true,
|
||||
true,
|
||||
travel_mode);
|
||||
BOOST_ASSERT(path_description.back().duration == segment_duration);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendSegment(const FixedPointCoordinate &coordinate,
|
||||
const PathData &path_point)
|
||||
{
|
||||
// if the start location is on top of a node, the first movement might be zero-length,
|
||||
// in which case we dont' add a new description, but instead update the existing one
|
||||
if ((1 == path_description.size()) && (path_description.front().location == coordinate))
|
||||
{
|
||||
if (path_point.segment_duration > 0)
|
||||
{
|
||||
path_description.front().name_id = path_point.name_id;
|
||||
path_description.front().travel_mode = path_point.travel_mode;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure mode changes are announced, even when there otherwise is no turn
|
||||
const TurnInstruction turn = [&]() -> TurnInstruction
|
||||
{
|
||||
if (TurnInstruction::NoTurn == path_point.turn_instruction &&
|
||||
path_description.front().travel_mode != path_point.travel_mode &&
|
||||
path_point.segment_duration > 0)
|
||||
{
|
||||
return TurnInstruction::GoStraight;
|
||||
}
|
||||
return path_point.turn_instruction;
|
||||
}();
|
||||
|
||||
path_description.emplace_back(coordinate,
|
||||
path_point.name_id,
|
||||
path_point.segment_duration,
|
||||
0.f,
|
||||
turn,
|
||||
path_point.travel_mode);
|
||||
}
|
||||
|
||||
JSON::Value DescriptionFactory::AppendGeometryString(const bool return_encoded)
|
||||
{
|
||||
if (return_encoded)
|
||||
{
|
||||
return polyline_compressor.printEncodedString(path_description);
|
||||
}
|
||||
return polyline_compressor.printUnencodedString(path_description);
|
||||
}
|
||||
|
||||
void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time)
|
||||
{
|
||||
summary.source_name_id = start_phantom.name_id;
|
||||
summary.target_name_id = target_phantom.name_id;
|
||||
summary.BuildDurationAndLengthStrings(distance, time);
|
||||
}
|
||||
@@ -1,218 +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/SegmentInformation.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
struct PathData;
|
||||
/* 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;
|
||||
|
||||
std::vector<unsigned> via_indices;
|
||||
|
||||
public:
|
||||
struct RouteSummary
|
||||
{
|
||||
unsigned distance;
|
||||
EdgeWeight duration;
|
||||
unsigned source_name_id;
|
||||
unsigned target_name_id;
|
||||
RouteSummary() : distance(0), duration(0), source_name_id(0), target_name_id(0) {}
|
||||
|
||||
void BuildDurationAndLengthStrings(const double raw_distance, const unsigned raw_duration)
|
||||
{
|
||||
// compute distance/duration for route summary
|
||||
distance = static_cast<unsigned>(round(raw_distance));
|
||||
duration = static_cast<unsigned>(round(raw_duration / 10.));
|
||||
}
|
||||
} summary;
|
||||
|
||||
double entireLength;
|
||||
|
||||
// I know, declaring this public is considered bad. I'm lazy
|
||||
std::vector<SegmentInformation> path_description;
|
||||
DescriptionFactory();
|
||||
void AppendSegment(const FixedPointCoordinate &coordinate, const PathData &data);
|
||||
void BuildRouteSummary(const double distance, const unsigned time);
|
||||
void SetStartSegment(const PhantomNode &start_phantom, const bool traversed_in_reverse);
|
||||
void SetEndSegment(const PhantomNode &start_phantom,
|
||||
const bool traversed_in_reverse,
|
||||
const bool is_via_location = false);
|
||||
JSON::Value AppendGeometryString(const bool return_encoded);
|
||||
std::vector<unsigned> const &GetViaIndices() const;
|
||||
|
||||
template <class DataFacadeT> void Run(const DataFacadeT *facade, const unsigned zoomLevel)
|
||||
{
|
||||
if (path_description.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/** starts at index 1 */
|
||||
path_description[0].length = 0;
|
||||
for (unsigned i = 1; i < path_description.size(); ++i)
|
||||
{
|
||||
// move down names by one, q&d hack
|
||||
path_description[i - 1].name_id = path_description[i].name_id;
|
||||
path_description[i].length = FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
path_description[i - 1].location, path_description[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 < path_description.size(); ++i) {
|
||||
// string1 = sEngine.GetEscapedNameForNameID(path_description[i].name_id);
|
||||
// if(TurnInstruction::GoStraight == path_description[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)
|
||||
// path_description[lastTurn].name_id = path_description[i].name_id;
|
||||
// path_description[i].turn_instruction = TurnInstruction::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;
|
||||
// path_description[i].name_id = path_description[i-1].name_id;
|
||||
// path_description[i].turn_instruction = TurnInstruction::NoTurn;
|
||||
// }
|
||||
// }
|
||||
// if (TurnInstruction::NoTurn != path_description[i].turn_instruction) {
|
||||
// lastTurn = i;
|
||||
// }
|
||||
// string0 = string1;
|
||||
// }
|
||||
|
||||
float segment_length = 0.;
|
||||
unsigned segment_duration = 0;
|
||||
unsigned segment_start_index = 0;
|
||||
|
||||
for (unsigned i = 1; i < path_description.size(); ++i)
|
||||
{
|
||||
entireLength += path_description[i].length;
|
||||
segment_length += path_description[i].length;
|
||||
segment_duration += path_description[i].duration;
|
||||
path_description[segment_start_index].length = segment_length;
|
||||
path_description[segment_start_index].duration = segment_duration;
|
||||
|
||||
if (TurnInstruction::NoTurn != path_description[i].turn_instruction)
|
||||
{
|
||||
BOOST_ASSERT(path_description[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() > path_description.back().length)
|
||||
{
|
||||
if (path_description.size() > 2)
|
||||
{
|
||||
path_description.pop_back();
|
||||
path_description.back().necessary = true;
|
||||
path_description.back().turn_instruction = TurnInstruction::NoTurn;
|
||||
target_phantom.name_id = (path_description.end() - 2)->name_id;
|
||||
}
|
||||
}
|
||||
if (std::numeric_limits<double>::epsilon() > path_description.front().length)
|
||||
{
|
||||
if (path_description.size() > 2)
|
||||
{
|
||||
path_description.erase(path_description.begin());
|
||||
path_description.front().turn_instruction = TurnInstruction::HeadOn;
|
||||
path_description.front().necessary = true;
|
||||
start_phantom.name_id = path_description.front().name_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Generalize poly line
|
||||
polyline_generalizer.Run(path_description, zoomLevel);
|
||||
|
||||
// fix what needs to be fixed else
|
||||
unsigned necessary_pieces = 0; // a running index that counts the necessary pieces
|
||||
for (unsigned i = 0; i < path_description.size() - 1 && path_description.size() >= 2; ++i)
|
||||
{
|
||||
if (path_description[i].necessary)
|
||||
{
|
||||
++necessary_pieces;
|
||||
if (path_description[i].is_via_location)
|
||||
{ // mark the end of a leg
|
||||
via_indices.push_back(necessary_pieces);
|
||||
}
|
||||
const double angle =
|
||||
path_description[i + 1].location.GetBearing(path_description[i].location);
|
||||
path_description[i].bearing = static_cast<unsigned>(angle * 10);
|
||||
}
|
||||
}
|
||||
via_indices.push_back(necessary_pieces + 1);
|
||||
BOOST_ASSERT(via_indices.size() >= 2);
|
||||
// BOOST_ASSERT(0 != necessary_pieces || path_description.empty());
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* DESCRIPTIONFACTORY_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 GPX_DESCRIPTOR_H
|
||||
#define GPX_DESCRIPTOR_H
|
||||
|
||||
#include "BaseDescriptor.h"
|
||||
|
||||
template <class DataFacadeT> class GPXDescriptor final : public BaseDescriptor<DataFacadeT>
|
||||
{
|
||||
private:
|
||||
DescriptorConfig config;
|
||||
FixedPointCoordinate current;
|
||||
DataFacadeT *facade;
|
||||
|
||||
void AddRoutePoint(const FixedPointCoordinate &coordinate, std::vector<char> &output)
|
||||
{
|
||||
const std::string route_point_head = "<rtept lat=\"";
|
||||
const std::string route_point_middle = " lon=\"";
|
||||
const std::string route_point_tail = "\"></rtept>";
|
||||
|
||||
std::string tmp;
|
||||
|
||||
FixedPointCoordinate::convertInternalLatLonToString(coordinate.lat, tmp);
|
||||
output.insert(output.end(), route_point_head.begin(), route_point_head.end());
|
||||
output.insert(output.end(), tmp.begin(), tmp.end());
|
||||
output.push_back('\"');
|
||||
|
||||
FixedPointCoordinate::convertInternalLatLonToString(coordinate.lon, tmp);
|
||||
output.insert(output.end(), route_point_middle.begin(), route_point_middle.end());
|
||||
output.insert(output.end(), tmp.begin(), tmp.end());
|
||||
output.insert(output.end(), route_point_tail.begin(), route_point_tail.end());
|
||||
}
|
||||
|
||||
public:
|
||||
explicit GPXDescriptor(DataFacadeT *facade) : facade(facade) {}
|
||||
|
||||
void SetConfig(const DescriptorConfig &c) final { config = c; }
|
||||
|
||||
// TODO: reorder parameters
|
||||
void Run(const RawRouteData &raw_route, http::Reply &reply) final
|
||||
{
|
||||
std::string header("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||
"<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"
|
||||
"\">"
|
||||
"<metadata><copyright author=\"Project OSRM\"><license>Data (c)"
|
||||
" OpenStreetMap contributors (ODbL)</license></copyright>"
|
||||
"</metadata>"
|
||||
"<rte>");
|
||||
reply.content.insert(reply.content.end(), header.begin(), header.end());
|
||||
const bool found_route = (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT) &&
|
||||
(!raw_route.unpacked_path_segments.front().empty());
|
||||
if (found_route)
|
||||
{
|
||||
AddRoutePoint(raw_route.segment_end_coordinates.front().source_phantom.location,
|
||||
reply.content);
|
||||
|
||||
for (const std::vector<PathData> &path_data_vector : raw_route.unpacked_path_segments)
|
||||
{
|
||||
for (const PathData &path_data : path_data_vector)
|
||||
{
|
||||
const FixedPointCoordinate current_coordinate =
|
||||
facade->GetCoordinateOfNode(path_data.node);
|
||||
AddRoutePoint(current_coordinate, reply.content);
|
||||
}
|
||||
}
|
||||
AddRoutePoint(raw_route.segment_end_coordinates.back().target_phantom.location,
|
||||
reply.content);
|
||||
}
|
||||
std::string footer("</rte></gpx>");
|
||||
reply.content.insert(reply.content.end(), footer.begin(), footer.end());
|
||||
}
|
||||
};
|
||||
#endif // GPX_DESCRIPTOR_H
|
||||
@@ -1,391 +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 "../Algorithms/ExtractRouteNames.h"
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "../DataStructures/Range.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../Util/Azimuth.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
template <class DataFacadeT> class JSONDescriptor final : public BaseDescriptor<DataFacadeT>
|
||||
{
|
||||
private:
|
||||
DataFacadeT *facade;
|
||||
DescriptorConfig config;
|
||||
DescriptionFactory description_factory, alternate_description_factory;
|
||||
FixedPointCoordinate current;
|
||||
unsigned entered_restricted_area_count;
|
||||
struct RoundAbout
|
||||
{
|
||||
RoundAbout() : start_index(INT_MAX), name_id(INVALID_NAMEID), leave_at_exit(INT_MAX) {}
|
||||
int start_index;
|
||||
unsigned name_id;
|
||||
int leave_at_exit;
|
||||
} round_about;
|
||||
|
||||
struct Segment
|
||||
{
|
||||
Segment() : name_id(INVALID_NAMEID), length(-1), position(0) {}
|
||||
Segment(unsigned n, int l, unsigned p) : name_id(n), length(l), position(p) {}
|
||||
unsigned name_id;
|
||||
int length;
|
||||
unsigned position;
|
||||
};
|
||||
std::vector<Segment> shortest_path_segments, alternative_path_segments;
|
||||
ExtractRouteNames<DataFacadeT, Segment> GenerateRouteNames;
|
||||
|
||||
public:
|
||||
explicit JSONDescriptor(DataFacadeT *facade) : facade(facade), entered_restricted_area_count(0) {}
|
||||
|
||||
void SetConfig(const DescriptorConfig &c) final { config = c; }
|
||||
|
||||
unsigned DescribeLeg(const std::vector<PathData> route_leg,
|
||||
const PhantomNodes &leg_phantoms,
|
||||
const bool target_traversed_in_reverse,
|
||||
const bool is_via_leg)
|
||||
{
|
||||
unsigned added_element_count = 0;
|
||||
// Get all the coordinates for the computed route
|
||||
FixedPointCoordinate current_coordinate;
|
||||
for (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, target_traversed_in_reverse, is_via_leg);
|
||||
++added_element_count;
|
||||
BOOST_ASSERT((route_leg.size() + 1) == added_element_count);
|
||||
return added_element_count;
|
||||
}
|
||||
|
||||
void Run(const RawRouteData &raw_route, http::Reply &reply) final
|
||||
{
|
||||
JSON::Object json_result;
|
||||
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
|
||||
{
|
||||
// We do not need to do much, if there is no route ;-)
|
||||
json_result.values["status"] = 207;
|
||||
json_result.values["status_message"] = "Cannot find route between points";
|
||||
JSON::render(reply.content, json_result);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if first segment is non-zero
|
||||
std::string road_name = facade->GetEscapedNameForNameID(
|
||||
raw_route.segment_end_coordinates.front().source_phantom.name_id);
|
||||
|
||||
BOOST_ASSERT(raw_route.unpacked_path_segments.size() ==
|
||||
raw_route.segment_end_coordinates.size());
|
||||
|
||||
description_factory.SetStartSegment(
|
||||
raw_route.segment_end_coordinates.front().source_phantom,
|
||||
raw_route.source_traversed_in_reverse.front());
|
||||
json_result.values["status"] = 0;
|
||||
json_result.values["status_message"] = "Found route between points";
|
||||
|
||||
// for each unpacked segment add the leg to the description
|
||||
for (const auto i : osrm::irange<std::size_t>(0, raw_route.unpacked_path_segments.size()))
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
const int added_segments =
|
||||
#endif
|
||||
DescribeLeg(raw_route.unpacked_path_segments[i],
|
||||
raw_route.segment_end_coordinates[i],
|
||||
raw_route.target_traversed_in_reverse[i],
|
||||
raw_route.is_via_leg(i));
|
||||
BOOST_ASSERT(0 < added_segments);
|
||||
}
|
||||
description_factory.Run(facade, config.zoom_level);
|
||||
|
||||
if (config.geometry)
|
||||
{
|
||||
JSON::Value route_geometry =
|
||||
description_factory.AppendGeometryString(config.encode_geometry);
|
||||
json_result.values["route_geometry"] = route_geometry;
|
||||
}
|
||||
if (config.instructions)
|
||||
{
|
||||
JSON::Array json_route_instructions;
|
||||
BuildTextualDescription(description_factory,
|
||||
json_route_instructions,
|
||||
raw_route.shortest_path_length,
|
||||
shortest_path_segments);
|
||||
json_result.values["route_instructions"] = json_route_instructions;
|
||||
}
|
||||
description_factory.BuildRouteSummary(description_factory.entireLength,
|
||||
raw_route.shortest_path_length);
|
||||
JSON::Object json_route_summary;
|
||||
json_route_summary.values["total_distance"] = description_factory.summary.distance;
|
||||
json_route_summary.values["total_time"] = description_factory.summary.duration;
|
||||
json_route_summary.values["start_point"] =
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.source_name_id);
|
||||
json_route_summary.values["end_point"] =
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.target_name_id);
|
||||
json_result.values["route_summary"] = json_route_summary;
|
||||
|
||||
BOOST_ASSERT(!raw_route.segment_end_coordinates.empty());
|
||||
|
||||
JSON::Array json_via_points_array;
|
||||
JSON::Array json_first_coordinate;
|
||||
json_first_coordinate.values.push_back(
|
||||
raw_route.segment_end_coordinates.front().source_phantom.location.lat /
|
||||
COORDINATE_PRECISION);
|
||||
json_first_coordinate.values.push_back(
|
||||
raw_route.segment_end_coordinates.front().source_phantom.location.lon /
|
||||
COORDINATE_PRECISION);
|
||||
json_via_points_array.values.push_back(json_first_coordinate);
|
||||
for (const PhantomNodes &nodes : raw_route.segment_end_coordinates)
|
||||
{
|
||||
std::string tmp;
|
||||
JSON::Array json_coordinate;
|
||||
json_coordinate.values.push_back(nodes.target_phantom.location.lat /
|
||||
COORDINATE_PRECISION);
|
||||
json_coordinate.values.push_back(nodes.target_phantom.location.lon /
|
||||
COORDINATE_PRECISION);
|
||||
json_via_points_array.values.push_back(json_coordinate);
|
||||
}
|
||||
json_result.values["via_points"] = json_via_points_array;
|
||||
|
||||
JSON::Array json_via_indices_array;
|
||||
|
||||
std::vector<unsigned> const &shortest_leg_end_indices = description_factory.GetViaIndices();
|
||||
json_via_indices_array.values.insert(json_via_indices_array.values.end(),
|
||||
shortest_leg_end_indices.begin(),
|
||||
shortest_leg_end_indices.end());
|
||||
json_result.values["via_indices"] = json_via_indices_array;
|
||||
|
||||
// only one alternative route is computed at this time, so this is hardcoded
|
||||
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
json_result.values["found_alternative"] = JSON::True();
|
||||
BOOST_ASSERT(!raw_route.alt_source_traversed_in_reverse.empty());
|
||||
alternate_description_factory.SetStartSegment(
|
||||
raw_route.segment_end_coordinates.front().source_phantom,
|
||||
raw_route.alt_source_traversed_in_reverse.front());
|
||||
// Get all the coordinates for the computed route
|
||||
for (const PathData &path_data : raw_route.unpacked_alternative)
|
||||
{
|
||||
current = facade->GetCoordinateOfNode(path_data.node);
|
||||
alternate_description_factory.AppendSegment(current, path_data);
|
||||
}
|
||||
alternate_description_factory.SetEndSegment(
|
||||
raw_route.segment_end_coordinates.back().target_phantom,
|
||||
raw_route.alt_source_traversed_in_reverse.back());
|
||||
alternate_description_factory.Run(facade, config.zoom_level);
|
||||
|
||||
if (config.geometry)
|
||||
{
|
||||
JSON::Value alternate_geometry_string =
|
||||
alternate_description_factory.AppendGeometryString(config.encode_geometry);
|
||||
JSON::Array json_alternate_geometries_array;
|
||||
json_alternate_geometries_array.values.push_back(alternate_geometry_string);
|
||||
json_result.values["alternative_geometries"] = json_alternate_geometries_array;
|
||||
}
|
||||
// Generate instructions for each alternative (simulated here)
|
||||
JSON::Array json_alt_instructions;
|
||||
JSON::Array json_current_alt_instructions;
|
||||
if (config.instructions)
|
||||
{
|
||||
BuildTextualDescription(alternate_description_factory,
|
||||
json_current_alt_instructions,
|
||||
raw_route.alternative_path_length,
|
||||
alternative_path_segments);
|
||||
json_alt_instructions.values.push_back(json_current_alt_instructions);
|
||||
json_result.values["alternative_instructions"] = json_alt_instructions;
|
||||
}
|
||||
alternate_description_factory.BuildRouteSummary(
|
||||
alternate_description_factory.entireLength, raw_route.alternative_path_length);
|
||||
|
||||
JSON::Object json_alternate_route_summary;
|
||||
JSON::Array json_alternate_route_summary_array;
|
||||
json_alternate_route_summary.values["total_distance"] =
|
||||
alternate_description_factory.summary.distance;
|
||||
json_alternate_route_summary.values["total_time"] =
|
||||
alternate_description_factory.summary.duration;
|
||||
json_alternate_route_summary.values["start_point"] = facade->GetEscapedNameForNameID(
|
||||
alternate_description_factory.summary.source_name_id);
|
||||
json_alternate_route_summary.values["end_point"] = facade->GetEscapedNameForNameID(
|
||||
alternate_description_factory.summary.target_name_id);
|
||||
json_alternate_route_summary_array.values.push_back(json_alternate_route_summary);
|
||||
json_result.values["alternative_summaries"] = json_alternate_route_summary_array;
|
||||
|
||||
std::vector<unsigned> const &alternate_leg_end_indices =
|
||||
alternate_description_factory.GetViaIndices();
|
||||
JSON::Array json_altenative_indices_array;
|
||||
json_altenative_indices_array.values.insert(json_altenative_indices_array.values.end(),
|
||||
alternate_leg_end_indices.begin(),
|
||||
alternate_leg_end_indices.end());
|
||||
json_result.values["alternative_indices"] = json_altenative_indices_array;
|
||||
}
|
||||
else
|
||||
{
|
||||
json_result.values["found_alternative"] = JSON::False();
|
||||
}
|
||||
|
||||
// Get Names for both routes
|
||||
RouteNames route_names =
|
||||
GenerateRouteNames(shortest_path_segments, alternative_path_segments, facade);
|
||||
JSON::Array json_route_names;
|
||||
json_route_names.values.push_back(route_names.shortest_path_name_1);
|
||||
json_route_names.values.push_back(route_names.shortest_path_name_2);
|
||||
json_result.values["route_name"] = json_route_names;
|
||||
|
||||
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
JSON::Array json_alternate_names_array;
|
||||
JSON::Array json_alternate_names;
|
||||
json_alternate_names.values.push_back(route_names.alternative_path_name_1);
|
||||
json_alternate_names.values.push_back(route_names.alternative_path_name_2);
|
||||
json_alternate_names_array.values.push_back(json_alternate_names);
|
||||
json_result.values["alternative_names"] = json_alternate_names_array;
|
||||
}
|
||||
|
||||
JSON::Object json_hint_object;
|
||||
json_hint_object.values["checksum"] = raw_route.check_sum;
|
||||
JSON::Array json_location_hint_array;
|
||||
std::string hint;
|
||||
for (const auto i : osrm::irange<std::size_t>(0, raw_route.segment_end_coordinates.size()))
|
||||
{
|
||||
ObjectEncoder::EncodeToBase64(raw_route.segment_end_coordinates[i].source_phantom, hint);
|
||||
json_location_hint_array.values.push_back(hint);
|
||||
}
|
||||
ObjectEncoder::EncodeToBase64(raw_route.segment_end_coordinates.back().target_phantom, hint);
|
||||
json_location_hint_array.values.push_back(hint);
|
||||
json_hint_object.values["locations"] = json_location_hint_array;
|
||||
json_result.values["hint_data"] = json_hint_object;
|
||||
|
||||
// render the content to the output array
|
||||
TIMER_START(route_render);
|
||||
JSON::render(reply.content, json_result);
|
||||
TIMER_STOP(route_render);
|
||||
SimpleLogger().Write(logDEBUG) << "rendering took: " << TIMER_MSEC(route_render);
|
||||
}
|
||||
|
||||
// TODO: reorder parameters
|
||||
inline void BuildTextualDescription(DescriptionFactory &description_factory,
|
||||
JSON::Array &json_instruction_array,
|
||||
const int route_length,
|
||||
std::vector<Segment> &route_segments_list)
|
||||
{
|
||||
// Segment information has following format:
|
||||
//["instruction id","streetname",length,position,time,"length","earth_direction",azimuth]
|
||||
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.
|
||||
for (const SegmentInformation &segment : description_factory.path_description)
|
||||
{
|
||||
JSON::Array json_instruction_row;
|
||||
TurnInstruction current_instruction = segment.turn_instruction;
|
||||
entered_restricted_area_count += (current_instruction != segment.turn_instruction);
|
||||
if (TurnInstructionsClass::TurnIsNecessary(current_instruction))
|
||||
{
|
||||
if (TurnInstruction::EnterRoundAbout == current_instruction)
|
||||
{
|
||||
round_about.name_id = segment.name_id;
|
||||
round_about.start_index = necessary_segments_running_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string current_turn_instruction;
|
||||
if (TurnInstruction::LeaveRoundAbout == current_instruction)
|
||||
{
|
||||
temp_instruction =
|
||||
cast::integral_to_string(cast::enum_to_underlying(TurnInstruction::EnterRoundAbout));
|
||||
current_turn_instruction += temp_instruction;
|
||||
current_turn_instruction += "-";
|
||||
temp_instruction = cast::integral_to_string(round_about.leave_at_exit + 1);
|
||||
current_turn_instruction += temp_instruction;
|
||||
round_about.leave_at_exit = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp_instruction = cast::integral_to_string(cast::enum_to_underlying(current_instruction));
|
||||
current_turn_instruction += temp_instruction;
|
||||
}
|
||||
json_instruction_row.values.push_back(current_turn_instruction);
|
||||
|
||||
json_instruction_row.values.push_back(
|
||||
facade->GetEscapedNameForNameID(segment.name_id));
|
||||
json_instruction_row.values.push_back(std::round(segment.length));
|
||||
json_instruction_row.values.push_back(necessary_segments_running_index);
|
||||
json_instruction_row.values.push_back(round(segment.duration / 10));
|
||||
json_instruction_row.values.push_back(
|
||||
cast::integral_to_string(static_cast<unsigned>(segment.length)) + "m");
|
||||
const double bearing_value = (segment.bearing / 10.);
|
||||
json_instruction_row.values.push_back(Azimuth::Get(bearing_value));
|
||||
json_instruction_row.values.push_back(
|
||||
static_cast<unsigned>(round(bearing_value)));
|
||||
json_instruction_row.values.push_back(segment.travel_mode);
|
||||
|
||||
route_segments_list.emplace_back(
|
||||
segment.name_id,
|
||||
static_cast<int>(segment.length),
|
||||
static_cast<unsigned>(route_segments_list.size()));
|
||||
json_instruction_array.values.push_back(json_instruction_row);
|
||||
}
|
||||
}
|
||||
else if (TurnInstruction::StayOnRoundAbout == current_instruction)
|
||||
{
|
||||
++round_about.leave_at_exit;
|
||||
}
|
||||
if (segment.necessary)
|
||||
{
|
||||
++necessary_segments_running_index;
|
||||
}
|
||||
}
|
||||
|
||||
JSON::Array json_last_instruction_row;
|
||||
temp_instruction = cast::integral_to_string(cast::enum_to_underlying(TurnInstruction::ReachedYourDestination));
|
||||
json_last_instruction_row.values.push_back(temp_instruction);
|
||||
json_last_instruction_row.values.push_back("");
|
||||
json_last_instruction_row.values.push_back(0);
|
||||
json_last_instruction_row.values.push_back(necessary_segments_running_index - 1);
|
||||
json_last_instruction_row.values.push_back(0);
|
||||
json_last_instruction_row.values.push_back("0m");
|
||||
json_last_instruction_row.values.push_back(Azimuth::Get(0.0));
|
||||
json_last_instruction_row.values.push_back(0.);
|
||||
json_instruction_array.values.push_back(json_last_instruction_row);
|
||||
}
|
||||
};
|
||||
|
||||
#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,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 "BaseParser.h"
|
||||
#include "ExtractionWay.h"
|
||||
#include "ScriptingEnvironment.h"
|
||||
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
#include "../Util/LuaUtil.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/simple_logger.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/regex.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
BaseParser::BaseParser(ExtractorCallbacks *extractor_callbacks,
|
||||
ScriptingEnvironment &scripting_environment)
|
||||
: extractor_callbacks(extractor_callbacks),
|
||||
lua_state(scripting_environment.getLuaState()),
|
||||
scripting_environment(scripting_environment), use_turn_restrictions(true)
|
||||
{
|
||||
ReadUseRestrictionsSetting();
|
||||
ReadRestrictionExceptions();
|
||||
}
|
||||
|
||||
void BaseParser::ReadUseRestrictionsSetting()
|
||||
{
|
||||
if (0 != luaL_dostring(lua_state, "return use_turn_restrictions\n"))
|
||||
{
|
||||
use_turn_restrictions = false;
|
||||
}
|
||||
else 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:";
|
||||
for (const std::string &str : restriction_exceptions)
|
||||
{
|
||||
SimpleLogger().Write() << " " << str;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SimpleLogger().Write() << "Found no exceptions to turn restrictions";
|
||||
}
|
||||
}
|
||||
|
||||
void BaseParser::report_errors(lua_State *lua_state, const int status) const
|
||||
{
|
||||
if (0 != status)
|
||||
{
|
||||
std::cerr << "-- " << lua_tostring(lua_state, -1) << std::endl;
|
||||
lua_pop(lua_state, 1); // remove error message
|
||||
}
|
||||
}
|
||||
|
||||
void BaseParser::ParseNodeInLua(ImportNode &node, lua_State *local_lua_state)
|
||||
{
|
||||
luabind::call_function<void>(local_lua_state, "node_function", boost::ref(node));
|
||||
}
|
||||
|
||||
void BaseParser::ParseWayInLua(ExtractionWay &way, lua_State *local_lua_state)
|
||||
{
|
||||
luabind::call_function<void>(local_lua_state, "way_function", boost::ref(way));
|
||||
}
|
||||
|
||||
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("[;][ ]*"));
|
||||
for (std::string ¤t_string : exceptions)
|
||||
{
|
||||
const auto string_iterator =
|
||||
std::find(restriction_exceptions.begin(), restriction_exceptions.end(), current_string);
|
||||
if (restriction_exceptions.end() != string_iterator)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -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 BASEPARSER_H_
|
||||
#define BASEPARSER_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct lua_State;
|
||||
class ExtractorCallbacks;
|
||||
class ScriptingEnvironment;
|
||||
struct ExtractionWay;
|
||||
struct ImportNode;
|
||||
|
||||
class BaseParser
|
||||
{
|
||||
public:
|
||||
BaseParser() = delete;
|
||||
BaseParser(const BaseParser &) = delete;
|
||||
BaseParser(ExtractorCallbacks *extractor_callbacks,
|
||||
ScriptingEnvironment &scripting_environment);
|
||||
virtual ~BaseParser() {}
|
||||
virtual bool ReadHeader() = 0;
|
||||
virtual bool Parse() = 0;
|
||||
|
||||
virtual void ParseNodeInLua(ImportNode &node, lua_State *lua_state);
|
||||
virtual void ParseWayInLua(ExtractionWay &way, lua_State *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,430 +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/OSRMException.h"
|
||||
#include "../Util/simple_logger.hpp"
|
||||
#include "../Util/TimingUtil.h"
|
||||
#include "../DataStructures/RangeTable.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
#include <stxxl/sort>
|
||||
|
||||
#include <chrono>
|
||||
#include <limits>
|
||||
|
||||
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;
|
||||
|
||||
std::cout << "[extractor] Sorting used nodes ... " << std::flush;
|
||||
TIMER_START(sorting_used_nodes);
|
||||
stxxl::sort(used_node_id_list.begin(), used_node_id_list.end(), Cmp(), stxxl_memory);
|
||||
TIMER_STOP(sorting_used_nodes);
|
||||
std::cout << "ok, after " << TIMER_SEC(sorting_used_nodes) << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] Erasing duplicate nodes ... " << std::flush;
|
||||
TIMER_START(erasing_dups);
|
||||
auto new_end = std::unique(used_node_id_list.begin(), used_node_id_list.end());
|
||||
used_node_id_list.resize(new_end - used_node_id_list.begin());
|
||||
TIMER_STOP(erasing_dups);
|
||||
std::cout << "ok, after " << TIMER_SEC(erasing_dups) << "s" << std::endl;
|
||||
|
||||
|
||||
std::cout << "[extractor] Sorting all nodes ... " << std::flush;
|
||||
TIMER_START(sorting_nodes);
|
||||
stxxl::sort(all_nodes_list.begin(), all_nodes_list.end(), CmpNodeByID(), stxxl_memory);
|
||||
TIMER_STOP(sorting_nodes);
|
||||
std::cout << "ok, after " << TIMER_SEC(sorting_nodes) << "s" << std::endl;
|
||||
|
||||
|
||||
std::cout << "[extractor] Sorting used ways ... " << std::flush;
|
||||
TIMER_START(sort_ways);
|
||||
stxxl::sort(
|
||||
way_start_end_id_list.begin(), way_start_end_id_list.end(), CmpWayByID(), stxxl_memory);
|
||||
TIMER_STOP(sort_ways);
|
||||
std::cout << "ok, after " << TIMER_SEC(sort_ways) << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] Sorting restrictions. by from... " << std::flush;
|
||||
TIMER_START(sort_restrictions);
|
||||
stxxl::sort(restrictions_list.begin(),
|
||||
restrictions_list.end(),
|
||||
CmpRestrictionContainerByFrom(),
|
||||
stxxl_memory);
|
||||
TIMER_STOP(sort_restrictions);
|
||||
std::cout << "ok, after " << TIMER_SEC(sort_restrictions) << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] Fixing restriction starts ... " << std::flush;
|
||||
TIMER_START(fix_restriction_starts);
|
||||
auto restrictions_iterator = restrictions_list.begin();
|
||||
auto 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);
|
||||
const 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;
|
||||
}
|
||||
|
||||
TIMER_STOP(fix_restriction_starts);
|
||||
std::cout << "ok, after " << TIMER_SEC(fix_restriction_starts) << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] Sorting restrictions. by to ... " << std::flush;
|
||||
TIMER_START(sort_restrictions_to);
|
||||
stxxl::sort(restrictions_list.begin(),
|
||||
restrictions_list.end(),
|
||||
CmpRestrictionContainerByTo(),
|
||||
stxxl_memory);
|
||||
TIMER_STOP(sort_restrictions_to);
|
||||
std::cout << "ok, after " << TIMER_SEC(sort_restrictions_to) << "s" << std::endl;
|
||||
|
||||
unsigned number_of_useable_restrictions = 0;
|
||||
std::cout << "[extractor] Fixing restriction ends ... " << std::flush;
|
||||
TIMER_START(fix_restriction_ends);
|
||||
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 (std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.fromNode &&
|
||||
std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.toNode)
|
||||
{
|
||||
++number_of_useable_restrictions;
|
||||
}
|
||||
++restrictions_iterator;
|
||||
}
|
||||
TIMER_STOP(fix_restriction_ends);
|
||||
std::cout << "ok, after " << TIMER_SEC(fix_restriction_ends) << "s" << std::endl;
|
||||
|
||||
SimpleLogger().Write() << "usable restrictions: " << number_of_useable_restrictions;
|
||||
// serialize restrictions
|
||||
std::ofstream restrictions_out_stream;
|
||||
restrictions_out_stream.open(restrictions_file_name.c_str(), std::ios::binary);
|
||||
restrictions_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
|
||||
restrictions_out_stream.write((char *)&number_of_useable_restrictions, sizeof(unsigned));
|
||||
|
||||
for(const auto & restriction_container : restrictions_list)
|
||||
{
|
||||
if (std::numeric_limits<unsigned>::max() != restriction_container.restriction.fromNode &&
|
||||
std::numeric_limits<unsigned>::max() != restriction_container.restriction.toNode)
|
||||
{
|
||||
restrictions_out_stream.write((char *)&(restriction_container.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 *)&fingerprint, sizeof(FingerPrint));
|
||||
file_out_stream.write((char *)&number_of_used_nodes, sizeof(unsigned));
|
||||
std::cout << "[extractor] Confirming/Writing used nodes ... " << std::flush;
|
||||
TIMER_START(write_nodes);
|
||||
// identify all used nodes by a merging step of two sorted lists
|
||||
auto node_iterator = all_nodes_list.begin();
|
||||
auto 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->node_id)
|
||||
{
|
||||
++node_id_iterator;
|
||||
continue;
|
||||
}
|
||||
if (*node_id_iterator > node_iterator->node_id)
|
||||
{
|
||||
++node_iterator;
|
||||
continue;
|
||||
}
|
||||
BOOST_ASSERT(*node_id_iterator == node_iterator->node_id);
|
||||
|
||||
file_out_stream.write((char *)&(*node_iterator), sizeof(ExternalMemoryNode));
|
||||
|
||||
++number_of_used_nodes;
|
||||
++node_id_iterator;
|
||||
++node_iterator;
|
||||
}
|
||||
|
||||
TIMER_STOP(write_nodes);
|
||||
std::cout << "ok, after " << TIMER_SEC(write_nodes) << "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(FingerPrint));
|
||||
file_out_stream.write((char *)&number_of_used_nodes, sizeof(unsigned));
|
||||
file_out_stream.seekp(previous_file_position);
|
||||
|
||||
std::cout << "ok" << std::endl;
|
||||
|
||||
// Sort edges by start.
|
||||
std::cout << "[extractor] Sorting edges by start ... " << std::flush;
|
||||
TIMER_START(sort_edges_by_start);
|
||||
stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByStartID(), stxxl_memory);
|
||||
TIMER_STOP(sort_edges_by_start);
|
||||
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_start) << "s" << std::endl;
|
||||
|
||||
|
||||
std::cout << "[extractor] Setting start coords ... " << std::flush;
|
||||
TIMER_START(set_start_coords);
|
||||
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();
|
||||
auto 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->node_id)
|
||||
{
|
||||
++edge_iterator;
|
||||
continue;
|
||||
}
|
||||
if (edge_iterator->start > node_iterator->node_id)
|
||||
{
|
||||
node_iterator++;
|
||||
continue;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(edge_iterator->start == node_iterator->node_id);
|
||||
edge_iterator->source_coordinate.lat = node_iterator->lat;
|
||||
edge_iterator->source_coordinate.lon = node_iterator->lon;
|
||||
++edge_iterator;
|
||||
}
|
||||
TIMER_STOP(set_start_coords);
|
||||
std::cout << "ok, after " << TIMER_SEC(set_start_coords) << "s" << std::endl;
|
||||
|
||||
// Sort Edges by target
|
||||
std::cout << "[extractor] Sorting edges by target ... " << std::flush;
|
||||
TIMER_START(sort_edges_by_target);
|
||||
stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByTargetID(), stxxl_memory);
|
||||
TIMER_STOP(sort_edges_by_target);
|
||||
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_target) << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] Setting target coords ... " << std::flush;
|
||||
TIMER_START(set_target_coords);
|
||||
// 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->node_id)
|
||||
{
|
||||
++edge_iterator;
|
||||
continue;
|
||||
}
|
||||
if (edge_iterator->target > node_iterator->node_id)
|
||||
{
|
||||
++node_iterator;
|
||||
continue;
|
||||
}
|
||||
BOOST_ASSERT(edge_iterator->target == node_iterator->node_id);
|
||||
if (edge_iterator->source_coordinate.lat != std::numeric_limits<int>::min() &&
|
||||
edge_iterator->source_coordinate.lon != std::numeric_limits<int>::min())
|
||||
{
|
||||
BOOST_ASSERT(edge_iterator->speed != -1);
|
||||
edge_iterator->target_coordinate.lat = node_iterator->lat;
|
||||
edge_iterator->target_coordinate.lon = node_iterator->lon;
|
||||
|
||||
const double distance = FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
edge_iterator->source_coordinate.lat,
|
||||
edge_iterator->source_coordinate.lon,
|
||||
node_iterator->lat,
|
||||
node_iterator->lon);
|
||||
|
||||
const double weight = (distance * 10.) / (edge_iterator->speed / 3.6);
|
||||
int integer_weight = std::max(
|
||||
1,
|
||||
(int)std::floor(
|
||||
(edge_iterator->is_duration_set ? 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));
|
||||
file_out_stream.write((char *)&edge_iterator->name_id, sizeof(unsigned));
|
||||
file_out_stream.write((char *)&edge_iterator->is_roundabout, sizeof(bool));
|
||||
file_out_stream.write((char *)&edge_iterator->is_in_tiny_cc, sizeof(bool));
|
||||
file_out_stream.write((char *)&edge_iterator->is_access_restricted, sizeof(bool));
|
||||
|
||||
// cannot take adress of bit field, so use local
|
||||
const TravelMode travel_mode = edge_iterator->travel_mode;
|
||||
file_out_stream.write((char *)&travel_mode, sizeof(TravelMode));
|
||||
|
||||
file_out_stream.write((char *)&edge_iterator->is_split, sizeof(bool));
|
||||
++number_of_used_edges;
|
||||
}
|
||||
++edge_iterator;
|
||||
}
|
||||
TIMER_STOP(set_target_coords);
|
||||
std::cout << "ok, after " << TIMER_SEC(set_target_coords) << "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;
|
||||
|
||||
std::cout << "[extractor] writing street name index ... " << std::flush;
|
||||
TIMER_START(write_name_index);
|
||||
std::string name_file_streamName = (output_file_name + ".names");
|
||||
boost::filesystem::ofstream name_file_stream(name_file_streamName, std::ios::binary);
|
||||
|
||||
unsigned total_length = 0;
|
||||
std::vector<unsigned> name_lengths;
|
||||
for (const std::string &temp_string : name_list)
|
||||
{
|
||||
const unsigned string_length = std::min(static_cast<unsigned>(temp_string.length()), 255u);
|
||||
name_lengths.push_back(string_length);
|
||||
total_length += string_length;
|
||||
}
|
||||
|
||||
RangeTable<> table(name_lengths);
|
||||
name_file_stream << table;
|
||||
|
||||
name_file_stream.write((char*) &total_length, sizeof(unsigned));
|
||||
// write all chars consecutively
|
||||
for (const std::string &temp_string : name_list)
|
||||
{
|
||||
const unsigned string_length = std::min(static_cast<unsigned>(temp_string.length()), 255u);
|
||||
name_file_stream.write(temp_string.c_str(), string_length);
|
||||
}
|
||||
|
||||
name_file_stream.close();
|
||||
TIMER_STOP(write_name_index);
|
||||
std::cout << "ok, after " << TIMER_SEC(write_name_index) << "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,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 EXTRACTIONCONTAINERS_H_
|
||||
#define EXTRACTIONCONTAINERS_H_
|
||||
|
||||
#include "InternalExtractorEdge.h"
|
||||
#include "ExtractorStructs.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../Util/FingerPrint.h"
|
||||
|
||||
#include <stxxl/vector>
|
||||
|
||||
class ExtractionContainers
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
constexpr static unsigned stxxl_memory = ((sizeof(std::size_t) == 4) ? std::numeric_limits<int>::max() : std::numeric_limits<unsigned>::max());
|
||||
#else
|
||||
const static unsigned stxxl_memory = ((sizeof(std::size_t) == 4) ? INT_MAX : UINT_MAX);
|
||||
#endif
|
||||
public:
|
||||
using STXXLNodeIDVector = stxxl::vector<NodeID>;
|
||||
using STXXLNodeVector = stxxl::vector<ExternalMemoryNode>;
|
||||
using STXXLEdgeVector = stxxl::vector<InternalExtractorEdge>;
|
||||
using STXXLStringVector = stxxl::vector<std::string>;
|
||||
using STXXLRestrictionsVector = stxxl::vector<InputRestrictionContainer>;
|
||||
using STXXLWayIDStartEndVector = stxxl::vector<WayIDStartAndEndEdge>;
|
||||
|
||||
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 FingerPrint fingerprint;
|
||||
|
||||
ExtractionContainers();
|
||||
|
||||
~ExtractionContainers();
|
||||
|
||||
void PrepareData(const std::string &output_file_name,
|
||||
const std::string &restrictions_file_name);
|
||||
};
|
||||
|
||||
#endif /* EXTRACTIONCONTAINERS_H_ */
|
||||
@@ -1,90 +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_HELPER_FUNCTIONS_H
|
||||
#define EXTRACTION_HELPER_FUNCTIONS_H
|
||||
|
||||
#include "../Util/cast.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string_regex.hpp>
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include <limits>
|
||||
|
||||
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(":"));
|
||||
const 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(":"));
|
||||
const bool matched = regex_match(s, e);
|
||||
if (matched)
|
||||
{
|
||||
if (1 == result.size())
|
||||
{
|
||||
minutes = cast::string_to_int(result[0]);
|
||||
}
|
||||
if (2 == result.size())
|
||||
{
|
||||
minutes = cast::string_to_int(result[1]);
|
||||
hours = cast::string_to_int(result[0]);
|
||||
}
|
||||
if (3 == result.size())
|
||||
{
|
||||
seconds = cast::string_to_int(result[2]);
|
||||
minutes = cast::string_to_int(result[1]);
|
||||
hours = cast::string_to_int(result[0]);
|
||||
}
|
||||
return 10 * (3600 * hours + 60 * minutes + seconds);
|
||||
}
|
||||
return std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
|
||||
#endif // EXTRACTION_HELPER_FUNCTIONS_H_
|
||||
@@ -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 EXTRACTION_WAY_H
|
||||
#define EXTRACTION_WAY_H
|
||||
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../DataStructures/TravelMode.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct ExtractionWay
|
||||
{
|
||||
ExtractionWay() { Clear(); }
|
||||
|
||||
inline void Clear()
|
||||
{
|
||||
id = SPECIAL_NODEID;
|
||||
nameID = INVALID_NAMEID;
|
||||
path.clear();
|
||||
keyVals.Clear();
|
||||
forward_speed = -1;
|
||||
backward_speed = -1;
|
||||
duration = -1;
|
||||
access = true;
|
||||
roundabout = false;
|
||||
isAccessRestricted = false;
|
||||
ignoreInGrid = false;
|
||||
forward_travel_mode = TRAVEL_MODE_DEFAULT;
|
||||
backward_travel_mode = TRAVEL_MODE_DEFAULT;
|
||||
}
|
||||
|
||||
enum Directions
|
||||
{ notSure = 0,
|
||||
oneway,
|
||||
bidirectional,
|
||||
opposite };
|
||||
|
||||
// These accessor methods exists to support the depreciated "way.direction" access
|
||||
// in LUA. Since the direction attribute was removed from ExtractionWay, the
|
||||
// accessors translate to/from the mode attributes.
|
||||
inline void set_direction(const Directions m)
|
||||
{
|
||||
if (Directions::oneway == m)
|
||||
{
|
||||
forward_travel_mode = TRAVEL_MODE_DEFAULT;
|
||||
backward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
|
||||
}
|
||||
else if (Directions::opposite == m)
|
||||
{
|
||||
forward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
|
||||
backward_travel_mode = TRAVEL_MODE_DEFAULT;
|
||||
}
|
||||
else if (Directions::bidirectional == m)
|
||||
{
|
||||
forward_travel_mode = TRAVEL_MODE_DEFAULT;
|
||||
backward_travel_mode = TRAVEL_MODE_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
inline const Directions get_direction() const
|
||||
{
|
||||
if (TRAVEL_MODE_INACCESSIBLE != forward_travel_mode && TRAVEL_MODE_INACCESSIBLE != backward_travel_mode)
|
||||
{
|
||||
return Directions::bidirectional;
|
||||
}
|
||||
else if (TRAVEL_MODE_INACCESSIBLE != forward_travel_mode)
|
||||
{
|
||||
return Directions::oneway;
|
||||
}
|
||||
else if (TRAVEL_MODE_INACCESSIBLE != backward_travel_mode)
|
||||
{
|
||||
return Directions::opposite;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Directions::notSure;
|
||||
}
|
||||
}
|
||||
|
||||
// These accessors exists because it's not possible to take the address of a bitfield,
|
||||
// and LUA therefore cannot read/write the mode attributes directly.
|
||||
inline void set_forward_mode(const TravelMode m) { forward_travel_mode = m; }
|
||||
inline const TravelMode get_forward_mode() const { return forward_travel_mode; }
|
||||
inline void set_backward_mode(const TravelMode m) { backward_travel_mode = m; }
|
||||
inline const TravelMode get_backward_mode() const { return backward_travel_mode; }
|
||||
|
||||
unsigned id;
|
||||
unsigned nameID;
|
||||
double forward_speed;
|
||||
double backward_speed;
|
||||
double duration;
|
||||
std::string name;
|
||||
bool access;
|
||||
bool roundabout;
|
||||
bool isAccessRestricted;
|
||||
bool ignoreInGrid;
|
||||
std::vector<NodeID> path;
|
||||
HashTable<std::string, std::string> keyVals;
|
||||
TravelMode forward_travel_mode : 4;
|
||||
TravelMode backward_travel_mode : 4;
|
||||
};
|
||||
|
||||
#endif // EXTRACTION_WAY_H
|
||||
@@ -1,302 +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 "Extractor.h"
|
||||
|
||||
#include "ExtractorCallbacks.h"
|
||||
#include "ExtractionContainers.h"
|
||||
#include "PBFParser.h"
|
||||
#include "ScriptingEnvironment.h"
|
||||
#include "XMLParser.h"
|
||||
|
||||
#include "../Util/GitDescription.h"
|
||||
#include "../Util/IniFileUtil.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/simple_logger.hpp"
|
||||
#include "../Util/TimingUtil.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <tbb/task_scheduler_init.h>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
Extractor::Extractor() : requested_num_threads(0), file_has_pbf_format(false)
|
||||
{
|
||||
}
|
||||
|
||||
Extractor::~Extractor() {}
|
||||
|
||||
bool Extractor::ParseArguments(int argc, char *argv[])
|
||||
{
|
||||
// declare a group of options that will be allowed only on command line
|
||||
boost::program_options::options_description generic_options("Options");
|
||||
generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
|
||||
"config,c",
|
||||
boost::program_options::value<boost::filesystem::path>(&config_file_path)
|
||||
->default_value("extractor.ini"),
|
||||
"Path to a configuration file.");
|
||||
|
||||
// declare a group of options that will be allowed both on command line and in config file
|
||||
boost::program_options::options_description config_options("Configuration");
|
||||
config_options.add_options()("profile,p",
|
||||
boost::program_options::value<boost::filesystem::path>(
|
||||
&profile_path)->default_value("profile.lua"),
|
||||
"Path to LUA routing profile")(
|
||||
"threads,t",
|
||||
boost::program_options::value<unsigned int>(&requested_num_threads)
|
||||
->default_value(tbb::task_scheduler_init::default_num_threads()),
|
||||
"Number of threads to use");
|
||||
|
||||
// hidden options, will be allowed both on command line and in config file, but will not be
|
||||
// shown to the user
|
||||
boost::program_options::options_description hidden_options("Hidden options");
|
||||
hidden_options.add_options()(
|
||||
"input,i",
|
||||
boost::program_options::value<boost::filesystem::path>(&input_path),
|
||||
"Input file in .osm, .osm.bz2 or .osm.pbf format");
|
||||
|
||||
// positional option
|
||||
boost::program_options::positional_options_description positional_options;
|
||||
positional_options.add("input", 1);
|
||||
|
||||
// combine above options for parsing
|
||||
boost::program_options::options_description cmdline_options;
|
||||
cmdline_options.add(generic_options).add(config_options).add(hidden_options);
|
||||
|
||||
boost::program_options::options_description config_file_options;
|
||||
config_file_options.add(config_options).add(hidden_options);
|
||||
|
||||
boost::program_options::options_description visible_options(
|
||||
boost::filesystem::basename(argv[0]) + " <input.osm/.osm.bz2/.osm.pbf> [options]");
|
||||
visible_options.add(generic_options).add(config_options);
|
||||
|
||||
// parse command line options
|
||||
boost::program_options::variables_map option_variables;
|
||||
boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
|
||||
.options(cmdline_options)
|
||||
.positional(positional_options)
|
||||
.run(),
|
||||
option_variables);
|
||||
|
||||
if (option_variables.count("version"))
|
||||
{
|
||||
SimpleLogger().Write() << g_GIT_DESCRIPTION;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (option_variables.count("help"))
|
||||
{
|
||||
SimpleLogger().Write() << visible_options;
|
||||
return false;
|
||||
}
|
||||
|
||||
boost::program_options::notify(option_variables);
|
||||
|
||||
// parse config file
|
||||
if (boost::filesystem::is_regular_file(config_file_path))
|
||||
{
|
||||
SimpleLogger().Write() << "Reading options from: " << config_file_path.string();
|
||||
std::string ini_file_contents = ReadIniFileAndLowerContents(config_file_path);
|
||||
std::stringstream config_stream(ini_file_contents);
|
||||
boost::program_options::store(parse_config_file(config_stream, config_file_options),
|
||||
option_variables);
|
||||
boost::program_options::notify(option_variables);
|
||||
}
|
||||
|
||||
if (!option_variables.count("input"))
|
||||
{
|
||||
SimpleLogger().Write() << visible_options;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Extractor::GenerateOutputFilesNames()
|
||||
{
|
||||
output_file_name = input_path.string();
|
||||
restriction_file_name = input_path.string();
|
||||
std::string::size_type pos = output_file_name.find(".osm.bz2");
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
pos = output_file_name.find(".osm.pbf");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
file_has_pbf_format = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = output_file_name.find(".osm.xml");
|
||||
}
|
||||
}
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
pos = output_file_name.find(".pbf");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
file_has_pbf_format = true;
|
||||
}
|
||||
}
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
pos = output_file_name.find(".osm");
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
output_file_name.append(".osrm");
|
||||
restriction_file_name.append(".osrm.restrictions");
|
||||
}
|
||||
else
|
||||
{
|
||||
output_file_name.replace(pos, 5, ".osrm");
|
||||
restriction_file_name.replace(pos, 5, ".osrm.restrictions");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
output_file_name.replace(pos, 8, ".osrm");
|
||||
restriction_file_name.replace(pos, 8, ".osrm.restrictions");
|
||||
}
|
||||
}
|
||||
|
||||
int Extractor::Run(int argc, char *argv[])
|
||||
{
|
||||
try
|
||||
{
|
||||
LogPolicy::GetInstance().Unmute();
|
||||
|
||||
TIMER_START(extracting);
|
||||
|
||||
if (!ParseArguments(argc, argv))
|
||||
return 0;
|
||||
|
||||
if (1 > requested_num_threads)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!boost::filesystem::is_regular_file(input_path))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "Input file " << input_path.string()
|
||||
<< " not found!";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!boost::filesystem::is_regular_file(profile_path))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "Profile " << profile_path.string()
|
||||
<< " not found!";
|
||||
return 1;
|
||||
}
|
||||
|
||||
const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
|
||||
|
||||
SimpleLogger().Write() << "Input file: " << input_path.filename().string();
|
||||
SimpleLogger().Write() << "Profile: " << profile_path.filename().string();
|
||||
SimpleLogger().Write() << "Threads: " << requested_num_threads;
|
||||
if (recommended_num_threads != requested_num_threads)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "The recommended number of threads is "
|
||||
<< recommended_num_threads
|
||||
<< "! This setting may have performance side-effects.";
|
||||
}
|
||||
|
||||
tbb::task_scheduler_init init(requested_num_threads);
|
||||
|
||||
/*** Setup Scripting Environment ***/
|
||||
ScriptingEnvironment scripting_environment(profile_path.string().c_str());
|
||||
|
||||
GenerateOutputFilesNames();
|
||||
|
||||
std::unordered_map<std::string, NodeID> string_map;
|
||||
ExtractionContainers extraction_containers;
|
||||
|
||||
string_map[""] = 0;
|
||||
auto extractor_callbacks = new ExtractorCallbacks(extraction_containers, string_map);
|
||||
BaseParser *parser;
|
||||
if (file_has_pbf_format)
|
||||
{
|
||||
parser = new PBFParser(input_path.string().c_str(),
|
||||
extractor_callbacks,
|
||||
scripting_environment,
|
||||
requested_num_threads);
|
||||
}
|
||||
else
|
||||
{
|
||||
parser = new XMLParser(input_path.string().c_str(),
|
||||
extractor_callbacks,
|
||||
scripting_environment);
|
||||
}
|
||||
|
||||
if (!parser->ReadHeader())
|
||||
{
|
||||
throw OSRMException("Parser not initialized!");
|
||||
}
|
||||
|
||||
SimpleLogger().Write() << "Parsing in progress..";
|
||||
TIMER_START(parsing);
|
||||
|
||||
parser->Parse();
|
||||
delete parser;
|
||||
delete extractor_callbacks;
|
||||
|
||||
TIMER_STOP(parsing);
|
||||
SimpleLogger().Write() << "Parsing finished after " << TIMER_SEC(parsing) << " seconds";
|
||||
|
||||
if (extraction_containers.all_edges_list.empty())
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
|
||||
return 1;
|
||||
}
|
||||
|
||||
extraction_containers.PrepareData(output_file_name, restriction_file_name);
|
||||
|
||||
TIMER_STOP(extracting);
|
||||
SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting) << "s";
|
||||
SimpleLogger().Write() << "To prepare the data for routing, run: "
|
||||
<< "./osrm-prepare " << output_file_name << std::endl;
|
||||
}
|
||||
catch (boost::program_options::too_many_positional_options_error &)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "Only one input file can be specified";
|
||||
return 1;
|
||||
}
|
||||
catch (std::exception &e)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << e.what();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#ifndef EXTRACTOR_H_
|
||||
#define EXTRACTOR_H_
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
class ExtractorCallbacks;
|
||||
|
||||
/** \brief Class of 'extract' utility. */
|
||||
class Extractor
|
||||
{
|
||||
protected:
|
||||
unsigned requested_num_threads;
|
||||
boost::filesystem::path config_file_path;
|
||||
boost::filesystem::path input_path;
|
||||
boost::filesystem::path profile_path;
|
||||
|
||||
std::string output_file_name;
|
||||
std::string restriction_file_name;
|
||||
bool file_has_pbf_format;
|
||||
|
||||
/** \brief Parses "extractor's" command line arguments */
|
||||
bool ParseArguments(int argc, char *argv[]);
|
||||
|
||||
/** \brief Parses config file, if present in options */
|
||||
void GenerateOutputFilesNames();
|
||||
|
||||
public:
|
||||
explicit Extractor();
|
||||
Extractor(const Extractor &) = delete;
|
||||
virtual ~Extractor();
|
||||
|
||||
int Run(int argc, char *argv[]);
|
||||
};
|
||||
#endif /* EXTRACTOR_H_ */
|
||||
@@ -1,182 +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/simple_logger.hpp"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containers,
|
||||
std::unordered_map<std::string, NodeID> &string_map)
|
||||
: string_map(string_map), external_memory(extraction_containers)
|
||||
{
|
||||
}
|
||||
|
||||
/** warning: caller needs to take care of synchronization! */
|
||||
void ExtractorCallbacks::ProcessNode(const ExternalMemoryNode &n)
|
||||
{
|
||||
if (n.lat <= 85 * COORDINATE_PRECISION && n.lat >= -85 * COORDINATE_PRECISION)
|
||||
{
|
||||
external_memory.all_nodes_list.push_back(n);
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtractorCallbacks::ProcessRestriction(const InputRestrictionContainer &restriction)
|
||||
{
|
||||
external_memory.restrictions_list.push_back(restriction);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** warning: caller needs to take care of synchronization! */
|
||||
void ExtractorCallbacks::ProcessWay(ExtractionWay &parsed_way)
|
||||
{
|
||||
if (((0 >= parsed_way.forward_speed) ||
|
||||
(TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode)) &&
|
||||
((0 >= parsed_way.backward_speed) ||
|
||||
(TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode)) &&
|
||||
(0 >= parsed_way.duration))
|
||||
{ // Only true if the way is specified by the speed profile
|
||||
return;
|
||||
}
|
||||
|
||||
if (parsed_way.path.size() <= 1)
|
||||
{ // safe-guard against broken data
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::numeric_limits<unsigned>::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.forward_speed = parsed_way.duration / (parsed_way.path.size() - 1);
|
||||
parsed_way.backward_speed = parsed_way.duration / (parsed_way.path.size() - 1);
|
||||
}
|
||||
|
||||
if (std::numeric_limits<double>::epsilon() >= std::abs(-1. - parsed_way.forward_speed))
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << parsed_way.id;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the unique identifier for the street name
|
||||
const auto &string_map_iterator = string_map.find(parsed_way.name);
|
||||
if (string_map.end() == string_map_iterator)
|
||||
{
|
||||
parsed_way.nameID = external_memory.name_list.size();
|
||||
external_memory.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 (TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode)
|
||||
{
|
||||
std::reverse(parsed_way.path.begin(), parsed_way.path.end());
|
||||
parsed_way.forward_travel_mode = parsed_way.backward_travel_mode;
|
||||
parsed_way.backward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
|
||||
}
|
||||
|
||||
const bool split_edge =
|
||||
(parsed_way.forward_speed>0) && (TRAVEL_MODE_INACCESSIBLE != parsed_way.forward_travel_mode) &&
|
||||
(parsed_way.backward_speed>0) && (TRAVEL_MODE_INACCESSIBLE != parsed_way.backward_travel_mode) &&
|
||||
((parsed_way.forward_speed != parsed_way.backward_speed) ||
|
||||
(parsed_way.forward_travel_mode != parsed_way.backward_travel_mode));
|
||||
|
||||
BOOST_ASSERT(parsed_way.forward_travel_mode>0);
|
||||
for (unsigned n = 0; n < (parsed_way.path.size() - 1); ++n)
|
||||
{
|
||||
external_memory.all_edges_list.push_back(InternalExtractorEdge(
|
||||
parsed_way.path[n],
|
||||
parsed_way.path[n + 1],
|
||||
((split_edge || TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode) ? ExtractionWay::oneway
|
||||
: ExtractionWay::bidirectional),
|
||||
parsed_way.forward_speed,
|
||||
parsed_way.nameID,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.ignoreInGrid,
|
||||
(0 < parsed_way.duration),
|
||||
parsed_way.isAccessRestricted,
|
||||
parsed_way.forward_travel_mode,
|
||||
split_edge));
|
||||
external_memory.used_node_id_list.push_back(parsed_way.path[n]);
|
||||
}
|
||||
external_memory.used_node_id_list.push_back(parsed_way.path.back());
|
||||
|
||||
// The following information is needed to identify start and end segments of restrictions
|
||||
external_memory.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_edge)
|
||||
{ // Only true if the way should be split
|
||||
BOOST_ASSERT(parsed_way.backward_travel_mode>0);
|
||||
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)
|
||||
{
|
||||
external_memory.all_edges_list.push_back(
|
||||
InternalExtractorEdge(parsed_way.path[n],
|
||||
parsed_way.path[n + 1],
|
||||
ExtractionWay::oneway,
|
||||
parsed_way.backward_speed,
|
||||
parsed_way.nameID,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.ignoreInGrid,
|
||||
(0 < parsed_way.duration),
|
||||
parsed_way.isAccessRestricted,
|
||||
parsed_way.backward_travel_mode,
|
||||
split_edge));
|
||||
}
|
||||
external_memory.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,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 EXTRACTOR_CALLBACKS_H
|
||||
#define EXTRACTOR_CALLBACKS_H
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
struct ExternalMemoryNode;
|
||||
class ExtractionContainers;
|
||||
struct ExtractionWay;
|
||||
struct InputRestrictionContainer;
|
||||
|
||||
class ExtractorCallbacks
|
||||
{
|
||||
private:
|
||||
std::unordered_map<std::string, NodeID> &string_map;
|
||||
ExtractionContainers &external_memory;
|
||||
|
||||
public:
|
||||
ExtractorCallbacks() = delete;
|
||||
ExtractorCallbacks(const ExtractorCallbacks &) = delete;
|
||||
explicit ExtractorCallbacks(ExtractionContainers &extraction_containers,
|
||||
std::unordered_map<std::string, NodeID> &string_map);
|
||||
|
||||
// warning: caller needs to take care of synchronization!
|
||||
void ProcessNode(const ExternalMemoryNode &node);
|
||||
|
||||
// warning: caller needs to take care of synchronization!
|
||||
bool ProcessRestriction(const InputRestrictionContainer &restriction);
|
||||
|
||||
// warning: caller needs to take care of synchronization!
|
||||
void ProcessWay(ExtractionWay &way);
|
||||
};
|
||||
|
||||
#endif /* EXTRACTOR_CALLBACKS_H */
|
||||
@@ -1,114 +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 <limits>
|
||||
#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(std::numeric_limits<unsigned>::max()), firstStart(std::numeric_limits<unsigned>::max()), firstTarget(std::numeric_limits<unsigned>::max()), lastStart(std::numeric_limits<unsigned>::max()),
|
||||
lastTarget(std::numeric_limits<unsigned>::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
|
||||
{
|
||||
using value_type = WayIDStartAndEndEdge;
|
||||
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
|
||||
{
|
||||
using value_type = NodeID;
|
||||
bool operator()(const NodeID left, const NodeID right) const { return left < right; }
|
||||
value_type max_value() { return 0xffffffff; }
|
||||
value_type min_value() { return 0x0; }
|
||||
};
|
||||
|
||||
struct CmpNodeByID
|
||||
{
|
||||
using value_type = ExternalMemoryNode;
|
||||
bool operator()(const ExternalMemoryNode &left, const ExternalMemoryNode &right) const
|
||||
{
|
||||
return left.node_id < right.node_id;
|
||||
}
|
||||
value_type max_value() { return ExternalMemoryNode::max_value(); }
|
||||
value_type min_value() { return ExternalMemoryNode::min_value(); }
|
||||
};
|
||||
|
||||
#endif /* EXTRACTORSTRUCTS_H_ */
|
||||
@@ -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 INTERNAL_EXTRACTOR_EDGE_H
|
||||
#define INTERNAL_EXTRACTOR_EDGE_H
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../DataStructures/TravelMode.h"
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
struct InternalExtractorEdge
|
||||
{
|
||||
InternalExtractorEdge()
|
||||
: start(0), target(0), direction(0), speed(0), name_id(0), is_roundabout(false),
|
||||
is_in_tiny_cc(false), is_duration_set(false), is_access_restricted(false),
|
||||
travel_mode(TRAVEL_MODE_INACCESSIBLE), is_split(false)
|
||||
{
|
||||
}
|
||||
|
||||
explicit InternalExtractorEdge(NodeID start,
|
||||
NodeID target,
|
||||
short direction,
|
||||
double speed,
|
||||
unsigned name_id,
|
||||
bool is_roundabout,
|
||||
bool is_in_tiny_cc,
|
||||
bool is_duration_set,
|
||||
bool is_access_restricted,
|
||||
TravelMode travel_mode,
|
||||
bool is_split)
|
||||
: start(start), target(target), direction(direction), speed(speed),
|
||||
name_id(name_id), is_roundabout(is_roundabout), is_in_tiny_cc(is_in_tiny_cc),
|
||||
is_duration_set(is_duration_set), is_access_restricted(is_access_restricted),
|
||||
travel_mode(travel_mode), is_split(is_split)
|
||||
{
|
||||
}
|
||||
|
||||
// necessary static util functions for stxxl's sorting
|
||||
static InternalExtractorEdge min_value()
|
||||
{
|
||||
return InternalExtractorEdge(0, 0, 0, 0, 0, false, false, false, false, TRAVEL_MODE_INACCESSIBLE, false);
|
||||
}
|
||||
static InternalExtractorEdge max_value()
|
||||
{
|
||||
return InternalExtractorEdge(
|
||||
SPECIAL_NODEID, SPECIAL_NODEID, 0, 0, 0, false, false, false, false, TRAVEL_MODE_INACCESSIBLE, false);
|
||||
}
|
||||
|
||||
NodeID start;
|
||||
NodeID target;
|
||||
short direction;
|
||||
double speed;
|
||||
unsigned name_id;
|
||||
bool is_roundabout;
|
||||
bool is_in_tiny_cc;
|
||||
bool is_duration_set;
|
||||
bool is_access_restricted;
|
||||
TravelMode travel_mode : 4;
|
||||
bool is_split;
|
||||
|
||||
FixedPointCoordinate source_coordinate;
|
||||
FixedPointCoordinate target_coordinate;
|
||||
};
|
||||
|
||||
struct CmpEdgeByStartID
|
||||
{
|
||||
using value_type = InternalExtractorEdge;
|
||||
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
|
||||
{
|
||||
using value_type = InternalExtractorEdge;
|
||||
|
||||
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,665 +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/OSRMException.h"
|
||||
#include "../Util/simple_logger.hpp"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/task_scheduler_init.h>
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <thread>
|
||||
|
||||
PBFParser::PBFParser(const char *fileName,
|
||||
ExtractorCallbacks *extractor_callbacks,
|
||||
ScriptingEnvironment &scripting_environment,
|
||||
unsigned num_threads)
|
||||
: BaseParser(extractor_callbacks, scripting_environment)
|
||||
{
|
||||
if (0 == num_threads)
|
||||
{
|
||||
num_parser_threads = tbb::task_scheduler_init::default_num_threads();
|
||||
}
|
||||
else
|
||||
{
|
||||
num_parser_threads = num_threads;
|
||||
}
|
||||
|
||||
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.
|
||||
thread_data_queue = std::make_shared<ConcurrentQueue<ParserThreadData *>>(2500);
|
||||
input.open(fileName, std::ios::in | std::ios::binary);
|
||||
|
||||
if (!input)
|
||||
{
|
||||
throw OSRMException("pbf file not found.");
|
||||
}
|
||||
|
||||
block_count = 0;
|
||||
group_count = 0;
|
||||
}
|
||||
|
||||
PBFParser::~PBFParser()
|
||||
{
|
||||
if (input.is_open())
|
||||
{
|
||||
input.close();
|
||||
}
|
||||
|
||||
// Clean up any leftover ThreadData objects in the queue
|
||||
ParserThreadData *thread_data;
|
||||
while (thread_data_queue->try_pop(thread_data))
|
||||
{
|
||||
delete thread_data;
|
||||
}
|
||||
google::protobuf::ShutdownProtobufLibrary();
|
||||
|
||||
SimpleLogger().Write(logDEBUG) << "parsed " << block_count << " blocks from pbf with "
|
||||
<< group_count << " groups";
|
||||
}
|
||||
|
||||
inline bool PBFParser::ReadHeader()
|
||||
{
|
||||
ParserThreadData init_data;
|
||||
/** read Header */
|
||||
if (!readPBFBlobHeader(input, &init_data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (readBlob(input, &init_data))
|
||||
{
|
||||
if (!init_data.PBFHeaderBlock.ParseFromArray(&(init_data.charBuffer[0]),
|
||||
static_cast<int>(init_data.charBuffer.size())))
|
||||
{
|
||||
std::cerr << "[error] Header not parseable!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto feature_size = init_data.PBFHeaderBlock.required_features_size();
|
||||
for (int i = 0; i < feature_size; ++i)
|
||||
{
|
||||
const std::string &feature = init_data.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 keep_running = true;
|
||||
do
|
||||
{
|
||||
ParserThreadData *thread_data = new ParserThreadData();
|
||||
keep_running = readNextBlock(input, thread_data);
|
||||
|
||||
if (keep_running)
|
||||
{
|
||||
thread_data_queue->push(thread_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No more data to read, parse stops when nullptr encountered
|
||||
thread_data_queue->push(nullptr);
|
||||
delete thread_data;
|
||||
}
|
||||
} while (keep_running);
|
||||
}
|
||||
|
||||
inline void PBFParser::ParseData()
|
||||
{
|
||||
tbb::task_scheduler_init init(num_parser_threads);
|
||||
|
||||
while (true)
|
||||
{
|
||||
ParserThreadData *thread_data;
|
||||
thread_data_queue->wait_and_pop(thread_data);
|
||||
if (nullptr == thread_data)
|
||||
{
|
||||
thread_data_queue->push(nullptr); // Signal end of data for other threads
|
||||
break;
|
||||
}
|
||||
|
||||
loadBlock(thread_data);
|
||||
|
||||
int group_size = thread_data->PBFprimitiveBlock.primitivegroup_size();
|
||||
for (int i = 0; i < group_size; ++i)
|
||||
{
|
||||
thread_data->currentGroupID = i;
|
||||
loadGroup(thread_data);
|
||||
|
||||
if (thread_data->entityTypeIndicator == TypeNode)
|
||||
{
|
||||
parseNode(thread_data);
|
||||
}
|
||||
if (thread_data->entityTypeIndicator == TypeWay)
|
||||
{
|
||||
parseWay(thread_data);
|
||||
}
|
||||
if (thread_data->entityTypeIndicator == TypeRelation)
|
||||
{
|
||||
parseRelation(thread_data);
|
||||
}
|
||||
if (thread_data->entityTypeIndicator == TypeDenseNode)
|
||||
{
|
||||
parseDenseNode(thread_data);
|
||||
}
|
||||
}
|
||||
|
||||
delete thread_data;
|
||||
thread_data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool PBFParser::Parse()
|
||||
{
|
||||
// Start the read and parse threads
|
||||
std::thread read_thread(std::bind(&PBFParser::ReadData, this));
|
||||
|
||||
// Open several parse threads that are synchronized before call to
|
||||
std::thread parse_thread(std::bind(&PBFParser::ParseData, this));
|
||||
|
||||
// Wait for the threads to finish
|
||||
read_thread.join();
|
||||
parse_thread.join();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void PBFParser::parseDenseNode(ParserThreadData *thread_data)
|
||||
{
|
||||
const OSMPBF::DenseNodes &dense =
|
||||
thread_data->PBFprimitiveBlock.primitivegroup(thread_data->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].node_id = static_cast<NodeID>(m_lastDenseID);
|
||||
extracted_nodes_vector[i].lat = static_cast<int>(
|
||||
COORDINATE_PRECISION *
|
||||
((double)m_lastDenseLatitude * thread_data->PBFprimitiveBlock.granularity() +
|
||||
thread_data->PBFprimitiveBlock.lat_offset()) /
|
||||
NANO);
|
||||
extracted_nodes_vector[i].lon = static_cast<int>(
|
||||
COORDINATE_PRECISION *
|
||||
((double)m_lastDenseLongitude * thread_data->PBFprimitiveBlock.granularity() +
|
||||
thread_data->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 = thread_data->PBFprimitiveBlock.stringtable().s(tagValue);
|
||||
const std::string &value = thread_data->PBFprimitiveBlock.stringtable().s(keyValue);
|
||||
extracted_nodes_vector[i].keyVals.Add(std::move(key), std::move(value));
|
||||
denseTagIndex += 2;
|
||||
}
|
||||
}
|
||||
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, extracted_nodes_vector.size()),
|
||||
[this, &extracted_nodes_vector](const tbb::blocked_range<size_t> &range)
|
||||
{
|
||||
lua_State *lua_state = this->scripting_environment.getLuaState();
|
||||
for (size_t i = range.begin(); i != range.end(); ++i)
|
||||
{
|
||||
ImportNode &import_node = extracted_nodes_vector[i];
|
||||
ParseNodeInLua(import_node, lua_state);
|
||||
}
|
||||
});
|
||||
|
||||
for (const ImportNode &import_node : extracted_nodes_vector)
|
||||
{
|
||||
extractor_callbacks->ProcessNode(import_node);
|
||||
}
|
||||
}
|
||||
|
||||
inline void PBFParser::parseNode(ParserThreadData *)
|
||||
{
|
||||
throw OSRMException("Parsing of simple nodes not supported. PBF should use dense nodes");
|
||||
}
|
||||
|
||||
inline void PBFParser::parseRelation(ParserThreadData *thread_data)
|
||||
{
|
||||
// TODO: leave early, if relation is not a restriction
|
||||
// TODO: reuse rawRestriction container
|
||||
if (!use_turn_restrictions)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const OSMPBF::PrimitiveGroup &group =
|
||||
thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID);
|
||||
|
||||
for (int i = 0, relation_size = group.relations_size(); i < relation_size; ++i)
|
||||
{
|
||||
std::string except_tag_string;
|
||||
const OSMPBF::Relation &inputRelation =
|
||||
thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID).relations(i);
|
||||
bool is_restriction = false;
|
||||
bool is_only_restriction = false;
|
||||
for (int k = 0, endOfKeys = inputRelation.keys_size(); k < endOfKeys; ++k)
|
||||
{
|
||||
const std::string &key =
|
||||
thread_data->PBFprimitiveBlock.stringtable().s(inputRelation.keys(k));
|
||||
const std::string &val =
|
||||
thread_data->PBFprimitiveBlock.stringtable().s(inputRelation.vals(k));
|
||||
if ("type" == key)
|
||||
{
|
||||
if ("restriction" == val)
|
||||
{
|
||||
is_restriction = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (("restriction" == key) && (val.find("only_") == 0))
|
||||
{
|
||||
is_only_restriction = true;
|
||||
}
|
||||
if ("except" == key)
|
||||
{
|
||||
except_tag_string = val;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_restriction && ShouldIgnoreRestriction(except_tag_string))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_restriction)
|
||||
{
|
||||
int64_t last_ref = 0;
|
||||
InputRestrictionContainer current_restriction_container(is_only_restriction);
|
||||
for (int rolesIndex = 0, last_role = inputRelation.roles_sid_size();
|
||||
rolesIndex < last_role;
|
||||
++rolesIndex)
|
||||
{
|
||||
const std::string &role = thread_data->PBFprimitiveBlock.stringtable().s(
|
||||
inputRelation.roles_sid(rolesIndex));
|
||||
last_ref += 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;
|
||||
}
|
||||
BOOST_ASSERT("via" == role);
|
||||
if (std::numeric_limits<unsigned>::max() !=
|
||||
current_restriction_container.viaNode)
|
||||
{
|
||||
current_restriction_container.viaNode =
|
||||
std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
BOOST_ASSERT(std::numeric_limits<unsigned>::max() ==
|
||||
current_restriction_container.viaNode);
|
||||
current_restriction_container.restriction.viaNode =
|
||||
static_cast<NodeID>(last_ref);
|
||||
break;
|
||||
case 1: // way
|
||||
BOOST_ASSERT("from" == role || "to" == role || "via" == role);
|
||||
if ("from" == role)
|
||||
{
|
||||
current_restriction_container.fromWay = static_cast<EdgeID>(last_ref);
|
||||
}
|
||||
if ("to" == role)
|
||||
{
|
||||
current_restriction_container.toWay = static_cast<EdgeID>(last_ref);
|
||||
}
|
||||
if ("via" == role)
|
||||
{
|
||||
BOOST_ASSERT(current_restriction_container.restriction.toNode ==
|
||||
std::numeric_limits<unsigned>::max());
|
||||
current_restriction_container.viaNode = static_cast<NodeID>(last_ref);
|
||||
}
|
||||
break;
|
||||
case 2: // relation, not used. relations relating to relations are evil.
|
||||
continue;
|
||||
BOOST_ASSERT(false);
|
||||
break;
|
||||
|
||||
default: // should not happen
|
||||
BOOST_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!extractor_callbacks->ProcessRestriction(current_restriction_container))
|
||||
{
|
||||
std::cerr << "[PBFParser] relation not parsed" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void PBFParser::parseWay(ParserThreadData *thread_data)
|
||||
{
|
||||
const int number_of_ways =
|
||||
thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID).ways_size();
|
||||
std::vector<ExtractionWay> parsed_way_vector(number_of_ways);
|
||||
for (int i = 0; i < number_of_ways; ++i)
|
||||
{
|
||||
const OSMPBF::Way &input_way =
|
||||
thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID).ways(i);
|
||||
parsed_way_vector[i].id = static_cast<EdgeID>(input_way.id());
|
||||
unsigned node_id_in_path = 0;
|
||||
const auto number_of_referenced_nodes = input_way.refs_size();
|
||||
for (auto j = 0; j < number_of_referenced_nodes; ++j)
|
||||
{
|
||||
node_id_in_path += static_cast<NodeID>(input_way.refs(j));
|
||||
parsed_way_vector[i].path.push_back(node_id_in_path);
|
||||
}
|
||||
BOOST_ASSERT(input_way.keys_size() == input_way.vals_size());
|
||||
const auto number_of_keys = input_way.keys_size();
|
||||
for (auto j = 0; j < number_of_keys; ++j)
|
||||
{
|
||||
const std::string &key =
|
||||
thread_data->PBFprimitiveBlock.stringtable().s(input_way.keys(j));
|
||||
const std::string &val =
|
||||
thread_data->PBFprimitiveBlock.stringtable().s(input_way.vals(j));
|
||||
parsed_way_vector[i].keyVals.Add(std::move(key), std::move(val));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: investigate if schedule guided will be handled by tbb automatically
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, parsed_way_vector.size()),
|
||||
[this, &parsed_way_vector](const tbb::blocked_range<size_t> &range)
|
||||
{
|
||||
lua_State *lua_state = this->scripting_environment.getLuaState();
|
||||
for (size_t i = range.begin(); i != range.end(); i++)
|
||||
{
|
||||
ExtractionWay &extraction_way = parsed_way_vector[i];
|
||||
if (2 <= extraction_way.path.size())
|
||||
{
|
||||
ParseWayInLua(extraction_way, lua_state);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (ExtractionWay &extraction_way : parsed_way_vector)
|
||||
{
|
||||
if (2 <= extraction_way.path.size())
|
||||
{
|
||||
extractor_callbacks->ProcessWay(extraction_way);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void PBFParser::loadGroup(ParserThreadData *thread_data)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
++group_count;
|
||||
#endif
|
||||
|
||||
const OSMPBF::PrimitiveGroup &group =
|
||||
thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID);
|
||||
thread_data->entityTypeIndicator = TypeDummy;
|
||||
if (0 != group.nodes_size())
|
||||
{
|
||||
thread_data->entityTypeIndicator = TypeNode;
|
||||
}
|
||||
if (0 != group.ways_size())
|
||||
{
|
||||
thread_data->entityTypeIndicator = TypeWay;
|
||||
}
|
||||
if (0 != group.relations_size())
|
||||
{
|
||||
thread_data->entityTypeIndicator = TypeRelation;
|
||||
}
|
||||
if (group.has_dense())
|
||||
{
|
||||
thread_data->entityTypeIndicator = TypeDenseNode;
|
||||
BOOST_ASSERT(0 != group.dense().id_size());
|
||||
}
|
||||
BOOST_ASSERT(thread_data->entityTypeIndicator != TypeDummy);
|
||||
}
|
||||
|
||||
inline void PBFParser::loadBlock(ParserThreadData *thread_data)
|
||||
{
|
||||
++block_count;
|
||||
thread_data->currentGroupID = 0;
|
||||
thread_data->currentEntityID = 0;
|
||||
}
|
||||
|
||||
inline bool PBFParser::readPBFBlobHeader(std::fstream &stream, ParserThreadData *thread_data)
|
||||
{
|
||||
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 = (thread_data->PBFBlobHeader).ParseFromArray(data, size);
|
||||
delete[] data;
|
||||
return dataSuccessfullyParsed;
|
||||
}
|
||||
|
||||
inline bool PBFParser::unpackZLIB(ParserThreadData *thread_data)
|
||||
{
|
||||
auto raw_size = thread_data->PBFBlob.raw_size();
|
||||
char *unpacked_data_array = new char[raw_size];
|
||||
z_stream compressed_data_stream;
|
||||
compressed_data_stream.next_in = (unsigned char *)thread_data->PBFBlob.zlib_data().data();
|
||||
compressed_data_stream.avail_in = thread_data->PBFBlob.zlib_data().size();
|
||||
compressed_data_stream.next_out = (unsigned char *)unpacked_data_array;
|
||||
compressed_data_stream.avail_out = raw_size;
|
||||
compressed_data_stream.zalloc = Z_NULL;
|
||||
compressed_data_stream.zfree = Z_NULL;
|
||||
compressed_data_stream.opaque = Z_NULL;
|
||||
int return_code = inflateInit(&compressed_data_stream);
|
||||
if (return_code != Z_OK)
|
||||
{
|
||||
std::cerr << "[error] failed to init zlib stream" << std::endl;
|
||||
delete[] unpacked_data_array;
|
||||
return false;
|
||||
}
|
||||
|
||||
return_code = inflate(&compressed_data_stream, Z_FINISH);
|
||||
if (return_code != Z_STREAM_END)
|
||||
{
|
||||
std::cerr << "[error] failed to inflate zlib stream" << std::endl;
|
||||
std::cerr << "[error] Error type: " << return_code << std::endl;
|
||||
delete[] unpacked_data_array;
|
||||
return false;
|
||||
}
|
||||
|
||||
return_code = inflateEnd(&compressed_data_stream);
|
||||
if (return_code != Z_OK)
|
||||
{
|
||||
std::cerr << "[error] failed to deinit zlib stream" << std::endl;
|
||||
delete[] unpacked_data_array;
|
||||
return false;
|
||||
}
|
||||
|
||||
thread_data->charBuffer.clear();
|
||||
thread_data->charBuffer.resize(raw_size);
|
||||
std::copy(unpacked_data_array, unpacked_data_array + raw_size, thread_data->charBuffer.begin());
|
||||
delete[] unpacked_data_array;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool PBFParser::unpackLZMA(ParserThreadData *) { return false; }
|
||||
|
||||
inline bool PBFParser::readBlob(std::fstream &stream, ParserThreadData *thread_data)
|
||||
{
|
||||
if (stream.eof())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const int size = thread_data->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 (!thread_data->PBFBlob.ParseFromArray(data, size))
|
||||
{
|
||||
std::cerr << "[error] failed to parse blob" << std::endl;
|
||||
delete[] data;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (thread_data->PBFBlob.has_raw())
|
||||
{
|
||||
const std::string &data = thread_data->PBFBlob.raw();
|
||||
thread_data->charBuffer.clear();
|
||||
thread_data->charBuffer.resize(data.size());
|
||||
std::copy(data.begin(), data.end(), thread_data->charBuffer.begin());
|
||||
}
|
||||
else if (thread_data->PBFBlob.has_zlib_data())
|
||||
{
|
||||
if (!unpackZLIB(thread_data))
|
||||
{
|
||||
std::cerr << "[error] zlib data encountered that could not be unpacked" << std::endl;
|
||||
delete[] data;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (thread_data->PBFBlob.has_lzma_data())
|
||||
{
|
||||
if (!unpackLZMA(thread_data))
|
||||
{
|
||||
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, ParserThreadData *thread_data)
|
||||
{
|
||||
if (stream.eof())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!readPBFBlobHeader(stream, thread_data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (thread_data->PBFBlobHeader.type() != "OSMData")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!readBlob(stream, thread_data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!thread_data->PBFprimitiveBlock.ParseFromArray(&(thread_data->charBuffer[0]),
|
||||
thread_data->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 <osmpbf/fileformat.pb.h>
|
||||
#include <osmpbf/osmformat.pb.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
|
||||
class PBFParser : public BaseParser
|
||||
{
|
||||
|
||||
enum EntityType
|
||||
{ TypeDummy = 0,
|
||||
TypeNode = 1,
|
||||
TypeWay = 2,
|
||||
TypeRelation = 4,
|
||||
TypeDenseNode = 8 };
|
||||
|
||||
struct ParserThreadData
|
||||
{
|
||||
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 *file_name,
|
||||
ExtractorCallbacks *extractor_callbacks,
|
||||
ScriptingEnvironment &scripting_environment,
|
||||
unsigned num_parser_threads = 0);
|
||||
virtual ~PBFParser();
|
||||
|
||||
inline bool ReadHeader();
|
||||
inline bool Parse();
|
||||
|
||||
private:
|
||||
inline void ReadData();
|
||||
inline void ParseData();
|
||||
inline void parseDenseNode(ParserThreadData *thread_data);
|
||||
inline void parseNode(ParserThreadData *thread_data);
|
||||
inline void parseRelation(ParserThreadData *thread_data);
|
||||
inline void parseWay(ParserThreadData *thread_data);
|
||||
|
||||
inline void loadGroup(ParserThreadData *thread_data);
|
||||
inline void loadBlock(ParserThreadData *thread_data);
|
||||
inline bool readPBFBlobHeader(std::fstream &stream, ParserThreadData *thread_data);
|
||||
inline bool unpackZLIB(ParserThreadData *thread_data);
|
||||
inline bool unpackLZMA(ParserThreadData *thread_data);
|
||||
inline bool readBlob(std::fstream &stream, ParserThreadData *thread_data);
|
||||
inline bool readNextBlock(std::fstream &stream, ParserThreadData *thread_data);
|
||||
|
||||
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 group_count;
|
||||
unsigned block_count;
|
||||
|
||||
std::fstream input; // the input stream to parse
|
||||
std::shared_ptr<ConcurrentQueue<ParserThreadData *>> thread_data_queue;
|
||||
unsigned num_parser_threads;
|
||||
};
|
||||
|
||||
#endif /* PBFPARSER_H_ */
|
||||
@@ -1,122 +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/OSRMException.h"
|
||||
#include "../Util/simple_logger.hpp"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
ScriptingEnvironment::ScriptingEnvironment() {}
|
||||
ScriptingEnvironment::ScriptingEnvironment(const char *file_name)
|
||||
: file_name(file_name)
|
||||
{
|
||||
SimpleLogger().Write() << "Using script " << file_name;
|
||||
}
|
||||
|
||||
void ScriptingEnvironment::initLuaState(lua_State* lua_state)
|
||||
{
|
||||
luabind::open(lua_state);
|
||||
// open utility libraries string library;
|
||||
luaL_openlibs(lua_state);
|
||||
|
||||
luaAddScriptFolderToLoadPath(lua_state, file_name.c_str());
|
||||
|
||||
// Add our function to the state's global scope
|
||||
luabind::module(lua_state)[
|
||||
luabind::def("print", LUA_print<std::string>),
|
||||
luabind::def("durationIsValid", durationIsValid),
|
||||
luabind::def("parseDuration", parseDuration),
|
||||
|
||||
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::class_<ImportNode>("Node")
|
||||
// .def(luabind::constructor<>())
|
||||
.def_readwrite("lat", &ImportNode::lat)
|
||||
.def_readwrite("lon", &ImportNode::lon)
|
||||
.def_readonly("id", &ImportNode::node_id)
|
||||
.def_readwrite("bollard", &ImportNode::bollard)
|
||||
.def_readwrite("traffic_light", &ImportNode::trafficLight)
|
||||
.def_readwrite("tags", &ImportNode::keyVals),
|
||||
|
||||
luabind::class_<ExtractionWay>("Way")
|
||||
// .def(luabind::constructor<>())
|
||||
.def_readonly("id", &ExtractionWay::id)
|
||||
.def_readwrite("name", &ExtractionWay::name)
|
||||
.def_readwrite("forward_speed", &ExtractionWay::forward_speed)
|
||||
.def_readwrite("backward_speed", &ExtractionWay::backward_speed)
|
||||
.def_readwrite("duration", &ExtractionWay::duration)
|
||||
.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)
|
||||
.property("direction", &ExtractionWay::get_direction, &ExtractionWay::set_direction)
|
||||
.property("forward_mode", &ExtractionWay::get_forward_mode, &ExtractionWay::set_forward_mode)
|
||||
.property("backward_mode", &ExtractionWay::get_backward_mode, &ExtractionWay::set_backward_mode)
|
||||
.enum_("constants")[
|
||||
luabind::value("notSure", 0),
|
||||
luabind::value("oneway", 1),
|
||||
luabind::value("bidirectional", 2),
|
||||
luabind::value("opposite", 3)
|
||||
],
|
||||
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(lua_state, file_name.c_str()))
|
||||
{
|
||||
luabind::object error_msg(luabind::from_stack(lua_state, -1));
|
||||
std::ostringstream error_stream;
|
||||
error_stream << error_msg;
|
||||
throw OSRMException("ERROR occured in profile script:\n" + error_stream.str());
|
||||
}
|
||||
}
|
||||
|
||||
lua_State *ScriptingEnvironment::getLuaState()
|
||||
{
|
||||
bool initialized = false;
|
||||
auto& ref = script_contexts.local(initialized);
|
||||
if (!initialized)
|
||||
{
|
||||
std::shared_ptr<lua_State> state(luaL_newstate(), lua_close);
|
||||
ref = state;
|
||||
initLuaState(ref.get());
|
||||
}
|
||||
|
||||
return ref.get();
|
||||
}
|
||||
|
||||
@@ -1,52 +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 SCRIPTINGENVIRONMENT_H_
|
||||
#define SCRIPTINGENVIRONMENT_H_
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <tbb/enumerable_thread_specific.h>
|
||||
|
||||
struct lua_State;
|
||||
|
||||
class ScriptingEnvironment
|
||||
{
|
||||
public:
|
||||
ScriptingEnvironment();
|
||||
explicit ScriptingEnvironment(const char *file_name);
|
||||
|
||||
lua_State *getLuaState();
|
||||
|
||||
private:
|
||||
void initLuaState(lua_State* lua_state);
|
||||
|
||||
std::string file_name;
|
||||
tbb::enumerable_thread_specific<std::shared_ptr<lua_State>> script_contexts;
|
||||
};
|
||||
|
||||
#endif /* SCRIPTINGENVIRONMENT_H_ */
|
||||
@@ -1,354 +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/cast.hpp"
|
||||
#include "../Util/simple_logger.hpp"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
XMLParser::XMLParser(const char *filename,
|
||||
ExtractorCallbacks *extractor_callbacks,
|
||||
ScriptingEnvironment &scripting_environment)
|
||||
: BaseParser(extractor_callbacks, scripting_environment)
|
||||
{
|
||||
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 == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(currentName, (const xmlChar *)"node") == 1)
|
||||
{
|
||||
ImportNode current_node = ReadXMLNode();
|
||||
ParseNodeInLua(current_node, lua_state);
|
||||
extractor_callbacks->ProcessNode(current_node);
|
||||
}
|
||||
|
||||
if (xmlStrEqual(currentName, (const xmlChar *)"way") == 1)
|
||||
{
|
||||
ExtractionWay way = ReadXMLWay();
|
||||
ParseWayInLua(way, lua_state);
|
||||
extractor_callbacks->ProcessWay(way);
|
||||
}
|
||||
if (use_turn_restrictions && xmlStrEqual(currentName, (const xmlChar *)"relation") == 1)
|
||||
{
|
||||
InputRestrictionContainer current_restriction = ReadXMLRestriction();
|
||||
if ((UINT_MAX != current_restriction.fromWay) &&
|
||||
!extractor_callbacks->ProcessRestriction(current_restriction))
|
||||
{
|
||||
std::cerr << "[XMLParser] restriction not parsed" << std::endl;
|
||||
}
|
||||
}
|
||||
xmlFree(currentName);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
InputRestrictionContainer XMLParser::ReadXMLRestriction()
|
||||
{
|
||||
|
||||
InputRestrictionContainer restriction;
|
||||
|
||||
if (xmlTextReaderIsEmptyElement(inputReader) == 1)
|
||||
{
|
||||
return restriction;
|
||||
}
|
||||
|
||||
std::string except_tag_string;
|
||||
const int depth = xmlTextReaderDepth(inputReader);
|
||||
while (xmlTextReaderRead(inputReader) == 1)
|
||||
{
|
||||
const int child_type = xmlTextReaderNodeType(inputReader);
|
||||
if (child_type != 1 && child_type != 15)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const int child_depth = xmlTextReaderDepth(inputReader);
|
||||
xmlChar *child_name = xmlTextReaderName(inputReader);
|
||||
if (child_name == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (depth == child_depth && child_type == 15 &&
|
||||
xmlStrEqual(child_name, (const xmlChar *)"relation") == 1)
|
||||
{
|
||||
xmlFree(child_name);
|
||||
break;
|
||||
}
|
||||
if (child_type != 1)
|
||||
{
|
||||
xmlFree(child_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(child_name, (const xmlChar *)"tag") == 1)
|
||||
{
|
||||
xmlChar *key = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
|
||||
xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
|
||||
if (key != nullptr && value != nullptr)
|
||||
{
|
||||
if (xmlStrEqual(key, (const xmlChar *)"restriction") &&
|
||||
StringStartsWith((const char *)value, "only_"))
|
||||
{
|
||||
restriction.restriction.flags.isOnly = true;
|
||||
}
|
||||
if (xmlStrEqual(key, (const xmlChar *)"except"))
|
||||
{
|
||||
except_tag_string = (const char *)value;
|
||||
}
|
||||
}
|
||||
|
||||
if (key != nullptr)
|
||||
{
|
||||
xmlFree(key);
|
||||
}
|
||||
if (value != nullptr)
|
||||
{
|
||||
xmlFree(value);
|
||||
}
|
||||
}
|
||||
else if (xmlStrEqual(child_name, (const xmlChar *)"member") == 1)
|
||||
{
|
||||
xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref");
|
||||
if (ref != nullptr)
|
||||
{
|
||||
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 = cast::string_to_uint((const char *)ref);
|
||||
}
|
||||
if (xmlStrEqual(role, (const xmlChar *)"from") &&
|
||||
xmlStrEqual(type, (const xmlChar *)"way"))
|
||||
{
|
||||
restriction.fromWay = cast::string_to_uint((const char *)ref);
|
||||
}
|
||||
if (xmlStrEqual(role, (const xmlChar *)"via") &&
|
||||
xmlStrEqual(type, (const xmlChar *)"node"))
|
||||
{
|
||||
restriction.restriction.viaNode = cast::string_to_uint((const char *)ref);
|
||||
}
|
||||
|
||||
if (nullptr != type)
|
||||
{
|
||||
xmlFree(type);
|
||||
}
|
||||
if (nullptr != role)
|
||||
{
|
||||
xmlFree(role);
|
||||
}
|
||||
if (nullptr != ref)
|
||||
{
|
||||
xmlFree(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlFree(child_name);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return way;
|
||||
}
|
||||
const int depth = xmlTextReaderDepth(inputReader);
|
||||
while (xmlTextReaderRead(inputReader) == 1)
|
||||
{
|
||||
const int child_type = xmlTextReaderNodeType(inputReader);
|
||||
if (child_type != 1 && child_type != 15)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const int child_depth = xmlTextReaderDepth(inputReader);
|
||||
xmlChar *child_name = xmlTextReaderName(inputReader);
|
||||
if (child_name == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (depth == child_depth && child_type == 15 &&
|
||||
xmlStrEqual(child_name, (const xmlChar *)"way") == 1)
|
||||
{
|
||||
xmlChar *way_id = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id");
|
||||
way.id = cast::string_to_uint((char *)way_id);
|
||||
xmlFree(way_id);
|
||||
xmlFree(child_name);
|
||||
break;
|
||||
}
|
||||
if (child_type != 1)
|
||||
{
|
||||
xmlFree(child_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(child_name, (const xmlChar *)"tag") == 1)
|
||||
{
|
||||
xmlChar *key = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
|
||||
xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
|
||||
|
||||
if (key != nullptr && value != nullptr)
|
||||
{
|
||||
way.keyVals.Add(std::string((char *)key), std::string((char *)value));
|
||||
}
|
||||
if (key != nullptr)
|
||||
{
|
||||
xmlFree(key);
|
||||
}
|
||||
if (value != nullptr)
|
||||
{
|
||||
xmlFree(value);
|
||||
}
|
||||
}
|
||||
else if (xmlStrEqual(child_name, (const xmlChar *)"nd") == 1)
|
||||
{
|
||||
xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref");
|
||||
if (ref != nullptr)
|
||||
{
|
||||
way.path.push_back(cast::string_to_uint((const char *)ref));
|
||||
xmlFree(ref);
|
||||
}
|
||||
}
|
||||
xmlFree(child_name);
|
||||
}
|
||||
return way;
|
||||
}
|
||||
|
||||
ImportNode XMLParser::ReadXMLNode()
|
||||
{
|
||||
ImportNode node;
|
||||
|
||||
xmlChar *attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"lat");
|
||||
if (attribute != nullptr)
|
||||
{
|
||||
node.lat = static_cast<int>(COORDINATE_PRECISION * cast::string_to_double((const char *)attribute));
|
||||
xmlFree(attribute);
|
||||
}
|
||||
attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"lon");
|
||||
if (attribute != nullptr)
|
||||
{
|
||||
node.lon = static_cast<int>(COORDINATE_PRECISION * cast::string_to_double((const char *)attribute));
|
||||
xmlFree(attribute);
|
||||
}
|
||||
attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id");
|
||||
if (attribute != nullptr)
|
||||
{
|
||||
node.node_id = cast::string_to_uint((const char *)attribute);
|
||||
xmlFree(attribute);
|
||||
}
|
||||
|
||||
if (xmlTextReaderIsEmptyElement(inputReader) == 1)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
const int depth = xmlTextReaderDepth(inputReader);
|
||||
while (xmlTextReaderRead(inputReader) == 1)
|
||||
{
|
||||
const int child_type = xmlTextReaderNodeType(inputReader);
|
||||
// 1 = Element, 15 = EndElement
|
||||
if (child_type != 1 && child_type != 15)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const int child_depth = xmlTextReaderDepth(inputReader);
|
||||
xmlChar *child_name = xmlTextReaderName(inputReader);
|
||||
if (child_name == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (depth == child_depth && child_type == 15 &&
|
||||
xmlStrEqual(child_name, (const xmlChar *)"node") == 1)
|
||||
{
|
||||
xmlFree(child_name);
|
||||
break;
|
||||
}
|
||||
if (child_type != 1)
|
||||
{
|
||||
xmlFree(child_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(child_name, (const xmlChar *)"tag") == 1)
|
||||
{
|
||||
xmlChar *key = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
|
||||
xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
|
||||
if (key != nullptr && value != nullptr)
|
||||
{
|
||||
node.keyVals.Add(std::string((char *)(key)), std::string((char *)(value)));
|
||||
}
|
||||
if (key != nullptr)
|
||||
{
|
||||
xmlFree(key);
|
||||
}
|
||||
if (value != nullptr)
|
||||
{
|
||||
xmlFree(value);
|
||||
}
|
||||
}
|
||||
|
||||
xmlFree(child_name);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
@@ -1,54 +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 XMLPARSER_H_
|
||||
#define XMLPARSER_H_
|
||||
|
||||
#include "BaseParser.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
|
||||
#include <libxml/xmlreader.h>
|
||||
|
||||
class ExtractorCallbacks;
|
||||
|
||||
class XMLParser : public BaseParser
|
||||
{
|
||||
public:
|
||||
XMLParser(const char *filename,
|
||||
ExtractorCallbacks *extractor_callbacks,
|
||||
ScriptingEnvironment &scripting_environment);
|
||||
bool ReadHeader();
|
||||
bool Parse();
|
||||
|
||||
private:
|
||||
InputRestrictionContainer ReadXMLRestriction();
|
||||
ExtractionWay ReadXMLWay();
|
||||
ImportNode ReadXMLNode();
|
||||
xmlTextReaderPtr inputReader;
|
||||
};
|
||||
|
||||
#endif /* XMLPARSER_H_ */
|
||||
@@ -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,111 +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
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
constexpr float COORDINATE_PRECISION = 1000000.f;
|
||||
|
||||
struct FixedPointCoordinate
|
||||
{
|
||||
int lat;
|
||||
int lon;
|
||||
|
||||
FixedPointCoordinate();
|
||||
FixedPointCoordinate(int lat, int lon);
|
||||
|
||||
template<class T>
|
||||
FixedPointCoordinate(const T &coordinate) : lat(coordinate.lat), lon(coordinate.lon)
|
||||
{
|
||||
static_assert(std::is_same<decltype(lat), decltype(coordinate.lat)>::value, "coordinate types incompatible");
|
||||
static_assert(std::is_same<decltype(lon), decltype(coordinate.lon)>::value, "coordinate types incompatible");
|
||||
}
|
||||
|
||||
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 &first_coordinate,
|
||||
const FixedPointCoordinate &second_coordinate);
|
||||
|
||||
static float ApproximateEuclideanDistance(const FixedPointCoordinate &first_coordinate,
|
||||
const FixedPointCoordinate &second_coordinate);
|
||||
|
||||
static float
|
||||
ApproximateEuclideanDistance(const int lat1, const int lon1, const int lat2, const int lon2);
|
||||
|
||||
static float ApproximateSquaredEuclideanDistance(const FixedPointCoordinate &first_coordinate,
|
||||
const FixedPointCoordinate &second_coordinate);
|
||||
|
||||
static void convertInternalLatLonToString(const int value, std::string &output);
|
||||
|
||||
static void convertInternalCoordinateToString(const FixedPointCoordinate &coordinate,
|
||||
std::string &output);
|
||||
|
||||
static void convertInternalReversedCoordinateToString(const FixedPointCoordinate &coordinate,
|
||||
std::string &output);
|
||||
|
||||
static float ComputePerpendicularDistance(const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location);
|
||||
|
||||
static float ComputePerpendicularDistance(const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location,
|
||||
FixedPointCoordinate &nearest_location,
|
||||
float &ratio);
|
||||
|
||||
static int
|
||||
OrderedPerpendicularDistanceApproximation(const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location);
|
||||
|
||||
static float GetBearing(const FixedPointCoordinate &A, const FixedPointCoordinate &B);
|
||||
|
||||
float GetBearing(const FixedPointCoordinate &other) const;
|
||||
|
||||
void Output(std::ostream &out) const;
|
||||
|
||||
static float DegreeToRadian(const float degree);
|
||||
static float RadianToDegree(const float radian);
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &out_stream, FixedPointCoordinate const &coordinate)
|
||||
{
|
||||
coordinate.Output(out_stream);
|
||||
return out_stream;
|
||||
}
|
||||
|
||||
#endif /* FIXED_POINT_COORDINATE_H_ */
|
||||
@@ -1,53 +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>
|
||||
#include <algorithm>
|
||||
|
||||
namespace http
|
||||
{
|
||||
struct Header
|
||||
{
|
||||
Header& operator=(const Header& other) = default;
|
||||
Header(const std::string & name, const std::string & value) : name(name), value(value) {}
|
||||
Header(Header && other) : name(std::move(other.name)), value(std::move(other.value)) {}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
name.clear();
|
||||
value.clear();
|
||||
}
|
||||
|
||||
std::string name;
|
||||
std::string value;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // HTTP_HEADER_H
|
||||
@@ -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 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<char> 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,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 ROUTE_PARAMETERS_H
|
||||
#define ROUTE_PARAMETERS_H
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/fusion/container/vector/vector_fwd.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct RouteParameters
|
||||
{
|
||||
RouteParameters();
|
||||
|
||||
void setZoomLevel(const short level);
|
||||
|
||||
void setNumberOfResults(const short number);
|
||||
|
||||
void setAlternateRouteFlag(const bool flag);
|
||||
|
||||
void setUTurn(const bool flag);
|
||||
|
||||
void setAllUTurns(const bool flag);
|
||||
|
||||
void setDeprecatedAPIFlag(const std::string &);
|
||||
|
||||
void setChecksum(const unsigned check_sum);
|
||||
|
||||
void setInstructionFlag(const bool flag);
|
||||
|
||||
void setService(const std::string &service);
|
||||
|
||||
void setOutputFormat(const std::string &format);
|
||||
|
||||
void setJSONpParameter(const std::string ¶meter);
|
||||
|
||||
void addHint(const std::string &hint);
|
||||
|
||||
void setLanguage(const std::string &language);
|
||||
|
||||
void setGeometryFlag(const bool flag);
|
||||
|
||||
void setCompressionFlag(const bool flag);
|
||||
|
||||
void addCoordinate(const boost::fusion::vector<double, double> &coordinates);
|
||||
|
||||
short zoom_level;
|
||||
bool print_instructions;
|
||||
bool alternate_route;
|
||||
bool geometry;
|
||||
bool compression;
|
||||
bool deprecatedAPI;
|
||||
bool uturn_default;
|
||||
unsigned check_sum;
|
||||
short num_results;
|
||||
std::string service;
|
||||
std::string output_format;
|
||||
std::string jsonp_parameter;
|
||||
std::string language;
|
||||
std::vector<std::string> hints;
|
||||
std::vector<bool> uturns;
|
||||
std::vector<FixedPointCoordinate> coordinates;
|
||||
};
|
||||
|
||||
#endif // ROUTE_PARAMETERS_H
|
||||
@@ -1,38 +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 SERVER_PATH_H
|
||||
#define SERVER_PATH_H
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
typedef std::unordered_map<std::string, boost::filesystem::path> ServerPaths;
|
||||
|
||||
#endif // SERVER_PATH_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,166 +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.
|
||||
|
||||
*/
|
||||
|
||||
namespace boost { namespace interprocess { class named_mutex; } }
|
||||
|
||||
#include "OSRM_impl.h"
|
||||
#include "OSRM.h"
|
||||
|
||||
#include <osrm/Reply.h>
|
||||
#include <osrm/RouteParameters.h>
|
||||
#include <osrm/ServerPaths.h>
|
||||
|
||||
#include "../Plugins/BasePlugin.h"
|
||||
#include "../Plugins/DistanceTablePlugin.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 "../Util/make_unique.hpp"
|
||||
#include "../Util/ProgramOptions.h"
|
||||
#include "../Util/simple_logger.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/interprocess/sync/named_condition.hpp>
|
||||
#include <boost/interprocess/sync/scoped_lock.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
OSRM_impl::OSRM_impl(ServerPaths server_paths, const bool use_shared_memory)
|
||||
{
|
||||
if (use_shared_memory)
|
||||
{
|
||||
barrier = osrm::make_unique<SharedBarriers>();
|
||||
query_data_facade = new SharedDataFacade<QueryEdge::EdgeData>();
|
||||
}
|
||||
else
|
||||
{
|
||||
// populate base path
|
||||
populate_base_path(server_paths);
|
||||
query_data_facade = new InternalDataFacade<QueryEdge::EdgeData>(server_paths);
|
||||
}
|
||||
|
||||
// The following plugins handle all requests.
|
||||
RegisterPlugin(new DistanceTablePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
|
||||
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()
|
||||
{
|
||||
delete query_data_facade;
|
||||
for (PluginMap::value_type &plugin_pointer : plugin_map)
|
||||
{
|
||||
delete plugin_pointer.second;
|
||||
}
|
||||
}
|
||||
|
||||
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 (barrier)
|
||||
{
|
||||
// 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 (barrier)
|
||||
{
|
||||
// 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(ServerPaths paths, const bool use_shared_memory)
|
||||
: OSRM_pimpl_(osrm::make_unique<OSRM_impl>(paths, use_shared_memory))
|
||||
{
|
||||
}
|
||||
|
||||
OSRM::~OSRM() { OSRM_pimpl_.reset(); }
|
||||
|
||||
void OSRM::RunQuery(RouteParameters &route_parameters, http::Reply &reply)
|
||||
{
|
||||
OSRM_pimpl_->RunQuery(route_parameters, reply);
|
||||
}
|
||||
@@ -1,66 +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
|
||||
|
||||
class BasePlugin;
|
||||
namespace http { class Reply; }
|
||||
struct RouteParameters;
|
||||
|
||||
#include <osrm/ServerPaths.h>
|
||||
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
struct SharedBarriers;
|
||||
template <class EdgeDataT> class BaseDataFacade;
|
||||
|
||||
class OSRM_impl
|
||||
{
|
||||
private:
|
||||
using PluginMap = std::unordered_map<std::string, BasePlugin *>;
|
||||
|
||||
public:
|
||||
OSRM_impl(ServerPaths paths, const bool use_shared_memory);
|
||||
OSRM_impl(const OSRM_impl &) = delete;
|
||||
virtual ~OSRM_impl();
|
||||
void RunQuery(RouteParameters &route_parameters, http::Reply &reply);
|
||||
|
||||
private:
|
||||
void RegisterPlugin(BasePlugin *plugin);
|
||||
PluginMap plugin_map;
|
||||
// will only be initialized if shared memory is used
|
||||
std::unique_ptr<SharedBarriers> barrier;
|
||||
// base class pointer to the objects
|
||||
BaseDataFacade<QueryEdge::EdgeData> *query_data_facade;
|
||||
};
|
||||
|
||||
#endif // OSRM_IMPL_H
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, 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 DISTANCE_TABLE_PLUGIN_H
|
||||
#define DISTANCE_TABLE_PLUGIN_H
|
||||
|
||||
#include "BasePlugin.h"
|
||||
|
||||
#include "../Algorithms/ObjectToBase64.h"
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "../DataStructures/SearchEngine.h"
|
||||
#include "../Descriptors/BaseDescriptor.h"
|
||||
#include "../Util/make_unique.hpp"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin
|
||||
{
|
||||
private:
|
||||
std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
|
||||
|
||||
public:
|
||||
explicit DistanceTablePlugin(DataFacadeT *facade) : descriptor_string("table"), facade(facade)
|
||||
{
|
||||
search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
|
||||
}
|
||||
|
||||
virtual ~DistanceTablePlugin() {}
|
||||
|
||||
const std::string GetDescriptor() const final { return descriptor_string; }
|
||||
|
||||
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
|
||||
{
|
||||
// check number of parameters
|
||||
if (2 > route_parameters.coordinates.size())
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
RawRouteData raw_route;
|
||||
raw_route.check_sum = facade->GetCheckSum();
|
||||
|
||||
if (std::any_of(begin(route_parameters.coordinates),
|
||||
end(route_parameters.coordinates),
|
||||
[&](FixedPointCoordinate coordinate)
|
||||
{
|
||||
return !coordinate.isValid();
|
||||
}))
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const FixedPointCoordinate &coordinate : route_parameters.coordinates)
|
||||
{
|
||||
raw_route.raw_via_node_coordinates.emplace_back(std::move(coordinate));
|
||||
}
|
||||
|
||||
const bool checksum_OK = (route_parameters.check_sum == raw_route.check_sum);
|
||||
unsigned max_locations =
|
||||
std::min(100u, static_cast<unsigned>(raw_route.raw_via_node_coordinates.size()));
|
||||
PhantomNodeArray phantom_node_vector(max_locations);
|
||||
for (unsigned i = 0; i < max_locations; ++i)
|
||||
{
|
||||
if (checksum_OK && i < route_parameters.hints.size() &&
|
||||
!route_parameters.hints[i].empty())
|
||||
{
|
||||
PhantomNode current_phantom_node;
|
||||
ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node);
|
||||
if (current_phantom_node.isValid(facade->GetNumberOfNodes()))
|
||||
{
|
||||
phantom_node_vector[i].emplace_back(std::move(current_phantom_node));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
facade->IncrementalFindPhantomNodeForCoordinate(raw_route.raw_via_node_coordinates[i],
|
||||
phantom_node_vector[i],
|
||||
route_parameters.zoom_level,
|
||||
1);
|
||||
|
||||
BOOST_ASSERT(phantom_node_vector[i].front().isValid(facade->GetNumberOfNodes()));
|
||||
}
|
||||
|
||||
// TIMER_START(distance_table);
|
||||
std::shared_ptr<std::vector<EdgeWeight>> result_table =
|
||||
search_engine_ptr->distance_table(phantom_node_vector);
|
||||
// TIMER_STOP(distance_table);
|
||||
|
||||
if (!result_table)
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
JSON::Object json_object;
|
||||
JSON::Array json_array;
|
||||
const unsigned number_of_locations = static_cast<unsigned>(phantom_node_vector.size());
|
||||
for (unsigned row = 0; row < number_of_locations; ++row)
|
||||
{
|
||||
JSON::Array json_row;
|
||||
auto row_begin_iterator = result_table->begin() + (row * number_of_locations);
|
||||
auto row_end_iterator = result_table->begin() + ((row + 1) * number_of_locations);
|
||||
json_row.values.insert(json_row.values.end(), row_begin_iterator, row_end_iterator);
|
||||
json_array.values.push_back(json_row);
|
||||
}
|
||||
json_object.values["distance_table"] = json_array;
|
||||
JSON::render(reply.content, json_object);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
DataFacadeT *facade;
|
||||
};
|
||||
|
||||
#endif // DISTANCE_TABLE_PLUGIN_H
|
||||
@@ -1,105 +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 HELLO_WORLD_PLUGIN_H
|
||||
#define HELLO_WORLD_PLUGIN_H
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "../Util/cast.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
class HelloWorldPlugin final : public BasePlugin
|
||||
{
|
||||
private:
|
||||
std::string temp_string;
|
||||
|
||||
public:
|
||||
HelloWorldPlugin() : descriptor_string("hello") {}
|
||||
virtual ~HelloWorldPlugin() {}
|
||||
const std::string GetDescriptor() const final { return descriptor_string; }
|
||||
|
||||
void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply) final
|
||||
{
|
||||
reply.status = http::Reply::ok;
|
||||
|
||||
JSON::Object json_result;
|
||||
std::string temp_string;
|
||||
json_result.values["title"] = "Hello World";
|
||||
|
||||
temp_string = cast::integral_to_string(routeParameters.zoom_level);
|
||||
json_result.values["zoom_level"] = temp_string;
|
||||
|
||||
temp_string = cast::integral_to_string(routeParameters.check_sum);
|
||||
json_result.values["check_sum"] = temp_string;
|
||||
json_result.values["instructions"] = (routeParameters.print_instructions ? "yes" : "no");
|
||||
json_result.values["geometry"] = (routeParameters.geometry ? "yes" : "no");
|
||||
json_result.values["compression"] = (routeParameters.compression ? "yes" : "no");
|
||||
json_result.values["output_format"] =
|
||||
(!routeParameters.output_format.empty() ? "yes" : "no");
|
||||
|
||||
json_result.values["jsonp_parameter"] =
|
||||
(!routeParameters.jsonp_parameter.empty() ? "yes" : "no");
|
||||
json_result.values["language"] = (!routeParameters.language.empty() ? "yes" : "no");
|
||||
|
||||
temp_string = cast::integral_to_string(routeParameters.coordinates.size());
|
||||
json_result.values["location_count"] = temp_string;
|
||||
|
||||
JSON::Array json_locations;
|
||||
unsigned counter = 0;
|
||||
for (const FixedPointCoordinate &coordinate : routeParameters.coordinates)
|
||||
{
|
||||
JSON::Object json_location;
|
||||
JSON::Array json_coordinates;
|
||||
|
||||
json_coordinates.values.push_back(coordinate.lat / COORDINATE_PRECISION);
|
||||
json_coordinates.values.push_back(coordinate.lon / COORDINATE_PRECISION);
|
||||
json_location.values[cast::integral_to_string(counter)] = json_coordinates;
|
||||
json_locations.values.push_back(json_location);
|
||||
++counter;
|
||||
}
|
||||
json_result.values["locations"] = json_locations;
|
||||
json_result.values["hint_count"] = routeParameters.hints.size();
|
||||
|
||||
JSON::Array json_hints;
|
||||
counter = 0;
|
||||
for (const std::string ¤t_hint : routeParameters.hints)
|
||||
{
|
||||
json_hints.values.push_back(current_hint);
|
||||
++counter;
|
||||
}
|
||||
json_result.values["hints"] = json_hints;
|
||||
|
||||
JSON::render(reply.content, json_result);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
#endif // HELLO_WORLD_PLUGIN_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 LOCATE_PLUGIN_H
|
||||
#define LOCATE_PLUGIN_H
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
// locates the nearest node in the road network for a given coordinate.
|
||||
template <class DataFacadeT> class LocatePlugin final : public BasePlugin
|
||||
{
|
||||
public:
|
||||
explicit LocatePlugin(DataFacadeT *facade) : descriptor_string("locate"), facade(facade) {}
|
||||
const std::string GetDescriptor() const final { return descriptor_string; }
|
||||
|
||||
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
|
||||
{
|
||||
// check number of parameters
|
||||
if (route_parameters.coordinates.empty() || !route_parameters.coordinates.front().isValid())
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
JSON::Object json_result;
|
||||
FixedPointCoordinate result;
|
||||
if (!facade->LocateClosestEndPointForCoordinate(route_parameters.coordinates.front(),
|
||||
result))
|
||||
{
|
||||
json_result.values["status"] = 207;
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.status = http::Reply::ok;
|
||||
json_result.values["status"] = 0;
|
||||
JSON::Array json_coordinate;
|
||||
json_coordinate.values.push_back(result.lat / COORDINATE_PRECISION);
|
||||
json_coordinate.values.push_back(result.lon / COORDINATE_PRECISION);
|
||||
json_result.values["mapped_coordinate"] = json_coordinate;
|
||||
}
|
||||
|
||||
JSON::render(reply.content, json_result);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
DataFacadeT *facade;
|
||||
};
|
||||
|
||||
#endif /* LOCATE_PLUGIN_H */
|
||||
@@ -1,116 +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/JSONContainer.h"
|
||||
#include "../DataStructures/PhantomNodes.h"
|
||||
#include "../DataStructures/Range.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
/*
|
||||
* This Plugin locates the nearest point on a street in the road network for a given coordinate.
|
||||
*/
|
||||
|
||||
template <class DataFacadeT> class NearestPlugin final : public BasePlugin
|
||||
{
|
||||
public:
|
||||
explicit NearestPlugin(DataFacadeT *facade) : facade(facade), descriptor_string("nearest") {}
|
||||
|
||||
const std::string GetDescriptor() const final { return descriptor_string; }
|
||||
|
||||
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
|
||||
{
|
||||
// check number of parameters
|
||||
if (route_parameters.coordinates.empty() || !route_parameters.coordinates.front().isValid())
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
auto number_of_results = static_cast<std::size_t>(route_parameters.num_results);
|
||||
std::vector<PhantomNode> phantom_node_vector;
|
||||
facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates.front(),
|
||||
phantom_node_vector,
|
||||
route_parameters.zoom_level,
|
||||
static_cast<int>(number_of_results));
|
||||
|
||||
JSON::Object json_result;
|
||||
if (phantom_node_vector.empty() || !phantom_node_vector.front().isValid())
|
||||
{
|
||||
json_result.values["status"] = 207;
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.status = http::Reply::ok;
|
||||
json_result.values["status"] = 0;
|
||||
|
||||
if (number_of_results > 1)
|
||||
{
|
||||
JSON::Array results;
|
||||
|
||||
auto vector_length = phantom_node_vector.size();
|
||||
for (const auto i : osrm::irange<std::size_t>(0, std::min(number_of_results, vector_length)))
|
||||
{
|
||||
JSON::Array json_coordinate;
|
||||
JSON::Object result;
|
||||
json_coordinate.values.push_back(phantom_node_vector.at(i).location.lat /
|
||||
COORDINATE_PRECISION);
|
||||
json_coordinate.values.push_back(phantom_node_vector.at(i).location.lon /
|
||||
COORDINATE_PRECISION);
|
||||
result.values["mapped coordinate"] = json_coordinate;
|
||||
std::string temp_string;
|
||||
facade->GetName(phantom_node_vector.front().name_id, temp_string);
|
||||
result.values["name"] = temp_string;
|
||||
results.values.push_back(result);
|
||||
}
|
||||
json_result.values["results"] = results;
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON::Array json_coordinate;
|
||||
json_coordinate.values.push_back(phantom_node_vector.front().location.lat /
|
||||
COORDINATE_PRECISION);
|
||||
json_coordinate.values.push_back(phantom_node_vector.front().location.lon /
|
||||
COORDINATE_PRECISION);
|
||||
json_result.values["mapped_coordinate"] = json_coordinate;
|
||||
std::string temp_string;
|
||||
facade->GetName(phantom_node_vector.front().name_id, temp_string);
|
||||
json_result.values["name"] = temp_string;
|
||||
}
|
||||
}
|
||||
JSON::render(reply.content, json_result);
|
||||
}
|
||||
|
||||
private:
|
||||
DataFacadeT *facade;
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
#endif /* NEAREST_PLUGIN_H */
|
||||
@@ -1,59 +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 TIMESTAMP_PLUGIN_H
|
||||
#define TIMESTAMP_PLUGIN_H
|
||||
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "BasePlugin.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
template <class DataFacadeT> class TimestampPlugin final : public BasePlugin
|
||||
{
|
||||
public:
|
||||
explicit TimestampPlugin(const DataFacadeT *facade)
|
||||
: facade(facade), descriptor_string("timestamp")
|
||||
{
|
||||
}
|
||||
const std::string GetDescriptor() const final { return descriptor_string; }
|
||||
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
|
||||
{
|
||||
reply.status = http::Reply::ok;
|
||||
JSON::Object json_result;
|
||||
json_result.values["status"] = 0;
|
||||
const std::string timestamp = facade->GetTimestamp();
|
||||
json_result.values["timestamp"] = timestamp;
|
||||
JSON::render(reply.content, json_result);
|
||||
}
|
||||
|
||||
private:
|
||||
const DataFacadeT *facade;
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
#endif /* TIMESTAMP_PLUGIN_H */
|
||||
@@ -1,176 +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 VIA_ROUTE_PLUGIN_H
|
||||
#define VIA_ROUTE_PLUGIN_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/make_unique.hpp"
|
||||
#include "../Util/simple_logger.hpp"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
|
||||
{
|
||||
private:
|
||||
std::unordered_map<std::string, unsigned> descriptor_table;
|
||||
std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
|
||||
|
||||
public:
|
||||
explicit ViaRoutePlugin(DataFacadeT *facade) : descriptor_string("viaroute"), facade(facade)
|
||||
{
|
||||
search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
|
||||
|
||||
descriptor_table.emplace("json", 0);
|
||||
descriptor_table.emplace("gpx", 1);
|
||||
// descriptor_table.emplace("geojson", 2);
|
||||
}
|
||||
|
||||
virtual ~ViaRoutePlugin() {}
|
||||
|
||||
const std::string GetDescriptor() const final { return descriptor_string; }
|
||||
|
||||
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
|
||||
{
|
||||
// check number of parameters
|
||||
if (2 > route_parameters.coordinates.size() ||
|
||||
std::any_of(begin(route_parameters.coordinates),
|
||||
end(route_parameters.coordinates),
|
||||
[&](FixedPointCoordinate coordinate)
|
||||
{
|
||||
return !coordinate.isValid();
|
||||
}))
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
RawRouteData raw_route;
|
||||
raw_route.check_sum = facade->GetCheckSum();
|
||||
for (const FixedPointCoordinate &coordinate : route_parameters.coordinates)
|
||||
{
|
||||
raw_route.raw_via_node_coordinates.emplace_back(coordinate);
|
||||
}
|
||||
|
||||
std::vector<PhantomNode> phantom_node_vector(raw_route.raw_via_node_coordinates.size());
|
||||
const bool checksum_OK = (route_parameters.check_sum == raw_route.check_sum);
|
||||
|
||||
for (unsigned i = 0; i < raw_route.raw_via_node_coordinates.size(); ++i)
|
||||
{
|
||||
if (checksum_OK && i < route_parameters.hints.size() &&
|
||||
!route_parameters.hints[i].empty())
|
||||
{
|
||||
ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], phantom_node_vector[i]);
|
||||
if (phantom_node_vector[i].isValid(facade->GetNumberOfNodes()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
facade->FindPhantomNodeForCoordinate(raw_route.raw_via_node_coordinates[i],
|
||||
phantom_node_vector[i],
|
||||
route_parameters.zoom_level);
|
||||
}
|
||||
|
||||
PhantomNodes current_phantom_node_pair;
|
||||
for (unsigned i = 0; i < phantom_node_vector.size() - 1; ++i)
|
||||
{
|
||||
current_phantom_node_pair.source_phantom = phantom_node_vector[i];
|
||||
current_phantom_node_pair.target_phantom = phantom_node_vector[i + 1];
|
||||
raw_route.segment_end_coordinates.emplace_back(current_phantom_node_pair);
|
||||
}
|
||||
|
||||
const bool is_alternate_requested = route_parameters.alternate_route;
|
||||
const bool is_only_one_segment = (1 == raw_route.segment_end_coordinates.size());
|
||||
if (is_alternate_requested && is_only_one_segment)
|
||||
{
|
||||
search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
|
||||
raw_route);
|
||||
}
|
||||
else
|
||||
{
|
||||
search_engine_ptr->shortest_path(
|
||||
raw_route.segment_end_coordinates, route_parameters.uturns, raw_route);
|
||||
}
|
||||
|
||||
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found";
|
||||
}
|
||||
reply.status = http::Reply::ok;
|
||||
|
||||
DescriptorConfig descriptor_config;
|
||||
|
||||
auto iter = descriptor_table.find(route_parameters.output_format);
|
||||
unsigned descriptor_type = (iter != descriptor_table.end() ? iter->second : 0);
|
||||
|
||||
descriptor_config.zoom_level = route_parameters.zoom_level;
|
||||
descriptor_config.instructions = route_parameters.print_instructions;
|
||||
descriptor_config.geometry = route_parameters.geometry;
|
||||
descriptor_config.encode_geometry = route_parameters.compression;
|
||||
|
||||
std::shared_ptr<BaseDescriptor<DataFacadeT>> descriptor;
|
||||
switch (descriptor_type)
|
||||
{
|
||||
// case 0:
|
||||
// descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>();
|
||||
// break;
|
||||
case 1:
|
||||
descriptor = std::make_shared<GPXDescriptor<DataFacadeT>>(facade);
|
||||
break;
|
||||
// case 2:
|
||||
// descriptor = std::make_shared<GEOJSONDescriptor<DataFacadeT>>();
|
||||
// break;
|
||||
default:
|
||||
descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>(facade);
|
||||
break;
|
||||
}
|
||||
|
||||
descriptor->SetConfig(descriptor_config);
|
||||
descriptor->Run(raw_route, reply);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
DataFacadeT *facade;
|
||||
};
|
||||
|
||||
#endif // VIA_ROUTE_PLUGIN_H
|
||||
@@ -1,12 +1,68 @@
|
||||
# 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/Project-OSRM/osrm-backend/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
|
||||
## Contact
|
||||
|
||||
- IRC: server `irc.oftc.net`, channel: `#osrm` (see: `https://www.oftc.net`, and for a webchat: `https://webchat.oftc.net`)
|
||||
- Mailinglist: `https://lists.openstreetmap.org/listinfo/osrm-talk`
|
||||
|
||||
## 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/route/v1/driving/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/route/v1/driving/13.388860,52.517037;13.385983,52.496891?steps=true&alternatives=true
|
||||
```
|
||||
|
||||
## References in publications
|
||||
|
||||
@@ -31,11 +87,3 @@ When using the code in a (scientific) publication, please cite
|
||||
}
|
||||
```
|
||||
|
||||
## Current build status
|
||||
|
||||
| build config | branch | status |
|
||||
|:-------------|:--------|:------------|
|
||||
| Linux | master | [](https://travis-ci.org/DennisOSRM/Project-OSRM) |
|
||||
| Linux | develop | [](https://travis-ci.org/DennisOSRM/Project-OSRM) |
|
||||
| Windows | master/develop | [](https://ci.appveyor.com/project/DennisOSRM/osrm-backend) |
|
||||
| LUAbind fork | master | [](https://travis-ci.org/DennisOSRM/luabind) |
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
require 'OSM/StreamParser'
|
||||
require 'socket'
|
||||
require 'digest/sha1'
|
||||
require 'cucumber/rake/task'
|
||||
require 'sys/proctable'
|
||||
|
||||
BUILD_FOLDER = 'build'
|
||||
DATA_FOLDER = 'sandbox'
|
||||
PROFILE = 'bicycle'
|
||||
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
|
||||
|
||||
|
||||
desc "Remove test cache files."
|
||||
task :sweep do
|
||||
system "rm test/cache/*"
|
||||
end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user