Compare commits
1902 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f6116db957 | |||
| c824429458 | |||
| 23b2154d98 | |||
| 25c8711aad | |||
| cf30628d4e | |||
| 7675c730b6 | |||
| 2ce74c05e1 | |||
| 88e6558da3 | |||
| f1140ec903 | |||
| 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 | |||
| 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 | |||
| 048be2da2c | |||
| 788bc67faa | |||
| 8e1f70865e | |||
| 6143f1ff5b | |||
| db30836b53 | |||
| 3e8ef5e462 | |||
| 0a53dccd4c | |||
| 2b5aa142fb | |||
| 40443d1e25 | |||
| cb4e7614ee | |||
| 3d84dbc73f | |||
| beb2ab9ad5 | |||
| 9a0877379c | |||
| bbd0239ece | |||
| 92956f2b45 | |||
| 48d1a5ec5d | |||
| 2ff2ce460c | |||
| 7cc875b8db | |||
| 9387f583fa | |||
| 707dd700b0 | |||
| ddff9b612f | |||
| 338ac5d4a3 | |||
| ca7abd727a | |||
| 62b20769ee | |||
| 4ec323c5cc | |||
| 84e72ede72 | |||
| bd37c48596 | |||
| e30f0e8e11 | |||
| c43a2513a8 | |||
| 4b4bc0dde2 | |||
| 49adf2192a | |||
| a7eabeb73f | |||
| f838f3427b | |||
| 1cc75ca636 | |||
| d4356b0453 | |||
| 35542e5823 | |||
| c80c2233c5 | |||
| c2f0e4f683 | |||
| 2621f4a2fa | |||
| 3c055642d5 | |||
| 43b881d0cd | |||
| 8b7b32e225 | |||
| 00b0ff50f3 | |||
| 1acde593b5 | |||
| c43c043521 | |||
| b526cadebd | |||
| 94f44e1d5d | |||
| 0352d9c99e | |||
| 0cd3f37e1b | |||
| 486d7b6d62 | |||
| 8f4e332409 | |||
| f0389c0b2f | |||
| 922e8a4912 | |||
| 021a1c7a39 | |||
| 4a7451682b | |||
| faa880d60a | |||
| fd30e82836 | |||
| 3ef34fbb56 | |||
| 7345dc6861 | |||
| 9958937fd1 | |||
| f19c57200d | |||
| 8a2652f53d | |||
| dddde4ddab | |||
| 300d901618 | |||
| 1cb72acd27 | |||
| a17776cb5f | |||
| 94b749ab00 | |||
| 5fc0d284cb | |||
| bbe1211451 | |||
| ce152b205f | |||
| a5fd7cf4e9 | |||
| da38a1367a | |||
| 1445f11c19 | |||
| 86df55f5cc | |||
| cf294c938e | |||
| ebff45f803 | |||
| 7b8021a36e | |||
| 5c77bb7c67 | |||
| 8ade26b4a4 | |||
| bdbc60b4f7 | |||
| 373fa7a7d9 | |||
| eec4f173a7 | |||
| d726ce6340 | |||
| b406844c96 | |||
| 153d38f10c | |||
| dce917eb74 | |||
| eb711787ae | |||
| 9967dbbaa9 | |||
| 71dc10ebea | |||
| 782fba2ce7 | |||
| 4d73f98050 | |||
| 79d2083a00 | |||
| ee3b296a99 | |||
| 8b62d04453 | |||
| 9b0d3dfaeb | |||
| b1ef4cfee9 | |||
| f12f6a56ba | |||
| 2777d53a12 | |||
| aba3ec692f | |||
| b7c8fcd062 | |||
| 3065de63dd | |||
| a57fb4f1ab | |||
| c493a22765 | |||
| d85e5def5d | |||
| 0aba499c8e | |||
| 4146695f34 | |||
| 4e57e10ba8 | |||
| daa6d02887 | |||
| a87d89302f | |||
| 2a9b1311d3 | |||
| 7d73501b87 | |||
| 039d6acd3e | |||
| 405fcdc483 | |||
| f52abc1a62 | |||
| e763953562 | |||
| 4cab617c25 | |||
| 0190b5e5af | |||
| abc0952247 | |||
| 6ce2726a87 | |||
| 17a4463f59 | |||
| e76d8df246 | |||
| a46bcf45d5 | |||
| 1f985d04a2 | |||
| d64e6e6c1f | |||
| 1164a65df8 | |||
| d57f07d57e | |||
| 5c0a964321 | |||
| cf3b8d09d9 | |||
| 1c7397fb21 | |||
| 6a08d93e2c | |||
| 4c03ace9eb | |||
| 2cd616dd30 | |||
| eab87c0827 | |||
| 8b8188710e | |||
| fd9bb3ac43 | |||
| 6d9c3bca33 | |||
| dd33a45644 | |||
| 074c7a9c40 | |||
| de2f06970d | |||
| 6166d946f7 | |||
| c778ab9622 | |||
| aad846b968 | |||
| f04a3e3d2e | |||
| 7ad52de2b1 | |||
| 0706ba9bec | |||
| ed53888fce | |||
| fd76fba235 | |||
| 95088a785a | |||
| f46b600ec0 | |||
| 566ab993df | |||
| 407036e215 | |||
| 7b1a5566fb | |||
| 1b0d8739c1 | |||
| 266feea397 | |||
| c4c6ab2494 | |||
| 079eea3f2b | |||
| a457d69034 | |||
| d0175798bf | |||
| 80e07943ee | |||
| e2954211ec | |||
| 337bed8176 | |||
| 71197e1c89 | |||
| e1a13f5ce8 | |||
| 1ed2c16a51 | |||
| 12e1bd80b3 | |||
| fd6daa580a | |||
| d2a19ec8ec | |||
| 8f3feac916 | |||
| c0e066440c | |||
| fbb4e9078a | |||
| d96e90c6f4 | |||
| 3b435d8956 | |||
| 345dd2481b | |||
| 006bcc0fc8 | |||
| c25d14e454 | |||
| 5ff95dc32d | |||
| 34031aab1b | |||
| 3035219212 | |||
| 8a608eb930 | |||
| c2fc47df34 | |||
| d4065774ce | |||
| 6d43d9f2b6 | |||
| 94d7fd9112 | |||
| 04b5833e98 | |||
| 52592b84fd | |||
| f2cd68e3ec | |||
| aff590a44d | |||
| 0d432f6377 | |||
| 59bceee258 | |||
| 4a0a0bac1d | |||
| c7bd96ea8b | |||
| 0eb2106067 | |||
| c03aec364c | |||
| f2cdb97867 | |||
| 727e284ed0 | |||
| 3248977e02 | |||
| 7ee8776165 | |||
| f89f4bd20b | |||
| a372ade7ce | |||
| 61dca4a35e | |||
| c0402345f7 | |||
| 9cc68b26e2 | |||
| 27c9230a82 | |||
| e985c9714b | |||
| 6c5015811e | |||
| 86e7de4d62 | |||
| 147d35e40d | |||
| b76fc724fd | |||
| 1bfab4e279 | |||
| 11bdfba37e | |||
| 405f08b807 | |||
| 592211cecd | |||
| a4f31001e8 | |||
| c2deedac8b | |||
| 9a61f8b894 | |||
| 3a291f5c8e | |||
| 559a2dcec7 | |||
| b7f003c4aa | |||
| d11c0bbd5c | |||
| c2f775fcaa | |||
| 19ac831c2e | |||
| 23b413a398 | |||
| 098de196e2 | |||
| 27d2c31f28 | |||
| c9c9edeb23 | |||
| 5adf792fad | |||
| 81af7d73a6 | |||
| 23e4e0786d | |||
| 0640ce9632 | |||
| 3e49bf4f42 | |||
| 66b038a010 | |||
| 9bbbebf31d | |||
| 19765cfa14 | |||
| d6badca610 | |||
| 6933804aa4 | |||
| 5bed7f292f | |||
| f553896e2d | |||
| 60663b5433 | |||
| 1851a31e66 | |||
| d853310bee | |||
| 11c671354b | |||
| b15599f01e | |||
| 4b957abc0c | |||
| 8ee82d1e03 | |||
| 5565662d87 | |||
| 78735fae6b | |||
| d3b9911445 | |||
| 7813dafc96 | |||
| 02b561edd2 | |||
| 272a1fda54 | |||
| bc8666df83 | |||
| 028fad94af | |||
| 0c735953c9 | |||
| 736bc87480 | |||
| dd94a64048 | |||
| cf9f88f8ce | |||
| 5694aeda5f | |||
| 7829e3c132 | |||
| 2ce0d60db1 | |||
| 68e66dad06 | |||
| 80db907857 | |||
| 76674a3594 | |||
| 98dba11c5e | |||
| de261d28ef | |||
| d43716612b | |||
| cfaacf7cb2 | |||
| b9922bc90b | |||
| 31cae8f05f | |||
| 133e382aae | |||
| e02c721c2b | |||
| 5af0ceb2d2 | |||
| 6460fdc62b | |||
| 402ca780bf | |||
| 643ab92cd2 | |||
| a9c3b343fc | |||
| 592bebaf29 | |||
| 4df215e674 | |||
| 91792f45ea | |||
| 20091e94c8 | |||
| 76aa494be4 | |||
| 6fb8fdc2bd | |||
| 0d879ed290 | |||
| d8d46e0f3e | |||
| e5830b0116 | |||
| d89b171f49 | |||
| a760aec791 | |||
| 34d5d353af | |||
| e8e637c4f2 | |||
| adbca39fef | |||
| a2c88b607f | |||
| 2115a67d24 | |||
| dec73b02e9 | |||
| 0e6ed53cee | |||
| fd6c70afe1 | |||
| c4f193b13e | |||
| 70703c39f3 | |||
| d429485f0c | |||
| 89460dd39c | |||
| f46b259384 | |||
| fb0ce48f2f | |||
| cb4a81008c | |||
| d620da365e | |||
| 0c3102721c | |||
| b3fa03043d | |||
| 38d7db49c8 | |||
| 1a8c832039 | |||
| 6e54f8cfa6 | |||
| 4838ffb82d | |||
| 1bcf41d382 | |||
| e381566494 | |||
| 66d7a073d3 | |||
| 0637215b85 | |||
| dc1405ffa8 | |||
| 0fce20c503 | |||
| 1b16dd126b | |||
| fe07f9208c | |||
| f092fc3fc6 | |||
| b5228dcda0 | |||
| a5db3ea25b | |||
| 173fad2362 | |||
| 496338d84d | |||
| 59727a6967 | |||
| 3a5e41ed91 | |||
| 2259bce05f | |||
| 7e00a86bb4 | |||
| 73a2a938b4 | |||
| c2098938f5 | |||
| 773ff182ee | |||
| 878c49e4e1 | |||
| 023dd3e880 | |||
| 6b88856c16 | |||
| dd5f926077 | |||
| 845020b0e2 | |||
| 7cf363eb06 | |||
| f67e670621 | |||
| 645e3ccbb3 | |||
| ab385f2bf5 | |||
| 5080b9a82b | |||
| 51e42ded44 | |||
| 37fb89c691 | |||
| 440eda3807 | |||
| bad2576397 | |||
| fdf2e5934d | |||
| 3da1e8598b | |||
| 0296c767bf | |||
| c215c42289 | |||
| 8adab95973 | |||
| b89c7580e6 | |||
| a85fe2cb08 | |||
| 4c4c126361 | |||
| e9e12b88f8 | |||
| dc08c516bf | |||
| 9b1f108051 | |||
| b0f9a0feb4 | |||
| 3bd27ae8c5 | |||
| 79b9bdf7ce | |||
| 9e09168597 | |||
| e5f12347bd | |||
| 86d3556c6d | |||
| 45838b33b7 | |||
| a1d4798ded | |||
| 25c52b7482 | |||
| fcf9f266ad | |||
| fa638ae3a0 | |||
| 6d9cd504a0 | |||
| f9e9bb8870 | |||
| 85ab2425a8 | |||
| 9931155c68 | |||
| 56b6d928b6 | |||
| b865bea482 | |||
| b6314e0c73 | |||
| 2c773750c7 | |||
| 539b9be1d3 | |||
| 00e8caa0e3 | |||
| 1ff8b62bf5 | |||
| 25fb985af8 | |||
| 858245db7d | |||
| 09bea2ad5b | |||
| adb520ec2a | |||
| 5a1ff4b50d | |||
| e0f8acf733 | |||
| a81542eeee | |||
| f67eeb66aa | |||
| 884c998622 | |||
| 88c8d73a94 | |||
| 86576768d1 | |||
| 3327c32b20 | |||
| 97ed6a3a4e | |||
| 85d8e0ac2c | |||
| 2a68f9f532 | |||
| b55d35c7bb | |||
| 98f85d7728 | |||
| 328a7caf61 | |||
| 275ea9b0bb | |||
| bb78bc8fe3 | |||
| 10224a692b | |||
| 3eb83d0737 | |||
| f35fa0049c | |||
| d77a88c21e | |||
| 3d55622237 | |||
| bf76465029 | |||
| 129a6ed99e | |||
| 9f5fc4ab0c | |||
| 97f6468663 | |||
| a883b73981 | |||
| 36aadc21a7 | |||
| da469911d3 | |||
| 4195b0d0e6 | |||
| d241aef502 | |||
| 8b2ca6b13d | |||
| ade94c87b5 | |||
| 46f3426c35 | |||
| 3503cd9b71 | |||
| 73cc040792 | |||
| 6c6029618a | |||
| 2a8084b6c6 | |||
| 86ca9bd0f9 | |||
| b192678abf | |||
| 9a998d7b41 | |||
| 64a6859753 | |||
| b20b7e65bf | |||
| 203e3ef077 | |||
| 7be5502a12 | |||
| 0de6e4ccbb | |||
| c8041bacd6 | |||
| 1187f83ffd | |||
| dd3b8469dd | |||
| 34bbd7dcaa | |||
| 8318b3ba83 | |||
| 6768ecc3fc | |||
| 9672f00ec3 | |||
| 0c1101739d | |||
| 872cb2d9c8 | |||
| 3e47fe54fa | |||
| f0d3d23b5f | |||
| 69e59b0ced | |||
| ad4fb5afe3 | |||
| dd6dd63798 | |||
| 7a3748b8f6 | |||
| 06a08a874f | |||
| 37a9813482 | |||
| fe7b436a8c | |||
| 601eff1af6 | |||
| 29949eae1b | |||
| 9dfe6d1e85 | |||
| fb3bc22c64 | |||
| b89304a24b | |||
| 69b3457e83 | |||
| cf21074f10 | |||
| dc7f21513a | |||
| a15450af91 | |||
| efbcce0ffe | |||
| 1c2c87e03d | |||
| 93b33c0518 | |||
| 53e01952be | |||
| 1c12b468a8 | |||
| ccd803416e | |||
| 62f2a42f28 | |||
| d6e76fd1c0 | |||
| 9135c56ac6 | |||
| 0e7eff3963 | |||
| bd1928e445 | |||
| 8e105af232 | |||
| 796cbafde4 | |||
| 29354a1586 | |||
| bcd73e604c | |||
| e80ca6553d | |||
| 90f17c2140 | |||
| 2e5cc1e6ae | |||
| 0ea7fd9c3d | |||
| 814d9aa01b | |||
| 3fa12445a5 | |||
| 547a2aec09 | |||
| 9175fb7da8 | |||
| 887032881a | |||
| e67f82283f | |||
| cfa83658dc | |||
| c881aa7b32 | |||
| a8db29399f | |||
| baacd0e50c | |||
| 0f8c3b1960 | |||
| cd523cc934 | |||
| 044271a55c | |||
| f662b9a081 | |||
| ba10f97420 | |||
| 50c460ebd5 | |||
| 501863a0eb | |||
| ec9b2dbe42 | |||
| db2ba22bd6 | |||
| 087f08dad2 | |||
| bf7b146dfc | |||
| 01f3237416 | |||
| 8f813fbc67 | |||
| f4ff695080 | |||
| 08cc2bbd70 | |||
| 46a7e46068 | |||
| 472a567f42 | |||
| f3bc1ed3a9 | |||
| 7ba9b97afc | |||
| 061d281d2a | |||
| 2835508292 | |||
| 959d9a3ad9 | |||
| 7cf34a6d6f | |||
| 8d6d7d1f20 | |||
| b115764d9c | |||
| 1b5d332e93 | |||
| 356dfc806d | |||
| f2b556adfd | |||
| 1bbfced61a | |||
| 800cb8c6dd | |||
| 6b1d672dc1 | |||
| 6e138bbf54 | |||
| 6dabf4507a | |||
| 527e6cbc72 | |||
| 39edbcbabd | |||
| 0077856d2f | |||
| b65f1d7df0 | |||
| 201afbbeec | |||
| f5caf96d2e | |||
| 73efcc6b0c | |||
| d69510f997 | |||
| d6946a8aae | |||
| ebbc168f3f | |||
| 347cbd37ca | |||
| d190e0b771 | |||
| 5f28a7db0d | |||
| d0c99f1999 | |||
| bf71781ee9 | |||
| fbce104f3b | |||
| ef9074f8e4 | |||
| 67f3111cc0 | |||
| 56d2101b1a | |||
| a28395b116 | |||
| eebf3a54e2 | |||
| 7e70fa63d7 | |||
| bea4b520c0 | |||
| 64c17c4ecd | |||
| 26f7ac9ca1 | |||
| b1a12768e1 | |||
| 0e5a448d04 | |||
| 91a89399f8 | |||
| c6bb7c5993 | |||
| 48b131eb5c | |||
| 1328be2b61 | |||
| 88c1e622dd | |||
| 10672786a1 | |||
| d896a9efec | |||
| 0ccdd4b6ad | |||
| 66fc676858 | |||
| 12f2acc9ff | |||
| b53e8bf501 | |||
| e296264ea6 | |||
| 598f5519d1 | |||
| ced64d7a09 | |||
| 7075a8a8ef | |||
| e2605c2838 | |||
| be63939441 | |||
| dea9c37d99 | |||
| 4d27366ead | |||
| a11a8429bb | |||
| 6da33cafe5 | |||
| 06f82d5e8a | |||
| 89dd0c4a40 | |||
| 1b10f53eff | |||
| 8bd7d57dd8 | |||
| 4a6325696e | |||
| b50a907ca3 | |||
| 59e9a67abd | |||
| 1d2f06df6d | |||
| 725b93a961 | |||
| a21e4c5a0b | |||
| 433db17083 | |||
| f8753fb9f1 | |||
| 25d5653f66 | |||
| 703a88a639 | |||
| 25326b571b | |||
| 5e2f4c9d2d | |||
| f43d380fe2 | |||
| 2240d3d0d1 | |||
| b6eea9a880 | |||
| 6bbd7c0c0b | |||
| 2caeb4008c | |||
| a4919ffb45 | |||
| b384340cbb | |||
| 061f46306f | |||
| fe1f11b071 | |||
| d3f5db576a | |||
| 0ca586e1c8 | |||
| a0b55f9df3 | |||
| 24943ccee6 | |||
| bcaaf34fa7 | |||
| ea17d1f6c7 | |||
| 3be734010c | |||
| e79787cc77 | |||
| 7de428233e | |||
| 9722f56be8 | |||
| e766d206f1 | |||
| 1fa9091239 | |||
| 04e1e5e3a2 | |||
| fa5c0560fa | |||
| 55d47b3e31 | |||
| 5bb96fd477 | |||
| 22b404a1b4 | |||
| 03dcf82602 | |||
| 95d1e8a4f1 | |||
| 67f68b47db | |||
| 593808f24d | |||
| 0a884cc64a | |||
| a54d4b98b1 | |||
| 23132e5292 | |||
| d741b624be | |||
| 00bc394bdb | |||
| d7215ad185 | |||
| 2b63eb8243 | |||
| 1bb3da0332 | |||
| c7d3d635f6 | |||
| f4c8db6105 | |||
| b2637b9a43 | |||
| 09d0ac3838 | |||
| f42cc848d5 | |||
| 4b1224f874 | |||
| 10bb2cce8e | |||
| 8174b3b85a | |||
| 71e2f2ed61 | |||
| 8d8724b3e1 | |||
| 47f65ccba6 | |||
| df0c1106ce | |||
| 47a2271e27 | |||
| ea367a7f37 | |||
| f4b192e33c | |||
| a5c824f694 | |||
| ccc4607d6d | |||
| 4ec41392f7 | |||
| 5f2b2cd0f7 | |||
| 361e3ca356 | |||
| 13bf4fab32 | |||
| 4b583e8ce9 | |||
| d31c6fe286 | |||
| 79de97d814 | |||
| 1c5d093b59 | |||
| ecff2beafa | |||
| 7e0b19c43d | |||
| 2ebe2faa74 | |||
| aec1451168 | |||
| 38251aa513 | |||
| d92e8ca8d2 | |||
| 2e5876d488 | |||
| 3dddd16ec7 | |||
| 40ff7ad999 | |||
| cb79f769c9 | |||
| e95feff016 | |||
| f65b32c1af | |||
| 46dd9b9887 | |||
| 4445f21e8a | |||
| 00d3676a20 | |||
| 0f7cb12e97 | |||
| 8485e02c00 | |||
| ae7300f9b4 | |||
| fc796539e8 | |||
| 1d8c43b445 | |||
| 58de37e822 | |||
| 7b3a0c5105 | |||
| 592034653c | |||
| 8d9f830c53 | |||
| d8eea0ce0e | |||
| c28c441e77 | |||
| 1391420699 | |||
| c0be751ef4 | |||
| 5e2462e061 | |||
| 5c0eb4772d | |||
| ef8706b4e1 | |||
| acd1919e8d | |||
| 459e2a322b | |||
| e62caf33aa | |||
| 72fd0f3d41 | |||
| 032c21c545 | |||
| b391daac6d | |||
| 8cb6959e3f | |||
| 49c817a60e | |||
| 6859b53155 | |||
| c581563230 | |||
| fc1db35f27 | |||
| 2734a4aee4 | |||
| 172f65969c | |||
| f0dbe0deb9 | |||
| 8f8d81f90c | |||
| 665523bc7e | |||
| 99e8fa70ba | |||
| 4c1d7c9d73 | |||
| d1cc8e7ad7 | |||
| 7629e44e4c | |||
| b62f6a6141 | |||
| 10d7a2396c | |||
| 007eced326 | |||
| 1128270d4b | |||
| c7d889bf9e | |||
| 7cb585c1a1 | |||
| 75157221b2 | |||
| 9807520ef0 | |||
| c658ee5c78 | |||
| cbfbcdcff5 | |||
| 9a0581ea7f | |||
| 60c268ddd6 | |||
| 0361e0204a | |||
| 2da427134b | |||
| 4fce0dadcf | |||
| 288c241fb4 | |||
| f3e3eda69e | |||
| 0f4dd8103d | |||
| 86ee05ee5e | |||
| 3b9c6a6465 | |||
| 8e73a4a19d | |||
| 428bb36ec6 | |||
| 0a24df6bd0 | |||
| d3ca080729 | |||
| 7658031784 | |||
| 710e74219a | |||
| 0249bed53a | |||
| 9d14f81b79 | |||
| a7c683a83c | |||
| 16631bf454 | |||
| 3c563f7073 | |||
| 344bdbb707 | |||
| a0256dfc60 | |||
| b131f27eb9 | |||
| 0d9b70552e | |||
| ea1a89290a | |||
| 59f1679d37 | |||
| 5121983218 | |||
| 0d7141ce5b | |||
| b4b753ce2e | |||
| 4f666e4d53 | |||
| 874a988527 | |||
| 51c79f9784 | |||
| 4d19811026 | |||
| d1454075ab | |||
| becb6cf5bf | |||
| a6f34d2044 | |||
| 7300024e13 | |||
| 282800e6b1 | |||
| e938bd3481 | |||
| 9b501276fb | |||
| 90d191f5f8 | |||
| f452e7f9d2 | |||
| 1d25f41122 | |||
| 5556785804 | |||
| 22ce4c24fb | |||
| d4d2d127d1 | |||
| 3c28932862 | |||
| 7e9177cb3c | |||
| f692103c81 | |||
| 5a1dfe9b89 | |||
| 7175180dc9 | |||
| f95d1fa8ba | |||
| 7b57068f6f | |||
| d79eac3e26 | |||
| 27c255c874 | |||
| bdc611b23a | |||
| 4cddf0bf5d | |||
| 462d4c99cc | |||
| 94a2188090 | |||
| ebcdcb5f00 | |||
| f9e780ed67 | |||
| 18f8ce69cd | |||
| dce665f14e | |||
| 80046b646b | |||
| 06ddceeac0 | |||
| b7ea1dfcd0 | |||
| 6d9598cd4c | |||
| 60c9701c3f | |||
| 2a8644b72c | |||
| b6e469abd1 | |||
| 004c237085 | |||
| 398e3bdf82 | |||
| 958350af82 | |||
| 2d677a8af9 | |||
| 05a79f5b55 | |||
| ac9566d3d7 | |||
| 8b7bf94aae | |||
| c4e785e523 | |||
| 2f6f883f7f | |||
| d071e92a1c | |||
| b18b4072e1 | |||
| 0a2898da17 | |||
| 73fb596973 | |||
| c3f9dc7400 | |||
| c75ce210ea | |||
| ffca6d8ba5 | |||
| 1ec35befc8 | |||
| 6080eaebbd | |||
| 41ea339053 | |||
| 75f9c08445 | |||
| cec3d1488a | |||
| ebec082da2 | |||
| bec585e382 | |||
| 2cc8ae875a | |||
| db8252e650 | |||
| e3cb26a1c4 | |||
| 44036ae26d | |||
| 5b5f871a6e | |||
| 9a8f9cae6d | |||
| 8f804581c0 | |||
| e26ef17545 | |||
| 800bb223b5 | |||
| 75606f2100 | |||
| a28928e6ca | |||
| 8700007025 | |||
| 520f7fa2de | |||
| 096208a154 | |||
| 27caab69ec | |||
| 3fe2b587cb | |||
| c791188811 | |||
| b227c90c18 | |||
| 8a5538356b | |||
| b257c881b5 | |||
| 0f5dffb1c3 | |||
| d2bd238274 | |||
| fed700440d | |||
| 32a9d42412 | |||
| efc938d870 | |||
| 369f669227 | |||
| 1c56671f01 | |||
| 4dbc1e0e96 | |||
| 94288843f1 | |||
| b12decc865 | |||
| 0fc944abf3 | |||
| 9f96c98f02 | |||
| 9805b05738 | |||
| 13ed186469 | |||
| 00a43221ac | |||
| edc39112e2 | |||
| 3b727dea99 | |||
| f16b2adec7 | |||
| 7d425aa76f | |||
| 651c07c724 | |||
| 4d27b75897 | |||
| 6f75d68d07 | |||
| ae269e12bb | |||
| 3a48929fe6 | |||
| be970326b6 | |||
| 463511871f | |||
| 002da1e02d | |||
| b095aae5ce | |||
| 511c21029e | |||
| 81b0447024 | |||
| d42772a261 | |||
| c1136099a9 | |||
| 06f8a975c0 | |||
| c8cd8775f6 | |||
| f9900c91bd | |||
| accaf6e77e | |||
| 8490e297a9 | |||
| 6d3a4b5f6c | |||
| 1f36206f45 | |||
| 952e10936c | |||
| 2b3093a687 | |||
| d7e25772b0 | |||
| c66c9b0353 | |||
| bbde0d75da | |||
| c3aec4f627 | |||
| 113852eed4 | |||
| 6b9b2c1468 | |||
| 2c87b295ff | |||
| 93767d68f8 | |||
| cc3646ca16 | |||
| 48333f73d5 | |||
| 1f4241a63d | |||
| 8eccfaa034 | |||
| 438d1af12a | |||
| 5be6ef380f | |||
| 76419ed2fc | |||
| 4684921e51 | |||
| edd8caa2bf | |||
| cb5575ae89 | |||
| 42e726dec5 | |||
| e3d33aa171 | |||
| f2ceeb35da | |||
| 577cf5ddc4 | |||
| 91ced39233 | |||
| 4b6cb0b8b8 | |||
| fb81302382 | |||
| dfc81f65ee | |||
| 909db4c861 | |||
| 4277eed1b6 | |||
| 6f5703a5fe | |||
| f7469f298d | |||
| b29d5df7a2 | |||
| 549ba65861 | |||
| a9d99cbe54 | |||
| 8438024370 | |||
| e6a00ddcfd | |||
| 71b967d243 | |||
| 1fc1e9590a | |||
| 0a0099fb41 | |||
| b890d394ad | |||
| a7fd37ae76 | |||
| 41fafae21d | |||
| a38c007f51 | |||
| c7ee402b0e | |||
| 1c19796e3e | |||
| 76fb0cb965 | |||
| 23c79f5cc9 | |||
| 14eac50261 | |||
| cf3eae1c91 | |||
| db06cdb4ce | |||
| 7ba8e51fa9 | |||
| bc6466cc36 | |||
| 4fbefaef9a | |||
| be11d3325d | |||
| 274140d309 | |||
| ed960ccc8d | |||
| f2b72113c1 | |||
| 67a8d30e87 | |||
| dafd0e5db7 | |||
| d6d10cbf06 | |||
| 3d3ba86be4 | |||
| 52ed8a7ed0 | |||
| 9449c99e25 | |||
| 4c0846734e | |||
| 4c64f5fe62 | |||
| 9455ea0547 | |||
| c3b54a63c3 | |||
| b9e1d3116c | |||
| 5bb7e62a7c | |||
| a443f3a0bb | |||
| 440244eed8 | |||
| 2b9e25300f | |||
| de264dbf94 | |||
| 848b773e24 | |||
| d92f022041 | |||
| 57fab61789 | |||
| ec8f977ebe | |||
| 8dc85e7641 | |||
| 4e00ebcd74 | |||
| 335e719b5d | |||
| 415f8ef2d8 | |||
| 17615d1d4a | |||
| 5072252c72 | |||
| 46e93770c9 | |||
| fe43734811 | |||
| 0df81c49d5 | |||
| 5653516b32 | |||
| 22da5be08e | |||
| 862656aecc | |||
| ec119a6d52 | |||
| 6b98b5f4c7 | |||
| 5effe95f2c | |||
| f22e3fd3ff | |||
| 0047040af9 | |||
| 60987e6b9b | |||
| 27d5e2b219 | |||
| 53fd0c3a55 | |||
| 63456a6d4f | |||
| d4cd3c2f7b | |||
| dbf7137a1a | |||
| 785891c315 | |||
| b7417ec954 | |||
| 61b861f0e5 | |||
| 0fea0738bf | |||
| 4f25d29815 | |||
| 28302a5040 | |||
| 9cc5ca5c58 | |||
| 4c4e60b3c9 | |||
| 5689a96602 | |||
| 8b57db467a | |||
| 50339e53e2 | |||
| bc9f5189a5 | |||
| fee83fee40 | |||
| cd5112ab0e | |||
| a43b88f9a2 | |||
| c20fd5dcaa | |||
| f12e296c09 | |||
| 9c3a572646 | |||
| 6175faa9a4 | |||
| af02fc6bbe | |||
| cc0bbc42a2 | |||
| fd747c7340 | |||
| bd33202972 | |||
| f6f0de0e38 | |||
| 881041800b | |||
| 11f3ac16f6 | |||
| 969bf95230 | |||
| abc6b4180c | |||
| f74d762a92 | |||
| f00892ed66 | |||
| f14c6e6845 | |||
| b1bbf2ef84 | |||
| 201062cade | |||
| 8cb9198bcf | |||
| f5e53c0452 | |||
| 41d9c00f70 | |||
| b52f392c92 | |||
| efaa3b5ab2 | |||
| 36f3d8d6ac | |||
| e469afa4a9 | |||
| 9d4b0caa5b | |||
| 392c07951e | |||
| 8e72c3d81e | |||
| 02428f1e06 | |||
| b3aa513563 | |||
| b8b08cb114 | |||
| ebbbf1059d | |||
| 37297076f8 | |||
| a75b2df6fe | |||
| 9ccd0f0282 | |||
| e57d9f2e2e | |||
| cf593ba9f9 | |||
| 9eb862a6a4 | |||
| bc84e08da5 | |||
| 24dae2f096 | |||
| ab24d6bd96 | |||
| 7782c80c4f | |||
| 994bd0a910 | |||
| bc9dcba4d4 | |||
| 85c244ed08 | |||
| 495196193c | |||
| def1e5e1d8 | |||
| 2727091e47 | |||
| d7fbd416ba | |||
| 6a09ce1613 | |||
| 774e6346e7 | |||
| 05b939760c | |||
| d6c6fbfe03 | |||
| bb3cbf2dda | |||
| 39d96a45aa | |||
| 6a8c5c8869 | |||
| 96318bbe11 | |||
| 00dd2463fd | |||
| bcd55626ef | |||
| 8f8cb6a52f | |||
| 2e3d33dfcd | |||
| 1e40cd6f0b | |||
| 6e2608b2f2 | |||
| 60d80cf261 | |||
| 9c23fd4a31 | |||
| fccb1aad32 | |||
| 2780ff31b5 | |||
| c37c8dc21d | |||
| 6ee7a81f10 | |||
| 3d94638d86 | |||
| 418ff95543 | |||
| 221113cbb7 | |||
| 13ea12cf6e | |||
| 1945aae4dc | |||
| 30362cfc0c | |||
| 6cdc590db5 | |||
| eb122a2b8c | |||
| feaf8711d3 | |||
| 6e364ff0ba | |||
| 6f6aff7493 | |||
| 207cddd50b | |||
| 35988d8f09 | |||
| bea63028c7 | |||
| 0244060806 | |||
| bfdc296f43 | |||
| 8e625a5d07 | |||
| 3460bd0ba9 | |||
| 4dd0377eb8 | |||
| 6e1ab9fe3a | |||
| 7a2d214cc4 | |||
| 62495a6de4 | |||
| 8ea88468f3 | |||
| 687892890b | |||
| ff0dfacc48 | |||
| 235a52032a | |||
| a5ee7e78f6 | |||
| 181dbe8493 | |||
| dae9c9a7ed | |||
| 6d6d299ea4 | |||
| 6fd615b9cd | |||
| d09394ed52 | |||
| 3e6f27d173 | |||
| 82c2ae5441 | |||
| 7edf2bb2c2 | |||
| c9607b99a3 | |||
| 2fe1a84dd4 | |||
| c63218a889 | |||
| 5efa9664db | |||
| dc75469e78 | |||
| 9d1e21b5ad | |||
| 27a367c733 | |||
| ffa0ace2a7 | |||
| 074e1e992c | |||
| cdd72c7e56 | |||
| a5e99a95a3 | |||
| 1de736019d | |||
| d6b2712070 | |||
| eda8f4ccec | |||
| 7e3f476407 | |||
| e10f36d5f0 | |||
| 1bfd9abda3 | |||
| 4a1a10fde8 | |||
| 4c3cb76ced | |||
| e2794e9f06 | |||
| 7d2c627ad2 | |||
| b310e0f718 | |||
| 18915ae2bd | |||
| 5dbda8f519 | |||
| 82ce9dfc04 | |||
| ad5cd564ab | |||
| 6f01f580ca | |||
| d5130d9fe4 | |||
| 0341a0d5e7 | |||
| 32191fb05a | |||
| 1592fe377a | |||
| 5add28410f | |||
| d54a55c12b | |||
| aab5e8430f | |||
| 2e20fdb462 | |||
| 2ac3da7a90 | |||
| 399b79bab2 | |||
| b9eb936cac | |||
| 38117df11b | |||
| 27d729baf0 | |||
| d408a64c8c | |||
| 9aeb28066d | |||
| 6fb7c8687e | |||
| d9666008e3 | |||
| e132230651 | |||
| c2877a0c22 | |||
| 251fc3ec68 | |||
| 287f0a3b68 | |||
| b03d9fe987 | |||
| 98372ef33f | |||
| d00f4afb84 | |||
| d4bf02c882 | |||
| 284e671163 | |||
| 0f112e5c9d | |||
| 759449b4be | |||
| 9c03f919a3 | |||
| c9afd9a281 | |||
| a999cb9db9 | |||
| fdc5bd6195 | |||
| e1d94eee21 | |||
| 885f237217 | |||
| 5860a4e28e | |||
| 2bebed44ff | |||
| 4990e544cf | |||
| 8010506d4e | |||
| f2f7abb9a8 | |||
| 85f6ab869e | |||
| fc87b0a11e | |||
| 79bc071754 | |||
| 797243fc9c | |||
| cc7c6b9ece | |||
| 279071e5bb | |||
| 426374ff8a | |||
| 1508874ebc | |||
| bbe440cacd | |||
| e647e73af9 | |||
| 696ddfde0e | |||
| 37d6257524 | |||
| faee894052 | |||
| 61f16b8c5e | |||
| 85eb38e755 | |||
| a87cf60dfc | |||
| 3b135447f3 | |||
| 0c3713f7e5 | |||
| 4d0571fd73 | |||
| 4722988bf0 | |||
| 61151535e6 | |||
| bcff6c192c | |||
| 020d0cfb49 | |||
| d38e3bd729 | |||
| 84a604f70b | |||
| 782baf54a3 | |||
| d754e4eeca | |||
| db98f6191e | |||
| b453a42f77 | |||
| 2a6585e664 | |||
| bc013925b8 | |||
| 8108ecc4d3 | |||
| 1c80584206 | |||
| a3dd9c3e57 | |||
| 8f05fc0a84 | |||
| 3c4feecda0 | |||
| e776a51c73 | |||
| 129e8ef98a | |||
| 69134f6d6a | |||
| b32062f875 | |||
| 8d46ee85f1 | |||
| 9f9fde1f2b | |||
| 2b041e09ac | |||
| 73b32bb45e | |||
| 11e6e74f09 | |||
| bf3e3f0c3d | |||
| 2656acc321 | |||
| e46c9be79f | |||
| 507167d5c1 | |||
| fc90162f69 | |||
| 1e8fb7a38c | |||
| afb6c5a09d | |||
| 2255ab0a37 | |||
| a6ab042078 | |||
| 480f70c049 | |||
| 0592897859 | |||
| d5a9f8e177 | |||
| 5840829cdc | |||
| fd0946b770 | |||
| 293b462fd2 | |||
| 3db50fdd54 | |||
| 1540e6518c | |||
| 8b30c13cd9 | |||
| a7eb89b2f0 | |||
| 53c102e1e9 | |||
| 7d90737921 | |||
| e281f88f2e | |||
| 16c5c7bbb4 | |||
| 7d4dfd87f1 | |||
| 6156bf0f9d | |||
| ee1fdca52e | |||
| 95b5bcbd49 | |||
| 0c529361a3 | |||
| 7110acc94f | |||
| 1188002bcb | |||
| b47a3f15ce | |||
| 695a2a2b6e | |||
| c8b4ef3eed | |||
| 6091248493 | |||
| 32fd507ad9 | |||
| 0ee77a37d1 | |||
| 05241544c5 | |||
| 495c872489 | |||
| 8c09edfdbd | |||
| 67722cf788 | |||
| 8e3484b873 | |||
| 4622aebabb | |||
| 96f29c27cd | |||
| 3de98f7a9d | |||
| 2b33fcd92d | |||
| b1ffcd4350 | |||
| fd500001fb | |||
| 54a757a917 | |||
| 98dfc218d9 | |||
| f6f0f1fb72 | |||
| 218c810860 | |||
| c836b6df3b | |||
| 637bab29c6 | |||
| 0061b3fcbf | |||
| 2a19ded9d5 | |||
| bda9de0775 | |||
| 7047610a45 | |||
| 903d6f9e12 | |||
| 7d61bb2868 | |||
| def7164cad | |||
| fc399e01fe | |||
| ffdc3eee2d | |||
| 1f6f44ab01 | |||
| 19740758c9 | |||
| f618660d24 | |||
| f50dbe298a | |||
| c324fbace4 | |||
| d05152af71 | |||
| bf228b4ae4 | |||
| ba0c17e287 | |||
| 6cfbd4cefe | |||
| e17a2e79a0 | |||
| 72d709ae6c | |||
| 08ca450c40 | |||
| a2951659ac | |||
| 3a6af3810f | |||
| 3973554f07 | |||
| 718cba2e36 | |||
| d2a70d1504 | |||
| 4bc847ac42 | |||
| c3621edf9c | |||
| a64f2de9e1 | |||
| ce684cf9d4 | |||
| 1d1be10f16 | |||
| a09f97c9d5 | |||
| 48da2d2dfb | |||
| 36c0edea2a | |||
| 3568dc2083 | |||
| 51ad72a432 | |||
| 9ce970df8f | |||
| cfa4d80dd7 | |||
| 885cd05f1a | |||
| 21188725d5 | |||
| 70f257b62f | |||
| e8fb8e13df | |||
| 7b7b93e9ba | |||
| 4014da3cc5 | |||
| 410120adee | |||
| a98e65aa1e | |||
| dba9998118 | |||
| 1c75ce5911 | |||
| 33b30aeb95 | |||
| abd8d3459a | |||
| 471698c59f | |||
| e67cf578ae | |||
| 186ad5d444 | |||
| 7eb810c34a | |||
| 7817384e3c | |||
| 34256ba358 | |||
| 08eb5aa7d1 | |||
| 1d3932e8c5 | |||
| 3f85b30d4a | |||
| e4c398aa23 | |||
| f9417555d0 | |||
| 5d3123b97f | |||
| 25080aaf1d | |||
| 05ac4b5ab6 | |||
| 07e13e2499 | |||
| 2d9645b9b0 | |||
| 65ccbedab2 | |||
| 631567864b | |||
| 39d479128c | |||
| 4c0b315c07 | |||
| 264e83a1f3 | |||
| 2b2ed50721 | |||
| 31fbf99109 | |||
| 63381ad221 | |||
| 6ee2d1103e | |||
| bee18dba54 | |||
| 481e445e8a | |||
| 129f7b7441 | |||
| d6bc3c5175 | |||
| de7c56c6bc | |||
| 0c59ecfa14 | |||
| f67241a3cb | |||
| 3b2893944c | |||
| dd7d6df4c6 | |||
| efbda436f3 | |||
| 2064934939 | |||
| b36cf7c450 | |||
| a24dd3dee2 | |||
| 7b22f08869 | |||
| 840929754a | |||
| 51fd332806 | |||
| 4d7e0f6b79 | |||
| b74a573ec5 | |||
| 5faf88afdb | |||
| 5e1110930e | |||
| f11adf5f80 | |||
| 40a71e09a6 | |||
| 1231847a3c | |||
| b06a73e893 | |||
| f99f194927 | |||
| eac7d07ef6 | |||
| 60d70a9f4c | |||
| c944783590 | |||
| 8104a8aea1 | |||
| a4db678895 | |||
| da33d02461 | |||
| 9b4071006e | |||
| b3cdd5b3bf | |||
| 93e53ec612 | |||
| ea8319e2b9 | |||
| 2fae253c62 | |||
| e204b257ad | |||
| dd83d8ed61 | |||
| 61f3d85af1 | |||
| 804e515847 | |||
| 35977b6c7f | |||
| 23f1d3d83b | |||
| b8ea935424 | |||
| 7c0866f626 | |||
| 0f2062b739 | |||
| e91454eeee | |||
| 58134200df | |||
| f6bab21928 | |||
| 011910811b | |||
| bbc0ba147a | |||
| 922a4331db | |||
| 8f7f1e2683 | |||
| 1980cc007f | |||
| 39611f7477 | |||
| e3d659576f | |||
| 46d4670b74 | |||
| 15ca6d5ca9 | |||
| 58f23cda4a | |||
| a58d8420a2 | |||
| 96f834fb81 | |||
| 86617eccb1 | |||
| f2936d1c2d | |||
| 0fc8e04ab5 | |||
| a65e2d3115 | |||
| ca6e25b11c | |||
| 3ec6a6f5bc | |||
| c12fae47e7 | |||
| 604d2c698b | |||
| 5d14016366 | |||
| b112becbba | |||
| e68a09fb3c | |||
| 30e9b4513a | |||
| 671b14dac0 | |||
| 82e99988e8 | |||
| 313a7ed7fa | |||
| cf3365574e | |||
| 0e1f6f50ea | |||
| 5b6518d4a9 | |||
| c009dce591 | |||
| 40e2d7932b | |||
| e29b7a6eae | |||
| a3e9cbc000 | |||
| aedcc2ff40 | |||
| 4c17aeb180 | |||
| ef60ae652c | |||
| 1d62ed028e | |||
| 50bf7694c2 | |||
| 807f1d7c1c | |||
| 7a7d0c09d9 | |||
| f90ce77da4 | |||
| d27ac27bc7 | |||
| 44c6a64bf4 | |||
| 2d6eae9391 | |||
| ba440550a6 | |||
| 8e24fee9da | |||
| 1148652101 | |||
| ed01eeaeb3 | |||
| 096f187d6f | |||
| fa35eb1959 | |||
| 8d89d30c74 | |||
| f1bde40939 | |||
| 4e7ccaa298 | |||
| d0284991ed | |||
| c4998990e5 | |||
| 42d3ee9b94 | |||
| be5c3e41e1 | |||
| 3282d410c4 | |||
| 75303c95f8 | |||
| 0209272831 | |||
| 0e16c4ed97 | |||
| e49720f34a | |||
| 8aee371d81 | |||
| 71c4f81b59 | |||
| 3127fafc88 | |||
| 4e6bdf28cc | |||
| 621a5a86a0 | |||
| d80c8cbd2f | |||
| 686f1aeeb2 | |||
| e27a69bab7 | |||
| 4ee2e1d049 | |||
| 2102648102 | |||
| 8611e40172 | |||
| 7d5b88fff8 | |||
| cfd9aa31a9 | |||
| 62aea4c321 | |||
| f75fcb3041 | |||
| 971c557d85 | |||
| ea05aa225e | |||
| 56cdabff6a | |||
| 15f62e680a | |||
| 0af4e16c21 | |||
| c7b90bac1a | |||
| 4b81331d53 | |||
| 47ab0cbf62 | |||
| f5b079b8e7 | |||
| 21c4691d40 | |||
| 3726706608 | |||
| 28a53aa147 | |||
| 2ad572490c | |||
| 0ed9caf969 | |||
| 63ee376f71 | |||
| 67bcb98a84 | |||
| 9cd91ae99c | |||
| d111a0e5e6 | |||
| 11d4c04cea | |||
| 01773c2a00 | |||
| 1079bf7843 | |||
| 05bcfd2c1c | |||
| 5357a6a4fd | |||
| b6787b0014 | |||
| a32116d24c | |||
| a03b698e5a | |||
| fa0c5db18c | |||
| bc063ded7a | |||
| 846505cbc8 | |||
| 964118d1d6 | |||
| c43b67ea2e | |||
| f68af08931 | |||
| cdd5a41965 | |||
| e13ee59af3 | |||
| 9eb183e01d | |||
| 1163417722 | |||
| 3edc48cda5 | |||
| 2c01425ee5 | |||
| ed9c72814f | |||
| adbbe2b097 | |||
| 7335e0809a | |||
| 75dabb75e2 | |||
| 15adcd24be | |||
| e98ba99331 | |||
| 11459d38d0 | |||
| baf4ea2e8c | |||
| 6a29168c14 | |||
| a4689c7a27 | |||
| 8fda5a187b | |||
| 7b78270f4b | |||
| afd3599a9c | |||
| 4bc8562cd0 | |||
| 11fed4c06c | |||
| 9416a983c6 | |||
| 8108c6320d | |||
| b40b931568 | |||
| 282f70ea91 | |||
| a671f63a3e | |||
| f3ad14cb7f | |||
| 21eb5b661d | |||
| 87fe073118 | |||
| 507dadebf4 | |||
| 7dac8c621c | |||
| 19f4ebf3c5 | |||
| c21b40bebc | |||
| 0766c3c62d | |||
| cc40eb709c | |||
| 3625308585 | |||
| df3a7676eb | |||
| 8f6077e973 | |||
| e6689144c4 | |||
| a67de410bf | |||
| 54ec1a89de | |||
| 4b5f744c6f | |||
| df978345d7 | |||
| facc07c60d | |||
| 2f203ac22c | |||
| cc864191b8 | |||
| 547455245e | |||
| b0d7449bb4 | |||
| aed04c7d55 | |||
| bb5973f2fd | |||
| f801fd1f0d | |||
| 44ca12ead6 | |||
| 9c48389f74 | |||
| acefb5a5f3 | |||
| 3d691a3aec | |||
| 38ebdbb563 | |||
| 1090325c31 | |||
| f8ba4b9312 | |||
| 49a1dfff60 | |||
| 5f4d342d45 | |||
| e1c1f79068 | |||
| a716fa252f | |||
| 0b12e4d8be | |||
| 6ad6c94355 | |||
| 78270c8155 | |||
| 4573ae21e6 | |||
| 0ab6220635 | |||
| 3b51976b96 | |||
| c35211b2f6 | |||
| f62515e13b | |||
| 7f2daf8926 | |||
| 0325861ef3 | |||
| 37f8285a6e | |||
| d3906cffdc | |||
| bee1c77efe | |||
| 7250a82286 | |||
| 984457f9c6 | |||
| 5db23f7e46 | |||
| f4f49b2b46 | |||
| 58b35f6e2d | |||
| b51ad16756 | |||
| d790bda7d2 | |||
| 15ce232f61 | |||
| d999a47600 | |||
| 644286111f | |||
| 917b1cbd6c | |||
| 6d1b585212 | |||
| 6ca35a6264 | |||
| 0290b1b4e0 | |||
| 1d86bf3e56 | |||
| 3fd8ab8d3a | |||
| d240ae3b03 | |||
| b875765c52 | |||
| 2bdec31219 | |||
| a9eebdb1fa | |||
| b25f3a9e91 | |||
| 06f3375a97 | |||
| 5057ae920c | |||
| 6a03f13d55 | |||
| 20cbfd95d6 | |||
| 885dbe1e65 | |||
| 7d7cce5c72 | |||
| 0c66f84555 | |||
| 044e41c079 | |||
| 8dc631e13c | |||
| d93b4feb99 | |||
| 0b873f590c | |||
| f52d637f58 | |||
| e2daf5c2fc | |||
| bef113001a | |||
| f0b403bc2e | |||
| a21fb5fc89 | |||
| bbc0424563 | |||
| f487845e9d | |||
| 77641a9fce | |||
| 56d93eb18b | |||
| da1fd96d4e | |||
| d1fdc7061f | |||
| 2822382797 | |||
| 35c9021bdf | |||
| 493b13364f | |||
| a8ff3231a8 | |||
| c2a750a690 | |||
| 6a9541833a | |||
| 9117b45899 | |||
| 812cf36d52 | |||
| 4aa7420d6a | |||
| 1802839a22 | |||
| 9a2d701e2e | |||
| 69ad3f3365 | |||
| d53eb881c2 | |||
| e28e45f38e | |||
| bf6ca22b00 | |||
| b8acbae3e8 | |||
| 4ec9f2c00f | |||
| 4fc329a1eb | |||
| 0574a60bc2 | |||
| e490c4afed | |||
| d028a30f87 | |||
| 75a2d4d00a | |||
| a122a1e8c7 | |||
| 8fe09c85b6 | |||
| bc951de2a5 | |||
| c970cd13cc | |||
| 8983c0f927 | |||
| a47467f29b | |||
| ef206eb4d9 | |||
| da5eec1c5f | |||
| a69b3535a5 | |||
| f4c23f3259 | |||
| e36e9fd629 | |||
| d2f19353ed | |||
| 2d498cb88b | |||
| a80815d57a | |||
| acab77f4f8 | |||
| bddad0c57c | |||
| 3968349480 | |||
| 3ae17761b3 | |||
| 9a28bdbf76 | |||
| e769821e0f | |||
| 9b68821f05 | |||
| b2adb22b2d | |||
| 981941edf4 | |||
| 111dea89a9 | |||
| 2720f4de9c | |||
| 21645643b0 | |||
| c6a07acd90 | |||
| 1816e6607e | |||
| 37dd05a9b5 | |||
| 529997de9b | |||
| 4f37270300 | |||
| faf9c96442 |
@@ -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'
|
||||
...
|
||||
|
||||
+8
-20
@@ -1,3 +1,7 @@
|
||||
# pre compiled dependencies #
|
||||
#############################
|
||||
osrm-deps
|
||||
|
||||
# Compiled source #
|
||||
###################
|
||||
*.com
|
||||
@@ -36,8 +40,7 @@ Thumbs.db
|
||||
# build related files #
|
||||
#######################
|
||||
/build/
|
||||
/Util/UUID.cpp
|
||||
/Util/GitDescription.cpp
|
||||
/cmake/postinst
|
||||
|
||||
# Eclipse related files #
|
||||
#########################
|
||||
@@ -52,25 +55,8 @@ Thumbs.db
|
||||
stxxl.log
|
||||
stxxl.errlog
|
||||
|
||||
# compiled protobuffers #
|
||||
#########################
|
||||
/DataStructures/pbf-proto/*.pb.h
|
||||
/DataStructures/pbf-proto/*.pb.cc
|
||||
|
||||
# External Libs #
|
||||
#################
|
||||
/lib/
|
||||
/win/lib
|
||||
|
||||
# Visual Studio Temp + build Files #
|
||||
# Compiled Binary Files #
|
||||
####################################
|
||||
/win/*.user
|
||||
/win/*.ncb
|
||||
/win/*.suo
|
||||
/win/Debug/
|
||||
/win/Release/
|
||||
/win/bin/
|
||||
/win/bin-debug/
|
||||
/osrm-extract
|
||||
/osrm-io-benchmark
|
||||
/osrm-components
|
||||
@@ -79,6 +65,8 @@ stxxl.errlog
|
||||
/osrm-prepare
|
||||
/osrm-unlock-all
|
||||
/osrm-cli
|
||||
/osrm-check-hsgr
|
||||
/osrm-springclean
|
||||
/nohup.out
|
||||
|
||||
# Sandbox folder #
|
||||
|
||||
+140
-48
@@ -1,54 +1,146 @@
|
||||
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 libprotoc-dev libprotobuf7 libprotobuf-dev libosmpbf-dev libbz2-dev libstxxl-dev libstxxl1 libxml2-dev libzip-dev lua5.1 liblua5.1-0-dev rubygems
|
||||
- sudo apt-get -q install g++-4.7
|
||||
- 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
|
||||
before_script:
|
||||
- rvm use 1.9.3
|
||||
- gem install bundler
|
||||
- bundle install
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake .. $CMAKEOPTIONS
|
||||
script:
|
||||
- make -j 2
|
||||
- cd ..
|
||||
- cucumber -p verify
|
||||
after_script:
|
||||
# - cd ..
|
||||
# - cucumber -p verify
|
||||
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.7" OSRM_PORT=5000 OSRM_TIMEOUT=60
|
||||
- CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=g++-4.7" OSRM_PORT=5010 OSRM_TIMEOUT=60
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- irc.oftc.net#osrm
|
||||
on_success: change
|
||||
on_failure: always
|
||||
use_notice: true
|
||||
skip_join: false
|
||||
|
||||
recipients:
|
||||
- dennis@mapbox.com
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: always
|
||||
matrix:
|
||||
include:
|
||||
|
||||
# 1/ Linux Clang Builds
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: &clang38
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test']
|
||||
packages: ['clang-3.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'rubygems-integration', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
|
||||
env: COMPILER='clang++-3.8' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: &clang38
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test']
|
||||
packages: ['clang-3.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'rubygems-integration', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
|
||||
env: COMPILER='clang++-3.8' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: *clang38
|
||||
env: COMPILER='clang++-3.8' BUILD_TYPE='Debug'
|
||||
|
||||
|
||||
# 2/ Linux GCC Builds
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: &gcc48
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-4.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'rubygems-integration', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
|
||||
env: COMPILER='g++-4.8' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc48
|
||||
env: COMPILER='g++-4.8' BUILD_TYPE='Debug'
|
||||
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
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', 'rubygems-integration', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
|
||||
env: COMPILER='g++-5' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
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', 'rubygems-integration', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
|
||||
env: COMPILER='g++-5' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc5
|
||||
env: COMPILER='g++-5' BUILD_TYPE='Debug'
|
||||
|
||||
|
||||
# Disabled until tests all pass on OSX:
|
||||
#
|
||||
# 3/ OSX Clang Builds
|
||||
#- os: osx
|
||||
# osx_image: xcode6.4
|
||||
# compiler: clang
|
||||
# env: COMPILER='clang++' BUILD_TYPE='Debug'
|
||||
|
||||
#- os: osx
|
||||
# osx_image: xcode6.4
|
||||
# compiler: clang
|
||||
# env: COMPILER='clang++' BUILD_TYPE='Release'
|
||||
|
||||
#- os: osx
|
||||
# osx_image: xcode6.4
|
||||
# compiler: clang
|
||||
# env: COMPILER='clang++' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
|
||||
|
||||
#- os: osx
|
||||
# osx_image: xcode7
|
||||
# compiler: clang
|
||||
# env: COMPILER='clang++' BUILD_TYPE='Debug'
|
||||
|
||||
#- os: osx
|
||||
# osx_image: xcode7
|
||||
# compiler: clang
|
||||
# env: COMPILER='clang++' BUILD_TYPE='Release'
|
||||
|
||||
#- os: osx
|
||||
# osx_image: xcode7
|
||||
# compiler: clang
|
||||
# env: COMPILER='clang++' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
|
||||
|
||||
|
||||
install:
|
||||
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
|
||||
- mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR}
|
||||
- |
|
||||
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
|
||||
CMAKE_URL="http://www.cmake.org/files/v3.3/cmake-3.3.2-Linux-x86_64.tar.gz"
|
||||
mkdir cmake && travis_retry wget --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
|
||||
export PATH=${DEPS_DIR}/cmake/bin:${PATH}
|
||||
|
||||
OSMOSIS_URL="http://bretth.dev.openstreetmap.org/osmosis-build/osmosis-latest.tgz"
|
||||
mkdir osmosis && travis_retry wget --quiet -O - ${OSMOSIS_URL} | tar -xz -C osmosis
|
||||
export PATH=${DEPS_DIR}/osmosis/bin:${PATH}
|
||||
|
||||
elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
||||
brew install cmake boost libzip libstxxl libxml2 lua51 luabind tbb GDAL osmosis
|
||||
fi
|
||||
|
||||
before_script:
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
- rvm use 1.9.3
|
||||
- gem install bundler
|
||||
- bundle install
|
||||
- mkdir build && cd build
|
||||
- export CXX=${COMPILER}
|
||||
- export OSRM_PORT=5000 OSRM_TIMEOUT=60
|
||||
- cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS:-OFF} -DBUILD_TOOLS=1
|
||||
|
||||
script:
|
||||
- make --jobs=2
|
||||
- make tests --jobs=2
|
||||
- make benchmarks
|
||||
- ./algorithm-tests
|
||||
- ./datastructure-tests
|
||||
- ./util-tests
|
||||
- cd ..
|
||||
- cucumber -p verify
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
#ifndef __BFS_COMPONENT_EXPLORER_H__
|
||||
#define __BFS_COMPONENT_EXPLORER_H__
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../DataStructures/DynamicGraph.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 &dynamicGraph,
|
||||
const RestrictionMap &restrictions,
|
||||
const std::unordered_set<NodeID> &barrier_nodes)
|
||||
: m_graph(dynamicGraph), 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.
|
||||
*/
|
||||
inline unsigned int GetComponentSize(NodeID node)
|
||||
{
|
||||
BOOST_ASSERT(node < m_component_index_list.size());
|
||||
|
||||
return m_component_index_size[m_component_index_list[node]];
|
||||
}
|
||||
|
||||
inline 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.
|
||||
*/
|
||||
inline unsigned ExploreComponent(std::queue<std::pair<NodeID, NodeID>> &bfs_queue,
|
||||
NodeID node,
|
||||
unsigned current_component)
|
||||
{
|
||||
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.BeginEdges(v); e2 < m_graph.EndEdges(v); ++e2)
|
||||
{
|
||||
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
|
||||
@@ -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.
|
||||
|
||||
*/
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include "DouglasPeucker.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <limits>
|
||||
|
||||
DouglasPeucker::DouglasPeucker()
|
||||
: douglas_peucker_thresholds({262144., // z0
|
||||
131072., // z1
|
||||
65536., // z2
|
||||
32768., // z3
|
||||
16384., // z4
|
||||
8192., // z5
|
||||
4096., // z6
|
||||
2048., // z7
|
||||
960., // z8
|
||||
480., // z9
|
||||
240., // z10
|
||||
90., // z11
|
||||
50., // z12
|
||||
25., // z13
|
||||
15., // z14
|
||||
5., // z15
|
||||
.65, // z16
|
||||
.5, // z17
|
||||
.35 // z18
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level)
|
||||
{
|
||||
BOOST_ASSERT_MSG(!input_geometry.empty(), "geometry invalid");
|
||||
if (input_geometry.size() <= 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
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
|
||||
{
|
||||
BOOST_ASSERT_MSG(input_geometry[left_border].necessary,
|
||||
"left border must be necessary");
|
||||
BOOST_ASSERT_MSG(input_geometry.back().necessary, "right border must be necessary");
|
||||
|
||||
if (input_geometry[right_border].necessary)
|
||||
{
|
||||
recursion_stack.emplace(left_border, right_border);
|
||||
left_border = right_border;
|
||||
}
|
||||
++right_border;
|
||||
} while (right_border < input_geometry.size());
|
||||
}
|
||||
while (!recursion_stack.empty())
|
||||
{
|
||||
// pop next element
|
||||
const GeometryRange pair = recursion_stack.top();
|
||||
recursion_stack.pop();
|
||||
BOOST_ASSERT_MSG(input_geometry[pair.first].necessary, "left border mus be necessary");
|
||||
BOOST_ASSERT_MSG(input_geometry[pair.second].necessary, "right border must be necessary");
|
||||
BOOST_ASSERT_MSG(pair.second < input_geometry.size(), "right border outside of geometry");
|
||||
BOOST_ASSERT_MSG(pair.first < pair.second, "left border on the wrong side");
|
||||
double max_distance = std::numeric_limits<double>::min();
|
||||
|
||||
unsigned farthest_element_index = pair.second;
|
||||
// find index idx of element with max_distance
|
||||
for (unsigned i = pair.first + 1; i < pair.second; ++i)
|
||||
{
|
||||
const double temp_dist = FixedPointCoordinate::ComputePerpendicularDistance(
|
||||
input_geometry[i].location,
|
||||
input_geometry[pair.first].location,
|
||||
input_geometry[pair.second].location);
|
||||
const double distance = std::abs(temp_dist);
|
||||
if (distance > douglas_peucker_thresholds[zoom_level] && distance > max_distance)
|
||||
{
|
||||
farthest_element_index = i;
|
||||
max_distance = distance;
|
||||
}
|
||||
}
|
||||
if (max_distance > douglas_peucker_thresholds[zoom_level])
|
||||
{
|
||||
// mark idx as necessary
|
||||
input_geometry[farthest_element_index].necessary = true;
|
||||
if (1 < (farthest_element_index - pair.first))
|
||||
{
|
||||
recursion_stack.emplace(pair.first, farthest_element_index);
|
||||
}
|
||||
if (1 < (pair.second - farthest_element_index))
|
||||
{
|
||||
recursion_stack.emplace(farthest_element_index, pair.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OBJECTTOBASE64_H_
|
||||
#define OBJECTTOBASE64_H_
|
||||
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/archive/iterators/base64_from_binary.hpp>
|
||||
#include <boost/archive/iterators/binary_from_base64.hpp>
|
||||
#include <boost/archive/iterators/transform_width.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
typedef
|
||||
boost::archive::iterators::base64_from_binary<
|
||||
boost::archive::iterators::transform_width<const char *, 6, 8>
|
||||
> base64_t;
|
||||
|
||||
typedef
|
||||
boost::archive::iterators::transform_width<
|
||||
boost::archive::iterators::binary_from_base64<
|
||||
std::string::const_iterator>, 8, 6
|
||||
> binary_t;
|
||||
|
||||
template<class ObjectT>
|
||||
static void EncodeObjectToBase64(const ObjectT & object, std::string& encoded) {
|
||||
const char * char_ptr_to_object = (const char *)&object;
|
||||
std::vector<unsigned char> data(sizeof(object));
|
||||
std::copy(
|
||||
char_ptr_to_object,
|
||||
char_ptr_to_object + sizeof(ObjectT),
|
||||
data.begin()
|
||||
);
|
||||
|
||||
unsigned char number_of_padded_chars = 0; // is in {0,1,2};
|
||||
while(data.size() % 3 != 0) {
|
||||
++number_of_padded_chars;
|
||||
data.push_back(0x00);
|
||||
}
|
||||
|
||||
BOOST_ASSERT_MSG(
|
||||
0 == data.size() % 3,
|
||||
"base64 input data size is not a multiple of 3!"
|
||||
);
|
||||
encoded.resize(sizeof(ObjectT));
|
||||
encoded.assign(
|
||||
base64_t( &data[0] ),
|
||||
base64_t( &data[0] + (data.size() - number_of_padded_chars) )
|
||||
);
|
||||
replaceAll(encoded, "+", "-");
|
||||
replaceAll(encoded, "/", "_");
|
||||
}
|
||||
|
||||
template<class ObjectT>
|
||||
static void DecodeObjectFromBase64(const std::string& input, ObjectT & object) {
|
||||
try {
|
||||
std::string encoded(input);
|
||||
//replace "-" with "+" and "_" with "/"
|
||||
replaceAll(encoded, "-", "+");
|
||||
replaceAll(encoded, "_", "/");
|
||||
|
||||
std::copy (
|
||||
binary_t( encoded.begin() ),
|
||||
binary_t( encoded.begin() + encoded.length() - 1),
|
||||
(char *)&object
|
||||
);
|
||||
|
||||
} catch(...) { }
|
||||
}
|
||||
|
||||
#endif /* OBJECTTOBASE64_H_ */
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "PolylineCompressor.h"
|
||||
|
||||
void PolylineCompressor::encodeVectorSignedNumber(std::vector<int> &numbers, std::string &output)
|
||||
const
|
||||
{
|
||||
const unsigned end = numbers.size();
|
||||
for (unsigned i = 0; i < end; ++i)
|
||||
{
|
||||
numbers[i] <<= 1;
|
||||
if (numbers[i] < 0)
|
||||
{
|
||||
numbers[i] = ~(numbers[i]);
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < end; ++i)
|
||||
{
|
||||
encodeNumber(numbers[i], output);
|
||||
}
|
||||
}
|
||||
|
||||
void PolylineCompressor::encodeNumber(int number_to_encode, std::string &output) const
|
||||
{
|
||||
while (number_to_encode >= 0x20)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void PolylineCompressor::printEncodedString(const std::vector<SegmentInformation> &polyline,
|
||||
std::string &output) const
|
||||
{
|
||||
std::vector<int> delta_numbers;
|
||||
output += "\"";
|
||||
if (!polyline.empty())
|
||||
{
|
||||
FixedPointCoordinate last_coordinate = polyline[0].location;
|
||||
delta_numbers.emplace_back(last_coordinate.lat);
|
||||
delta_numbers.emplace_back(last_coordinate.lon);
|
||||
for (unsigned i = 1; i < polyline.size(); ++i)
|
||||
{
|
||||
if (polyline[i].necessary)
|
||||
{
|
||||
int lat_diff = polyline[i].location.lat - last_coordinate.lat;
|
||||
int lon_diff = polyline[i].location.lon - last_coordinate.lon;
|
||||
delta_numbers.emplace_back(lat_diff);
|
||||
delta_numbers.emplace_back(lon_diff);
|
||||
last_coordinate = polyline[i].location;
|
||||
}
|
||||
}
|
||||
encodeVectorSignedNumber(delta_numbers, output);
|
||||
}
|
||||
output += "\"";
|
||||
}
|
||||
|
||||
void PolylineCompressor::printEncodedString(const std::vector<FixedPointCoordinate> &polyline,
|
||||
std::string &output) const
|
||||
{
|
||||
std::vector<int> delta_numbers(2 * polyline.size());
|
||||
output += "\"";
|
||||
if (!polyline.empty())
|
||||
{
|
||||
delta_numbers[0] = polyline[0].lat;
|
||||
delta_numbers[1] = polyline[0].lon;
|
||||
for (unsigned i = 1; i < polyline.size(); ++i)
|
||||
{
|
||||
int lat_diff = polyline[i].lat - polyline[i - 1].lat;
|
||||
int lon_diff = polyline[i].lon - polyline[i - 1].lon;
|
||||
delta_numbers[(2 * i)] = (lat_diff);
|
||||
delta_numbers[(2 * i) + 1] = (lon_diff);
|
||||
}
|
||||
encodeVectorSignedNumber(delta_numbers, output);
|
||||
}
|
||||
output += "\"";
|
||||
}
|
||||
|
||||
void PolylineCompressor::printUnencodedString(const std::vector<FixedPointCoordinate> &polyline,
|
||||
std::string &output) const
|
||||
{
|
||||
output += "[";
|
||||
std::string tmp;
|
||||
for (unsigned i = 0; i < polyline.size(); i++)
|
||||
{
|
||||
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].lat, tmp);
|
||||
output += "[";
|
||||
output += tmp;
|
||||
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].lon, tmp);
|
||||
output += ", ";
|
||||
output += tmp;
|
||||
output += "]";
|
||||
if (i < polyline.size() - 1)
|
||||
{
|
||||
output += ",";
|
||||
}
|
||||
}
|
||||
output += "]";
|
||||
}
|
||||
|
||||
void PolylineCompressor::printUnencodedString(const std::vector<SegmentInformation> &polyline,
|
||||
std::string &output) const
|
||||
{
|
||||
output += "[";
|
||||
std::string tmp;
|
||||
for (unsigned i = 0; i < polyline.size(); i++)
|
||||
{
|
||||
if (!polyline[i].necessary)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].location.lat, tmp);
|
||||
output += "[";
|
||||
output += tmp;
|
||||
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].location.lon, tmp);
|
||||
output += ", ";
|
||||
output += tmp;
|
||||
output += "]";
|
||||
if (i < polyline.size() - 1)
|
||||
{
|
||||
output += ",";
|
||||
}
|
||||
}
|
||||
output += "]";
|
||||
}
|
||||
@@ -1,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 POLYLINECOMPRESSOR_H_
|
||||
#define POLYLINECOMPRESSOR_H_
|
||||
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class PolylineCompressor
|
||||
{
|
||||
private:
|
||||
void encodeVectorSignedNumber(std::vector<int> &numbers, std::string &output) const;
|
||||
|
||||
void encodeNumber(int number_to_encode, std::string &output) const;
|
||||
|
||||
public:
|
||||
void printEncodedString(const std::vector<SegmentInformation> &polyline,
|
||||
std::string &output) const;
|
||||
|
||||
void printEncodedString(const std::vector<FixedPointCoordinate> &polyline,
|
||||
std::string &output) const;
|
||||
|
||||
void printUnencodedString(const std::vector<FixedPointCoordinate> &polyline,
|
||||
std::string &output) const;
|
||||
|
||||
void printUnencodedString(const std::vector<SegmentInformation> &polyline,
|
||||
std::string &output) const;
|
||||
};
|
||||
|
||||
#endif /* POLYLINECOMPRESSOR_H_ */
|
||||
@@ -1,468 +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/Restriction.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#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>
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <> struct hash<std::pair<NodeID, NodeID>>
|
||||
{
|
||||
size_t operator()(const std::pair<NodeID, NodeID> &pair) const
|
||||
{
|
||||
return std::hash<int>()(pair.first) ^ std::hash<int>()(pair.second);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class TarjanSCC
|
||||
{
|
||||
private:
|
||||
struct TarjanNode
|
||||
{
|
||||
TarjanNode() : index(UINT_MAX), low_link(UINT_MAX), on_stack(false) {}
|
||||
unsigned index;
|
||||
unsigned low_link;
|
||||
bool on_stack;
|
||||
};
|
||||
|
||||
struct TarjanEdgeData
|
||||
{
|
||||
int distance;
|
||||
unsigned name_id : 31;
|
||||
bool shortcut : 1;
|
||||
short type;
|
||||
bool forward : 1;
|
||||
bool backward : 1;
|
||||
bool reversedEdge : 1;
|
||||
};
|
||||
|
||||
struct TarjanStackFrame
|
||||
{
|
||||
explicit TarjanStackFrame(NodeID v, NodeID parent) : v(v), parent(parent) {}
|
||||
NodeID v;
|
||||
NodeID parent;
|
||||
};
|
||||
|
||||
typedef DynamicGraph<TarjanEdgeData> TarjanDynamicGraph;
|
||||
typedef TarjanDynamicGraph::InputEdge TarjanEdge;
|
||||
typedef std::pair<NodeID, NodeID> RestrictionSource;
|
||||
typedef std::pair<NodeID, bool> restriction_target;
|
||||
typedef std::vector<restriction_target> EmanatingRestrictionsVector;
|
||||
typedef std::unordered_map<RestrictionSource, unsigned> RestrictionMap;
|
||||
|
||||
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> m_barrier_node_list;
|
||||
std::unordered_set<NodeID> m_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())
|
||||
{
|
||||
for (const TurnRestriction &restriction : irs)
|
||||
{
|
||||
std::pair<NodeID, NodeID> restrictionSource = {restriction.fromNode,
|
||||
restriction.viaNode};
|
||||
unsigned index;
|
||||
RestrictionMap::iterator restriction_iterator =
|
||||
m_restriction_map.find(restrictionSource);
|
||||
if (restriction_iterator == m_restriction_map.end())
|
||||
{
|
||||
index = m_restriction_bucket_list.size();
|
||||
m_restriction_bucket_list.resize(index + 1);
|
||||
m_restriction_map.emplace(restrictionSource, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
index = restriction_iterator->second;
|
||||
// Map already contains an is_only_*-restriction
|
||||
if (m_restriction_bucket_list.at(index).begin()->second)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (restriction.flags.isOnly)
|
||||
{
|
||||
// We are going to insert an is_only_*-restriction. There can be only one.
|
||||
m_restriction_bucket_list.at(index).clear();
|
||||
}
|
||||
}
|
||||
|
||||
m_restriction_bucket_list.at(index)
|
||||
.emplace_back(restriction.toNode, restriction.flags.isOnly);
|
||||
}
|
||||
|
||||
m_barrier_node_list.insert(bn.begin(), bn.end());
|
||||
m_traffic_light_list.insert(tl.begin(), tl.end());
|
||||
|
||||
DeallocatingVector<TarjanEdge> edge_list;
|
||||
for (const NodeBasedEdge &input_edge : input_edges)
|
||||
{
|
||||
if (input_edge.source() == input_edge.target())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
TarjanEdge edge;
|
||||
if (input_edge.isForward())
|
||||
{
|
||||
edge.source = input_edge.source();
|
||||
edge.target = input_edge.target();
|
||||
edge.data.forward = input_edge.isForward();
|
||||
edge.data.backward = input_edge.isBackward();
|
||||
}
|
||||
else
|
||||
{
|
||||
edge.source = input_edge.target();
|
||||
edge.target = input_edge.source();
|
||||
edge.data.backward = input_edge.isForward();
|
||||
edge.data.forward = input_edge.isBackward();
|
||||
}
|
||||
|
||||
edge.data.distance = (std::max)((int)input_edge.weight(), 1);
|
||||
BOOST_ASSERT(edge.data.distance > 0);
|
||||
edge.data.shortcut = false;
|
||||
// edge.data.roundabout = input_edge.isRoundabout();
|
||||
// edge.data.ignoreInGrid = input_edge.ignoreInGrid();
|
||||
edge.data.name_id = input_edge.name();
|
||||
edge.data.type = input_edge.type();
|
||||
// edge.data.isAccessRestricted = input_edge.isAccessRestricted();
|
||||
edge.data.reversedEdge = false;
|
||||
edge_list.push_back(edge);
|
||||
if (edge.data.backward)
|
||||
{
|
||||
std::swap(edge.source, edge.target);
|
||||
edge.data.forward = input_edge.isBackward();
|
||||
edge.data.backward = input_edge.isForward();
|
||||
edge.data.reversedEdge = true;
|
||||
edge_list.push_back(edge);
|
||||
}
|
||||
}
|
||||
std::vector<NodeBasedEdge>().swap(input_edges);
|
||||
BOOST_ASSERT_MSG(0 == input_edges.size() && 0 == input_edges.capacity(),
|
||||
"input edge vector not properly deallocated");
|
||||
|
||||
std::sort(edge_list.begin(), edge_list.end());
|
||||
|
||||
m_node_based_graph = std::make_shared<TarjanDynamicGraph>(number_of_nodes, edge_list);
|
||||
}
|
||||
|
||||
~TarjanSCC() { m_node_based_graph.reset(); }
|
||||
|
||||
void Run()
|
||||
{
|
||||
// remove files from previous run if exist
|
||||
DeleteFileIfExists("component.dbf");
|
||||
DeleteFileIfExists("component.shx");
|
||||
DeleteFileIfExists("component.shp");
|
||||
|
||||
Percent p(m_node_based_graph->GetNumberOfNodes());
|
||||
|
||||
OGRRegisterAll();
|
||||
|
||||
const char *pszDriverName = "ESRI Shapefile";
|
||||
OGRSFDriver *poDriver =
|
||||
OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(pszDriverName);
|
||||
if (NULL == poDriver)
|
||||
{
|
||||
throw OSRMException("ESRI Shapefile driver not available");
|
||||
}
|
||||
OGRDataSource *poDS = poDriver->CreateDataSource("component.shp", NULL);
|
||||
|
||||
if (NULL == poDS)
|
||||
{
|
||||
throw OSRMException("Creation of output file failed");
|
||||
}
|
||||
|
||||
OGRLayer *poLayer = poDS->CreateLayer("component", NULL, wkbLineString, NULL);
|
||||
|
||||
if (NULL == poLayer)
|
||||
{
|
||||
throw OSRMException("Layer creation failed.");
|
||||
}
|
||||
|
||||
// The following is a hack to distinguish between stuff that happens
|
||||
// before the recursive call and stuff that happens after
|
||||
std::stack<std::pair<bool, TarjanStackFrame>> recursion_stack;
|
||||
// true = stuff before, false = stuff after call
|
||||
std::stack<NodeID> tarjan_stack;
|
||||
std::vector<unsigned> components_index(m_node_based_graph->GetNumberOfNodes(), UINT_MAX);
|
||||
std::vector<NodeID> component_size_vector;
|
||||
std::vector<TarjanNode> tarjan_node_list(m_node_based_graph->GetNumberOfNodes());
|
||||
unsigned component_index = 0, size_of_current_component = 0;
|
||||
int index = 0;
|
||||
NodeID last_node = m_node_based_graph->GetNumberOfNodes();
|
||||
for (NodeID node = 0; node < last_node; ++node)
|
||||
{
|
||||
if (UINT_MAX == components_index[node])
|
||||
{
|
||||
recursion_stack.emplace(true, TarjanStackFrame(node, node));
|
||||
}
|
||||
|
||||
while (!recursion_stack.empty())
|
||||
{
|
||||
const bool before_recursion = recursion_stack.top().first;
|
||||
TarjanStackFrame currentFrame = recursion_stack.top().second;
|
||||
NodeID v = currentFrame.v;
|
||||
recursion_stack.pop();
|
||||
|
||||
if (before_recursion)
|
||||
{
|
||||
// Mark frame to handle tail of recursion
|
||||
recursion_stack.emplace(false, currentFrame);
|
||||
|
||||
// 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
|
||||
EdgeID end_edge = m_node_based_graph->EndEdges(v);
|
||||
for (auto e2 = m_node_based_graph->BeginEdges(v); e2 < end_edge; ++e2)
|
||||
{
|
||||
const TarjanDynamicGraph::NodeIterator vprime =
|
||||
m_node_based_graph->GetTarget(e2);
|
||||
if (UINT_MAX == tarjan_node_list[vprime].index)
|
||||
{
|
||||
recursion_stack.emplace(true, 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
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SimpleLogger().Write() << "identified: " << component_size_vector.size()
|
||||
<< " many components, marking small components";
|
||||
|
||||
// TODO/C++11: prime candidate for lambda function
|
||||
unsigned size_one_counter = 0;
|
||||
for (unsigned i = 0, end = component_size_vector.size(); i < end; ++i)
|
||||
{
|
||||
if (1 == component_size_vector[i])
|
||||
{
|
||||
++size_one_counter;
|
||||
}
|
||||
}
|
||||
|
||||
SimpleLogger().Write() << "identified " << size_one_counter << " SCCs of size 1";
|
||||
|
||||
uint64_t total_network_distance = 0;
|
||||
p.reinit(m_node_based_graph->GetNumberOfNodes());
|
||||
NodeID last_u_node = m_node_based_graph->GetNumberOfNodes();
|
||||
for (NodeID u = 0; u < last_u_node; ++u)
|
||||
{
|
||||
p.printIncrement();
|
||||
EdgeID last_edge = m_node_based_graph->EndEdges(u);
|
||||
for (auto e1 = m_node_based_graph->BeginEdges(u); e1 < last_edge; ++e1)
|
||||
{
|
||||
if (!m_node_based_graph->GetEdgeData(e1).reversedEdge)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const TarjanDynamicGraph::NodeIterator v = m_node_based_graph->GetTarget(e1);
|
||||
|
||||
total_network_distance +=
|
||||
100 * FixedPointCoordinate::ApproximateDistance(m_coordinate_list[u].lat,
|
||||
m_coordinate_list[u].lon,
|
||||
m_coordinate_list[v].lat,
|
||||
m_coordinate_list[v].lon);
|
||||
|
||||
if (SHRT_MAX != m_node_based_graph->GetEdgeData(e1).type)
|
||||
{
|
||||
BOOST_ASSERT(e1 != UINT_MAX);
|
||||
BOOST_ASSERT(u != UINT_MAX);
|
||||
BOOST_ASSERT(v != UINT_MAX);
|
||||
|
||||
const unsigned size_of_containing_component =
|
||||
std::min(component_size_vector[components_index[u]],
|
||||
component_size_vector[components_index[v]]);
|
||||
|
||||
// edges that end on bollard nodes may actually be in two distinct components
|
||||
if (size_of_containing_component < 10)
|
||||
{
|
||||
OGRLineString lineString;
|
||||
lineString.addPoint(m_coordinate_list[u].lon / COORDINATE_PRECISION,
|
||||
m_coordinate_list[u].lat / COORDINATE_PRECISION);
|
||||
lineString.addPoint(m_coordinate_list[v].lon / COORDINATE_PRECISION,
|
||||
m_coordinate_list[v].lat / COORDINATE_PRECISION);
|
||||
|
||||
OGRFeature *poFeature = OGRFeature::CreateFeature(poLayer->GetLayerDefn());
|
||||
|
||||
poFeature->SetGeometry(&lineString);
|
||||
if (OGRERR_NONE != poLayer->CreateFeature(poFeature))
|
||||
{
|
||||
throw OSRMException("Failed to create feature in shapefile.");
|
||||
}
|
||||
OGRFeature::DestroyFeature(poFeature);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
OGRDataSource::DestroyDataSource(poDS);
|
||||
std::vector<NodeID>().swap(component_size_vector);
|
||||
BOOST_ASSERT_MSG(0 == component_size_vector.size() && 0 == component_size_vector.capacity(),
|
||||
"component_size_vector not properly deallocated");
|
||||
|
||||
std::vector<NodeID>().swap(components_index);
|
||||
BOOST_ASSERT_MSG(0 == components_index.size() && 0 == components_index.capacity(),
|
||||
"icomponents_index not properly deallocated");
|
||||
|
||||
SimpleLogger().Write() << "total network distance: " << (uint64_t)total_network_distance /
|
||||
100 / 1000. << " km";
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const
|
||||
{
|
||||
std::pair<NodeID, NodeID> restriction_source = {u, v};
|
||||
RestrictionMap::const_iterator restriction_iterator =
|
||||
m_restriction_map.find(restriction_source);
|
||||
if (restriction_iterator != m_restriction_map.end())
|
||||
{
|
||||
const unsigned index = restriction_iterator->second;
|
||||
for (const RestrictionSource &restriction_target : m_restriction_bucket_list.at(index))
|
||||
{
|
||||
if (restriction_target.second)
|
||||
{
|
||||
return restriction_target.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
bool CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const
|
||||
{
|
||||
// only add an edge if turn is not a U-turn except it is the end of dead-end street.
|
||||
std::pair<NodeID, NodeID> restriction_source = {u, v};
|
||||
RestrictionMap::const_iterator restriction_iterator =
|
||||
m_restriction_map.find(restriction_source);
|
||||
if (restriction_iterator != m_restriction_map.end())
|
||||
{
|
||||
const unsigned index = restriction_iterator->second;
|
||||
for (const restriction_target &restriction_target : m_restriction_bucket_list.at(index))
|
||||
{
|
||||
if (w == restriction_target.first)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeleteFileIfExists(const std::string &file_name) const
|
||||
{
|
||||
if (boost::filesystem::exists(file_name))
|
||||
{
|
||||
boost::filesystem::remove(file_name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* STRONGLYCONNECTEDCOMPONENTS_H_ */
|
||||
+307
-148
@@ -1,14 +1,21 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
project(OSRM)
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
|
||||
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR AND NOT MSVC_IDE)
|
||||
message(FATAL_ERROR "In-source builds are not allowed.
|
||||
Please create a directory and run cmake from there, passing the path to this source directory as the last argument.
|
||||
This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. Please delete them.")
|
||||
endif()
|
||||
|
||||
project(OSRM C CXX)
|
||||
set(OSRM_VERSION_MAJOR 4)
|
||||
set(OSRM_VERSION_MINOR 9)
|
||||
set(OSRM_VERSION_PATCH 0)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||
include(GetGitRevisionDescription)
|
||||
git_describe(GIT_DESCRIPTION)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
set(bitness 32)
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
@@ -18,60 +25,95 @@ else()
|
||||
message(WARNING "Building on a 32 bit system is unsupported")
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/Include/)
|
||||
if(WIN32 AND MSVC_VERSION LESS 1800)
|
||||
message(FATAL_ERROR "Building with Microsoft compiler needs Visual Studio 2013 or later (Express version works too)")
|
||||
endif()
|
||||
|
||||
add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/Util/UUID.cpp UUID.cpp.alwaysbuild
|
||||
COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR}
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/UUID-Config.cmake
|
||||
DEPENDS
|
||||
${CMAKE_SOURCE_DIR}/Util/UUID.cpp.in
|
||||
${CMAKE_SOURCE_DIR}/cmake/UUID-Config.cmake
|
||||
COMMENT "Configuring UUID.cpp"
|
||||
option(ENABLE_JSON_LOGGING "Adds additional JSON debug logging to the response" OFF)
|
||||
option(DEBUG_GEOMETRY "Enables an option to dump GeoJSON of the final routing graph" OFF)
|
||||
option(BUILD_TOOLS "Build OSRM tools" OFF)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/)
|
||||
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/)
|
||||
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include/)
|
||||
|
||||
add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND}
|
||||
"-DOUTPUT_DIR=${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"-DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
-P "${CMAKE_CURRENT_SOURCE_DIR}/cmake/FingerPrint-Config.cmake"
|
||||
COMMENT "Configuring revision fingerprint"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target(UUIDConfigure DEPENDS ${CMAKE_SOURCE_DIR}/Util/UUID.cpp)
|
||||
add_custom_target(tests DEPENDS datastructure-tests algorithm-tests util-tests)
|
||||
add_custom_target(benchmarks DEPENDS rtree-bench)
|
||||
|
||||
set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread)
|
||||
set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread unit_test_framework)
|
||||
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/Util/GitDescription.cpp.in
|
||||
${CMAKE_SOURCE_DIR}/Util/GitDescription.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/util/version.hpp.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/util/version.hpp
|
||||
)
|
||||
file(GLOB ExtractorGlob Extractor/*.cpp)
|
||||
set(ExtractorSources extractor.cpp ${ExtractorGlob})
|
||||
add_executable(osrm-extract ${ExtractorSources})
|
||||
file(GLOB ExtractorGlob extractor/*.cpp data_structures/hilbert_value.cpp)
|
||||
file(GLOB ImporterGlob data_structures/import_edge.cpp data_structures/external_memory_node.cpp data_structures/raster_source.cpp)
|
||||
add_library(IMPORT OBJECT ${ImporterGlob})
|
||||
add_library(LOGGER OBJECT util/simple_logger.cpp)
|
||||
add_library(PHANTOMNODE OBJECT data_structures/phantom_node.cpp)
|
||||
add_library(RASTERSOURCE OBJECT data_structures/raster_source.cpp)
|
||||
add_library(EXCEPTION OBJECT util/osrm_exception.cpp)
|
||||
add_library(MERCATOR OBJECT util/mercator.cpp)
|
||||
add_library(ANGLE OBJECT util/compute_angle.cpp)
|
||||
|
||||
file(GLOB PrepareGlob Contractor/*.cpp DataStructures/HilbertValue.cpp DataStructures/RestrictionMap.cpp)
|
||||
set(ExtractorSources extract.cpp ${ExtractorGlob})
|
||||
add_executable(osrm-extract ${ExtractorSources} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR> $<TARGET_OBJECTS:COMPRESSEDEDGE> $<TARGET_OBJECTS:GRAPHCOMPRESSOR> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:ANGLE>)
|
||||
|
||||
add_library(RESTRICTION OBJECT data_structures/restriction_map.cpp)
|
||||
add_library(COMPRESSEDEDGE OBJECT data_structures/compressed_edge_container.cpp)
|
||||
add_library(GRAPHCOMPRESSOR OBJECT algorithms/graph_compressor.cpp)
|
||||
|
||||
file(GLOB PrepareGlob contractor/*.cpp data_structures/hilbert_value.cpp {RestrictionMapGlob})
|
||||
set(PrepareSources prepare.cpp ${PrepareGlob})
|
||||
add_executable(osrm-prepare ${PrepareSources})
|
||||
add_executable(osrm-prepare ${PrepareSources} $<TARGET_OBJECTS:ANGLE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR> $<TARGET_OBJECTS:COMPRESSEDEDGE> $<TARGET_OBJECTS:GRAPHCOMPRESSOR>)
|
||||
|
||||
file(GLOB ServerGlob Server/*.cpp)
|
||||
file(GLOB DescriptorGlob Descriptors/*.cpp)
|
||||
file(GLOB DatastructureGlob DataStructures/SearchEngineData.cpp DataStructures/RouteParameters.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 ServerGlob server/*.cpp)
|
||||
file(GLOB DescriptorGlob descriptors/*.cpp)
|
||||
file(GLOB DatastructureGlob data_structures/search_engine_data.cpp data_structures/route_parameters.cpp util/bearing.cpp)
|
||||
file(GLOB CoordinateGlob data_structures/coordinate.cpp algorithms/coordinate_calculation.cpp)
|
||||
file(GLOB AlgorithmGlob algorithms/polyline_compressor.cpp algorithms/polyline_formatter.cpp algorithms/douglas_peucker.cpp)
|
||||
file(GLOB HttpGlob server/http/*.cpp)
|
||||
file(GLOB LibOSRMGlob library/*.cpp)
|
||||
file(GLOB DataStructureTestsGlob unit_tests/data_structures/*.cpp data_structures/hilbert_value.cpp)
|
||||
file(GLOB AlgorithmTestsGlob unit_tests/algorithms/*.cpp algorithms/graph_compressor.cpp)
|
||||
file(GLOB UtilTestsGlob unit_tests/util/*.cpp)
|
||||
|
||||
set(
|
||||
OSRMSources
|
||||
${LibOSRMGlob}
|
||||
${DescriptorGlob}
|
||||
${DatastructureGlob}
|
||||
${CoordinateGlob}
|
||||
${AlgorithmGlob}
|
||||
${HttpGlob}
|
||||
)
|
||||
add_library(COORDLIB STATIC ${CoordinateGlob})
|
||||
add_library(OSRM ${OSRMSources} Util/GitDescription.cpp Util/UUID.cpp)
|
||||
add_library(UUID STATIC Util/UUID.cpp)
|
||||
add_library(GITDESCRIPTION STATIC Util/GitDescription.cpp)
|
||||
add_dependencies(UUID UUIDConfigure)
|
||||
add_dependencies(GITDESCRIPTION GIT_DESCRIPTION)
|
||||
|
||||
add_executable(osrm-routed routed.cpp ${ServerGlob})
|
||||
set_target_properties(osrm-routed PROPERTIES COMPILE_FLAGS -DROUTED)
|
||||
add_executable(osrm-datastore datastore.cpp)
|
||||
add_library(COORDINATE OBJECT ${CoordinateGlob})
|
||||
add_library(OSRM ${OSRMSources} $<TARGET_OBJECTS:ANGLE> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR> $<TARGET_OBJECTS:IMPORT>)
|
||||
|
||||
add_library(FINGERPRINT OBJECT util/fingerprint.cpp)
|
||||
add_dependencies(FINGERPRINT FingerPrintConfigure)
|
||||
add_dependencies(OSRM FingerPrintConfigure)
|
||||
set_target_properties(FINGERPRINT PROPERTIES LINKER_LANGUAGE CXX)
|
||||
|
||||
add_executable(osrm-routed routed.cpp ${ServerGlob} $<TARGET_OBJECTS:EXCEPTION>)
|
||||
add_executable(osrm-datastore datastore.cpp $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR>)
|
||||
|
||||
# Unit tests
|
||||
add_executable(datastructure-tests EXCLUDE_FROM_ALL unit_tests/datastructure_tests.cpp ${DataStructureTestsGlob} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR> $<TARGET_OBJECTS:COMPRESSEDEDGE> $<TARGET_OBJECTS:GRAPHCOMPRESSOR> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:RASTERSOURCE>)
|
||||
add_executable(algorithm-tests EXCLUDE_FROM_ALL unit_tests/algorithm_tests.cpp ${AlgorithmTestsGlob} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:COMPRESSEDEDGE>)
|
||||
add_executable(util-tests EXCLUDE_FROM_ALL unit_tests/util_tests.cpp ${UtilTestsGlob})
|
||||
|
||||
# Benchmarks
|
||||
add_executable(rtree-bench EXCLUDE_FROM_ALL benchmarks/static_rtree.cpp $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR>)
|
||||
|
||||
# Check the release mode
|
||||
if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
@@ -79,63 +121,113 @@ 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")
|
||||
if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-inline -fno-omit-frame-pointer")
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Og -ggdb")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
endif()
|
||||
if(CMAKE_BUILD_TYPE MATCHES Release)
|
||||
message(STATUS "Configuring OSRM in release mode")
|
||||
message(STATUS "Configuring OSRM in release mode")
|
||||
# Check if LTO is available
|
||||
check_cxx_compiler_flag("-flto" LTO_AVAILABLE)
|
||||
if(LTO_AVAILABLE)
|
||||
set(OLD_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
# GCC in addition allows parallelizing LTO
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
include(ProcessorCount)
|
||||
ProcessorCount(NPROC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto=${NPROC}")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto")
|
||||
endif()
|
||||
set(CHECK_LTO_SRC "int main(){return 0;}")
|
||||
check_cxx_source_compiles("${CHECK_LTO_SRC}" LTO_WORKS)
|
||||
if(LTO_WORKS)
|
||||
message(STATUS "LTO working")
|
||||
else()
|
||||
message(STATUS "LTO broken")
|
||||
set(CMAKE_CXX_FLAGS "${OLD_CXX_FLAGS}")
|
||||
endif()
|
||||
|
||||
# Since gcc 4.9 the LTO format is non-standart ('slim'), so we need to use the build-in tools
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND
|
||||
NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0" AND NOT MINGW)
|
||||
message(STATUS "Using gcc specific binutils for LTO.")
|
||||
set(CMAKE_AR "/usr/bin/gcc-ar")
|
||||
set(CMAKE_RANLIB "/usr/bin/gcc-ranlib")
|
||||
endif()
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0")
|
||||
message(STATUS "Disabling LTO on GCC < 4.9.0 since it is broken, see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57038")
|
||||
set(CMAKE_CXX_FLAGS "${OLD_CXX_FLAGS}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT WIN32)
|
||||
add_definitions(-DBOOST_TEST_DYN_LINK)
|
||||
endif()
|
||||
|
||||
# Configuring compilers
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
# using Clang
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wunreachable-code -Wno-unknown-pragmas -Wno-unneeded-internal-declaration -pedantic -fPIC")
|
||||
message(STATUS "OpenMP parallelization not available using clang++")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wuninitialized -Wunreachable-code -Wstrict-overflow=2 -D_FORTIFY_SOURCE=2 -fPIC")
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
|
||||
set(COLOR_FLAG "-fdiagnostics-color=auto")
|
||||
check_cxx_compiler_flag("-fdiagnostics-color=auto" HAS_COLOR_FLAG)
|
||||
if(NOT HAS_COLOR_FLAG)
|
||||
set(COLOR_FLAG "")
|
||||
endif()
|
||||
# using GCC
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fopenmp -pedantic -fPIC")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wuninitialized -Wunreachable-code -Wstrict-overflow=1 -D_FORTIFY_SOURCE=2 ${COLOR_FLAG} -fPIC")
|
||||
if(WIN32) # using mingw
|
||||
add_definitions(-D_USE_MATH_DEFINES) # define M_PI, M_1_PI etc.
|
||||
add_definitions(-DWIN32)
|
||||
set(OPTIONAL_SOCKET_LIBS ws2_32 wsock32)
|
||||
endif()
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel")
|
||||
# using Intel C++
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-intel -wd10237 -Wall -openmp -ipo -fPIC")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-intel -wd10237 -Wall -ipo -fPIC")
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
|
||||
# using Visual Studio C++
|
||||
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} date_time chrono zlib)
|
||||
add_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_definitions(-DXML_STATIC)
|
||||
find_library(ws2_32_LIBRARY_PATH ws2_32)
|
||||
target_link_libraries(osrm-extract wsock32 ws2_32)
|
||||
endif()
|
||||
|
||||
# Check if LTO is available
|
||||
set(LTO_FLAGS "")
|
||||
CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG)
|
||||
if (HAS_LTO_FLAG)
|
||||
set(LTO_FLAGS "${LTO_FLAGS} -flto")
|
||||
|
||||
# Since gcc 4.9 the LTO format is non-standart ('slim'), so we need to use the build-in tools
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND
|
||||
NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0")
|
||||
message(STATUS "Using gcc specific binutils for LTO.")
|
||||
set(CMAKE_AR "/usr/bin/gcc-ar")
|
||||
set(CMAKE_RANLIB "/usr/bin/gcc-ranlib")
|
||||
# Configuring linker
|
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} "-Wl,--version" ERROR_QUIET OUTPUT_VARIABLE LINKER_VERSION)
|
||||
# For ld.gold and ld.bfs (the GNU linkers) we optimize hard
|
||||
if("${LINKER_VERSION}" MATCHES "GNU gold" OR "${LINKER_VERSION}" MATCHES "GNU ld")
|
||||
message(STATUS "Setting linker optimizations")
|
||||
if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
|
||||
# Tell compiler to put every function in separate section, linker can then match sections and functions
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections")
|
||||
# Tell linker to do dead code and data eminination during link time discarding sections
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -Wl,--gc-sections")
|
||||
endif()
|
||||
endif (HAS_LTO_FLAG)
|
||||
|
||||
# disable partitioning of LTO process when possible (fixes Debian issues)
|
||||
set(LTO_PARTITION_FLAGS "")
|
||||
CHECK_CXX_COMPILER_FLAG("-flto-partition=none" HAS_LTO_PARTITION_FLAG)
|
||||
if (HAS_LTO_PARTITION_FLAG)
|
||||
set(LTO_PARTITION_FLAGS "${LTO_PARTITION_FLAGS} -flto-partition=none")
|
||||
endif (HAS_LTO_PARTITION_FLAG)
|
||||
|
||||
# Add Link-Time-Optimization flags, if supported (GCC >= 4.7) and enabled
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LTO_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LTO_FLAGS} ${LTO_PARTITION_FLAGS}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LTO_FLAGS} ${LTO_PARTITION_FLAGS}")
|
||||
# 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++11
|
||||
ADD_DEFINITIONS(
|
||||
-std=c++11 # Or -std=c++0x
|
||||
# Other flags
|
||||
)
|
||||
if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ")
|
||||
endif()
|
||||
|
||||
# Configuring other platform dependencies
|
||||
if(APPLE)
|
||||
@@ -143,10 +235,6 @@ if(APPLE)
|
||||
message(STATUS "Set Architecture to x64 on OS X")
|
||||
exec_program(uname ARGS -v OUTPUT_VARIABLE DARWIN_VERSION)
|
||||
string(REGEX MATCH "[0-9]+" DARWIN_VERSION ${DARWIN_VERSION})
|
||||
# if(DARWIN_VERSION GREATER 12 AND NOT OSXLIBSTD)
|
||||
# message(STATUS "Activating -std=c++11 flag for >= OS X 10.9")
|
||||
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
# endif()
|
||||
if(OSXLIBSTD)
|
||||
message(STATUS "linking against ${OSXLIBSTD}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=${OSXLIBSTD}")
|
||||
@@ -157,104 +245,139 @@ 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)
|
||||
endif()
|
||||
|
||||
#Check Boost
|
||||
set(BOOST_MIN_VERSION "1.49.0")
|
||||
find_package(Boost ${BOOST_MIN_VERSION} COMPONENTS ${BOOST_COMPONENTS} REQUIRED)
|
||||
find_package(Boost 1.49.0 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})
|
||||
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
|
||||
|
||||
target_link_libraries(OSRM ${Boost_LIBRARIES} COORDLIB)
|
||||
target_link_libraries(osrm-extract ${Boost_LIBRARIES} UUID GITDESCRIPTION COORDLIB)
|
||||
target_link_libraries(osrm-prepare ${Boost_LIBRARIES} UUID GITDESCRIPTION COORDLIB)
|
||||
target_link_libraries(osrm-routed ${Boost_LIBRARIES} OSRM UUID GITDESCRIPTION)
|
||||
target_link_libraries(osrm-datastore ${Boost_LIBRARIES} UUID GITDESCRIPTION COORDLIB)
|
||||
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(algorithm-tests ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM)
|
||||
target_link_libraries(util-tests ${Boost_LIBRARIES})
|
||||
target_link_libraries(rtree-bench ${Boost_LIBRARIES})
|
||||
|
||||
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(algorithm-tests ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(rtree-bench ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
find_package(Lua52)
|
||||
if(NOT LUA52_FOUND)
|
||||
find_package(Lua51 REQUIRED)
|
||||
if(NOT APPLE)
|
||||
find_package(LuaJIT 5.1)
|
||||
endif()
|
||||
else()
|
||||
if(NOT APPLE)
|
||||
find_package(LuaJIT 5.2)
|
||||
endif()
|
||||
find_package(TBB REQUIRED)
|
||||
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(algorithm-tests ${TBB_LIBRARIES})
|
||||
target_link_libraries(rtree-bench ${TBB_LIBRARIES})
|
||||
include_directories(SYSTEM ${TBB_INCLUDE_DIR})
|
||||
|
||||
if( LUAJIT_FOUND )
|
||||
find_package( Luabind REQUIRED )
|
||||
include(check_luabind)
|
||||
|
||||
include_directories(SYSTEM ${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})
|
||||
endif()
|
||||
include_directories(${LUA_INCLUDE_DIR})
|
||||
include_directories(SYSTEM ${LUA_INCLUDE_DIR})
|
||||
|
||||
find_package(LibXml2 REQUIRED)
|
||||
include_directories(${LIBXML2_INCLUDE_DIR})
|
||||
target_link_libraries(osrm-extract ${LIBXML2_LIBRARIES})
|
||||
find_package(EXPAT REQUIRED)
|
||||
include_directories(SYSTEM ${EXPAT_INCLUDE_DIRS})
|
||||
target_link_libraries(osrm-extract ${EXPAT_LIBRARIES})
|
||||
|
||||
find_package( Luabind REQUIRED )
|
||||
include_directories(${LUABIND_INCLUDE_DIR})
|
||||
target_link_libraries(osrm-extract ${LUABIND_LIBRARY})
|
||||
target_link_libraries(osrm-prepare ${LUABIND_LIBRARY})
|
||||
|
||||
find_package( STXXL REQUIRED )
|
||||
include_directories(${STXXL_INCLUDE_DIR})
|
||||
find_package(STXXL REQUIRED)
|
||||
include_directories(SYSTEM ${STXXL_INCLUDE_DIR})
|
||||
target_link_libraries(OSRM ${STXXL_LIBRARY})
|
||||
target_link_libraries(osrm-extract ${STXXL_LIBRARY})
|
||||
target_link_libraries(osrm-prepare ${STXXL_LIBRARY})
|
||||
target_link_libraries(datastructure-tests ${STXXL_LIBRARY})
|
||||
|
||||
find_package( OSMPBF REQUIRED )
|
||||
include_directories(${OSMPBF_INCLUDE_DIR})
|
||||
target_link_libraries(osrm-extract ${OSMPBF_LIBRARY})
|
||||
target_link_libraries(osrm-prepare ${OSMPBF_LIBRARY})
|
||||
|
||||
find_package(Protobuf REQUIRED)
|
||||
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||
target_link_libraries(osrm-extract ${PROTOBUF_LIBRARY})
|
||||
target_link_libraries(osrm-prepare ${PROTOBUF_LIBRARY})
|
||||
set(OpenMP_FIND_QUIETLY ON)
|
||||
find_package(OpenMP)
|
||||
if(OPENMP_FOUND)
|
||||
message(STATUS "OpenMP support found. Linking just in case for stxxl")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
|
||||
endif()
|
||||
|
||||
find_package(BZip2 REQUIRED)
|
||||
include_directories(${BZIP_INCLUDE_DIRS})
|
||||
include_directories(SYSTEM ${BZIP_INCLUDE_DIRS})
|
||||
target_link_libraries(osrm-extract ${BZIP2_LIBRARIES})
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
include_directories(${ZLIB_INCLUDE_DIRS})
|
||||
include_directories(SYSTEM ${ZLIB_INCLUDE_DIRS})
|
||||
target_link_libraries(osrm-extract ${ZLIB_LIBRARY})
|
||||
target_link_libraries(osrm-routed ${ZLIB_LIBRARY})
|
||||
|
||||
if(WITH_TOOLS)
|
||||
if (ENABLE_JSON_LOGGING)
|
||||
message(STATUS "Enabling json logging")
|
||||
add_definitions(-DENABLE_JSON_LOGGING)
|
||||
endif()
|
||||
|
||||
if (DEBUG_GEOMETRY)
|
||||
message(STATUS "Enabling final edge weight GeoJSON output option")
|
||||
add_definitions(-DDEBUG_GEOMETRY)
|
||||
endif()
|
||||
|
||||
if(BUILD_TOOLS)
|
||||
message(STATUS "Activating OSRM internal tools")
|
||||
find_package(GDAL)
|
||||
if(GDAL_FOUND)
|
||||
add_executable(osrm-components Tools/components.cpp)
|
||||
include_directories(${GDAL_INCLUDE_DIR})
|
||||
target_link_libraries(
|
||||
osrm-components
|
||||
${GDAL_LIBRARIES} ${Boost_LIBRARIES} UUID GITDESCRIPTION COORDLIB)
|
||||
add_executable(osrm-components tools/components.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR>)
|
||||
target_link_libraries(osrm-components ${TBB_LIBRARIES})
|
||||
include_directories(SYSTEM ${GDAL_INCLUDE_DIR})
|
||||
target_link_libraries(osrm-components ${GDAL_LIBRARIES} ${Boost_LIBRARIES})
|
||||
install(TARGETS osrm-components DESTINATION bin)
|
||||
else()
|
||||
message(FATAL_ERROR "libgdal and/or development headers not found")
|
||||
endif()
|
||||
add_executable(osrm-cli Tools/simpleclient.cpp)
|
||||
target_link_libraries(osrm-cli ${Boost_LIBRARIES} OSRM UUID GITDESCRIPTION)
|
||||
add_executable(osrm-io-benchmark Tools/io-benchmark.cpp)
|
||||
target_link_libraries(osrm-io-benchmark ${Boost_LIBRARIES} GITDESCRIPTION)
|
||||
add_executable(osrm-unlock-all Tools/unlock_all_mutexes.cpp)
|
||||
target_link_libraries(osrm-unlock-all ${Boost_LIBRARIES} GITDESCRIPTION)
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(osrm-unlock-all rt)
|
||||
endif()
|
||||
add_executable(osrm-cli tools/simpleclient.cpp $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:COORDINATE>)
|
||||
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:EXCEPTION> $<TARGET_OBJECTS:LOGGER>)
|
||||
target_link_libraries(osrm-io-benchmark ${Boost_LIBRARIES})
|
||||
add_executable(osrm-unlock-all tools/unlock_all_mutexes.cpp $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION>)
|
||||
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:EXCEPTION> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:IMPORT>)
|
||||
target_link_libraries(osrm-check-hsgr ${Boost_LIBRARIES} ${TBB_LIBRARIES})
|
||||
add_executable(osrm-springclean tools/springclean.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION>)
|
||||
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)
|
||||
file(GLOB InstallGlob include/osrm/*.hpp)
|
||||
file(GLOB VariantGlob third_party/variant/*.hpp)
|
||||
|
||||
# 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
|
||||
@@ -265,19 +388,55 @@ 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)
|
||||
install(FILES ${VariantGlob} DESTINATION include/variant)
|
||||
install(TARGETS osrm-extract DESTINATION bin)
|
||||
install(TARGETS osrm-prepare 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})
|
||||
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 ()
|
||||
endforeach()
|
||||
list(GET TBB_LIBRARIES 1 TBB_LIBRARY_FIRST)
|
||||
get_filename_component(TBB_LIBRARY_LISTING "${TBB_LIBRARY_FIRST}" PATH)
|
||||
set(TBB_LIBRARY_LISTING "-L${TBB_LIBRARY_LISTING}")
|
||||
foreach(lib ${TBB_LIBRARIES})
|
||||
get_filename_component(TBB_LIBRARY_NAME "${lib}" NAME_WE)
|
||||
string(REPLACE "lib" "" TBB_LIBRARY_NAME ${TBB_LIBRARY_NAME})
|
||||
set(TBB_LIBRARY_LISTING "${TBB_LIBRARY_LISTING} -l${TBB_LIBRARY_NAME}")
|
||||
endforeach()
|
||||
|
||||
configure_file(${CMAKE_SOURCE_DIR}/cmake/pkgconfig.in libosrm.pc @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkgconfig.in libosrm.pc @ONLY)
|
||||
install(FILES ${PROJECT_BINARY_DIR}/libosrm.pc DESTINATION lib/pkgconfig)
|
||||
|
||||
if(BUILD_DEBIAN_PACKAGE)
|
||||
include(CPackDebianConfig)
|
||||
include(CPack)
|
||||
endif()
|
||||
|
||||
# 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(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(CCACHE_FOUND)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
set(ENV{CCACHE_CPP2} "true")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -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 "../Util/ComputeAngle.h"
|
||||
#include "../Util/LuaUtil.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#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> &m_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(m_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(NodeID u, NodeID v, EdgeID e1, bool belongs_to_tiny_cc)
|
||||
{
|
||||
// merge edges together into one EdgeBasedNode
|
||||
BOOST_ASSERT(u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(v != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(e1 != SPECIAL_EDGEID);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// find forward edge id and
|
||||
const EdgeID e1b = m_node_based_graph->FindEdge(u, v);
|
||||
BOOST_ASSERT(e1 == e1b);
|
||||
#endif
|
||||
|
||||
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(v, u);
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (e2 == m_node_based_graph->EndEdges(v))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "Did not find edge (" << v << "," << u << ")";
|
||||
}
|
||||
#endif
|
||||
BOOST_ASSERT(e2 != SPECIAL_EDGEID);
|
||||
BOOST_ASSERT(e2 < m_node_based_graph->EndEdges(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());
|
||||
|
||||
// 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 (unsigned i = 0; i < forward_geometry.size(); ++i)
|
||||
{
|
||||
forward_dist_prefix_sum[i] = temp_sum;
|
||||
temp_sum += forward_geometry[i].second;
|
||||
|
||||
BOOST_ASSERT(forward_data.distance >= temp_sum);
|
||||
}
|
||||
|
||||
temp_sum = 0;
|
||||
for (unsigned i = 0; i < reverse_geometry.size(); ++i)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
BOOST_ASSERT(forward_geometry.size() == reverse_geometry.size());
|
||||
|
||||
const unsigned geometry_size = forward_geometry.size();
|
||||
BOOST_ASSERT(geometry_size > 1);
|
||||
NodeID current_edge_start_coordinate_id = u;
|
||||
|
||||
if (forward_data.edgeBasedNodeID != SPECIAL_NODEID)
|
||||
{
|
||||
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 (unsigned i = 0; i < geometry_size; ++i)
|
||||
{
|
||||
BOOST_ASSERT(current_edge_start_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_start_coordinate_id);
|
||||
|
||||
// build edges
|
||||
m_edge_based_node_list.emplace_back(forward_data.edgeBasedNodeID,
|
||||
reverse_data.edgeBasedNodeID,
|
||||
current_edge_start_coordinate_id,
|
||||
current_edge_target_coordinate_id,
|
||||
forward_data.nameID,
|
||||
forward_geometry[i].second,
|
||||
reverse_geometry[i].second,
|
||||
forward_dist_prefix_sum[i],
|
||||
reverse_dist_prefix_sum[i],
|
||||
m_geometry_compressor.GetPositionForID(e1),
|
||||
i,
|
||||
belongs_to_tiny_cc);
|
||||
current_edge_start_coordinate_id = current_edge_target_coordinate_id;
|
||||
|
||||
BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
|
||||
|
||||
BOOST_ASSERT(u != m_edge_based_node_list.back().u ||
|
||||
v != m_edge_based_node_list.back().v);
|
||||
|
||||
BOOST_ASSERT(u != m_edge_based_node_list.back().v ||
|
||||
v != m_edge_based_node_list.back().u);
|
||||
}
|
||||
|
||||
BOOST_ASSERT(current_edge_start_coordinate_id == 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(EdgeBasedNode(forward_data.edgeBasedNodeID,
|
||||
reverse_data.edgeBasedNodeID,
|
||||
u,
|
||||
v,
|
||||
forward_data.nameID,
|
||||
forward_data.distance,
|
||||
reverse_data.distance,
|
||||
0,
|
||||
0,
|
||||
SPECIAL_EDGEID,
|
||||
0,
|
||||
belongs_to_tiny_cc));
|
||||
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
|
||||
{
|
||||
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_MSEC(geometry)*0.001 << "s";
|
||||
SimpleLogger().Write() << "Renumbering edges: " << TIMER_MSEC(renumber)*0.001 << "s";
|
||||
SimpleLogger().Write() << "Generating nodes: " << TIMER_MSEC(generate_nodes)*0.001 << "s";
|
||||
SimpleLogger().Write() << "Generating edges: " << TIMER_MSEC(generate_edges)*0.001 << "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 p(original_number_of_nodes);
|
||||
unsigned removed_node_count = 0;
|
||||
|
||||
for (NodeID v = 0; v < original_number_of_nodes; ++v)
|
||||
{
|
||||
p.printStatus(v);
|
||||
|
||||
// only contract degree 2 vertices
|
||||
if (2 != m_node_based_graph->GetOutDegree(v))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// don't contract barrier node
|
||||
if (m_barrier_nodes.end() != m_barrier_nodes.find(v))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool reverse_edge_order =
|
||||
!(m_node_based_graph->GetEdgeData(m_node_based_graph->BeginEdges(v)).forward);
|
||||
const EdgeID forward_e2 = m_node_based_graph->BeginEdges(v) + reverse_edge_order;
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != forward_e2);
|
||||
const EdgeID reverse_e2 = m_node_based_graph->BeginEdges(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 w = m_node_based_graph->GetTarget(forward_e2);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != w);
|
||||
BOOST_ASSERT(v != w);
|
||||
const NodeID u = m_node_based_graph->GetTarget(reverse_e2);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != u);
|
||||
BOOST_ASSERT(u != v);
|
||||
|
||||
const EdgeID forward_e1 = m_node_based_graph->FindEdge(u, v);
|
||||
BOOST_ASSERT(m_node_based_graph->EndEdges(u) != forward_e1);
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != forward_e1);
|
||||
BOOST_ASSERT(v == m_node_based_graph->GetTarget(forward_e1));
|
||||
const EdgeID reverse_e1 = m_node_based_graph->FindEdge(w, v);
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != reverse_e1);
|
||||
BOOST_ASSERT(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(u, w) != m_node_based_graph->EndEdges(u)) ||
|
||||
(m_node_based_graph->FindEdge(w, u) != m_node_based_graph->EndEdges(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(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.trafficSignalPenalty;
|
||||
m_node_based_graph->GetEdgeData(reverse_e1).distance +=
|
||||
speed_profile.trafficSignalPenalty;
|
||||
}
|
||||
|
||||
// extend e1's to targets of e2's
|
||||
m_node_based_graph->SetTarget(forward_e1, w);
|
||||
m_node_based_graph->SetTarget(reverse_e1, u);
|
||||
|
||||
// remove e2's (if bidir, otherwise only one)
|
||||
m_node_based_graph->DeleteEdge(v, forward_e2);
|
||||
m_node_based_graph->DeleteEdge(v, reverse_e2);
|
||||
|
||||
// update any involved turn restrictions
|
||||
m_restriction_map->FixupStartingTurnRestriction(u, v, w);
|
||||
m_restriction_map->FixupArrivingTurnRestriction(u, v, w);
|
||||
|
||||
m_restriction_map->FixupStartingTurnRestriction(w, v, u);
|
||||
m_restriction_map->FixupArrivingTurnRestriction(w, v, u);
|
||||
|
||||
// store compressed geometry in container
|
||||
m_geometry_compressor.CompressEdge(
|
||||
forward_e1,
|
||||
forward_e2,
|
||||
v,
|
||||
w,
|
||||
forward_weight1 +
|
||||
(add_traffic_signal_penalty ? speed_profile.trafficSignalPenalty : 0),
|
||||
forward_weight2);
|
||||
m_geometry_compressor.CompressEdge(
|
||||
reverse_e1,
|
||||
reverse_e2,
|
||||
v,
|
||||
u,
|
||||
reverse_weight1,
|
||||
reverse_weight2 +
|
||||
(add_traffic_signal_penalty ? speed_profile.trafficSignalPenalty : 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 (unsigned i = 0; i < m_node_based_graph->GetNumberOfNodes(); ++i)
|
||||
{
|
||||
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 egde 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->BeginEdges(current_node);
|
||||
current_edge < m_node_based_graph->EndEdges(current_node);
|
||||
++current_edge)
|
||||
{
|
||||
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 p(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());
|
||||
p.printIncrement();
|
||||
for (EdgeID e1 = m_node_based_graph->BeginEdges(u),
|
||||
last_edge = m_node_based_graph->EndEdges(u);
|
||||
e1 < last_edge;
|
||||
++e1)
|
||||
{
|
||||
const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
|
||||
if (edge_data.edgeBasedNodeID == SPECIAL_NODEID)
|
||||
{
|
||||
// continue;
|
||||
}
|
||||
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);
|
||||
BOOST_ASSERT(edge_data.type != SHRT_MAX);
|
||||
|
||||
// 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);
|
||||
InsertEdgeBasedNode(u, v, e1, 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 p(m_node_based_graph->GetNumberOfNodes());
|
||||
|
||||
for (NodeID u = 0, end = m_node_based_graph->GetNumberOfNodes(); u < end; ++u)
|
||||
{
|
||||
for (EdgeID e1 = m_node_based_graph->BeginEdges(u),
|
||||
last_edge_u = m_node_based_graph->EndEdges(u);
|
||||
e1 < last_edge_u;
|
||||
++e1)
|
||||
{
|
||||
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->BeginEdges(v),
|
||||
last_edge_v = m_node_based_graph->EndEdges(v);
|
||||
e2 < last_edge_v;
|
||||
++e2)
|
||||
{
|
||||
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))
|
||||
{
|
||||
++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.trafficSignalPenalty;
|
||||
}
|
||||
const int turn_penalty = GetTurnPenalty(u, v, w, lua_state);
|
||||
TurnInstruction turn_instruction = AnalyzeTurn(u, v, w);
|
||||
if (turn_instruction == TurnInstruction::UTurn)
|
||||
{
|
||||
distance += speed_profile.uTurnPenalty;
|
||||
}
|
||||
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);
|
||||
|
||||
++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));
|
||||
}
|
||||
}
|
||||
p.printIncrement();
|
||||
}
|
||||
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(const NodeID u,
|
||||
const NodeID v,
|
||||
const NodeID w,
|
||||
lua_State *lua_state) const
|
||||
{
|
||||
const double angle = GetAngleBetweenThreeFixedPointCoordinates(
|
||||
m_node_info_list[u], m_node_info_list[v], m_node_info_list[w]);
|
||||
|
||||
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 u, const NodeID v, const NodeID w)
|
||||
const
|
||||
{
|
||||
if (u == w)
|
||||
{
|
||||
return TurnInstruction::UTurn;
|
||||
}
|
||||
|
||||
const EdgeID edge1 = m_node_based_graph->FindEdge(u, v);
|
||||
const EdgeID edge2 = m_node_based_graph->FindEdge(v, w);
|
||||
|
||||
const EdgeData &data1 = m_node_based_graph->GetEdgeData(edge1);
|
||||
const EdgeData &data2 = m_node_based_graph->GetEdgeData(edge2);
|
||||
|
||||
if (!data1.contraFlow && data2.contraFlow)
|
||||
{
|
||||
return TurnInstruction::EnterAgainstAllowedDirection;
|
||||
}
|
||||
if (data1.contraFlow && !data2.contraFlow)
|
||||
{
|
||||
return TurnInstruction::LeaveAgainstAllowedDirection;
|
||||
}
|
||||
|
||||
// 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->GetOutDegree(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)
|
||||
{
|
||||
return TurnInstruction::NoTurn;
|
||||
}
|
||||
else if (m_node_based_graph->GetOutDegree(v) <= 2)
|
||||
{
|
||||
return TurnInstruction::NoTurn;
|
||||
}
|
||||
}
|
||||
|
||||
const double angle = GetAngleBetweenThreeFixedPointCoordinates(
|
||||
m_node_info_list[u], m_node_info_list[v], m_node_info_list[w]);
|
||||
return TurnInstructionsClass::GetTurnDirectionOfInstruction(angle);
|
||||
}
|
||||
|
||||
unsigned EdgeBasedGraphFactory::GetNumberOfEdgeBasedNodes() const
|
||||
{
|
||||
return m_number_of_edge_based_nodes;
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
// This class constructs the edge-expanded routing graph
|
||||
|
||||
#ifndef EDGEBASEDGRAPHFACTORY_H_
|
||||
#define EDGEBASEDGRAPHFACTORY_H_
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
#include "../DataStructures/DynamicGraph.h"
|
||||
#include "../DataStructures/EdgeBasedNode.h"
|
||||
#include "../DataStructures/OriginalEdgeData.h"
|
||||
#include "../DataStructures/QueryNode.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../DataStructures/Restriction.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;
|
||||
|
||||
int GetTurnPenalty(const NodeID u, const NodeID v, const NodeID w, lua_State *lua_state) const;
|
||||
|
||||
unsigned GetNumberOfEdgeBasedNodes() const;
|
||||
|
||||
struct SpeedProfileProperties
|
||||
{
|
||||
SpeedProfileProperties()
|
||||
: trafficSignalPenalty(0), uTurnPenalty(0), has_turn_penalty_function(false)
|
||||
{
|
||||
}
|
||||
|
||||
int trafficSignalPenalty;
|
||||
int uTurnPenalty;
|
||||
bool has_turn_penalty_function;
|
||||
} speed_profile;
|
||||
|
||||
private:
|
||||
typedef NodeBasedDynamicGraph::EdgeData 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(NodeID u, NodeID v, EdgeID e1, bool belongsToTinyComponent);
|
||||
|
||||
void FlushVectorToStream(std::ofstream &edge_data_file,
|
||||
std::vector<OriginalEdgeData> &original_edge_data_vector) const;
|
||||
|
||||
unsigned max_id;
|
||||
};
|
||||
|
||||
#endif /* EDGEBASEDGRAPHFACTORY_H_ */
|
||||
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "TemporaryStorage.h"
|
||||
|
||||
StreamData::StreamData()
|
||||
: write_mode(true), temp_path(boost::filesystem::unique_path(temp_directory.append(
|
||||
TemporaryFilePattern.begin(), TemporaryFilePattern.end()))),
|
||||
temp_file(new boost::filesystem::fstream(
|
||||
temp_path, std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary)),
|
||||
readWriteMutex(std::make_shared<boost::mutex>())
|
||||
{
|
||||
if (temp_file->fail())
|
||||
{
|
||||
throw OSRMException("temporary file could not be created");
|
||||
}
|
||||
}
|
||||
|
||||
TemporaryStorage::TemporaryStorage() { temp_directory = boost::filesystem::temp_directory_path(); }
|
||||
|
||||
TemporaryStorage &TemporaryStorage::GetInstance()
|
||||
{
|
||||
static TemporaryStorage static_instance;
|
||||
return static_instance;
|
||||
}
|
||||
|
||||
TemporaryStorage::~TemporaryStorage() { RemoveAll(); }
|
||||
|
||||
void TemporaryStorage::RemoveAll()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
for (unsigned slot_id = 0; slot_id < stream_data_list.size(); ++slot_id)
|
||||
{
|
||||
DeallocateSlot(slot_id);
|
||||
}
|
||||
stream_data_list.clear();
|
||||
}
|
||||
|
||||
int TemporaryStorage::AllocateSlot()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
try { stream_data_list.push_back(StreamData()); }
|
||||
catch (boost::filesystem::filesystem_error &e) { Abort(e); }
|
||||
CheckIfTemporaryDeviceFull();
|
||||
return stream_data_list.size() - 1;
|
||||
}
|
||||
|
||||
void TemporaryStorage::DeallocateSlot(const int slot_id)
|
||||
{
|
||||
try
|
||||
{
|
||||
StreamData &data = stream_data_list[slot_id];
|
||||
boost::mutex::scoped_lock lock(*data.readWriteMutex);
|
||||
if (!boost::filesystem::exists(data.temp_path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (data.temp_file->is_open())
|
||||
{
|
||||
data.temp_file->close();
|
||||
}
|
||||
|
||||
boost::filesystem::remove(data.temp_path);
|
||||
}
|
||||
catch (boost::filesystem::filesystem_error &e) { Abort(e); }
|
||||
}
|
||||
|
||||
void TemporaryStorage::WriteToSlot(const int slot_id, char *pointer, const std::size_t size)
|
||||
{
|
||||
try
|
||||
{
|
||||
StreamData &data = stream_data_list[slot_id];
|
||||
BOOST_ASSERT(data.write_mode);
|
||||
|
||||
boost::mutex::scoped_lock lock(*data.readWriteMutex);
|
||||
BOOST_ASSERT_MSG(data.write_mode, "Writing after first read is not allowed");
|
||||
if (1073741824 < data.buffer.size())
|
||||
{
|
||||
data.temp_file->write(&data.buffer[0], data.buffer.size());
|
||||
// data.temp_file->write(pointer, size);
|
||||
data.buffer.clear();
|
||||
CheckIfTemporaryDeviceFull();
|
||||
}
|
||||
data.buffer.insert(data.buffer.end(), pointer, pointer + size);
|
||||
}
|
||||
catch (boost::filesystem::filesystem_error &e) { Abort(e); }
|
||||
}
|
||||
void TemporaryStorage::ReadFromSlot(const int slot_id, char *pointer, const std::size_t size)
|
||||
{
|
||||
try
|
||||
{
|
||||
StreamData &data = stream_data_list[slot_id];
|
||||
boost::mutex::scoped_lock lock(*data.readWriteMutex);
|
||||
if (data.write_mode)
|
||||
{
|
||||
data.write_mode = false;
|
||||
data.temp_file->write(&data.buffer[0], data.buffer.size());
|
||||
data.buffer.clear();
|
||||
data.temp_file->seekg(data.temp_file->beg);
|
||||
BOOST_ASSERT(data.temp_file->beg == data.temp_file->tellg());
|
||||
}
|
||||
BOOST_ASSERT(!data.write_mode);
|
||||
data.temp_file->read(pointer, size);
|
||||
}
|
||||
catch (boost::filesystem::filesystem_error &e) { Abort(e); }
|
||||
}
|
||||
|
||||
uint64_t TemporaryStorage::GetFreeBytesOnTemporaryDevice()
|
||||
{
|
||||
uint64_t value = -1;
|
||||
try
|
||||
{
|
||||
boost::filesystem::path p = boost::filesystem::temp_directory_path();
|
||||
boost::filesystem::space_info s = boost::filesystem::space(p);
|
||||
value = s.free;
|
||||
}
|
||||
catch (boost::filesystem::filesystem_error &e) { Abort(e); }
|
||||
return value;
|
||||
}
|
||||
|
||||
void TemporaryStorage::CheckIfTemporaryDeviceFull()
|
||||
{
|
||||
boost::filesystem::path p = boost::filesystem::temp_directory_path();
|
||||
boost::filesystem::space_info s = boost::filesystem::space(p);
|
||||
if ((1024 * 1024) > s.free)
|
||||
{
|
||||
throw OSRMException("temporary device is full");
|
||||
}
|
||||
}
|
||||
|
||||
boost::filesystem::fstream::pos_type TemporaryStorage::Tell(const int slot_id)
|
||||
{
|
||||
boost::filesystem::fstream::pos_type position;
|
||||
try
|
||||
{
|
||||
StreamData &data = stream_data_list[slot_id];
|
||||
boost::mutex::scoped_lock lock(*data.readWriteMutex);
|
||||
position = data.temp_file->tellp();
|
||||
}
|
||||
catch (boost::filesystem::filesystem_error &e) { Abort(e); }
|
||||
return position;
|
||||
}
|
||||
|
||||
void TemporaryStorage::Abort(const boost::filesystem::filesystem_error &e)
|
||||
{
|
||||
RemoveAll();
|
||||
throw OSRMException(e.what());
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TEMPORARYSTORAGE_H_
|
||||
#define TEMPORARYSTORAGE_H_
|
||||
|
||||
#include "../Util/BoostFileSystemFix.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
|
||||
struct StreamData
|
||||
{
|
||||
bool write_mode;
|
||||
boost::filesystem::path temp_path;
|
||||
std::shared_ptr<boost::filesystem::fstream> temp_file;
|
||||
std::shared_ptr<boost::mutex> readWriteMutex;
|
||||
std::vector<char> buffer;
|
||||
|
||||
StreamData();
|
||||
};
|
||||
|
||||
// This class implements a singleton file storage for temporary data.
|
||||
// temporary slots can be accessed by other objects through an int
|
||||
// On deallocation every slot gets deallocated
|
||||
//
|
||||
// Access is sequential, which means, that there is no random access
|
||||
// -> Data is written in first phase and reread in second.
|
||||
|
||||
static boost::filesystem::path temp_directory;
|
||||
static std::string TemporaryFilePattern("OSRM-%%%%-%%%%-%%%%");
|
||||
class TemporaryStorage
|
||||
{
|
||||
public:
|
||||
static TemporaryStorage &GetInstance();
|
||||
virtual ~TemporaryStorage();
|
||||
|
||||
int AllocateSlot();
|
||||
void DeallocateSlot(const int slot_id);
|
||||
void WriteToSlot(const int slot_id, char *pointer, const std::size_t size);
|
||||
void ReadFromSlot(const int slot_id, char *pointer, const std::size_t size);
|
||||
// returns the number of free bytes
|
||||
uint64_t GetFreeBytesOnTemporaryDevice();
|
||||
boost::filesystem::fstream::pos_type Tell(const int slot_id);
|
||||
void RemoveAll();
|
||||
|
||||
private:
|
||||
TemporaryStorage();
|
||||
TemporaryStorage(TemporaryStorage const &) {};
|
||||
|
||||
TemporaryStorage &operator=(TemporaryStorage const &) { return *this; }
|
||||
|
||||
void Abort(const boost::filesystem::filesystem_error &e);
|
||||
void CheckIfTemporaryDeviceFull();
|
||||
|
||||
// vector of file streams that is used to store temporary data
|
||||
boost::mutex mutex;
|
||||
std::vector<StreamData> stream_data_list;
|
||||
};
|
||||
|
||||
#endif /* TEMPORARYSTORAGE_H_ */
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CONCURRENT_QUEUE_H
|
||||
#define CONCURRENT_QUEUE_H
|
||||
|
||||
#include "../typedefs.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_mutex.unlock();
|
||||
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_mutex.unlock();
|
||||
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_mutex.unlock();
|
||||
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,331 +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"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include <bitset>
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
FixedPointCoordinate::FixedPointCoordinate()
|
||||
: lat(std::numeric_limits<int>::min()), lon(std::numeric_limits<int>::min())
|
||||
{
|
||||
}
|
||||
|
||||
FixedPointCoordinate::FixedPointCoordinate(int lat, int lon) : lat(lat), lon(lon)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (0 != (std::abs(lat) >> 30))
|
||||
{
|
||||
std::bitset<32> y(lat);
|
||||
SimpleLogger().Write(logDEBUG) << "broken lat: " << lat << ", bits: " << y;
|
||||
}
|
||||
if (0 != (std::abs(lon) >> 30))
|
||||
{
|
||||
std::bitset<32> x(lon);
|
||||
SimpleLogger().Write(logDEBUG) << "broken lon: " << lon << ", bits: " << x;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FixedPointCoordinate::Reset()
|
||||
{
|
||||
lat = std::numeric_limits<int>::min();
|
||||
lon = std::numeric_limits<int>::min();
|
||||
}
|
||||
bool FixedPointCoordinate::isSet() const
|
||||
{
|
||||
return (std::numeric_limits<int>::min() != lat) && (std::numeric_limits<int>::min() != lon);
|
||||
}
|
||||
bool FixedPointCoordinate::isValid() const
|
||||
{
|
||||
if (lat > 90 * COORDINATE_PRECISION || lat < -90 * COORDINATE_PRECISION ||
|
||||
lon > 180 * COORDINATE_PRECISION || lon < -180 * COORDINATE_PRECISION)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool FixedPointCoordinate::operator==(const FixedPointCoordinate &other) const
|
||||
{
|
||||
return lat == other.lat && lon == other.lon;
|
||||
}
|
||||
|
||||
double FixedPointCoordinate::ApproximateDistance(const int lat1,
|
||||
const int lon1,
|
||||
const int lat2,
|
||||
const int lon2)
|
||||
{
|
||||
BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
|
||||
double RAD = 0.017453292519943295769236907684886;
|
||||
double lt1 = lat1 / COORDINATE_PRECISION;
|
||||
double ln1 = lon1 / COORDINATE_PRECISION;
|
||||
double lt2 = lat2 / COORDINATE_PRECISION;
|
||||
double ln2 = lon2 / COORDINATE_PRECISION;
|
||||
double dlat1 = lt1 * (RAD);
|
||||
|
||||
double dlong1 = ln1 * (RAD);
|
||||
double dlat2 = lt2 * (RAD);
|
||||
double dlong2 = ln2 * (RAD);
|
||||
|
||||
double dLong = dlong1 - dlong2;
|
||||
double dLat = dlat1 - dlat2;
|
||||
|
||||
double aHarv = pow(sin(dLat / 2.0), 2.0) + cos(dlat1) * cos(dlat2) * pow(sin(dLong / 2.), 2);
|
||||
double cHarv = 2. * atan2(sqrt(aHarv), sqrt(1.0 - aHarv));
|
||||
// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
|
||||
// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
|
||||
const double earth = 6372797.560856;
|
||||
return earth * cHarv;
|
||||
}
|
||||
|
||||
double FixedPointCoordinate::ApproximateDistance(const FixedPointCoordinate &c1,
|
||||
const FixedPointCoordinate &c2)
|
||||
{
|
||||
return ApproximateDistance(c1.lat, c1.lon, c2.lat, c2.lon);
|
||||
}
|
||||
|
||||
double FixedPointCoordinate::ApproximateEuclideanDistance(const FixedPointCoordinate &c1,
|
||||
const FixedPointCoordinate &c2)
|
||||
{
|
||||
return ApproximateEuclideanDistance(c1.lat, c1.lon, c2.lat, c2.lon);
|
||||
}
|
||||
|
||||
double 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 double RAD = 0.017453292519943295769236907684886;
|
||||
const double float_lat1 = (lat1 / COORDINATE_PRECISION) * RAD;
|
||||
const double float_lon1 = (lon1 / COORDINATE_PRECISION) * RAD;
|
||||
const double float_lat2 = (lat2 / COORDINATE_PRECISION) * RAD;
|
||||
const double float_lon2 = (lon2 / COORDINATE_PRECISION) * RAD;
|
||||
|
||||
const double x = (float_lon2 - float_lon1) * cos((float_lat1 + float_lat2) / 2.);
|
||||
const double y = (float_lat2 - float_lat1);
|
||||
const double earth_radius = 6372797.560856;
|
||||
return sqrt(x * x + y * y) * earth_radius;
|
||||
}
|
||||
|
||||
// Yuck! Code duplication. This function is also in EgdeBasedNode.h
|
||||
double FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &point,
|
||||
const FixedPointCoordinate &segA,
|
||||
const FixedPointCoordinate &segB)
|
||||
{
|
||||
const double x = lat2y(point.lat / COORDINATE_PRECISION);
|
||||
const double y = point.lon / COORDINATE_PRECISION;
|
||||
const double a = lat2y(segA.lat / COORDINATE_PRECISION);
|
||||
const double b = segA.lon / COORDINATE_PRECISION;
|
||||
const double c = lat2y(segB.lat / COORDINATE_PRECISION);
|
||||
const double d = segB.lon / COORDINATE_PRECISION;
|
||||
double p, q, nY;
|
||||
if (std::abs(a - c) > std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
const double m = (d - b) / (c - a); // slope
|
||||
// Projection of (x,y) on line joining (a,b) and (c,d)
|
||||
p = ((x + (m * y)) + (m * m * a - m * b)) / (1. + m * m);
|
||||
q = b + m * (p - a);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = c;
|
||||
q = y;
|
||||
}
|
||||
nY = (d * p - c * q) / (a * d - b * c);
|
||||
|
||||
// discretize the result to coordinate precision. it's a hack!
|
||||
if (std::abs(nY) < (1. / COORDINATE_PRECISION))
|
||||
{
|
||||
nY = 0.;
|
||||
}
|
||||
|
||||
double r = (p - nY * a) / c;
|
||||
if (std::isnan(r))
|
||||
{
|
||||
r = ((segB.lat == point.lat) && (segB.lon == point.lon)) ? 1. : 0.;
|
||||
}
|
||||
else if (std::abs(r) <= std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
r = 0.;
|
||||
}
|
||||
else if (std::abs(r - 1.) <= std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
r = 1.;
|
||||
}
|
||||
FixedPointCoordinate nearest_location;
|
||||
BOOST_ASSERT(!std::isnan(r));
|
||||
if (r <= 0.)
|
||||
{ // point is "left" of edge
|
||||
nearest_location.lat = segA.lat;
|
||||
nearest_location.lon = segA.lon;
|
||||
}
|
||||
else if (r >= 1.)
|
||||
{ // point is "right" of edge
|
||||
nearest_location.lat = segB.lat;
|
||||
nearest_location.lon = segB.lon;
|
||||
}
|
||||
else
|
||||
{ // point lies in between
|
||||
nearest_location.lat = y2lat(p) * COORDINATE_PRECISION;
|
||||
nearest_location.lon = q * COORDINATE_PRECISION;
|
||||
}
|
||||
BOOST_ASSERT(nearest_location.isValid());
|
||||
const double approximated_distance =
|
||||
FixedPointCoordinate::ApproximateDistance(point, nearest_location);
|
||||
BOOST_ASSERT(0. <= approximated_distance);
|
||||
return approximated_distance;
|
||||
}
|
||||
|
||||
double FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &coord_a,
|
||||
const FixedPointCoordinate &coord_b,
|
||||
const FixedPointCoordinate &query_location,
|
||||
FixedPointCoordinate &nearest_location,
|
||||
double &r)
|
||||
{
|
||||
BOOST_ASSERT(query_location.isValid());
|
||||
|
||||
const double x = lat2y(query_location.lat / COORDINATE_PRECISION);
|
||||
const double y = query_location.lon / COORDINATE_PRECISION;
|
||||
const double a = lat2y(coord_a.lat / COORDINATE_PRECISION);
|
||||
const double b = coord_a.lon / COORDINATE_PRECISION;
|
||||
const double c = lat2y(coord_b.lat / COORDINATE_PRECISION);
|
||||
const double d = coord_b.lon / COORDINATE_PRECISION;
|
||||
double p, q /*,mX*/, nY;
|
||||
if (std::abs(a - c) > std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
const double m = (d - b) / (c - a); // slope
|
||||
// Projection of (x,y) on line joining (a,b) and (c,d)
|
||||
p = ((x + (m * y)) + (m * m * a - m * b)) / (1. + m * m);
|
||||
q = b + m * (p - a);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = c;
|
||||
q = y;
|
||||
}
|
||||
nY = (d * p - c * q) / (a * d - b * c);
|
||||
|
||||
// discretize the result to coordinate precision. it's a hack!
|
||||
if (std::abs(nY) < (1. / COORDINATE_PRECISION))
|
||||
{
|
||||
nY = 0.;
|
||||
}
|
||||
|
||||
r = (p - nY * a) / c; // These values are actually n/m+n and m/m+n , we need
|
||||
// not calculate the explicit values of m an n as we
|
||||
// are just interested in the ratio
|
||||
if (std::isnan(r))
|
||||
{
|
||||
r = ((coord_b.lat == query_location.lat) && (coord_b.lon == query_location.lon)) ? 1. : 0.;
|
||||
}
|
||||
else if (std::abs(r) <= std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
r = 0.;
|
||||
}
|
||||
else if (std::abs(r - 1.) <= std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
r = 1.;
|
||||
}
|
||||
BOOST_ASSERT(!std::isnan(r));
|
||||
if (r <= 0.)
|
||||
{
|
||||
nearest_location.lat = coord_a.lat;
|
||||
nearest_location.lon = coord_a.lon;
|
||||
}
|
||||
else if (r >= 1.)
|
||||
{
|
||||
nearest_location.lat = coord_b.lat;
|
||||
nearest_location.lon = coord_b.lon;
|
||||
}
|
||||
else
|
||||
{
|
||||
// point lies in between
|
||||
nearest_location.lat = y2lat(p) * COORDINATE_PRECISION;
|
||||
nearest_location.lon = q * COORDINATE_PRECISION;
|
||||
}
|
||||
BOOST_ASSERT(nearest_location.isValid());
|
||||
|
||||
// TODO: Replace with euclidean approximation when k-NN search is done
|
||||
// const double approximated_distance = FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
const double approximated_distance =
|
||||
FixedPointCoordinate::ApproximateDistance(query_location, nearest_location);
|
||||
BOOST_ASSERT(0. <= approximated_distance);
|
||||
return approximated_distance;
|
||||
}
|
||||
|
||||
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 << ")";
|
||||
}
|
||||
@@ -1,401 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DEALLOCATINGVECTOR_H_
|
||||
#define DEALLOCATINGVECTOR_H_
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
template <typename ElementT,
|
||||
std::size_t bucketSizeC = 8388608 / sizeof(ElementT),
|
||||
bool DeallocateC = false>
|
||||
class DeallocatingVectorIterator : public std::iterator<std::random_access_iterator_tag, ElementT>
|
||||
{
|
||||
protected:
|
||||
class DeallocatingVectorIteratorState
|
||||
{
|
||||
private:
|
||||
// make constructors explicit, so we do not mix random access and deallocation iterators.
|
||||
DeallocatingVectorIteratorState();
|
||||
|
||||
public:
|
||||
explicit DeallocatingVectorIteratorState(const DeallocatingVectorIteratorState &r)
|
||||
: index(r.index), bucket_list(r.bucket_list)
|
||||
{
|
||||
}
|
||||
explicit DeallocatingVectorIteratorState(const std::size_t idx,
|
||||
std::vector<ElementT *> &input_list)
|
||||
: index(idx), bucket_list(input_list)
|
||||
{
|
||||
}
|
||||
std::size_t index;
|
||||
std::vector<ElementT *> &bucket_list;
|
||||
|
||||
inline bool operator!=(const DeallocatingVectorIteratorState &other)
|
||||
{
|
||||
return index != other.index;
|
||||
}
|
||||
|
||||
inline bool operator==(const DeallocatingVectorIteratorState &other)
|
||||
{
|
||||
return index == other.index;
|
||||
}
|
||||
|
||||
bool operator<(const DeallocatingVectorIteratorState &other) const
|
||||
{
|
||||
return index < other.index;
|
||||
}
|
||||
|
||||
bool operator>(const DeallocatingVectorIteratorState &other) const
|
||||
{
|
||||
return index > other.index;
|
||||
}
|
||||
|
||||
bool operator>=(const DeallocatingVectorIteratorState &other) const
|
||||
{
|
||||
return index >= other.index;
|
||||
}
|
||||
|
||||
// This is a hack to make assignment operator possible with reference member
|
||||
inline DeallocatingVectorIteratorState &operator=(const DeallocatingVectorIteratorState &a)
|
||||
{
|
||||
if (this != &a)
|
||||
{
|
||||
this->DeallocatingVectorIteratorState::
|
||||
~DeallocatingVectorIteratorState(); // explicit non-virtual destructor
|
||||
new (this) DeallocatingVectorIteratorState(a); // placement new
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
DeallocatingVectorIteratorState current_state;
|
||||
|
||||
public:
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::value_type
|
||||
value_type;
|
||||
typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::difference_type
|
||||
difference_type;
|
||||
typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::reference reference;
|
||||
typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::pointer pointer;
|
||||
|
||||
DeallocatingVectorIterator() {}
|
||||
|
||||
template <typename T2>
|
||||
explicit DeallocatingVectorIterator(const DeallocatingVectorIterator<T2> &r)
|
||||
: current_state(r.current_state)
|
||||
{
|
||||
}
|
||||
|
||||
DeallocatingVectorIterator(std::size_t idx, std::vector<ElementT *> &input_list)
|
||||
: current_state(idx, input_list)
|
||||
{
|
||||
}
|
||||
explicit DeallocatingVectorIterator(const DeallocatingVectorIteratorState &r) : current_state(r) {}
|
||||
|
||||
template <typename T2>
|
||||
DeallocatingVectorIterator &operator=(const DeallocatingVectorIterator<T2> &r)
|
||||
{
|
||||
if (DeallocateC)
|
||||
{
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
current_state = r.current_state;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator &operator++()
|
||||
{ // prefix
|
||||
++current_state.index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator &operator--()
|
||||
{ // prefix
|
||||
if (DeallocateC)
|
||||
{
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
--current_state.index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator operator++(int)
|
||||
{ // postfix
|
||||
DeallocatingVectorIteratorState my_state(current_state);
|
||||
current_state.index++;
|
||||
return DeallocatingVectorIterator(my_state);
|
||||
}
|
||||
inline DeallocatingVectorIterator operator--(int)
|
||||
{ // postfix
|
||||
if (DeallocateC)
|
||||
{
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
DeallocatingVectorIteratorState my_state(current_state);
|
||||
current_state.index--;
|
||||
return DeallocatingVectorIterator(my_state);
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator operator+(const difference_type &n) const
|
||||
{
|
||||
DeallocatingVectorIteratorState my_state(current_state);
|
||||
my_state.index += n;
|
||||
return DeallocatingVectorIterator(my_state);
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator &operator+=(const difference_type &n)
|
||||
{
|
||||
current_state.index += n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator operator-(const difference_type &n) const
|
||||
{
|
||||
if (DeallocateC)
|
||||
{
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
DeallocatingVectorIteratorState my_state(current_state);
|
||||
my_state.index -= n;
|
||||
return DeallocatingVectorIterator(my_state);
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator &operator-=(const difference_type &n) const
|
||||
{
|
||||
if (DeallocateC)
|
||||
{
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
current_state.index -= n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline reference operator*() const
|
||||
{
|
||||
std::size_t current_bucket = current_state.index / bucketSizeC;
|
||||
std::size_t current_index = current_state.index % bucketSizeC;
|
||||
return (current_state.bucket_list[current_bucket][current_index]);
|
||||
}
|
||||
|
||||
inline pointer operator->() const
|
||||
{
|
||||
std::size_t current_bucket = current_state.index / bucketSizeC;
|
||||
std::size_t current_index = current_state.index % bucketSizeC;
|
||||
return &(current_state.bucket_list[current_bucket][current_index]);
|
||||
}
|
||||
|
||||
inline bool operator!=(const DeallocatingVectorIterator &other)
|
||||
{
|
||||
return current_state != other.current_state;
|
||||
}
|
||||
|
||||
inline bool operator==(const DeallocatingVectorIterator &other)
|
||||
{
|
||||
return current_state == other.current_state;
|
||||
}
|
||||
|
||||
inline bool operator<(const DeallocatingVectorIterator &other) const
|
||||
{
|
||||
return current_state < other.current_state;
|
||||
}
|
||||
|
||||
inline bool operator>(const DeallocatingVectorIterator &other) const
|
||||
{
|
||||
return current_state > other.current_state;
|
||||
}
|
||||
|
||||
inline bool operator>=(const DeallocatingVectorIterator &other) const
|
||||
{
|
||||
return current_state >= other.current_state;
|
||||
}
|
||||
|
||||
difference_type operator-(const DeallocatingVectorIterator &other)
|
||||
{
|
||||
if (DeallocateC)
|
||||
{
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
return current_state.index - other.current_state.index;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ElementT, std::size_t bucketSizeC = 8388608 / sizeof(ElementT)>
|
||||
class DeallocatingVector
|
||||
{
|
||||
private:
|
||||
std::size_t current_size;
|
||||
std::vector<ElementT *> bucket_list;
|
||||
|
||||
public:
|
||||
typedef ElementT value_type;
|
||||
typedef DeallocatingVectorIterator<ElementT, bucketSizeC, false> iterator;
|
||||
typedef DeallocatingVectorIterator<ElementT, bucketSizeC, false> const_iterator;
|
||||
|
||||
// this iterator deallocates all buckets that have been visited. Iterators to visited objects
|
||||
// become invalid.
|
||||
typedef DeallocatingVectorIterator<ElementT, bucketSizeC, true> deallocation_iterator;
|
||||
|
||||
DeallocatingVector() : current_size(0)
|
||||
{
|
||||
// initial bucket
|
||||
bucket_list.emplace_back(new ElementT[bucketSizeC]);
|
||||
}
|
||||
|
||||
~DeallocatingVector() { clear(); }
|
||||
|
||||
inline void swap(DeallocatingVector<ElementT, bucketSizeC> &other)
|
||||
{
|
||||
std::swap(current_size, other.current_size);
|
||||
bucket_list.swap(other.bucket_list);
|
||||
}
|
||||
|
||||
inline void clear()
|
||||
{
|
||||
// Delete[]'ing ptr's to all Buckets
|
||||
for (unsigned i = 0; i < bucket_list.size(); ++i)
|
||||
{
|
||||
if (nullptr != bucket_list[i])
|
||||
{
|
||||
delete[] bucket_list[i];
|
||||
bucket_list[i] = nullptr;
|
||||
}
|
||||
}
|
||||
// Removing all ptrs from vector
|
||||
std::vector<ElementT *>().swap(bucket_list);
|
||||
current_size = 0;
|
||||
}
|
||||
|
||||
inline void push_back(const ElementT &element)
|
||||
{
|
||||
const std::size_t current_capacity = capacity();
|
||||
if (current_size == current_capacity)
|
||||
{
|
||||
bucket_list.push_back(new ElementT[bucketSizeC]);
|
||||
}
|
||||
|
||||
std::size_t current_index = size() % bucketSizeC;
|
||||
bucket_list.back()[current_index] = element;
|
||||
++current_size;
|
||||
}
|
||||
|
||||
inline void emplace_back(const ElementT &&element)
|
||||
{
|
||||
const std::size_t current_capacity = capacity();
|
||||
if (current_size == current_capacity)
|
||||
{
|
||||
bucket_list.push_back(new ElementT[bucketSizeC]);
|
||||
}
|
||||
|
||||
const std::size_t current_index = size() % bucketSizeC;
|
||||
bucket_list.back()[current_index] = element;
|
||||
++current_size;
|
||||
}
|
||||
|
||||
inline void reserve(const std::size_t) const
|
||||
{
|
||||
// don't do anything
|
||||
}
|
||||
|
||||
inline void resize(const std::size_t new_size)
|
||||
{
|
||||
if (new_size > current_size)
|
||||
{
|
||||
while (capacity() < new_size)
|
||||
{
|
||||
bucket_list.push_back(new ElementT[bucketSizeC]);
|
||||
}
|
||||
current_size = new_size;
|
||||
}
|
||||
if (new_size < current_size)
|
||||
{
|
||||
const std::size_t number_of_necessary_buckets = 1 + (new_size / bucketSizeC);
|
||||
|
||||
for (unsigned i = number_of_necessary_buckets; i < bucket_list.size(); ++i)
|
||||
{
|
||||
delete[] bucket_list[i];
|
||||
}
|
||||
bucket_list.resize(number_of_necessary_buckets);
|
||||
current_size = new_size;
|
||||
}
|
||||
}
|
||||
|
||||
inline std::size_t size() const { return current_size; }
|
||||
|
||||
inline std::size_t capacity() const { return bucket_list.size() * bucketSizeC; }
|
||||
|
||||
inline iterator begin() { return iterator(static_cast<std::size_t>(0), bucket_list); }
|
||||
|
||||
inline iterator end() { return iterator(size(), bucket_list); }
|
||||
|
||||
inline deallocation_iterator dbegin()
|
||||
{
|
||||
return deallocation_iterator(static_cast<std::size_t>(0), bucket_list);
|
||||
}
|
||||
|
||||
inline deallocation_iterator dend() { return deallocation_iterator(size(), bucket_list); }
|
||||
|
||||
inline const_iterator begin() const
|
||||
{
|
||||
return const_iterator(static_cast<std::size_t>(0), bucket_list);
|
||||
}
|
||||
|
||||
inline const_iterator end() const { return const_iterator(size(), bucket_list); }
|
||||
|
||||
inline ElementT &operator[](const std::size_t index)
|
||||
{
|
||||
std::size_t _bucket = index / bucketSizeC;
|
||||
std::size_t _index = index % bucketSizeC;
|
||||
return (bucket_list[_bucket][_index]);
|
||||
}
|
||||
|
||||
const inline ElementT &operator[](const std::size_t index) const
|
||||
{
|
||||
std::size_t _bucket = index / bucketSizeC;
|
||||
std::size_t _index = index % bucketSizeC;
|
||||
return (bucket_list[_bucket][_index]);
|
||||
}
|
||||
|
||||
inline ElementT &back()
|
||||
{
|
||||
std::size_t _bucket = current_size / bucketSizeC;
|
||||
std::size_t _index = current_size % bucketSizeC;
|
||||
return (bucket_list[_bucket][_index]);
|
||||
}
|
||||
|
||||
const inline ElementT &back() const
|
||||
{
|
||||
std::size_t _bucket = current_size / bucketSizeC;
|
||||
std::size_t _index = current_size % bucketSizeC;
|
||||
return (bucket_list[_bucket][_index]);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* DEALLOCATINGVECTOR_H_ */
|
||||
@@ -1,261 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DYNAMICGRAPH_H
|
||||
#define DYNAMICGRAPH_H
|
||||
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
template <typename EdgeDataT> class DynamicGraph
|
||||
{
|
||||
public:
|
||||
typedef EdgeDataT EdgeData;
|
||||
typedef unsigned NodeIterator;
|
||||
typedef unsigned EdgeIterator;
|
||||
|
||||
class InputEdge
|
||||
{
|
||||
public:
|
||||
NodeIterator source;
|
||||
NodeIterator target;
|
||||
EdgeDataT data;
|
||||
bool operator<(const InputEdge &right) const
|
||||
{
|
||||
if (source != right.source)
|
||||
return source < right.source;
|
||||
return target < right.target;
|
||||
}
|
||||
};
|
||||
|
||||
// Constructs an empty graph with a given number of nodes.
|
||||
explicit DynamicGraph(int32_t nodes) : m_numNodes(nodes), m_numEdges(0)
|
||||
{
|
||||
m_nodes.reserve(m_numNodes);
|
||||
m_nodes.resize(m_numNodes);
|
||||
|
||||
m_edges.reserve(m_numNodes * 1.1);
|
||||
m_edges.resize(m_numNodes);
|
||||
}
|
||||
|
||||
template <class ContainerT> DynamicGraph(const int32_t nodes, const ContainerT &graph)
|
||||
{
|
||||
m_numNodes = nodes;
|
||||
m_numEdges = (EdgeIterator)graph.size();
|
||||
m_nodes.reserve(m_numNodes + 1);
|
||||
m_nodes.resize(m_numNodes + 1);
|
||||
EdgeIterator edge = 0;
|
||||
EdgeIterator position = 0;
|
||||
for (NodeIterator node = 0; node < m_numNodes; ++node)
|
||||
{
|
||||
EdgeIterator lastEdge = edge;
|
||||
while (edge < m_numEdges && graph[edge].source == node)
|
||||
{
|
||||
++edge;
|
||||
}
|
||||
m_nodes[node].firstEdge = position;
|
||||
m_nodes[node].edges = edge - lastEdge;
|
||||
position += m_nodes[node].edges;
|
||||
}
|
||||
m_nodes.back().firstEdge = position;
|
||||
m_edges.reserve(position * 1.1);
|
||||
m_edges.resize(position);
|
||||
edge = 0;
|
||||
for (NodeIterator node = 0; node < m_numNodes; ++node)
|
||||
{
|
||||
for (EdgeIterator i = m_nodes[node].firstEdge,
|
||||
e = m_nodes[node].firstEdge + m_nodes[node].edges;
|
||||
i != e;
|
||||
++i)
|
||||
{
|
||||
m_edges[i].target = graph[edge].target;
|
||||
m_edges[i].data = graph[edge].data;
|
||||
BOOST_ASSERT_MSG(graph[edge].data.distance > 0, "edge distance invalid");
|
||||
++edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~DynamicGraph() {}
|
||||
|
||||
unsigned GetNumberOfNodes() const { return m_numNodes; }
|
||||
|
||||
unsigned GetNumberOfEdges() const { return m_numEdges; }
|
||||
|
||||
unsigned GetOutDegree(const NodeIterator n) const { return m_nodes[n].edges; }
|
||||
|
||||
NodeIterator GetTarget(const EdgeIterator e) const { return NodeIterator(m_edges[e].target); }
|
||||
|
||||
void SetTarget(const EdgeIterator e, const NodeIterator n) { m_edges[e].target = n; }
|
||||
|
||||
EdgeDataT &GetEdgeData(const EdgeIterator e) { return m_edges[e].data; }
|
||||
|
||||
const EdgeDataT &GetEdgeData(const EdgeIterator e) const { return m_edges[e].data; }
|
||||
|
||||
EdgeIterator BeginEdges(const NodeIterator n) const
|
||||
{
|
||||
return EdgeIterator(m_nodes[n].firstEdge);
|
||||
}
|
||||
|
||||
EdgeIterator EndEdges(const NodeIterator n) const
|
||||
{
|
||||
return EdgeIterator(m_nodes[n].firstEdge + m_nodes[n].edges);
|
||||
}
|
||||
|
||||
// adds an edge. Invalidates edge iterators for the source node
|
||||
EdgeIterator InsertEdge(const NodeIterator from, const NodeIterator to, const EdgeDataT &data)
|
||||
{
|
||||
Node &node = m_nodes[from];
|
||||
EdgeIterator newFirstEdge = node.edges + node.firstEdge;
|
||||
if (newFirstEdge >= m_edges.size() || !isDummy(newFirstEdge))
|
||||
{
|
||||
if (node.firstEdge != 0 && isDummy(node.firstEdge - 1))
|
||||
{
|
||||
node.firstEdge--;
|
||||
m_edges[node.firstEdge] = m_edges[node.firstEdge + node.edges];
|
||||
}
|
||||
else
|
||||
{
|
||||
EdgeIterator newFirstEdge = (EdgeIterator)m_edges.size();
|
||||
unsigned newSize = node.edges * 1.1 + 2;
|
||||
EdgeIterator requiredCapacity = newSize + m_edges.size();
|
||||
EdgeIterator oldCapacity = m_edges.capacity();
|
||||
if (requiredCapacity >= oldCapacity)
|
||||
{
|
||||
m_edges.reserve(requiredCapacity * 1.1);
|
||||
}
|
||||
m_edges.resize(m_edges.size() + newSize);
|
||||
for (EdgeIterator i = 0; i < node.edges; ++i)
|
||||
{
|
||||
m_edges[newFirstEdge + i] = m_edges[node.firstEdge + i];
|
||||
makeDummy(node.firstEdge + i);
|
||||
}
|
||||
for (EdgeIterator i = node.edges + 1; i < newSize; ++i)
|
||||
makeDummy(newFirstEdge + i);
|
||||
node.firstEdge = newFirstEdge;
|
||||
}
|
||||
}
|
||||
Edge &edge = m_edges[node.firstEdge + node.edges];
|
||||
edge.target = to;
|
||||
edge.data = data;
|
||||
++m_numEdges;
|
||||
++node.edges;
|
||||
return EdgeIterator(node.firstEdge + node.edges);
|
||||
}
|
||||
|
||||
// removes an edge. Invalidates edge iterators for the source node
|
||||
void DeleteEdge(const NodeIterator source, const EdgeIterator e)
|
||||
{
|
||||
Node &node = m_nodes[source];
|
||||
#pragma omp atomic
|
||||
--m_numEdges;
|
||||
--node.edges;
|
||||
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != node.edges);
|
||||
const unsigned last = node.firstEdge + node.edges;
|
||||
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != last);
|
||||
// swap with last edge
|
||||
m_edges[e] = m_edges[last];
|
||||
makeDummy(last);
|
||||
}
|
||||
|
||||
// removes all edges (source,target)
|
||||
int32_t DeleteEdgesTo(const NodeIterator source, const NodeIterator target)
|
||||
{
|
||||
int32_t deleted = 0;
|
||||
for (EdgeIterator i = BeginEdges(source), iend = EndEdges(source); i < iend - deleted; ++i)
|
||||
{
|
||||
if (m_edges[i].target == target)
|
||||
{
|
||||
do
|
||||
{
|
||||
deleted++;
|
||||
m_edges[i] = m_edges[iend - deleted];
|
||||
makeDummy(iend - deleted);
|
||||
} while (i < iend - deleted && m_edges[i].target == target);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma omp atomic
|
||||
m_numEdges -= deleted;
|
||||
m_nodes[source].edges -= deleted;
|
||||
|
||||
return deleted;
|
||||
}
|
||||
|
||||
// searches for a specific edge
|
||||
EdgeIterator FindEdge(const NodeIterator from, const NodeIterator to) const
|
||||
{
|
||||
for (EdgeIterator i = BeginEdges(from), iend = EndEdges(from); i != iend; ++i)
|
||||
{
|
||||
if (to == m_edges[i].target)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return EndEdges(from);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool isDummy(const EdgeIterator edge) const
|
||||
{
|
||||
return m_edges[edge].target == (std::numeric_limits<NodeIterator>::max)();
|
||||
}
|
||||
|
||||
void makeDummy(const EdgeIterator edge)
|
||||
{
|
||||
m_edges[edge].target = (std::numeric_limits<NodeIterator>::max)();
|
||||
}
|
||||
|
||||
struct Node
|
||||
{
|
||||
// index of the first edge
|
||||
EdgeIterator firstEdge;
|
||||
// amount of edges
|
||||
unsigned edges;
|
||||
};
|
||||
|
||||
struct Edge
|
||||
{
|
||||
NodeIterator target;
|
||||
EdgeDataT data;
|
||||
};
|
||||
|
||||
NodeIterator m_numNodes;
|
||||
EdgeIterator m_numEdges;
|
||||
|
||||
std::vector<Node> m_nodes;
|
||||
DeallocatingVector<Edge> m_edges;
|
||||
};
|
||||
|
||||
#endif // DYNAMICGRAPH_H
|
||||
@@ -1,90 +0,0 @@
|
||||
#ifndef EDGE_BASED_NODE_H
|
||||
#define EDGE_BASED_NODE_H
|
||||
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <limits>
|
||||
|
||||
struct EdgeBasedNode
|
||||
{
|
||||
|
||||
EdgeBasedNode() :
|
||||
forward_edge_based_node_id(SPECIAL_NODEID),
|
||||
reverse_edge_based_node_id(SPECIAL_NODEID),
|
||||
u(SPECIAL_NODEID),
|
||||
v(SPECIAL_NODEID),
|
||||
name_id(0),
|
||||
forward_weight(INVALID_EDGE_WEIGHT >> 1),
|
||||
reverse_weight(INVALID_EDGE_WEIGHT >> 1),
|
||||
forward_offset(0),
|
||||
reverse_offset(0),
|
||||
packed_geometry_id(SPECIAL_EDGEID),
|
||||
fwd_segment_position( std::numeric_limits<unsigned short>::max() ),
|
||||
is_in_tiny_cc(false)
|
||||
{ }
|
||||
|
||||
explicit EdgeBasedNode(
|
||||
NodeID forward_edge_based_node_id,
|
||||
NodeID reverse_edge_based_node_id,
|
||||
NodeID u,
|
||||
NodeID v,
|
||||
unsigned name_id,
|
||||
int forward_weight,
|
||||
int reverse_weight,
|
||||
int forward_offset,
|
||||
int reverse_offset,
|
||||
unsigned packed_geometry_id,
|
||||
unsigned short fwd_segment_position,
|
||||
bool belongs_to_tiny_component
|
||||
) :
|
||||
forward_edge_based_node_id(forward_edge_based_node_id),
|
||||
reverse_edge_based_node_id(reverse_edge_based_node_id),
|
||||
u(u),
|
||||
v(v),
|
||||
name_id(name_id),
|
||||
forward_weight(forward_weight),
|
||||
reverse_weight(reverse_weight),
|
||||
forward_offset(forward_offset),
|
||||
reverse_offset(reverse_offset),
|
||||
packed_geometry_id(packed_geometry_id),
|
||||
fwd_segment_position(fwd_segment_position),
|
||||
is_in_tiny_cc(belongs_to_tiny_component)
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
#endif //EDGE_BASED_NODE_H
|
||||
@@ -1,178 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef IMPORT_EDGE_H
|
||||
#define IMPORT_EDGE_H
|
||||
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
class NodeBasedEdge
|
||||
{
|
||||
|
||||
public:
|
||||
bool operator<(const NodeBasedEdge &e) const
|
||||
{
|
||||
if (source() == e.source())
|
||||
{
|
||||
if (target() == e.target())
|
||||
{
|
||||
if (weight() == e.weight())
|
||||
{
|
||||
return (isForward() && isBackward() && ((!e.isForward()) || (!e.isBackward())));
|
||||
}
|
||||
return (weight() < e.weight());
|
||||
}
|
||||
return (target() < e.target());
|
||||
}
|
||||
return (source() < e.source());
|
||||
}
|
||||
|
||||
explicit NodeBasedEdge(NodeID s,
|
||||
NodeID t,
|
||||
NodeID n,
|
||||
EdgeWeight w,
|
||||
bool f,
|
||||
bool b,
|
||||
short ty,
|
||||
bool ra,
|
||||
bool ig,
|
||||
bool ar,
|
||||
bool cf,
|
||||
bool is_split)
|
||||
: _source(s), _target(t), _name(n), _weight(w), _type(ty), forward(f), backward(b),
|
||||
_roundabout(ra), _ignoreInGrid(ig), _accessRestricted(ar), _contraFlow(cf),
|
||||
is_split(is_split)
|
||||
{
|
||||
if (ty < 0)
|
||||
{
|
||||
throw OSRMException("negative edge type");
|
||||
}
|
||||
}
|
||||
|
||||
NodeID target() const { return _target; }
|
||||
NodeID source() const { return _source; }
|
||||
NodeID name() const { return _name; }
|
||||
EdgeWeight weight() const { return _weight; }
|
||||
short type() const
|
||||
{
|
||||
BOOST_ASSERT_MSG(_type >= 0, "type of ImportEdge invalid");
|
||||
return _type;
|
||||
}
|
||||
bool isBackward() const { return backward; }
|
||||
bool isForward() const { return forward; }
|
||||
bool isLocatable() const { return _type != 14; }
|
||||
bool isRoundabout() const { return _roundabout; }
|
||||
bool ignoreInGrid() const { return _ignoreInGrid; }
|
||||
bool isAccessRestricted() const { return _accessRestricted; }
|
||||
bool isContraFlow() const { return _contraFlow; }
|
||||
bool IsSplit() const { return is_split; }
|
||||
|
||||
// TODO: names need to be fixed.
|
||||
NodeID _source;
|
||||
NodeID _target;
|
||||
NodeID _name;
|
||||
EdgeWeight _weight;
|
||||
short _type;
|
||||
bool forward : 1;
|
||||
bool backward : 1;
|
||||
bool _roundabout : 1;
|
||||
bool _ignoreInGrid : 1;
|
||||
bool _accessRestricted : 1;
|
||||
bool _contraFlow : 1;
|
||||
bool is_split : 1;
|
||||
|
||||
private:
|
||||
NodeBasedEdge() {}
|
||||
};
|
||||
|
||||
class EdgeBasedEdge
|
||||
{
|
||||
|
||||
public:
|
||||
bool operator<(const EdgeBasedEdge &e) const
|
||||
{
|
||||
if (source() == e.source())
|
||||
{
|
||||
if (target() == e.target())
|
||||
{
|
||||
if (weight() == e.weight())
|
||||
{
|
||||
return (isForward() && isBackward() && ((!e.isForward()) || (!e.isBackward())));
|
||||
}
|
||||
return (weight() < e.weight());
|
||||
}
|
||||
return (target() < e.target());
|
||||
}
|
||||
return (source() < e.source());
|
||||
}
|
||||
|
||||
template <class EdgeT>
|
||||
explicit EdgeBasedEdge(const EdgeT &myEdge)
|
||||
: m_source(myEdge.source), m_target(myEdge.target), m_edgeID(myEdge.data.via),
|
||||
m_weight(myEdge.data.distance), m_forward(myEdge.data.forward),
|
||||
m_backward(myEdge.data.backward)
|
||||
{
|
||||
}
|
||||
|
||||
/** Default constructor. target and weight are set to 0.*/
|
||||
EdgeBasedEdge()
|
||||
: m_source(0), m_target(0), m_edgeID(0), m_weight(0), m_forward(false), m_backward(false)
|
||||
{
|
||||
}
|
||||
|
||||
explicit EdgeBasedEdge(const NodeID s,
|
||||
const NodeID t,
|
||||
const NodeID v,
|
||||
const EdgeWeight w,
|
||||
const bool f,
|
||||
const bool b)
|
||||
: m_source(s), m_target(t), m_edgeID(v), m_weight(w), m_forward(f), m_backward(b)
|
||||
{
|
||||
}
|
||||
|
||||
NodeID target() const { return m_target; }
|
||||
NodeID source() const { return m_source; }
|
||||
EdgeWeight weight() const { return m_weight; }
|
||||
NodeID id() const { return m_edgeID; }
|
||||
bool isBackward() const { return m_backward; }
|
||||
bool isForward() const { return m_forward; }
|
||||
|
||||
private:
|
||||
NodeID m_source;
|
||||
NodeID m_target;
|
||||
NodeID m_edgeID;
|
||||
EdgeWeight m_weight : 30;
|
||||
bool m_forward : 1;
|
||||
bool m_backward : 1;
|
||||
};
|
||||
|
||||
typedef NodeBasedEdge ImportEdge;
|
||||
|
||||
#endif /* IMPORT_EDGE_H */
|
||||
@@ -1,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 = NULL;
|
||||
char *unusedTmp = NULL;
|
||||
BZ2Context *context = (BZ2Context *)pointer;
|
||||
int read = 0;
|
||||
while (0 == read &&
|
||||
!(BZ_STREAM_END == context->error && 0 == context->nUnused && feof(context->file)))
|
||||
{
|
||||
read = BZ2_bzRead(&context->error, context->bz2, buffer, len);
|
||||
if (BZ_OK == context->error)
|
||||
{
|
||||
return read;
|
||||
}
|
||||
else if (BZ_STREAM_END == context->error)
|
||||
{
|
||||
BZ2_bzReadGetUnused(&context->error, context->bz2, &unusedTmpVoid, &context->nUnused);
|
||||
BOOST_ASSERT_MSG(BZ_OK == context->error, "Could not BZ2_bzReadGetUnused");
|
||||
unusedTmp = (char *)unusedTmpVoid;
|
||||
for (int i = 0; i < context->nUnused; i++)
|
||||
{
|
||||
context->unused[i] = unusedTmp[i];
|
||||
}
|
||||
BZ2_bzReadClose(&context->error, context->bz2);
|
||||
BOOST_ASSERT_MSG(BZ_OK == context->error, "Could not BZ2_bzReadClose");
|
||||
context->error = BZ_STREAM_END; // set to the stream end for next call to this function
|
||||
if (0 == context->nUnused && feof(context->file))
|
||||
{
|
||||
return read;
|
||||
}
|
||||
else
|
||||
{
|
||||
context->bz2 = BZ2_bzReadOpen(
|
||||
&context->error, context->file, 0, 0, context->unused, context->nUnused);
|
||||
BOOST_ASSERT_MSG(NULL != context->bz2, "Could not open file");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT_MSG(false, "Could not read bz2 file");
|
||||
}
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
int closeBz2Stream(void *pointer)
|
||||
{
|
||||
BZ2Context *context = (BZ2Context *)pointer;
|
||||
fclose(context->file);
|
||||
delete context;
|
||||
return 0;
|
||||
}
|
||||
|
||||
xmlTextReaderPtr inputReaderFactory(const char *name)
|
||||
{
|
||||
std::string inputName(name);
|
||||
|
||||
if (inputName.find(".osm.bz2") != std::string::npos)
|
||||
{
|
||||
BZ2Context *context = new BZ2Context();
|
||||
context->error = false;
|
||||
context->file = fopen(name, "r");
|
||||
int error;
|
||||
context->bz2 =
|
||||
BZ2_bzReadOpen(&error, context->file, 0, 0, context->unused, context->nUnused);
|
||||
if (context->bz2 == NULL || context->file == NULL)
|
||||
{
|
||||
delete context;
|
||||
return NULL;
|
||||
}
|
||||
return xmlReaderForIO(readFromBz2Stream, closeBz2Stream, (void *)context, NULL, NULL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return xmlNewTextReaderFilename(name);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // INPUT_READER_FACTORY_H
|
||||
@@ -1,109 +0,0 @@
|
||||
#ifndef __NODE_BASED_GRAPH_H__
|
||||
#define __NODE_BASED_GRAPH_H__
|
||||
|
||||
#include "DynamicGraph.h"
|
||||
#include "ImportEdge.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
struct NodeBasedEdgeData
|
||||
{
|
||||
NodeBasedEdgeData()
|
||||
: distance(INVALID_EDGE_WEIGHT), edgeBasedNodeID(SPECIAL_NODEID),
|
||||
nameID(std::numeric_limits<unsigned>::max()), type(std::numeric_limits<short>::max()),
|
||||
isAccessRestricted(false), shortcut(false), forward(false), backward(false),
|
||||
roundabout(false), ignore_in_grid(false), contraFlow(false)
|
||||
{
|
||||
}
|
||||
|
||||
int distance;
|
||||
unsigned edgeBasedNodeID;
|
||||
unsigned nameID;
|
||||
short type;
|
||||
bool isAccessRestricted : 1;
|
||||
bool shortcut : 1;
|
||||
bool forward : 1;
|
||||
bool backward : 1;
|
||||
bool roundabout : 1;
|
||||
bool ignore_in_grid : 1;
|
||||
bool contraFlow : 1;
|
||||
|
||||
void SwapDirectionFlags()
|
||||
{
|
||||
bool temp_flag = forward;
|
||||
forward = backward;
|
||||
backward = temp_flag;
|
||||
}
|
||||
|
||||
bool IsEqualTo(const NodeBasedEdgeData &other) const
|
||||
{
|
||||
return (forward == other.forward) && (backward == other.backward) &&
|
||||
(nameID == other.nameID) && (ignore_in_grid == other.ignore_in_grid) &&
|
||||
(contraFlow == other.contraFlow);
|
||||
}
|
||||
};
|
||||
|
||||
typedef DynamicGraph<NodeBasedEdgeData> NodeBasedDynamicGraph;
|
||||
|
||||
// Factory method to create NodeBasedDynamicGraph from ImportEdges
|
||||
inline std::shared_ptr<NodeBasedDynamicGraph>
|
||||
NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge> &input_edge_list)
|
||||
{
|
||||
std::sort(input_edge_list.begin(), input_edge_list.end());
|
||||
|
||||
// TODO: remove duplicate edges
|
||||
DeallocatingVector<NodeBasedDynamicGraph::InputEdge> edges_list;
|
||||
NodeBasedDynamicGraph::InputEdge edge;
|
||||
for (const ImportEdge &import_edge : input_edge_list)
|
||||
{
|
||||
// TODO: give ImportEdge a proper c'tor to use emplace_back's below
|
||||
if (!import_edge.isForward())
|
||||
{
|
||||
edge.source = import_edge.target();
|
||||
edge.target = import_edge.source();
|
||||
edge.data.backward = import_edge.isForward();
|
||||
edge.data.forward = import_edge.isBackward();
|
||||
}
|
||||
else
|
||||
{
|
||||
edge.source = import_edge.source();
|
||||
edge.target = import_edge.target();
|
||||
edge.data.forward = import_edge.isForward();
|
||||
edge.data.backward = import_edge.isBackward();
|
||||
}
|
||||
|
||||
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.isRoundabout();
|
||||
edge.data.ignore_in_grid = import_edge.ignoreInGrid();
|
||||
edge.data.nameID = import_edge.name();
|
||||
edge.data.type = import_edge.type();
|
||||
edge.data.isAccessRestricted = import_edge.isAccessRestricted();
|
||||
edge.data.contraFlow = import_edge.isContraFlow();
|
||||
edges_list.push_back(edge);
|
||||
|
||||
if (!import_edge.IsSplit())
|
||||
{
|
||||
using std::swap; // enable ADL
|
||||
swap(edge.source, edge.target);
|
||||
edge.data.SwapDirectionFlags();
|
||||
edges_list.push_back(edge);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(edges_list.begin(), edges_list.end());
|
||||
auto graph = std::make_shared<NodeBasedDynamicGraph>(number_of_nodes, edges_list);
|
||||
|
||||
edges_list.clear();
|
||||
BOOST_ASSERT(0 == edges_list.size());
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
#endif // __NODE_BASED_GRAPH_H__
|
||||
@@ -1,174 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef PHANTOM_NODES_H
|
||||
#define PHANTOM_NODES_H
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
struct PhantomNode
|
||||
{
|
||||
PhantomNode() :
|
||||
forward_node_id(SPECIAL_NODEID),
|
||||
reverse_node_id(SPECIAL_NODEID),
|
||||
name_id(std::numeric_limits<unsigned>::max()),
|
||||
forward_weight(INVALID_EDGE_WEIGHT),
|
||||
reverse_weight(INVALID_EDGE_WEIGHT),
|
||||
forward_offset(0),
|
||||
reverse_offset(0),
|
||||
packed_geometry_id(SPECIAL_EDGEID),
|
||||
fwd_segment_position(0)
|
||||
{ }
|
||||
|
||||
NodeID forward_node_id;
|
||||
NodeID reverse_node_id;
|
||||
unsigned name_id;
|
||||
int forward_weight;
|
||||
int reverse_weight;
|
||||
int forward_offset;
|
||||
int reverse_offset;
|
||||
unsigned packed_geometry_id;
|
||||
FixedPointCoordinate location;
|
||||
unsigned short fwd_segment_position;
|
||||
|
||||
int GetForwardWeightPlusOffset() const
|
||||
{
|
||||
if (SPECIAL_NODEID == forward_node_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
const int result = (forward_offset + forward_weight);
|
||||
return result;
|
||||
}
|
||||
|
||||
int GetReverseWeightPlusOffset() const
|
||||
{
|
||||
if (SPECIAL_NODEID == reverse_node_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
const int result = (reverse_offset + reverse_weight);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
forward_node_id = SPECIAL_NODEID;
|
||||
name_id = SPECIAL_NODEID;
|
||||
forward_weight = INVALID_EDGE_WEIGHT;
|
||||
reverse_weight = INVALID_EDGE_WEIGHT;
|
||||
forward_offset = 0;
|
||||
reverse_offset = 0;
|
||||
location.Reset();
|
||||
}
|
||||
|
||||
bool isBidirected() const
|
||||
{
|
||||
return (forward_node_id != SPECIAL_NODEID) &&
|
||||
(reverse_node_id != SPECIAL_NODEID);
|
||||
}
|
||||
|
||||
bool IsCompressed() const
|
||||
{
|
||||
return (forward_offset != 0) || (reverse_offset != 0);
|
||||
}
|
||||
|
||||
bool isValid(const unsigned numberOfNodes) const
|
||||
{
|
||||
return
|
||||
location.isValid() &&
|
||||
(
|
||||
(forward_node_id < numberOfNodes) ||
|
||||
(reverse_node_id < numberOfNodes)
|
||||
) &&
|
||||
(
|
||||
(forward_weight != INVALID_EDGE_WEIGHT) ||
|
||||
(reverse_weight != INVALID_EDGE_WEIGHT)
|
||||
) &&
|
||||
(name_id != std::numeric_limits<unsigned>::max()
|
||||
);
|
||||
}
|
||||
|
||||
bool operator==(const PhantomNode & other) const
|
||||
{
|
||||
return location == other.location;
|
||||
}
|
||||
};
|
||||
|
||||
struct PhantomNodes
|
||||
{
|
||||
PhantomNode source_phantom;
|
||||
PhantomNode target_phantom;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
source_phantom.Reset();
|
||||
target_phantom.Reset();
|
||||
}
|
||||
|
||||
bool PhantomsAreOnSameNodeBasedEdge() const
|
||||
{
|
||||
return (source_phantom.forward_node_id == target_phantom.forward_node_id);
|
||||
}
|
||||
|
||||
bool AtLeastOnePhantomNodeIsInvalid() const
|
||||
{
|
||||
return ((source_phantom.forward_node_id == SPECIAL_NODEID) && (source_phantom.reverse_node_id == SPECIAL_NODEID)) ||
|
||||
((target_phantom.forward_node_id == SPECIAL_NODEID) && (target_phantom.reverse_node_id == SPECIAL_NODEID));
|
||||
}
|
||||
|
||||
bool PhantomNodesHaveEqualLocation() const
|
||||
{
|
||||
return source_phantom == target_phantom;
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream &out, const PhantomNodes & pn)
|
||||
{
|
||||
out << "source_coord: " << pn.source_phantom.location << "\n";
|
||||
out << "target_coord: " << pn.target_phantom.location << std::endl;
|
||||
return out;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream &out, const PhantomNode & pn)
|
||||
{
|
||||
out << "node1: " << pn.forward_node_id << ", " <<
|
||||
"node2: " << pn.reverse_node_id << ", " <<
|
||||
"name: " << pn.name_id << ", " <<
|
||||
"fwd-w: " << pn.forward_weight << ", " <<
|
||||
"rev-w: " << pn.reverse_weight << ", " <<
|
||||
"fwd-o: " << pn.forward_offset << ", " <<
|
||||
"rev-o: " << pn.reverse_offset << ", " <<
|
||||
"geom: " << pn.packed_geometry_id << ", " <<
|
||||
"pos: " << pn.fwd_segment_position << ", " <<
|
||||
"loc: " << pn.location;
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif // PHANTOM_NODES_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
|
||||
{
|
||||
typedef InputRestrictionContainer value_type;
|
||||
inline bool operator()(const InputRestrictionContainer &a, const InputRestrictionContainer &b)
|
||||
const
|
||||
{
|
||||
return a.fromWay < b.fromWay;
|
||||
}
|
||||
inline value_type max_value() const { return InputRestrictionContainer::max_value(); }
|
||||
inline value_type min_value() const { return InputRestrictionContainer::min_value(); }
|
||||
};
|
||||
|
||||
struct CmpRestrictionContainerByTo
|
||||
{
|
||||
typedef InputRestrictionContainer value_type;
|
||||
inline bool operator()(const InputRestrictionContainer &a, const InputRestrictionContainer &b)
|
||||
const
|
||||
{
|
||||
return a.toWay < b.toWay;
|
||||
}
|
||||
value_type max_value() const { return InputRestrictionContainer::max_value(); }
|
||||
value_type min_value() const { return InputRestrictionContainer::min_value(); }
|
||||
};
|
||||
|
||||
#endif // RESTRICTION_H
|
||||
@@ -1,168 +0,0 @@
|
||||
#include "RestrictionMap.h"
|
||||
#include "NodeBasedGraph.h"
|
||||
|
||||
RestrictionMap::RestrictionMap(const std::shared_ptr<NodeBasedDynamicGraph> &graph,
|
||||
const std::vector<TurnRestriction> &input_restrictions_list)
|
||||
: m_count(0), m_graph(graph)
|
||||
{
|
||||
// decompose restirction consisting of a start, via and end note into a start-edge
|
||||
// and all end-nodes
|
||||
for (auto &restriction : input_restrictions_list)
|
||||
{
|
||||
std::pair<NodeID, NodeID> restriction_source =
|
||||
std::make_pair(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()->second)
|
||||
{
|
||||
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)
|
||||
.push_back(std::make_pair(restriction.toNode, restriction.flags.isOnly));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace end v with w in each turn restriction containing u as via node
|
||||
*
|
||||
* Note: We need access to node based graph.
|
||||
*/
|
||||
void RestrictionMap::FixupArrivingTurnRestriction(const NodeID u, const NodeID v, const NodeID w)
|
||||
{
|
||||
BOOST_ASSERT(u != std::numeric_limits<unsigned>::max());
|
||||
BOOST_ASSERT(v != std::numeric_limits<unsigned>::max());
|
||||
BOOST_ASSERT(w != std::numeric_limits<unsigned>::max());
|
||||
|
||||
// find all possible 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 (EdgeID current_edge_id = m_graph->BeginEdges(u); current_edge_id < m_graph->EndEdges(u);
|
||||
++current_edge_id)
|
||||
{
|
||||
const EdgeData &edge_data = m_graph->GetEdgeData(current_edge_id);
|
||||
const NodeID target = m_graph->GetTarget(current_edge_id);
|
||||
if (edge_data.backward && (v != target))
|
||||
{
|
||||
predecessors.push_back(target);
|
||||
}
|
||||
}
|
||||
|
||||
for (const NodeID x : predecessors)
|
||||
{
|
||||
const std::pair<NodeID, NodeID> restr_start = std::make_pair(x, u);
|
||||
auto restriction_iterator = m_restriction_map.find(restr_start);
|
||||
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 (v == restriction_target.first)
|
||||
{
|
||||
restriction_target.first = w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the start edge (v, w) with (u, w), only start node changes.
|
||||
*/
|
||||
void RestrictionMap::FixupStartingTurnRestriction(const NodeID u, const NodeID v, const NodeID w)
|
||||
{
|
||||
BOOST_ASSERT(u != std::numeric_limits<unsigned>::max());
|
||||
BOOST_ASSERT(v != std::numeric_limits<unsigned>::max());
|
||||
BOOST_ASSERT(w != std::numeric_limits<unsigned>::max());
|
||||
|
||||
const std::pair<NodeID, NodeID> old_start = std::make_pair(v, w);
|
||||
|
||||
auto restriction_iterator = m_restriction_map.find(old_start);
|
||||
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);
|
||||
|
||||
// insert new restriction start (u,w) (point to index)
|
||||
const std::pair<NodeID, NodeID> new_start = std::make_pair(u, w);
|
||||
m_restriction_map.insert(std::make_pair(new_start, index));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the edge (u, v) is contained in any turn restriction.
|
||||
* If so returns id of first target node.
|
||||
*/
|
||||
NodeID RestrictionMap::CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const
|
||||
{
|
||||
BOOST_ASSERT(u != std::numeric_limits<unsigned>::max());
|
||||
BOOST_ASSERT(v != std::numeric_limits<unsigned>::max());
|
||||
|
||||
const std::pair<NodeID, NodeID> restriction_source = std::make_pair(u, v);
|
||||
auto restriction_iter = m_restriction_map.find(restriction_source);
|
||||
|
||||
if (restriction_iter != m_restriction_map.end())
|
||||
{
|
||||
const unsigned index = restriction_iter->second;
|
||||
auto &bucket = m_restriction_bucket_list.at(index);
|
||||
for (const RestrictionSource &restriction_target : bucket)
|
||||
{
|
||||
if (restriction_target.second)
|
||||
{
|
||||
return restriction_target.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the turn described by start u, via v and targed w is covert by any turn restriction.
|
||||
*/
|
||||
bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const
|
||||
{
|
||||
BOOST_ASSERT(u != std::numeric_limits<unsigned>::max());
|
||||
BOOST_ASSERT(v != std::numeric_limits<unsigned>::max());
|
||||
BOOST_ASSERT(w != std::numeric_limits<unsigned>::max());
|
||||
|
||||
const std::pair<NodeID, NodeID> restriction_source = std::make_pair(u, v);
|
||||
auto restriction_iter = m_restriction_map.find(restriction_source);
|
||||
|
||||
if (restriction_iter != m_restriction_map.end())
|
||||
{
|
||||
const unsigned index = restriction_iter->second;
|
||||
auto &bucket = m_restriction_bucket_list.at(index);
|
||||
for (const RestrictionTarget &restriction_target : bucket)
|
||||
{
|
||||
if ((w == restriction_target.first) && // target found
|
||||
(!restriction_target.second) // and not an only_-restr.
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,71 +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 "../typedefs.h"
|
||||
#include "DynamicGraph.h"
|
||||
#include "Restriction.h"
|
||||
#include "NodeBasedGraph.h"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
/*!
|
||||
* Makee it efficent to look up if an edge is the start + via node of a TurnRestriction.
|
||||
* Is needed by EdgeBasedGraphFactory.
|
||||
*/
|
||||
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;
|
||||
|
||||
unsigned size() { return m_count; }
|
||||
|
||||
private:
|
||||
typedef std::pair<NodeID, NodeID> RestrictionSource;
|
||||
typedef std::pair<NodeID, bool> RestrictionTarget;
|
||||
typedef std::vector<RestrictionTarget> EmanatingRestrictionsVector;
|
||||
typedef NodeBasedDynamicGraph::EdgeData EdgeData;
|
||||
|
||||
unsigned 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
|
||||
boost::unordered_map<RestrictionSource, unsigned> m_restriction_map;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#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), check_sum(-1)
|
||||
{
|
||||
}
|
||||
|
||||
void RouteParameters::setZoomLevel(const short level)
|
||||
{
|
||||
if (18 >= level && 0 <= level)
|
||||
{
|
||||
zoom_level = level;
|
||||
}
|
||||
}
|
||||
|
||||
void RouteParameters::setAlternateRouteFlag(const bool flag) { alternate_route = flag; }
|
||||
|
||||
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)
|
||||
{
|
||||
int lat = COORDINATE_PRECISION * boost::fusion::at_c<0>(transmitted_coordinates);
|
||||
int lon = COORDINATE_PRECISION * boost::fusion::at_c<1>(transmitted_coordinates);
|
||||
coordinates.emplace_back(lat, lon);
|
||||
}
|
||||
@@ -1,780 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef STATICRTREE_H
|
||||
#define STATICRTREE_H
|
||||
|
||||
#include "DeallocatingVector.h"
|
||||
#include "HilbertValue.h"
|
||||
#include "PhantomNodes.h"
|
||||
#include "QueryNode.h"
|
||||
#include "SharedMemoryFactory.h"
|
||||
#include "SharedMemoryVectorWrapper.h"
|
||||
|
||||
#include "../Util/MercatorUtil.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// tuning parameters
|
||||
const static uint32_t RTREE_BRANCHING_FACTOR = 64;
|
||||
const static uint32_t RTREE_LEAF_NODE_SIZE = 1024;
|
||||
|
||||
static boost::thread_specific_ptr<boost::filesystem::ifstream> thread_local_rtree_stream;
|
||||
|
||||
// Implements a static, i.e. packed, R-tree
|
||||
template <class DataT,
|
||||
class CoordinateListT = std::vector<FixedPointCoordinate>,
|
||||
bool UseSharedMemory = false>
|
||||
class StaticRTree
|
||||
{
|
||||
public:
|
||||
struct RectangleInt2D
|
||||
{
|
||||
RectangleInt2D() : min_lon(INT_MAX), max_lon(INT_MIN), min_lat(INT_MAX), max_lat(INT_MIN) {}
|
||||
|
||||
int32_t min_lon, max_lon;
|
||||
int32_t min_lat, max_lat;
|
||||
|
||||
inline void InitializeMBRectangle(const std::array<DataT, RTREE_LEAF_NODE_SIZE> &objects,
|
||||
const uint32_t element_count,
|
||||
const std::vector<NodeInfo> &coordinate_list)
|
||||
{
|
||||
for (uint32_t i = 0; i < element_count; ++i)
|
||||
{
|
||||
min_lon = std::min(min_lon,
|
||||
std::min(coordinate_list.at(objects[i].u).lon,
|
||||
coordinate_list.at(objects[i].v).lon));
|
||||
max_lon = std::max(max_lon,
|
||||
std::max(coordinate_list.at(objects[i].u).lon,
|
||||
coordinate_list.at(objects[i].v).lon));
|
||||
|
||||
min_lat = std::min(min_lat,
|
||||
std::min(coordinate_list.at(objects[i].u).lat,
|
||||
coordinate_list.at(objects[i].v).lat));
|
||||
max_lat = std::max(max_lat,
|
||||
std::max(coordinate_list.at(objects[i].u).lat,
|
||||
coordinate_list.at(objects[i].v).lat));
|
||||
}
|
||||
}
|
||||
|
||||
inline void AugmentMBRectangle(const RectangleInt2D &other)
|
||||
{
|
||||
min_lon = std::min(min_lon, other.min_lon);
|
||||
max_lon = std::max(max_lon, other.max_lon);
|
||||
min_lat = std::min(min_lat, other.min_lat);
|
||||
max_lat = std::max(max_lat, other.max_lat);
|
||||
}
|
||||
|
||||
inline FixedPointCoordinate Centroid() const
|
||||
{
|
||||
FixedPointCoordinate centroid;
|
||||
// The coordinates of the midpoints are given by:
|
||||
// x = (x1 + x2) /2 and y = (y1 + y2) /2.
|
||||
centroid.lon = (min_lon + max_lon) / 2;
|
||||
centroid.lat = (min_lat + max_lat) / 2;
|
||||
return centroid;
|
||||
}
|
||||
|
||||
inline bool Intersects(const RectangleInt2D &other) const
|
||||
{
|
||||
FixedPointCoordinate upper_left(other.max_lat, other.min_lon);
|
||||
FixedPointCoordinate upper_right(other.max_lat, other.max_lon);
|
||||
FixedPointCoordinate lower_right(other.min_lat, other.max_lon);
|
||||
FixedPointCoordinate lower_left(other.min_lat, other.min_lon);
|
||||
|
||||
return (Contains(upper_left) || Contains(upper_right) || Contains(lower_right) ||
|
||||
Contains(lower_left));
|
||||
}
|
||||
|
||||
inline double GetMinDist(const FixedPointCoordinate &location) const
|
||||
{
|
||||
bool is_contained = Contains(location);
|
||||
if (is_contained)
|
||||
{
|
||||
return 0.;
|
||||
}
|
||||
|
||||
double min_dist = std::numeric_limits<double>::max();
|
||||
min_dist = std::min(min_dist,
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
location.lat, location.lon, max_lat, min_lon));
|
||||
min_dist = std::min(min_dist,
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
location.lat, location.lon, max_lat, max_lon));
|
||||
min_dist = std::min(min_dist,
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
location.lat, location.lon, min_lat, max_lon));
|
||||
min_dist = std::min(min_dist,
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
location.lat, location.lon, min_lat, min_lon));
|
||||
return min_dist;
|
||||
}
|
||||
|
||||
inline double GetMinMaxDist(const FixedPointCoordinate &location) const
|
||||
{
|
||||
double min_max_dist = std::numeric_limits<double>::max();
|
||||
// Get minmax distance to each of the four sides
|
||||
FixedPointCoordinate upper_left(max_lat, min_lon);
|
||||
FixedPointCoordinate upper_right(max_lat, max_lon);
|
||||
FixedPointCoordinate lower_right(min_lat, max_lon);
|
||||
FixedPointCoordinate lower_left(min_lat, min_lon);
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_left),
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_right)));
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_right),
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_right)));
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_right),
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_left)));
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_left),
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_left)));
|
||||
return min_max_dist;
|
||||
}
|
||||
|
||||
inline bool Contains(const FixedPointCoordinate &location) const
|
||||
{
|
||||
const bool lats_contained = (location.lat > min_lat) && (location.lat < max_lat);
|
||||
const bool lons_contained = (location.lon > min_lon) && (location.lon < max_lon);
|
||||
return lats_contained && lons_contained;
|
||||
}
|
||||
|
||||
inline friend std::ostream &operator<<(std::ostream &out, const RectangleInt2D &rect)
|
||||
{
|
||||
out << rect.min_lat / COORDINATE_PRECISION << "," << rect.min_lon / COORDINATE_PRECISION
|
||||
<< " " << rect.max_lat / COORDINATE_PRECISION << ","
|
||||
<< rect.max_lon / COORDINATE_PRECISION;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
typedef RectangleInt2D RectangleT;
|
||||
|
||||
struct TreeNode
|
||||
{
|
||||
TreeNode() : child_count(0), child_is_on_disk(false) {}
|
||||
RectangleT minimum_bounding_rectangle;
|
||||
uint32_t child_count : 31;
|
||||
bool child_is_on_disk : 1;
|
||||
uint32_t children[RTREE_BRANCHING_FACTOR];
|
||||
};
|
||||
|
||||
private:
|
||||
struct WrappedInputElement
|
||||
{
|
||||
explicit WrappedInputElement(const uint32_t _array_index, const uint64_t _hilbert_value)
|
||||
: m_array_index(_array_index), m_hilbert_value(_hilbert_value)
|
||||
{
|
||||
}
|
||||
|
||||
WrappedInputElement() : m_array_index(UINT_MAX), m_hilbert_value(0) {}
|
||||
|
||||
uint32_t m_array_index;
|
||||
uint64_t m_hilbert_value;
|
||||
|
||||
inline bool operator<(const WrappedInputElement &other) const
|
||||
{
|
||||
return m_hilbert_value < other.m_hilbert_value;
|
||||
}
|
||||
};
|
||||
|
||||
struct LeafNode
|
||||
{
|
||||
LeafNode() : object_count(0) {}
|
||||
uint32_t object_count;
|
||||
std::array<DataT, RTREE_LEAF_NODE_SIZE> objects;
|
||||
};
|
||||
|
||||
struct QueryCandidate
|
||||
{
|
||||
explicit QueryCandidate(const uint32_t n_id, const double dist)
|
||||
: node_id(n_id), min_dist(dist)
|
||||
{
|
||||
}
|
||||
QueryCandidate() : node_id(UINT_MAX), min_dist(std::numeric_limits<double>::max()) {}
|
||||
uint32_t node_id;
|
||||
double min_dist;
|
||||
inline bool operator<(const QueryCandidate &other) const
|
||||
{
|
||||
return min_dist < other.min_dist;
|
||||
}
|
||||
};
|
||||
|
||||
typename ShM<TreeNode, UseSharedMemory>::vector m_search_tree;
|
||||
uint64_t m_element_count;
|
||||
const std::string m_leaf_node_filename;
|
||||
std::shared_ptr<CoordinateListT> m_coordinate_list;
|
||||
|
||||
public:
|
||||
StaticRTree() = delete;
|
||||
StaticRTree(const StaticRTree &) = delete;
|
||||
|
||||
// Construct a packed Hilbert-R-Tree with Kamel-Faloutsos algorithm [1]
|
||||
explicit StaticRTree(std::vector<DataT> &input_data_vector,
|
||||
const std::string tree_node_filename,
|
||||
const std::string leaf_node_filename,
|
||||
const std::vector<NodeInfo> &coordinate_list)
|
||||
: m_element_count(input_data_vector.size()), m_leaf_node_filename(leaf_node_filename)
|
||||
{
|
||||
SimpleLogger().Write() << "constructing r-tree of " << m_element_count
|
||||
<< " edge elements build on-top of " << coordinate_list.size()
|
||||
<< " coordinates";
|
||||
|
||||
std::chrono::time_point<std::chrono::steady_clock> time0 = std::chrono::steady_clock::now();
|
||||
std::vector<WrappedInputElement> input_wrapper_vector(m_element_count);
|
||||
|
||||
HilbertCode get_hilbert_number;
|
||||
|
||||
// generate auxiliary vector of hilbert-values
|
||||
#pragma omp parallel for schedule(guided)
|
||||
for (uint64_t element_counter = 0; element_counter < m_element_count; ++element_counter)
|
||||
{
|
||||
input_wrapper_vector[element_counter].m_array_index = element_counter;
|
||||
// Get Hilbert-Value for centroid in mercartor projection
|
||||
DataT const ¤t_element = input_data_vector[element_counter];
|
||||
FixedPointCoordinate current_centroid =
|
||||
DataT::Centroid(FixedPointCoordinate(coordinate_list.at(current_element.u).lat,
|
||||
coordinate_list.at(current_element.u).lon),
|
||||
FixedPointCoordinate(coordinate_list.at(current_element.v).lat,
|
||||
coordinate_list.at(current_element.v).lon));
|
||||
current_centroid.lat =
|
||||
COORDINATE_PRECISION * lat2y(current_centroid.lat / COORDINATE_PRECISION);
|
||||
|
||||
uint64_t current_hilbert_value = get_hilbert_number(current_centroid);
|
||||
input_wrapper_vector[element_counter].m_hilbert_value = current_hilbert_value;
|
||||
}
|
||||
|
||||
// open leaf file
|
||||
boost::filesystem::ofstream leaf_node_file(leaf_node_filename, std::ios::binary);
|
||||
leaf_node_file.write((char *)&m_element_count, sizeof(uint64_t));
|
||||
|
||||
// sort the hilbert-value representatives
|
||||
std::sort(input_wrapper_vector.begin(), input_wrapper_vector.end());
|
||||
std::vector<TreeNode> tree_nodes_in_level;
|
||||
|
||||
// pack M elements into leaf node and write to leaf file
|
||||
uint64_t processed_objects_count = 0;
|
||||
while (processed_objects_count < m_element_count)
|
||||
{
|
||||
|
||||
LeafNode current_leaf;
|
||||
TreeNode current_node;
|
||||
// SimpleLogger().Write() << "reading " << tree_size << " tree nodes in " <<
|
||||
// (sizeof(TreeNode)*tree_size) << " bytes";
|
||||
for (uint32_t current_element_index = 0; RTREE_LEAF_NODE_SIZE > current_element_index;
|
||||
++current_element_index)
|
||||
{
|
||||
if (m_element_count > (processed_objects_count + current_element_index))
|
||||
{
|
||||
uint32_t index_of_next_object =
|
||||
input_wrapper_vector[processed_objects_count + current_element_index]
|
||||
.m_array_index;
|
||||
current_leaf.objects[current_element_index] =
|
||||
input_data_vector[index_of_next_object];
|
||||
++current_leaf.object_count;
|
||||
}
|
||||
}
|
||||
|
||||
// generate tree node that resemble the objects in leaf and store it for next level
|
||||
current_node.minimum_bounding_rectangle.InitializeMBRectangle(
|
||||
current_leaf.objects, current_leaf.object_count, coordinate_list);
|
||||
current_node.child_is_on_disk = true;
|
||||
current_node.children[0] = tree_nodes_in_level.size();
|
||||
tree_nodes_in_level.emplace_back(current_node);
|
||||
|
||||
// write leaf_node to leaf node file
|
||||
leaf_node_file.write((char *)¤t_leaf, sizeof(current_leaf));
|
||||
processed_objects_count += current_leaf.object_count;
|
||||
}
|
||||
|
||||
// close leaf file
|
||||
leaf_node_file.close();
|
||||
|
||||
uint32_t processing_level = 0;
|
||||
while (1 < tree_nodes_in_level.size())
|
||||
{
|
||||
std::vector<TreeNode> tree_nodes_in_next_level;
|
||||
uint32_t processed_tree_nodes_in_level = 0;
|
||||
while (processed_tree_nodes_in_level < tree_nodes_in_level.size())
|
||||
{
|
||||
TreeNode parent_node;
|
||||
// pack RTREE_BRANCHING_FACTOR elements into tree_nodes each
|
||||
for (uint32_t current_child_node_index = 0;
|
||||
RTREE_BRANCHING_FACTOR > current_child_node_index;
|
||||
++current_child_node_index)
|
||||
{
|
||||
if (processed_tree_nodes_in_level < tree_nodes_in_level.size())
|
||||
{
|
||||
TreeNode ¤t_child_node =
|
||||
tree_nodes_in_level[processed_tree_nodes_in_level];
|
||||
// add tree node to parent entry
|
||||
parent_node.children[current_child_node_index] = m_search_tree.size();
|
||||
m_search_tree.emplace_back(current_child_node);
|
||||
// augment MBR of parent
|
||||
parent_node.minimum_bounding_rectangle.AugmentMBRectangle(
|
||||
current_child_node.minimum_bounding_rectangle);
|
||||
// increase counters
|
||||
++parent_node.child_count;
|
||||
++processed_tree_nodes_in_level;
|
||||
}
|
||||
}
|
||||
tree_nodes_in_next_level.emplace_back(parent_node);
|
||||
}
|
||||
tree_nodes_in_level.swap(tree_nodes_in_next_level);
|
||||
++processing_level;
|
||||
}
|
||||
BOOST_ASSERT_MSG(1 == tree_nodes_in_level.size(), "tree broken, more than one root node");
|
||||
// last remaining entry is the root node, store it
|
||||
m_search_tree.emplace_back(tree_nodes_in_level[0]);
|
||||
|
||||
// reverse and renumber tree to have root at index 0
|
||||
std::reverse(m_search_tree.begin(), m_search_tree.end());
|
||||
|
||||
#pragma omp parallel for schedule(guided)
|
||||
for (uint32_t i = 0; i < m_search_tree.size(); ++i)
|
||||
{
|
||||
TreeNode ¤t_tree_node = m_search_tree[i];
|
||||
for (uint32_t j = 0; j < current_tree_node.child_count; ++j)
|
||||
{
|
||||
const uint32_t old_id = current_tree_node.children[j];
|
||||
const uint32_t new_id = m_search_tree.size() - old_id - 1;
|
||||
current_tree_node.children[j] = new_id;
|
||||
}
|
||||
}
|
||||
|
||||
// open tree file
|
||||
boost::filesystem::ofstream tree_node_file(tree_node_filename, std::ios::binary);
|
||||
|
||||
uint32_t size_of_tree = m_search_tree.size();
|
||||
BOOST_ASSERT_MSG(0 < size_of_tree, "tree empty");
|
||||
tree_node_file.write((char *)&size_of_tree, sizeof(uint32_t));
|
||||
tree_node_file.write((char *)&m_search_tree[0], sizeof(TreeNode) * size_of_tree);
|
||||
// close tree node file.
|
||||
tree_node_file.close();
|
||||
std::chrono::time_point<std::chrono::steady_clock> time1 = std::chrono::steady_clock::now();
|
||||
std::chrono::duration<double> elapsed_seconds = time1 - time0;
|
||||
SimpleLogger().Write() << "finished r-tree construction in " << (elapsed_seconds.count())
|
||||
<< " seconds";
|
||||
}
|
||||
|
||||
// Read-only operation for queries
|
||||
explicit StaticRTree(const boost::filesystem::path &node_file,
|
||||
const boost::filesystem::path &leaf_file,
|
||||
const std::shared_ptr<CoordinateListT> coordinate_list)
|
||||
: m_leaf_node_filename(leaf_file.string())
|
||||
{
|
||||
// open tree node file and load into RAM.
|
||||
m_coordinate_list = coordinate_list;
|
||||
|
||||
if (!boost::filesystem::exists(node_file))
|
||||
{
|
||||
throw OSRMException("ram index file does not exist");
|
||||
}
|
||||
if (0 == boost::filesystem::file_size(node_file))
|
||||
{
|
||||
throw OSRMException("ram index file is empty");
|
||||
}
|
||||
boost::filesystem::ifstream tree_node_file(node_file, std::ios::binary);
|
||||
|
||||
uint32_t tree_size = 0;
|
||||
tree_node_file.read((char *)&tree_size, sizeof(uint32_t));
|
||||
|
||||
m_search_tree.resize(tree_size);
|
||||
tree_node_file.read((char *)&m_search_tree[0], sizeof(TreeNode) * tree_size);
|
||||
tree_node_file.close();
|
||||
// open leaf node file and store thread specific pointer
|
||||
if (!boost::filesystem::exists(leaf_file))
|
||||
{
|
||||
throw OSRMException("mem index file does not exist");
|
||||
}
|
||||
if (0 == boost::filesystem::file_size(leaf_file))
|
||||
{
|
||||
throw OSRMException("mem index file is empty");
|
||||
}
|
||||
|
||||
boost::filesystem::ifstream leaf_node_file(leaf_file, std::ios::binary);
|
||||
leaf_node_file.read((char *)&m_element_count, sizeof(uint64_t));
|
||||
leaf_node_file.close();
|
||||
|
||||
// SimpleLogger().Write() << tree_size << " nodes in search tree";
|
||||
// SimpleLogger().Write() << m_element_count << " elements in leafs";
|
||||
}
|
||||
|
||||
explicit StaticRTree(TreeNode *tree_node_ptr,
|
||||
const uint32_t number_of_nodes,
|
||||
const boost::filesystem::path &leaf_file,
|
||||
std::shared_ptr<CoordinateListT> coordinate_list)
|
||||
: m_search_tree(tree_node_ptr, number_of_nodes), m_leaf_node_filename(leaf_file.string()),
|
||||
m_coordinate_list(coordinate_list)
|
||||
{
|
||||
// open leaf node file and store thread specific pointer
|
||||
if (!boost::filesystem::exists(leaf_file))
|
||||
{
|
||||
throw OSRMException("mem index file does not exist");
|
||||
}
|
||||
if (0 == boost::filesystem::file_size(leaf_file))
|
||||
{
|
||||
throw OSRMException("mem index file is empty");
|
||||
}
|
||||
|
||||
boost::filesystem::ifstream leaf_node_file(leaf_file, std::ios::binary);
|
||||
leaf_node_file.read((char *)&m_element_count, sizeof(uint64_t));
|
||||
leaf_node_file.close();
|
||||
|
||||
if (thread_local_rtree_stream.get())
|
||||
{
|
||||
thread_local_rtree_stream->close();
|
||||
}
|
||||
|
||||
// SimpleLogger().Write() << tree_size << " nodes in search tree";
|
||||
// SimpleLogger().Write() << m_element_count << " elements in leafs";
|
||||
}
|
||||
// Read-only operation for queries
|
||||
|
||||
bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
FixedPointCoordinate &result_coordinate,
|
||||
const unsigned zoom_level)
|
||||
{
|
||||
bool ignore_tiny_components = (zoom_level <= 14);
|
||||
DataT nearest_edge;
|
||||
double min_dist = std::numeric_limits<double>::max();
|
||||
double min_max_dist = std::numeric_limits<double>::max();
|
||||
bool found_a_nearest_edge = false;
|
||||
|
||||
// initialize queue with root element
|
||||
std::priority_queue<QueryCandidate> traversal_queue;
|
||||
double current_min_dist =
|
||||
m_search_tree[0].minimum_bounding_rectangle.GetMinDist(input_coordinate);
|
||||
traversal_queue.emplace(0, current_min_dist);
|
||||
|
||||
while (!traversal_queue.empty())
|
||||
{
|
||||
const QueryCandidate current_query_node = traversal_queue.top();
|
||||
traversal_queue.pop();
|
||||
|
||||
const bool prune_downward = (current_query_node.min_dist >= min_max_dist);
|
||||
const bool prune_upward = (current_query_node.min_dist >= min_dist);
|
||||
if (!prune_downward && !prune_upward)
|
||||
{ // downward pruning
|
||||
TreeNode ¤t_tree_node = m_search_tree[current_query_node.node_id];
|
||||
if (current_tree_node.child_is_on_disk)
|
||||
{
|
||||
LeafNode current_leaf_node;
|
||||
LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
|
||||
for (uint32_t i = 0; i < current_leaf_node.object_count; ++i)
|
||||
{
|
||||
DataT const ¤t_edge = current_leaf_node.objects[i];
|
||||
if (ignore_tiny_components && current_edge.is_in_tiny_cc)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
double current_minimum_distance =
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
input_coordinate.lat,
|
||||
input_coordinate.lon,
|
||||
m_coordinate_list->at(current_edge.u).lat,
|
||||
m_coordinate_list->at(current_edge.u).lon);
|
||||
if (current_minimum_distance < min_dist)
|
||||
{
|
||||
// found a new minimum
|
||||
min_dist = current_minimum_distance;
|
||||
result_coordinate.lat = m_coordinate_list->at(current_edge.u).lat;
|
||||
result_coordinate.lon = m_coordinate_list->at(current_edge.u).lon;
|
||||
found_a_nearest_edge = true;
|
||||
}
|
||||
|
||||
current_minimum_distance =
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
input_coordinate.lat,
|
||||
input_coordinate.lon,
|
||||
m_coordinate_list->at(current_edge.v).lat,
|
||||
m_coordinate_list->at(current_edge.v).lon);
|
||||
|
||||
if (current_minimum_distance < min_dist)
|
||||
{
|
||||
// found a new minimum
|
||||
min_dist = current_minimum_distance;
|
||||
result_coordinate.lat = m_coordinate_list->at(current_edge.v).lat;
|
||||
result_coordinate.lon = m_coordinate_list->at(current_edge.v).lon;
|
||||
found_a_nearest_edge = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// traverse children, prune if global mindist is smaller than local one
|
||||
for (uint32_t i = 0; i < current_tree_node.child_count; ++i)
|
||||
{
|
||||
const int32_t child_id = current_tree_node.children[i];
|
||||
const TreeNode &child_tree_node = m_search_tree[child_id];
|
||||
const RectangleT &child_rectangle =
|
||||
child_tree_node.minimum_bounding_rectangle;
|
||||
const double current_min_dist =
|
||||
child_rectangle.GetMinDist(input_coordinate);
|
||||
const double current_min_max_dist =
|
||||
child_rectangle.GetMinMaxDist(input_coordinate);
|
||||
if (current_min_max_dist < min_max_dist)
|
||||
{
|
||||
min_max_dist = current_min_max_dist;
|
||||
}
|
||||
if (current_min_dist > min_max_dist)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (current_min_dist > min_dist)
|
||||
{ // upward pruning
|
||||
continue;
|
||||
}
|
||||
traversal_queue.emplace(child_id, current_min_dist);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found_a_nearest_edge;
|
||||
}
|
||||
|
||||
bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
PhantomNode &result_phantom_node,
|
||||
const unsigned zoom_level)
|
||||
{
|
||||
// SimpleLogger().Write() << "searching for coordinate " << input_coordinate;
|
||||
|
||||
const bool ignore_tiny_components = (zoom_level <= 14);
|
||||
DataT nearest_edge;
|
||||
|
||||
double min_dist = std::numeric_limits<double>::max();
|
||||
double min_max_dist = std::numeric_limits<double>::max();
|
||||
bool found_a_nearest_edge = false;
|
||||
|
||||
FixedPointCoordinate nearest, current_start_coordinate, current_end_coordinate;
|
||||
|
||||
// initialize queue with root element
|
||||
std::priority_queue<QueryCandidate> traversal_queue;
|
||||
double current_min_dist =
|
||||
m_search_tree[0].minimum_bounding_rectangle.GetMinDist(input_coordinate);
|
||||
traversal_queue.emplace(0, current_min_dist);
|
||||
|
||||
BOOST_ASSERT_MSG(std::numeric_limits<double>::epsilon() >
|
||||
(0. - traversal_queue.top().min_dist),
|
||||
"Root element in NN Search has min dist != 0.");
|
||||
|
||||
LeafNode current_leaf_node;
|
||||
while (!traversal_queue.empty())
|
||||
{
|
||||
const QueryCandidate current_query_node = traversal_queue.top();
|
||||
traversal_queue.pop();
|
||||
|
||||
const bool prune_downward = (current_query_node.min_dist >= min_max_dist);
|
||||
const bool prune_upward = (current_query_node.min_dist >= min_dist);
|
||||
if (!prune_downward && !prune_upward)
|
||||
{ // downward pruning
|
||||
const TreeNode ¤t_tree_node = m_search_tree[current_query_node.node_id];
|
||||
if (current_tree_node.child_is_on_disk)
|
||||
{
|
||||
LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
|
||||
for (uint32_t i = 0; i < current_leaf_node.object_count; ++i)
|
||||
{
|
||||
DataT ¤t_edge = current_leaf_node.objects[i];
|
||||
if (ignore_tiny_components && current_edge.is_in_tiny_cc)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
double current_ratio = 0.;
|
||||
const double current_perpendicular_distance =
|
||||
FixedPointCoordinate::ComputePerpendicularDistance(
|
||||
m_coordinate_list->at(current_edge.u),
|
||||
m_coordinate_list->at(current_edge.v),
|
||||
input_coordinate,
|
||||
nearest,
|
||||
current_ratio);
|
||||
|
||||
BOOST_ASSERT(0. <= current_perpendicular_distance);
|
||||
|
||||
if ((current_perpendicular_distance < min_dist) &&
|
||||
!DoubleEpsilonCompare(current_perpendicular_distance, min_dist))
|
||||
{ // found a new minimum
|
||||
min_dist = current_perpendicular_distance;
|
||||
// TODO: use assignment c'tor in PhantomNode
|
||||
result_phantom_node.forward_node_id =
|
||||
current_edge.forward_edge_based_node_id;
|
||||
result_phantom_node.reverse_node_id =
|
||||
current_edge.reverse_edge_based_node_id;
|
||||
result_phantom_node.name_id = current_edge.name_id;
|
||||
result_phantom_node.forward_weight = current_edge.forward_weight;
|
||||
result_phantom_node.reverse_weight = current_edge.reverse_weight;
|
||||
result_phantom_node.forward_offset = current_edge.forward_offset;
|
||||
result_phantom_node.reverse_offset = current_edge.reverse_offset;
|
||||
result_phantom_node.packed_geometry_id =
|
||||
current_edge.packed_geometry_id;
|
||||
result_phantom_node.fwd_segment_position =
|
||||
current_edge.fwd_segment_position;
|
||||
|
||||
result_phantom_node.location = nearest;
|
||||
current_start_coordinate.lat =
|
||||
m_coordinate_list->at(current_edge.u).lat;
|
||||
current_start_coordinate.lon =
|
||||
m_coordinate_list->at(current_edge.u).lon;
|
||||
current_end_coordinate.lat = m_coordinate_list->at(current_edge.v).lat;
|
||||
current_end_coordinate.lon = m_coordinate_list->at(current_edge.v).lon;
|
||||
nearest_edge = current_edge;
|
||||
found_a_nearest_edge = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// traverse children, prune if global mindist is smaller than local one
|
||||
for (uint32_t i = 0; i < current_tree_node.child_count; ++i)
|
||||
{
|
||||
const int32_t child_id = current_tree_node.children[i];
|
||||
TreeNode &child_tree_node = m_search_tree[child_id];
|
||||
RectangleT &child_rectangle = child_tree_node.minimum_bounding_rectangle;
|
||||
const double current_min_dist =
|
||||
child_rectangle.GetMinDist(input_coordinate);
|
||||
const double current_min_max_dist =
|
||||
child_rectangle.GetMinMaxDist(input_coordinate);
|
||||
if (current_min_max_dist < min_max_dist)
|
||||
{
|
||||
min_max_dist = current_min_max_dist;
|
||||
}
|
||||
if (current_min_dist > min_max_dist)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (current_min_dist > min_dist)
|
||||
{ // upward pruning
|
||||
continue;
|
||||
}
|
||||
traversal_queue.emplace(child_id, current_min_dist);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hack to fix rounding errors and wandering via nodes.
|
||||
if (1 == std::abs(input_coordinate.lon - result_phantom_node.location.lon))
|
||||
{
|
||||
result_phantom_node.location.lon = input_coordinate.lon;
|
||||
}
|
||||
if (1 == std::abs(input_coordinate.lat - result_phantom_node.location.lat))
|
||||
{
|
||||
result_phantom_node.location.lat = input_coordinate.lat;
|
||||
}
|
||||
|
||||
double ratio = 0.;
|
||||
|
||||
if (found_a_nearest_edge)
|
||||
{
|
||||
const double distance_1 = FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
current_start_coordinate, result_phantom_node.location);
|
||||
|
||||
const double distance_2 = FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
current_start_coordinate, current_end_coordinate);
|
||||
|
||||
ratio = distance_1 / distance_2;
|
||||
ratio = std::min(1., ratio);
|
||||
|
||||
if (SPECIAL_NODEID != result_phantom_node.forward_node_id)
|
||||
{
|
||||
result_phantom_node.forward_weight *= ratio;
|
||||
}
|
||||
if (SPECIAL_NODEID != result_phantom_node.reverse_node_id)
|
||||
{
|
||||
result_phantom_node.reverse_weight *= (1. - ratio);
|
||||
}
|
||||
}
|
||||
return found_a_nearest_edge;
|
||||
}
|
||||
|
||||
private:
|
||||
inline void LoadLeafFromDisk(const uint32_t leaf_id, LeafNode &result_node)
|
||||
{
|
||||
if (!thread_local_rtree_stream.get() || !thread_local_rtree_stream->is_open())
|
||||
{
|
||||
thread_local_rtree_stream.reset(new boost::filesystem::ifstream(
|
||||
m_leaf_node_filename, std::ios::in | std::ios::binary));
|
||||
}
|
||||
if (!thread_local_rtree_stream->good())
|
||||
{
|
||||
thread_local_rtree_stream->clear(std::ios::goodbit);
|
||||
SimpleLogger().Write(logDEBUG) << "Resetting stale filestream";
|
||||
}
|
||||
uint64_t seek_pos = sizeof(uint64_t) + leaf_id * sizeof(LeafNode);
|
||||
thread_local_rtree_stream->seekg(seek_pos);
|
||||
thread_local_rtree_stream->read((char *)&result_node, sizeof(LeafNode));
|
||||
}
|
||||
|
||||
inline bool EdgesAreEquivalent(const FixedPointCoordinate &a,
|
||||
const FixedPointCoordinate &b,
|
||||
const FixedPointCoordinate &c,
|
||||
const FixedPointCoordinate &d) const
|
||||
{
|
||||
return (a == b && c == d) || (a == c && b == d) || (a == d && b == c);
|
||||
}
|
||||
|
||||
inline bool DoubleEpsilonCompare(const double d1, const double d2) const
|
||||
{
|
||||
return (std::abs(d1 - d2) < std::numeric_limits<double>::epsilon());
|
||||
}
|
||||
};
|
||||
|
||||
//[1] "On Packing R-Trees"; I. Kamel, C. Faloutsos; 1993; DOI: 10.1145/170088.170403
|
||||
//[2] "Nearest Neighbor Queries", N. Roussopulos et al; 1995; DOI: 10.1145/223784.223794
|
||||
|
||||
#endif // STATICRTREE_H
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "DescriptionFactory.h"
|
||||
|
||||
DescriptionFactory::DescriptionFactory() : entireLength(0) {}
|
||||
|
||||
DescriptionFactory::~DescriptionFactory() {}
|
||||
|
||||
inline double DescriptionFactory::DegreeToRadian(const double degree) const
|
||||
{
|
||||
return degree * (M_PI / 180.);
|
||||
}
|
||||
|
||||
inline double DescriptionFactory::RadianToDegree(const double radian) const
|
||||
{
|
||||
return radian * (180. / M_PI);
|
||||
}
|
||||
|
||||
double DescriptionFactory::GetBearing(const FixedPointCoordinate &A, const FixedPointCoordinate &B)
|
||||
const
|
||||
{
|
||||
double delta_long = DegreeToRadian(B.lon / COORDINATE_PRECISION - A.lon / COORDINATE_PRECISION);
|
||||
|
||||
const double lat1 = DegreeToRadian(A.lat / COORDINATE_PRECISION);
|
||||
const double lat2 = DegreeToRadian(B.lat / COORDINATE_PRECISION);
|
||||
|
||||
const double y = sin(delta_long) * cos(lat2);
|
||||
const double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(delta_long);
|
||||
double result = RadianToDegree(atan2(y, x));
|
||||
while (result < 0.)
|
||||
{
|
||||
result += 360.;
|
||||
}
|
||||
|
||||
while (result >= 360.)
|
||||
{
|
||||
result -= 360.;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void DescriptionFactory::SetStartSegment(const PhantomNode &source)
|
||||
{
|
||||
start_phantom = source;
|
||||
AppendSegment(source.location, PathData(0, source.name_id, TurnInstruction::HeadOn, source.forward_weight));
|
||||
}
|
||||
|
||||
void DescriptionFactory::SetEndSegment(const PhantomNode &target)
|
||||
{
|
||||
target_phantom = target;
|
||||
path_description.emplace_back(
|
||||
target.location, target.name_id, 0, target.reverse_weight, TurnInstruction::NoTurn, true);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendSegment(const FixedPointCoordinate &coordinate,
|
||||
const PathData &path_point)
|
||||
{
|
||||
if ((1 == path_description.size()) && (path_description.back().location == coordinate))
|
||||
{
|
||||
path_description.back().name_id = path_point.name_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
path_description.emplace_back(coordinate,
|
||||
path_point.name_id,
|
||||
path_point.segment_duration,
|
||||
0,
|
||||
path_point.turn_instruction);
|
||||
}
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendEncodedPolylineString(const bool return_encoded,
|
||||
std::vector<std::string> &output)
|
||||
{
|
||||
std::string temp;
|
||||
if (return_encoded)
|
||||
{
|
||||
polyline_compressor.printEncodedString(path_description, temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
polyline_compressor.printUnencodedString(path_description, temp);
|
||||
}
|
||||
output.emplace_back(temp);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendEncodedPolylineString(std::vector<std::string> &output) const
|
||||
{
|
||||
std::string temp;
|
||||
polyline_compressor.printEncodedString(path_description, temp);
|
||||
output.emplace_back(temp);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendUnencodedPolylineString(std::vector<std::string> &output) const
|
||||
{
|
||||
std::string temp;
|
||||
polyline_compressor.printUnencodedString(path_description, temp);
|
||||
output.emplace_back(temp);
|
||||
}
|
||||
|
||||
void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time)
|
||||
{
|
||||
summary.startName = start_phantom.name_id;
|
||||
summary.destName = target_phantom.name_id;
|
||||
summary.BuildDurationAndLengthStrings(distance, time);
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DESCRIPTIONFACTORY_H_
|
||||
#define DESCRIPTIONFACTORY_H_
|
||||
|
||||
#include "../Algorithms/DouglasPeucker.h"
|
||||
#include "../Algorithms/PolylineCompressor.h"
|
||||
#include "../DataStructures/PhantomNodes.h"
|
||||
#include "../DataStructures/RawRouteData.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
/* This class is fed with all way segments in consecutive order
|
||||
* and produces the description plus the encoded polyline */
|
||||
|
||||
class DescriptionFactory
|
||||
{
|
||||
DouglasPeucker polyline_generalizer;
|
||||
PolylineCompressor polyline_compressor;
|
||||
PhantomNode start_phantom, target_phantom;
|
||||
|
||||
double DegreeToRadian(const double degree) const;
|
||||
double RadianToDegree(const double degree) const;
|
||||
|
||||
public:
|
||||
struct RouteSummary
|
||||
{
|
||||
std::string lengthString;
|
||||
std::string durationString;
|
||||
unsigned startName;
|
||||
unsigned destName;
|
||||
RouteSummary() : lengthString("0"), durationString("0"), startName(0), destName(0) {}
|
||||
|
||||
void BuildDurationAndLengthStrings(const double distance, const unsigned time)
|
||||
{
|
||||
// compute distance/duration for route summary
|
||||
intToString(round(distance), lengthString);
|
||||
int travel_time = round(time / 10.);
|
||||
intToString(std::max(travel_time, 1), durationString);
|
||||
}
|
||||
} summary;
|
||||
|
||||
double entireLength;
|
||||
|
||||
// I know, declaring this public is considered bad. I'm lazy
|
||||
std::vector<SegmentInformation> path_description;
|
||||
DescriptionFactory();
|
||||
virtual ~DescriptionFactory();
|
||||
double GetBearing(const FixedPointCoordinate &C, const FixedPointCoordinate &B) const;
|
||||
void AppendEncodedPolylineString(std::vector<std::string> &output) const;
|
||||
void AppendUnencodedPolylineString(std::vector<std::string> &output) const;
|
||||
void AppendSegment(const FixedPointCoordinate &coordinate, const PathData &data);
|
||||
void BuildRouteSummary(const double distance, const unsigned time);
|
||||
void SetStartSegment(const PhantomNode &start_phantom);
|
||||
void SetEndSegment(const PhantomNode &start_phantom);
|
||||
void AppendEncodedPolylineString(const bool return_encoded, std::vector<std::string> &output);
|
||||
|
||||
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;
|
||||
// }
|
||||
|
||||
double 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[0].length)
|
||||
{
|
||||
if (path_description.size() > 2)
|
||||
{
|
||||
path_description.erase(path_description.begin());
|
||||
path_description[0].turn_instruction = TurnInstruction::HeadOn;
|
||||
path_description[0].necessary = true;
|
||||
start_phantom.name_id = path_description[0].name_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Generalize poly line
|
||||
polyline_generalizer.Run(path_description, zoomLevel);
|
||||
|
||||
// fix what needs to be fixed else
|
||||
for (unsigned i = 0; i < path_description.size() - 1 && path_description.size() >= 2; ++i)
|
||||
{
|
||||
if (path_description[i].necessary)
|
||||
{
|
||||
double angle =
|
||||
GetBearing(path_description[i].location, path_description[i + 1].location);
|
||||
path_description[i].bearing = angle * 10;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* DESCRIPTIONFACTORY_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 GPX_DESCRIPTOR_H
|
||||
#define GPX_DESCRIPTOR_H
|
||||
|
||||
#include "BaseDescriptor.h"
|
||||
|
||||
template <class DataFacadeT> class GPXDescriptor : public BaseDescriptor<DataFacadeT>
|
||||
{
|
||||
private:
|
||||
DescriptorConfig config;
|
||||
FixedPointCoordinate current;
|
||||
|
||||
std::string tmp;
|
||||
|
||||
public:
|
||||
void SetConfig(const DescriptorConfig &c) { config = c; }
|
||||
|
||||
// TODO: reorder parameters
|
||||
void Run(const RawRouteData &raw_route,
|
||||
const PhantomNodes &phantom_node_list,
|
||||
DataFacadeT *facade,
|
||||
http::Reply &reply)
|
||||
{
|
||||
reply.content.emplace_back("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
reply.content.emplace_back("<gpx creator=\"OSRM Routing Engine\" version=\"1.1\" "
|
||||
"xmlns=\"http://www.topografix.com/GPX/1/1\" "
|
||||
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
||||
"xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd"
|
||||
"\">");
|
||||
reply.content.emplace_back("<metadata><copyright author=\"Project OSRM\"><license>Data (c)"
|
||||
" OpenStreetMap contributors (ODbL)</license></copyright>"
|
||||
"</metadata>");
|
||||
reply.content.emplace_back("<rte>");
|
||||
bool found_route = (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT) &&
|
||||
(!raw_route.unpacked_path_segments.front().empty());
|
||||
if (found_route)
|
||||
{
|
||||
FixedPointCoordinate::convertInternalLatLonToString(
|
||||
phantom_node_list.source_phantom.location.lat, tmp);
|
||||
reply.content.emplace_back("<rtept lat=\"" + tmp + "\" ");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(
|
||||
phantom_node_list.source_phantom.location.lon, tmp);
|
||||
reply.content.emplace_back("lon=\"" + tmp + "\"></rtept>");
|
||||
|
||||
for (const std::vector<PathData> &path_data_vector : raw_route.unpacked_path_segments)
|
||||
{
|
||||
for (const PathData &path_data : path_data_vector)
|
||||
{
|
||||
FixedPointCoordinate current_coordinate =
|
||||
facade->GetCoordinateOfNode(path_data.node);
|
||||
|
||||
FixedPointCoordinate::convertInternalLatLonToString(current_coordinate.lat,
|
||||
tmp);
|
||||
reply.content.emplace_back("<rtept lat=\"" + tmp + "\" ");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(current_coordinate.lon,
|
||||
tmp);
|
||||
reply.content.emplace_back("lon=\"" + tmp + "\"></rtept>");
|
||||
}
|
||||
}
|
||||
// Add the via point or the end coordinate
|
||||
FixedPointCoordinate::convertInternalLatLonToString(
|
||||
phantom_node_list.target_phantom.location.lat, tmp);
|
||||
reply.content.emplace_back("<rtept lat=\"" + tmp + "\" ");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(
|
||||
phantom_node_list.target_phantom.location.lon, tmp);
|
||||
reply.content.emplace_back("lon=\"" + tmp + "\"></rtept>");
|
||||
}
|
||||
reply.content.emplace_back("</rte></gpx>");
|
||||
}
|
||||
};
|
||||
#endif // GPX_DESCRIPTOR_H
|
||||
@@ -1,524 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef JSON_DESCRIPTOR_H_
|
||||
#define JSON_DESCRIPTOR_H_
|
||||
|
||||
#include "BaseDescriptor.h"
|
||||
#include "DescriptionFactory.h"
|
||||
#include "../Algorithms/ObjectToBase64.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../Util/Azimuth.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFacadeT>
|
||||
{
|
||||
private:
|
||||
// TODO: initalize in c'tor
|
||||
DataFacadeT *facade;
|
||||
DescriptorConfig config;
|
||||
DescriptionFactory description_factory;
|
||||
DescriptionFactory alternate_descriptionFactory;
|
||||
FixedPointCoordinate current;
|
||||
unsigned entered_restricted_area_count;
|
||||
struct RoundAbout
|
||||
{
|
||||
RoundAbout() : start_index(INT_MAX), name_id(INT_MAX), leave_at_exit(INT_MAX) {}
|
||||
int start_index;
|
||||
int name_id;
|
||||
int leave_at_exit;
|
||||
} round_about;
|
||||
|
||||
struct Segment
|
||||
{
|
||||
Segment() : name_id(-1), length(-1), position(-1) {}
|
||||
Segment(int n, int l, int p) : name_id(n), length(l), position(p) {}
|
||||
int name_id;
|
||||
int length;
|
||||
int position;
|
||||
};
|
||||
std::vector<Segment> shortest_path_segments, alternative_path_segments;
|
||||
std::vector<unsigned> shortest_leg_end_indices, alternative_leg_end_indices;
|
||||
|
||||
struct RouteNames
|
||||
{
|
||||
std::string shortest_path_name_1;
|
||||
std::string shortest_path_name_2;
|
||||
std::string alternative_path_name_1;
|
||||
std::string alternative_path_name_2;
|
||||
};
|
||||
|
||||
public:
|
||||
JSONDescriptor() : facade(nullptr), entered_restricted_area_count(0)
|
||||
{
|
||||
shortest_leg_end_indices.emplace_back(0);
|
||||
alternative_leg_end_indices.emplace_back(0);
|
||||
}
|
||||
|
||||
void SetConfig(const DescriptorConfig &c) { config = c; }
|
||||
|
||||
unsigned DescribeLeg(const std::vector<PathData> route_leg, const PhantomNodes &leg_phantoms)
|
||||
{
|
||||
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;
|
||||
}
|
||||
++added_element_count;
|
||||
BOOST_ASSERT((route_leg.size() + 1) == added_element_count);
|
||||
return added_element_count;
|
||||
}
|
||||
|
||||
void Run(const RawRouteData &raw_route,
|
||||
const PhantomNodes &phantom_nodes,
|
||||
// TODO: move facade initalization to c'tor
|
||||
DataFacadeT *f,
|
||||
http::Reply &reply)
|
||||
{
|
||||
facade = f;
|
||||
reply.content.emplace_back("{\"status\":");
|
||||
|
||||
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
|
||||
{
|
||||
// We do not need to do much, if there is no route ;-)
|
||||
reply.content.emplace_back(
|
||||
"207,\"status_message\": \"Cannot find route between points\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
SimpleLogger().Write(logDEBUG) << "distance: " << raw_route.shortest_path_length;
|
||||
|
||||
// check if first segment is non-zero
|
||||
std::string road_name =
|
||||
facade->GetEscapedNameForNameID(phantom_nodes.source_phantom.name_id);
|
||||
|
||||
BOOST_ASSERT(raw_route.unpacked_path_segments.size() ==
|
||||
raw_route.segment_end_coordinates.size());
|
||||
|
||||
description_factory.SetStartSegment(phantom_nodes.source_phantom);
|
||||
reply.content.emplace_back("0,"
|
||||
"\"status_message\": \"Found route between points\",");
|
||||
|
||||
// for each unpacked segment add the leg to the description
|
||||
for (unsigned i = 0; i < raw_route.unpacked_path_segments.size(); ++i)
|
||||
{
|
||||
const int added_segments = DescribeLeg(raw_route.unpacked_path_segments[i],
|
||||
raw_route.segment_end_coordinates[i]);
|
||||
BOOST_ASSERT(0 < added_segments);
|
||||
shortest_leg_end_indices.emplace_back(added_segments + shortest_leg_end_indices.back());
|
||||
}
|
||||
description_factory.SetEndSegment(phantom_nodes.target_phantom);
|
||||
description_factory.Run(facade, config.zoom_level);
|
||||
|
||||
reply.content.emplace_back("\"route_geometry\": ");
|
||||
if (config.geometry)
|
||||
{
|
||||
description_factory.AppendEncodedPolylineString(config.encode_geometry, reply.content);
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.content.emplace_back("[]");
|
||||
}
|
||||
|
||||
reply.content.emplace_back(",\"route_instructions\": [");
|
||||
if (config.instructions)
|
||||
{
|
||||
BuildTextualDescription(description_factory,
|
||||
reply,
|
||||
raw_route.shortest_path_length,
|
||||
facade,
|
||||
shortest_path_segments);
|
||||
}
|
||||
reply.content.emplace_back("],");
|
||||
description_factory.BuildRouteSummary(description_factory.entireLength,
|
||||
raw_route.shortest_path_length);
|
||||
|
||||
reply.content.emplace_back("\"route_summary\":");
|
||||
reply.content.emplace_back("{");
|
||||
reply.content.emplace_back("\"total_distance\":");
|
||||
reply.content.emplace_back(description_factory.summary.lengthString);
|
||||
reply.content.emplace_back(","
|
||||
"\"total_time\":");
|
||||
reply.content.emplace_back(description_factory.summary.durationString);
|
||||
reply.content.emplace_back(","
|
||||
"\"start_point\":\"");
|
||||
reply.content.emplace_back(
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.startName));
|
||||
reply.content.emplace_back("\","
|
||||
"\"end_point\":\"");
|
||||
reply.content.emplace_back(
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.destName));
|
||||
reply.content.emplace_back("\"");
|
||||
reply.content.emplace_back("}");
|
||||
reply.content.emplace_back(",");
|
||||
|
||||
// only one alternative route is computed at this time, so this is hardcoded
|
||||
if (raw_route.alternative_path_length != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
alternate_descriptionFactory.SetStartSegment(phantom_nodes.source_phantom);
|
||||
// Get all the coordinates for the computed route
|
||||
for (const PathData &path_data : raw_route.unpacked_alternative)
|
||||
{
|
||||
current = facade->GetCoordinateOfNode(path_data.node);
|
||||
alternate_descriptionFactory.AppendSegment(current, path_data);
|
||||
}
|
||||
}
|
||||
alternate_descriptionFactory.Run(facade, config.zoom_level);
|
||||
|
||||
// //give an array of alternative routes
|
||||
reply.content.emplace_back("\"alternative_geometries\": [");
|
||||
if (config.geometry && INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
// Generate the linestrings for each alternative
|
||||
alternate_descriptionFactory.AppendEncodedPolylineString(config.encode_geometry,
|
||||
reply.content);
|
||||
}
|
||||
reply.content.emplace_back("],");
|
||||
reply.content.emplace_back("\"alternative_instructions\":[");
|
||||
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
reply.content.emplace_back("[");
|
||||
// Generate instructions for each alternative
|
||||
if (config.instructions)
|
||||
{
|
||||
BuildTextualDescription(alternate_descriptionFactory,
|
||||
reply,
|
||||
raw_route.alternative_path_length,
|
||||
facade,
|
||||
alternative_path_segments);
|
||||
}
|
||||
reply.content.emplace_back("]");
|
||||
}
|
||||
reply.content.emplace_back("],");
|
||||
reply.content.emplace_back("\"alternative_summaries\":[");
|
||||
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
// Generate route summary (length, duration) for each alternative
|
||||
alternate_descriptionFactory.BuildRouteSummary(
|
||||
alternate_descriptionFactory.entireLength, raw_route.alternative_path_length);
|
||||
reply.content.emplace_back("{");
|
||||
reply.content.emplace_back("\"total_distance\":");
|
||||
reply.content.emplace_back(alternate_descriptionFactory.summary.lengthString);
|
||||
reply.content.emplace_back(","
|
||||
"\"total_time\":");
|
||||
reply.content.emplace_back(alternate_descriptionFactory.summary.durationString);
|
||||
reply.content.emplace_back(","
|
||||
"\"start_point\":\"");
|
||||
reply.content.emplace_back(
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.startName));
|
||||
reply.content.emplace_back("\","
|
||||
"\"end_point\":\"");
|
||||
reply.content.emplace_back(
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.destName));
|
||||
reply.content.emplace_back("\"");
|
||||
reply.content.emplace_back("}");
|
||||
}
|
||||
reply.content.emplace_back("],");
|
||||
|
||||
// //Get Names for both routes
|
||||
RouteNames routeNames;
|
||||
GetRouteNames(shortest_path_segments, alternative_path_segments, facade, routeNames);
|
||||
|
||||
reply.content.emplace_back("\"route_name\":[\"");
|
||||
reply.content.emplace_back(routeNames.shortest_path_name_1);
|
||||
reply.content.emplace_back("\",\"");
|
||||
reply.content.emplace_back(routeNames.shortest_path_name_2);
|
||||
reply.content.emplace_back("\"],"
|
||||
"\"alternative_names\":[");
|
||||
reply.content.emplace_back("[\"");
|
||||
reply.content.emplace_back(routeNames.alternative_path_name_1);
|
||||
reply.content.emplace_back("\",\"");
|
||||
reply.content.emplace_back(routeNames.alternative_path_name_2);
|
||||
reply.content.emplace_back("\"]");
|
||||
reply.content.emplace_back("],");
|
||||
// list all viapoints so that the client may display it
|
||||
reply.content.emplace_back("\"via_points\":[");
|
||||
|
||||
BOOST_ASSERT(!raw_route.segment_end_coordinates.empty());
|
||||
|
||||
std::string tmp;
|
||||
FixedPointCoordinate::convertInternalReversedCoordinateToString(
|
||||
raw_route.segment_end_coordinates.front().source_phantom.location, tmp);
|
||||
reply.content.emplace_back("[");
|
||||
reply.content.emplace_back(tmp);
|
||||
reply.content.emplace_back("]");
|
||||
|
||||
for (const PhantomNodes &nodes : raw_route.segment_end_coordinates)
|
||||
{
|
||||
tmp.clear();
|
||||
FixedPointCoordinate::convertInternalReversedCoordinateToString(
|
||||
nodes.target_phantom.location, tmp);
|
||||
reply.content.emplace_back(",[");
|
||||
reply.content.emplace_back(tmp);
|
||||
reply.content.emplace_back("]");
|
||||
}
|
||||
|
||||
reply.content.emplace_back("],");
|
||||
reply.content.emplace_back("\"via_indices\":[");
|
||||
for (const unsigned index : shortest_leg_end_indices)
|
||||
{
|
||||
tmp.clear();
|
||||
intToString(index, tmp);
|
||||
reply.content.emplace_back(tmp);
|
||||
if (index != shortest_leg_end_indices.back())
|
||||
{
|
||||
reply.content.emplace_back(",");
|
||||
}
|
||||
}
|
||||
reply.content.emplace_back("],\"alternative_indices\":[");
|
||||
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
reply.content.emplace_back("0,");
|
||||
tmp.clear();
|
||||
intToString(alternate_descriptionFactory.path_description.size(), tmp);
|
||||
reply.content.emplace_back(tmp);
|
||||
}
|
||||
|
||||
reply.content.emplace_back("],");
|
||||
reply.content.emplace_back("\"hint_data\": {");
|
||||
reply.content.emplace_back("\"checksum\":");
|
||||
intToString(raw_route.check_sum, tmp);
|
||||
reply.content.emplace_back(tmp);
|
||||
reply.content.emplace_back(", \"locations\": [");
|
||||
|
||||
std::string hint;
|
||||
for (unsigned i = 0; i < raw_route.segment_end_coordinates.size(); ++i)
|
||||
{
|
||||
reply.content.emplace_back("\"");
|
||||
EncodeObjectToBase64(raw_route.segment_end_coordinates[i].source_phantom, hint);
|
||||
reply.content.emplace_back(hint);
|
||||
reply.content.emplace_back("\", ");
|
||||
}
|
||||
EncodeObjectToBase64(raw_route.segment_end_coordinates.back().target_phantom, hint);
|
||||
reply.content.emplace_back("\"");
|
||||
reply.content.emplace_back(hint);
|
||||
reply.content.emplace_back("\"]");
|
||||
reply.content.emplace_back("}}");
|
||||
}
|
||||
|
||||
// construct routes names
|
||||
void GetRouteNames(std::vector<Segment> &shortest_path_segments,
|
||||
std::vector<Segment> &alternative_path_segments,
|
||||
const DataFacadeT *facade,
|
||||
RouteNames &routeNames)
|
||||
{
|
||||
Segment shortest_segment_1, shortest_segment_2;
|
||||
Segment alternativeSegment1, alternative_segment_2;
|
||||
|
||||
auto length_comperator = [](Segment a, Segment b)
|
||||
{ return a.length < b.length; };
|
||||
auto name_id_comperator = [](Segment a, Segment b)
|
||||
{ return a.name_id < b.name_id; };
|
||||
|
||||
if (!shortest_path_segments.empty())
|
||||
{
|
||||
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);
|
||||
alternativeSegment1 = alternative_path_segments[0];
|
||||
}
|
||||
std::vector<Segment> shortestDifference(shortest_path_segments.size());
|
||||
std::vector<Segment> alternativeDifference(alternative_path_segments.size());
|
||||
std::set_difference(shortest_path_segments.begin(),
|
||||
shortest_path_segments.end(),
|
||||
alternative_path_segments.begin(),
|
||||
alternative_path_segments.end(),
|
||||
shortestDifference.begin(),
|
||||
length_comperator);
|
||||
int size_of_difference = shortestDifference.size();
|
||||
if (size_of_difference)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < size_of_difference &&
|
||||
shortestDifference[i].name_id == shortest_path_segments[0].name_id)
|
||||
{
|
||||
++i;
|
||||
}
|
||||
if (i < size_of_difference)
|
||||
{
|
||||
shortest_segment_2 = shortestDifference[i];
|
||||
}
|
||||
}
|
||||
|
||||
std::set_difference(alternative_path_segments.begin(),
|
||||
alternative_path_segments.end(),
|
||||
shortest_path_segments.begin(),
|
||||
shortest_path_segments.end(),
|
||||
alternativeDifference.begin(),
|
||||
name_id_comperator);
|
||||
size_of_difference = alternativeDifference.size();
|
||||
if (size_of_difference)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < size_of_difference &&
|
||||
alternativeDifference[i].name_id == alternative_path_segments[0].name_id)
|
||||
{
|
||||
++i;
|
||||
}
|
||||
if (i < size_of_difference)
|
||||
{
|
||||
alternative_segment_2 = alternativeDifference[i];
|
||||
}
|
||||
}
|
||||
if (shortest_segment_1.position > shortest_segment_2.position)
|
||||
std::swap(shortest_segment_1, shortest_segment_2);
|
||||
|
||||
if (alternativeSegment1.position > alternative_segment_2.position)
|
||||
std::swap(alternativeSegment1, alternative_segment_2);
|
||||
|
||||
routeNames.shortest_path_name_1 =
|
||||
facade->GetEscapedNameForNameID(shortest_segment_1.name_id);
|
||||
routeNames.shortest_path_name_2 =
|
||||
facade->GetEscapedNameForNameID(shortest_segment_2.name_id);
|
||||
|
||||
routeNames.alternative_path_name_1 =
|
||||
facade->GetEscapedNameForNameID(alternativeSegment1.name_id);
|
||||
routeNames.alternative_path_name_2 =
|
||||
facade->GetEscapedNameForNameID(alternative_segment_2.name_id);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: reorder parameters
|
||||
inline void BuildTextualDescription(DescriptionFactory &description_factory,
|
||||
http::Reply &reply,
|
||||
const int route_length,
|
||||
const DataFacadeT *facade,
|
||||
std::vector<Segment> &route_segments_list)
|
||||
{
|
||||
// Segment information has following format:
|
||||
//["instruction","streetname",length,position,time,"length","earth_direction",azimuth]
|
||||
// Example: ["Turn left","High Street",200,4,10,"200m","NE",22.5]
|
||||
unsigned necessary_segments_running_index = 0;
|
||||
round_about.leave_at_exit = 0;
|
||||
round_about.name_id = 0;
|
||||
std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction;
|
||||
|
||||
// Fetch data from Factory and generate a string from it.
|
||||
for (const SegmentInformation &segment : description_factory.path_description)
|
||||
{
|
||||
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
|
||||
{
|
||||
if (necessary_segments_running_index)
|
||||
{
|
||||
reply.content.emplace_back(",");
|
||||
}
|
||||
reply.content.emplace_back("[\"");
|
||||
if (TurnInstruction::LeaveRoundAbout == current_instruction)
|
||||
{
|
||||
intToString(as_integer(TurnInstruction::EnterRoundAbout), temp_instruction);
|
||||
reply.content.emplace_back(temp_instruction);
|
||||
reply.content.emplace_back("-");
|
||||
intToString(round_about.leave_at_exit + 1, temp_instruction);
|
||||
reply.content.emplace_back(temp_instruction);
|
||||
round_about.leave_at_exit = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
intToString(as_integer(current_instruction), temp_instruction);
|
||||
reply.content.emplace_back(temp_instruction);
|
||||
}
|
||||
|
||||
reply.content.emplace_back("\",\"");
|
||||
reply.content.emplace_back(facade->GetEscapedNameForNameID(segment.name_id));
|
||||
reply.content.emplace_back("\",");
|
||||
intToString(segment.length, temp_dist);
|
||||
reply.content.emplace_back(temp_dist);
|
||||
reply.content.emplace_back(",");
|
||||
intToString(necessary_segments_running_index, temp_length);
|
||||
reply.content.emplace_back(temp_length);
|
||||
reply.content.emplace_back(",");
|
||||
intToString(round(segment.duration / 10.), temp_duration);
|
||||
reply.content.emplace_back(temp_duration);
|
||||
reply.content.emplace_back(",\"");
|
||||
intToString(segment.length, temp_length);
|
||||
reply.content.emplace_back(temp_length);
|
||||
reply.content.emplace_back("m\",\"");
|
||||
int bearing_value = round(segment.bearing / 10.);
|
||||
reply.content.emplace_back(Azimuth::Get(bearing_value));
|
||||
reply.content.emplace_back("\",");
|
||||
intToString(bearing_value, temp_bearing);
|
||||
reply.content.emplace_back(temp_bearing);
|
||||
reply.content.emplace_back("]");
|
||||
|
||||
route_segments_list.emplace_back(
|
||||
Segment(segment.name_id, segment.length, route_segments_list.size()));
|
||||
}
|
||||
}
|
||||
else if (TurnInstruction::StayOnRoundAbout == current_instruction)
|
||||
{
|
||||
++round_about.leave_at_exit;
|
||||
}
|
||||
if (segment.necessary)
|
||||
{
|
||||
++necessary_segments_running_index;
|
||||
}
|
||||
}
|
||||
if (INVALID_EDGE_WEIGHT != route_length)
|
||||
{
|
||||
reply.content.emplace_back(",[\"");
|
||||
intToString(as_integer(TurnInstruction::ReachedYourDestination), temp_instruction);
|
||||
reply.content.emplace_back(temp_instruction);
|
||||
reply.content.emplace_back("\",\"");
|
||||
reply.content.emplace_back("\",");
|
||||
reply.content.emplace_back("0");
|
||||
reply.content.emplace_back(",");
|
||||
intToString(necessary_segments_running_index - 1, temp_length);
|
||||
reply.content.emplace_back(temp_length);
|
||||
reply.content.emplace_back(",");
|
||||
reply.content.emplace_back("0");
|
||||
reply.content.emplace_back(",\"");
|
||||
reply.content.emplace_back("\",\"");
|
||||
reply.content.emplace_back(Azimuth::Get(0.0));
|
||||
reply.content.emplace_back("\",");
|
||||
reply.content.emplace_back("0.0");
|
||||
reply.content.emplace_back("]");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* JSON_DESCRIPTOR_H_ */
|
||||
@@ -1,3 +0,0 @@
|
||||
The javascript based web client is a seperate project available at
|
||||
|
||||
https://github.com/DennisSchiefer/Project-OSRM-Web
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
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@/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,138 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "BaseParser.h"
|
||||
#include "ExtractionWay.h"
|
||||
#include "ScriptingEnvironment.h"
|
||||
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
#include "../Util/LuaUtil.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/regex.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
BaseParser::BaseParser(ExtractorCallbacks *extractor_callbacks,
|
||||
ScriptingEnvironment &scripting_environment)
|
||||
: extractor_callbacks(extractor_callbacks),
|
||||
lua_state(scripting_environment.getLuaStateForThreadID(0)),
|
||||
scripting_environment(scripting_environment), use_turn_restrictions(true)
|
||||
{
|
||||
ReadUseRestrictionsSetting();
|
||||
ReadRestrictionExceptions();
|
||||
}
|
||||
|
||||
void BaseParser::ReadUseRestrictionsSetting()
|
||||
{
|
||||
if (0 != luaL_dostring(lua_state, "return use_turn_restrictions\n"))
|
||||
{
|
||||
throw OSRMException("ERROR occured in scripting block");
|
||||
}
|
||||
if (lua_isboolean(lua_state, -1))
|
||||
{
|
||||
use_turn_restrictions = lua_toboolean(lua_state, -1);
|
||||
}
|
||||
if (use_turn_restrictions)
|
||||
{
|
||||
SimpleLogger().Write() << "Using turn restrictions";
|
||||
}
|
||||
else
|
||||
{
|
||||
SimpleLogger().Write() << "Ignoring turn restrictions";
|
||||
}
|
||||
}
|
||||
|
||||
void BaseParser::ReadRestrictionExceptions()
|
||||
{
|
||||
if (lua_function_exists(lua_state, "get_exceptions"))
|
||||
{
|
||||
// get list of turn restriction exceptions
|
||||
luabind::call_function<void>(
|
||||
lua_state, "get_exceptions", boost::ref(restriction_exceptions));
|
||||
const unsigned exception_count = restriction_exceptions.size();
|
||||
SimpleLogger().Write() << "Found " << exception_count
|
||||
<< " exceptions to turn restrictions:";
|
||||
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,450 +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/SimpleLogger.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::chrono::time_point<std::chrono::steady_clock> time1 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << "[extractor] Sorting used nodes ... " << std::flush;
|
||||
stxxl::sort(used_node_id_list.begin(), used_node_id_list.end(), Cmp(), stxxl_memory);
|
||||
std::chrono::time_point<std::chrono::steady_clock> time2 = std::chrono::steady_clock::now();
|
||||
std::chrono::duration<double> elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
std::cout << "[extractor] Erasing duplicate nodes ... " << std::flush;
|
||||
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());
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << "[extractor] Sorting all nodes ... " << std::flush;
|
||||
stxxl::sort(all_nodes_list.begin(), all_nodes_list.end(), CmpNodeByID(), stxxl_memory);
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << "[extractor] Sorting used ways ... " << std::flush;
|
||||
stxxl::sort(
|
||||
way_start_end_id_list.begin(), way_start_end_id_list.end(), CmpWayByID(), stxxl_memory);
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] Sorting restrictions. by from... " << std::flush;
|
||||
stxxl::sort(restrictions_list.begin(),
|
||||
restrictions_list.end(),
|
||||
CmpRestrictionContainerByFrom(),
|
||||
stxxl_memory);
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] Fixing restriction starts ... " << std::flush;
|
||||
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;
|
||||
}
|
||||
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << "[extractor] Sorting restrictions. by to ... " << std::flush;
|
||||
stxxl::sort(restrictions_list.begin(),
|
||||
restrictions_list.end(),
|
||||
CmpRestrictionContainerByTo(),
|
||||
stxxl_memory);
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
unsigned number_of_useable_restrictions = 0;
|
||||
std::cout << "[extractor] Fixing restriction ends ... " << std::flush;
|
||||
restrictions_iterator = restrictions_list.begin();
|
||||
way_start_and_end_iterator = way_start_end_id_list.begin();
|
||||
while (way_start_and_end_iterator != way_start_end_id_list.end() &&
|
||||
restrictions_iterator != restrictions_list.end())
|
||||
{
|
||||
if (way_start_and_end_iterator->wayID < restrictions_iterator->toWay)
|
||||
{
|
||||
++way_start_and_end_iterator;
|
||||
continue;
|
||||
}
|
||||
if (way_start_and_end_iterator->wayID > restrictions_iterator->toWay)
|
||||
{
|
||||
++restrictions_iterator;
|
||||
continue;
|
||||
}
|
||||
NodeID via_node_id = restrictions_iterator->restriction.viaNode;
|
||||
if (way_start_and_end_iterator->lastStart == via_node_id)
|
||||
{
|
||||
restrictions_iterator->restriction.toNode = way_start_and_end_iterator->lastTarget;
|
||||
}
|
||||
else if (way_start_and_end_iterator->lastTarget == via_node_id)
|
||||
{
|
||||
restrictions_iterator->restriction.toNode = way_start_and_end_iterator->lastStart;
|
||||
}
|
||||
else if (way_start_and_end_iterator->firstStart == via_node_id)
|
||||
{
|
||||
restrictions_iterator->restriction.toNode = way_start_and_end_iterator->firstTarget;
|
||||
}
|
||||
else if (way_start_and_end_iterator->firstTarget == via_node_id)
|
||||
{
|
||||
restrictions_iterator->restriction.toNode = way_start_and_end_iterator->firstStart;
|
||||
}
|
||||
|
||||
if (std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.fromNode &&
|
||||
std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.toNode)
|
||||
{
|
||||
++number_of_useable_restrictions;
|
||||
}
|
||||
++restrictions_iterator;
|
||||
}
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "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 *)&uuid, sizeof(UUID));
|
||||
restrictions_out_stream.write((char *)&number_of_useable_restrictions, sizeof(unsigned));
|
||||
for (restrictions_iterator = restrictions_list.begin();
|
||||
restrictions_iterator != restrictions_list.end();
|
||||
++restrictions_iterator)
|
||||
{
|
||||
if (std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.fromNode &&
|
||||
std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.toNode)
|
||||
{
|
||||
restrictions_out_stream.write((char *)&(restrictions_iterator->restriction),
|
||||
sizeof(TurnRestriction));
|
||||
}
|
||||
}
|
||||
restrictions_out_stream.close();
|
||||
|
||||
std::ofstream file_out_stream;
|
||||
file_out_stream.open(output_file_name.c_str(), std::ios::binary);
|
||||
file_out_stream.write((char *)&uuid, sizeof(UUID));
|
||||
file_out_stream.write((char *)&number_of_used_nodes, sizeof(unsigned));
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
std::cout << "[extractor] Confirming/Writing used nodes ... " << std::flush;
|
||||
|
||||
// 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->id)
|
||||
{
|
||||
++node_id_iterator;
|
||||
continue;
|
||||
}
|
||||
if (*node_id_iterator > node_iterator->id)
|
||||
{
|
||||
++node_iterator;
|
||||
continue;
|
||||
}
|
||||
BOOST_ASSERT(*node_id_iterator == node_iterator->id);
|
||||
|
||||
file_out_stream.write((char *)&(*node_iterator), sizeof(ExternalMemoryNode));
|
||||
|
||||
++number_of_used_nodes;
|
||||
++node_id_iterator;
|
||||
++node_iterator;
|
||||
}
|
||||
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] setting number of nodes ... " << std::flush;
|
||||
std::ios::pos_type previous_file_position = file_out_stream.tellp();
|
||||
file_out_stream.seekp(std::ios::beg + sizeof(UUID));
|
||||
file_out_stream.write((char *)&number_of_used_nodes, sizeof(unsigned));
|
||||
file_out_stream.seekp(previous_file_position);
|
||||
|
||||
std::cout << "ok" << std::endl;
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
|
||||
// Sort edges by start.
|
||||
std::cout << "[extractor] Sorting edges by start ... " << std::flush;
|
||||
stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByStartID(), stxxl_memory);
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << "[extractor] Setting start coords ... " << std::flush;
|
||||
file_out_stream.write((char *)&number_of_used_edges, sizeof(unsigned));
|
||||
// Traverse list of edges and nodes in parallel and set start coord
|
||||
node_iterator = all_nodes_list.begin();
|
||||
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->id)
|
||||
{
|
||||
++edge_iterator;
|
||||
continue;
|
||||
}
|
||||
if (edge_iterator->start > node_iterator->id)
|
||||
{
|
||||
node_iterator++;
|
||||
continue;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(edge_iterator->start == node_iterator->id);
|
||||
edge_iterator->source_coordinate.lat = node_iterator->lat;
|
||||
edge_iterator->source_coordinate.lon = node_iterator->lon;
|
||||
++edge_iterator;
|
||||
}
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
// Sort Edges by target
|
||||
std::cout << "[extractor] Sorting edges by target ... " << std::flush;
|
||||
stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByTargetID(), stxxl_memory);
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
std::cout << "[extractor] Setting target coords ... " << std::flush;
|
||||
// Traverse list of edges and nodes in parallel and set target coord
|
||||
node_iterator = all_nodes_list.begin();
|
||||
edge_iterator = all_edges_list.begin();
|
||||
|
||||
while (edge_iterator != all_edges_list.end() && node_iterator != all_nodes_list.end())
|
||||
{
|
||||
if (edge_iterator->target < node_iterator->id)
|
||||
{
|
||||
++edge_iterator;
|
||||
continue;
|
||||
}
|
||||
if (edge_iterator->target > node_iterator->id)
|
||||
{
|
||||
++node_iterator;
|
||||
continue;
|
||||
}
|
||||
BOOST_ASSERT(edge_iterator->target == node_iterator->id);
|
||||
if (edge_iterator->source_coordinate.lat != std::numeric_limits<int>::min() &&
|
||||
edge_iterator->source_coordinate.lon != std::numeric_limits<int>::min())
|
||||
{
|
||||
BOOST_ASSERT(edge_iterator->speed != -1);
|
||||
BOOST_ASSERT(edge_iterator->type >= 0);
|
||||
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->type, sizeof(short));
|
||||
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));
|
||||
file_out_stream.write((char *)&edge_iterator->is_contra_flow, sizeof(bool));
|
||||
file_out_stream.write((char *)&edge_iterator->is_split, sizeof(bool));
|
||||
++number_of_used_edges;
|
||||
}
|
||||
++edge_iterator;
|
||||
}
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "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;
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << "[extractor] writing street name index ... " << std::flush;
|
||||
std::string name_file_streamName = (output_file_name + ".names");
|
||||
boost::filesystem::ofstream name_file_stream(name_file_streamName, std::ios::binary);
|
||||
|
||||
// write number of names
|
||||
const unsigned number_of_names = name_list.size() + 1;
|
||||
name_file_stream.write((char *)&(number_of_names), sizeof(unsigned));
|
||||
|
||||
// compute total number of chars
|
||||
unsigned total_number_of_chars = 0;
|
||||
for (const std::string &temp_string : name_list)
|
||||
{
|
||||
total_number_of_chars += temp_string.length();
|
||||
}
|
||||
// write total number of chars
|
||||
name_file_stream.write((char *)&(total_number_of_chars), sizeof(unsigned));
|
||||
// write prefixe sums
|
||||
unsigned name_lengths_prefix_sum = 0;
|
||||
for (const std::string &temp_string : name_list)
|
||||
{
|
||||
name_file_stream.write((char *)&(name_lengths_prefix_sum), sizeof(unsigned));
|
||||
name_lengths_prefix_sum += temp_string.length();
|
||||
}
|
||||
// duplicate on purpose!
|
||||
name_file_stream.write((char *)&(name_lengths_prefix_sum), sizeof(unsigned));
|
||||
|
||||
// write all chars consecutively
|
||||
for (const std::string &temp_string : name_list)
|
||||
{
|
||||
const unsigned string_length = temp_string.length();
|
||||
name_file_stream.write(temp_string.c_str(), string_length);
|
||||
}
|
||||
|
||||
name_file_stream.close();
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
|
||||
SimpleLogger().Write() << "Processed " << number_of_used_nodes << " nodes and "
|
||||
<< number_of_used_edges << " edges";
|
||||
}
|
||||
catch (const std::exception &e) { std::cerr << "Caught Execption:" << e.what() << std::endl; }
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTIONCONTAINERS_H_
|
||||
#define EXTRACTIONCONTAINERS_H_
|
||||
|
||||
#include "InternalExtractorEdge.h"
|
||||
#include "ExtractorStructs.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../Util/UUID.h"
|
||||
|
||||
#include <stxxl/vector>
|
||||
|
||||
class ExtractionContainers
|
||||
{
|
||||
constexpr static unsigned stxxl_memory = ((sizeof(std::size_t) == 4) ? std::numeric_limits<int>::max() : std::numeric_limits<unsigned>::max());
|
||||
public:
|
||||
typedef stxxl::vector<NodeID> STXXLNodeIDVector;
|
||||
typedef stxxl::vector<ExternalMemoryNode> STXXLNodeVector;
|
||||
typedef stxxl::vector<InternalExtractorEdge> STXXLEdgeVector;
|
||||
typedef stxxl::vector<std::string> STXXLStringVector;
|
||||
typedef stxxl::vector<InputRestrictionContainer> STXXLRestrictionsVector;
|
||||
typedef stxxl::vector<WayIDStartAndEndEdge> STXXLWayIDStartEndVector;
|
||||
|
||||
STXXLNodeIDVector used_node_id_list;
|
||||
STXXLNodeVector all_nodes_list;
|
||||
STXXLEdgeVector all_edges_list;
|
||||
STXXLStringVector name_list;
|
||||
STXXLRestrictionsVector restrictions_list;
|
||||
STXXLWayIDStartEndVector way_start_end_id_list;
|
||||
const UUID uuid;
|
||||
|
||||
ExtractionContainers();
|
||||
|
||||
virtual ~ExtractionContainers();
|
||||
|
||||
void PrepareData(const std::string &output_file_name,
|
||||
const std::string &restrictions_file_name);
|
||||
};
|
||||
|
||||
#endif /* EXTRACTIONCONTAINERS_H_ */
|
||||
@@ -1,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 EXTRACTION_HELPER_FUNCTIONS_H
|
||||
#define EXTRACTION_HELPER_FUNCTIONS_H
|
||||
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string_regex.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(":"));
|
||||
bool matched = regex_match(s, e);
|
||||
return matched;
|
||||
}
|
||||
|
||||
inline unsigned parseDuration(const std::string &s)
|
||||
{
|
||||
unsigned hours = 0;
|
||||
unsigned minutes = 0;
|
||||
unsigned seconds = 0;
|
||||
boost::regex e(
|
||||
"((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",
|
||||
boost::regex_constants::icase | boost::regex_constants::perl);
|
||||
|
||||
std::vector<std::string> result;
|
||||
boost::algorithm::split_regex(result, s, boost::regex(":"));
|
||||
bool matched = regex_match(s, e);
|
||||
if (matched)
|
||||
{
|
||||
if (1 == result.size())
|
||||
{
|
||||
minutes = stringToInt(result[0]);
|
||||
}
|
||||
if (2 == result.size())
|
||||
{
|
||||
minutes = stringToInt(result[1]);
|
||||
hours = stringToInt(result[0]);
|
||||
}
|
||||
if (3 == result.size())
|
||||
{
|
||||
seconds = stringToInt(result[2]);
|
||||
minutes = stringToInt(result[1]);
|
||||
hours = stringToInt(result[0]);
|
||||
}
|
||||
return 10 * (3600 * hours + 60 * minutes + seconds);
|
||||
}
|
||||
return std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
|
||||
#endif // EXTRACTION_HELPER_FUNCTIONS_H_
|
||||
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "ExtractorCallbacks.h"
|
||||
#include "ExtractionContainers.h"
|
||||
#include "ExtractionWay.h"
|
||||
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <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.speed) || (0 < parsed_way.duration))
|
||||
{ // Only true if the way is specified by the speed profile
|
||||
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.speed = parsed_way.duration / (parsed_way.path.size() - 1);
|
||||
}
|
||||
|
||||
if (std::numeric_limits<double>::epsilon() >= std::abs(-1. - parsed_way.speed))
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << parsed_way.id;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the unique identifier for the street name
|
||||
const 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 (ExtractionWay::opposite == parsed_way.direction)
|
||||
{
|
||||
std::reverse(parsed_way.path.begin(), parsed_way.path.end());
|
||||
parsed_way.direction = ExtractionWay::oneway;
|
||||
}
|
||||
|
||||
const bool split_bidirectional_edge =
|
||||
(parsed_way.backward_speed > 0) && (parsed_way.speed != parsed_way.backward_speed);
|
||||
|
||||
for (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],
|
||||
parsed_way.type,
|
||||
(split_bidirectional_edge ? ExtractionWay::oneway : parsed_way.direction),
|
||||
parsed_way.speed,
|
||||
parsed_way.nameID,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.ignoreInGrid,
|
||||
(0 < parsed_way.duration),
|
||||
parsed_way.isAccessRestricted,
|
||||
false,
|
||||
split_bidirectional_edge));
|
||||
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_bidirectional_edge)
|
||||
{ // Only true if the way should be split
|
||||
std::reverse(parsed_way.path.begin(), parsed_way.path.end());
|
||||
for (std::vector<NodeID>::size_type n = 0; n < parsed_way.path.size() - 1; ++n)
|
||||
{
|
||||
external_memory.all_edges_list.push_back(
|
||||
InternalExtractorEdge(parsed_way.path[n],
|
||||
parsed_way.path[n + 1],
|
||||
parsed_way.type,
|
||||
ExtractionWay::oneway,
|
||||
parsed_way.backward_speed,
|
||||
parsed_way.nameID,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.ignoreInGrid,
|
||||
(0 < parsed_way.duration),
|
||||
parsed_way.isAccessRestricted,
|
||||
(ExtractionWay::oneway == parsed_way.direction),
|
||||
split_bidirectional_edge));
|
||||
}
|
||||
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,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
|
||||
{
|
||||
typedef WayIDStartAndEndEdge value_type;
|
||||
bool operator()(const WayIDStartAndEndEdge &a, const WayIDStartAndEndEdge &b) const
|
||||
{
|
||||
return a.wayID < b.wayID;
|
||||
}
|
||||
value_type max_value() { return WayIDStartAndEndEdge::max_value(); }
|
||||
value_type min_value() { return WayIDStartAndEndEdge::min_value(); }
|
||||
};
|
||||
|
||||
struct Cmp
|
||||
{
|
||||
typedef NodeID value_type;
|
||||
bool operator()(const NodeID a, const NodeID b) const { return a < b; }
|
||||
value_type max_value() { return 0xffffffff; }
|
||||
value_type min_value() { return 0x0; }
|
||||
};
|
||||
|
||||
struct CmpNodeByID
|
||||
{
|
||||
typedef ExternalMemoryNode value_type;
|
||||
bool operator()(const ExternalMemoryNode &a, const ExternalMemoryNode &b) const
|
||||
{
|
||||
return a.id < b.id;
|
||||
}
|
||||
value_type max_value() { return ExternalMemoryNode::max_value(); }
|
||||
value_type min_value() { return ExternalMemoryNode::min_value(); }
|
||||
};
|
||||
|
||||
#endif /* EXTRACTORSTRUCTS_H_ */
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INTERNAL_EXTRACTOR_EDGE_H
|
||||
#define INTERNAL_EXTRACTOR_EDGE_H
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
struct InternalExtractorEdge
|
||||
{
|
||||
InternalExtractorEdge()
|
||||
: start(0), target(0), type(0), direction(0), speed(0), name_id(0), is_roundabout(false),
|
||||
is_in_tiny_cc(false), is_duration_set(false), is_access_restricted(false),
|
||||
is_contra_flow(false), is_split(false)
|
||||
{
|
||||
}
|
||||
|
||||
explicit InternalExtractorEdge(NodeID start,
|
||||
NodeID target,
|
||||
short type,
|
||||
short direction,
|
||||
double speed,
|
||||
unsigned name_id,
|
||||
bool is_roundabout,
|
||||
bool is_in_tiny_cc,
|
||||
bool is_duration_set,
|
||||
bool is_access_restricted,
|
||||
bool is_contra_flow,
|
||||
bool is_split)
|
||||
: start(start), target(target), type(type), 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),
|
||||
is_contra_flow(is_contra_flow), is_split(is_split)
|
||||
{
|
||||
BOOST_ASSERT(0 <= type);
|
||||
}
|
||||
|
||||
// necessary static util functions for stxxl's sorting
|
||||
static InternalExtractorEdge min_value()
|
||||
{
|
||||
return InternalExtractorEdge(0, 0, 0, 0, 0, 0, false, false, false, false, false, false);
|
||||
}
|
||||
static InternalExtractorEdge max_value()
|
||||
{
|
||||
return InternalExtractorEdge(
|
||||
SPECIAL_NODEID, SPECIAL_NODEID, 0, 0, 0, 0, false, false, false, false, false, false);
|
||||
}
|
||||
|
||||
NodeID start;
|
||||
NodeID target;
|
||||
short type;
|
||||
short direction;
|
||||
double speed;
|
||||
unsigned name_id;
|
||||
bool is_roundabout;
|
||||
bool is_in_tiny_cc;
|
||||
bool is_duration_set;
|
||||
bool is_access_restricted;
|
||||
bool is_contra_flow;
|
||||
bool is_split;
|
||||
|
||||
FixedPointCoordinate source_coordinate;
|
||||
FixedPointCoordinate target_coordinate;
|
||||
};
|
||||
|
||||
struct CmpEdgeByStartID
|
||||
{
|
||||
typedef InternalExtractorEdge value_type;
|
||||
bool operator()(const InternalExtractorEdge &a, const InternalExtractorEdge &b) const
|
||||
{
|
||||
return a.start < b.start;
|
||||
}
|
||||
|
||||
value_type max_value() { return InternalExtractorEdge::max_value(); }
|
||||
|
||||
value_type min_value() { return InternalExtractorEdge::min_value(); }
|
||||
};
|
||||
|
||||
struct CmpEdgeByTargetID
|
||||
{
|
||||
typedef InternalExtractorEdge value_type;
|
||||
|
||||
bool operator()(const InternalExtractorEdge &a, const InternalExtractorEdge &b) const
|
||||
{
|
||||
return a.target < b.target;
|
||||
}
|
||||
|
||||
value_type max_value() { return InternalExtractorEdge::max_value(); }
|
||||
|
||||
value_type min_value() { return InternalExtractorEdge::min_value(); }
|
||||
};
|
||||
|
||||
#endif // INTERNAL_EXTRACTOR_EDGE_H
|
||||
@@ -1,640 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "PBFParser.h"
|
||||
|
||||
#include "ExtractionWay.h"
|
||||
#include "ExtractorCallbacks.h"
|
||||
#include "ScriptingEnvironment.h"
|
||||
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../Util/MachineInfo.h"
|
||||
#include "../Util/OpenMPWrapper.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/ref.hpp>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <thread>
|
||||
|
||||
PBFParser::PBFParser(const char *fileName,
|
||||
ExtractorCallbacks *extractor_callbacks,
|
||||
ScriptingEnvironment &scripting_environment)
|
||||
: BaseParser(extractor_callbacks, scripting_environment)
|
||||
{
|
||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||
// TODO: What is the bottleneck here? Filling the queue or reading the stuff from disk?
|
||||
// NOTE: With Lua scripting, it is parsing the stuff. I/O is virtually for free.
|
||||
|
||||
// Max 2500 items in queue, hardcoded.
|
||||
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]),
|
||||
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()
|
||||
{
|
||||
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].id = m_lastDenseID;
|
||||
extracted_nodes_vector[i].lat =
|
||||
COORDINATE_PRECISION *
|
||||
((double)m_lastDenseLatitude * thread_data->PBFprimitiveBlock.granularity() +
|
||||
thread_data->PBFprimitiveBlock.lat_offset()) /
|
||||
NANO;
|
||||
extracted_nodes_vector[i].lon =
|
||||
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.emplace(key, value);
|
||||
denseTagIndex += 2;
|
||||
}
|
||||
}
|
||||
#pragma omp parallel
|
||||
{
|
||||
const int thread_num = omp_get_thread_num();
|
||||
#pragma omp parallel for schedule(guided)
|
||||
for (int i = 0; i < number_of_nodes; ++i)
|
||||
{
|
||||
ImportNode &import_node = extracted_nodes_vector[i];
|
||||
ParseNodeInLua(import_node, scripting_environment.getLuaStateForThreadID(thread_num));
|
||||
}
|
||||
}
|
||||
|
||||
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 isRestriction = false;
|
||||
bool isOnlyRestriction = 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)
|
||||
{
|
||||
isRestriction = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (("restriction" == key) && (val.find("only_") == 0))
|
||||
{
|
||||
isOnlyRestriction = true;
|
||||
}
|
||||
if ("except" == key)
|
||||
{
|
||||
except_tag_string = val;
|
||||
}
|
||||
}
|
||||
|
||||
if (isRestriction && ShouldIgnoreRestriction(except_tag_string))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isRestriction)
|
||||
{
|
||||
int64_t lastRef = 0;
|
||||
InputRestrictionContainer currentRestrictionContainer(isOnlyRestriction);
|
||||
for (int rolesIndex = 0, last_role = inputRelation.roles_sid_size();
|
||||
rolesIndex < last_role;
|
||||
++rolesIndex)
|
||||
{
|
||||
const std::string &role = thread_data->PBFprimitiveBlock.stringtable().s(
|
||||
inputRelation.roles_sid(rolesIndex));
|
||||
lastRef += inputRelation.memids(rolesIndex);
|
||||
|
||||
if (!("from" == role || "to" == role || "via" == role))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (inputRelation.types(rolesIndex))
|
||||
{
|
||||
case 0: // node
|
||||
if ("from" == role || "to" == role)
|
||||
{ // Only via should be a node
|
||||
continue;
|
||||
}
|
||||
assert("via" == role);
|
||||
if (std::numeric_limits<unsigned>::max() != currentRestrictionContainer.viaNode)
|
||||
{
|
||||
currentRestrictionContainer.viaNode = std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
assert(std::numeric_limits<unsigned>::max() == currentRestrictionContainer.viaNode);
|
||||
currentRestrictionContainer.restriction.viaNode = lastRef;
|
||||
break;
|
||||
case 1: // way
|
||||
assert("from" == role || "to" == role || "via" == role);
|
||||
if ("from" == role)
|
||||
{
|
||||
currentRestrictionContainer.fromWay = lastRef;
|
||||
}
|
||||
if ("to" == role)
|
||||
{
|
||||
currentRestrictionContainer.toWay = lastRef;
|
||||
}
|
||||
if ("via" == role)
|
||||
{
|
||||
assert(currentRestrictionContainer.restriction.toNode == std::numeric_limits<unsigned>::max());
|
||||
currentRestrictionContainer.viaNode = lastRef;
|
||||
}
|
||||
break;
|
||||
case 2: // relation, not used. relations relating to relations are evil.
|
||||
continue;
|
||||
assert(false);
|
||||
break;
|
||||
|
||||
default: // should not happen
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!extractor_callbacks->ProcessRestriction(currentRestrictionContainer))
|
||||
{
|
||||
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 &inputWay =
|
||||
thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID).ways(i);
|
||||
parsed_way_vector[i].id = inputWay.id();
|
||||
unsigned pathNode(0);
|
||||
const int number_of_referenced_nodes = inputWay.refs_size();
|
||||
for (int j = 0; j < number_of_referenced_nodes; ++j)
|
||||
{
|
||||
pathNode += inputWay.refs(j);
|
||||
parsed_way_vector[i].path.push_back(pathNode);
|
||||
}
|
||||
assert(inputWay.keys_size() == inputWay.vals_size());
|
||||
const int number_of_keys = inputWay.keys_size();
|
||||
for (int j = 0; j < number_of_keys; ++j)
|
||||
{
|
||||
const std::string &key =
|
||||
thread_data->PBFprimitiveBlock.stringtable().s(inputWay.keys(j));
|
||||
const std::string &val =
|
||||
thread_data->PBFprimitiveBlock.stringtable().s(inputWay.vals(j));
|
||||
parsed_way_vector[i].keyVals.emplace(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma omp parallel for schedule(guided)
|
||||
for (int i = 0; i < number_of_ways; ++i)
|
||||
{
|
||||
ExtractionWay &extraction_way = parsed_way_vector[i];
|
||||
if (2 <= extraction_way.path.size())
|
||||
{
|
||||
ParseWayInLua(extraction_way,
|
||||
scripting_environment.getLuaStateForThreadID(omp_get_thread_num()));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
assert(0 != group.dense().id_size());
|
||||
}
|
||||
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(std::fstream &, ParserThreadData *thread_data)
|
||||
{
|
||||
unsigned rawSize = thread_data->PBFBlob.raw_size();
|
||||
char *unpackedDataArray = new char[rawSize];
|
||||
z_stream compressedDataStream;
|
||||
compressedDataStream.next_in = (unsigned char *)thread_data->PBFBlob.zlib_data().data();
|
||||
compressedDataStream.avail_in = thread_data->PBFBlob.zlib_data().size();
|
||||
compressedDataStream.next_out = (unsigned char *)unpackedDataArray;
|
||||
compressedDataStream.avail_out = rawSize;
|
||||
compressedDataStream.zalloc = Z_NULL;
|
||||
compressedDataStream.zfree = Z_NULL;
|
||||
compressedDataStream.opaque = Z_NULL;
|
||||
int ret = inflateInit(&compressedDataStream);
|
||||
if (ret != Z_OK)
|
||||
{
|
||||
std::cerr << "[error] failed to init zlib stream" << std::endl;
|
||||
delete[] unpackedDataArray;
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = inflate(&compressedDataStream, Z_FINISH);
|
||||
if (ret != Z_STREAM_END)
|
||||
{
|
||||
std::cerr << "[error] failed to inflate zlib stream" << std::endl;
|
||||
std::cerr << "[error] Error type: " << ret << std::endl;
|
||||
delete[] unpackedDataArray;
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = inflateEnd(&compressedDataStream);
|
||||
if (ret != Z_OK)
|
||||
{
|
||||
std::cerr << "[error] failed to deinit zlib stream" << std::endl;
|
||||
delete[] unpackedDataArray;
|
||||
return false;
|
||||
}
|
||||
|
||||
thread_data->charBuffer.clear();
|
||||
thread_data->charBuffer.resize(rawSize);
|
||||
std::copy(unpackedDataArray, unpackedDataArray + rawSize, thread_data->charBuffer.begin());
|
||||
delete[] unpackedDataArray;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool PBFParser::unpackLZMA(std::fstream &, 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(stream, 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(stream, 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,99 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef 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);
|
||||
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(std::fstream &stream, ParserThreadData *thread_data);
|
||||
inline bool unpackLZMA(std::fstream &stream, 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;
|
||||
};
|
||||
|
||||
#endif /* PBFPARSER_H_ */
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "ScriptingEnvironment.h"
|
||||
|
||||
#include "ExtractionHelperFunctions.h"
|
||||
#include "ExtractionWay.h"
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
#include "../Util/LuaUtil.h"
|
||||
#include "../Util/OpenMPWrapper.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
ScriptingEnvironment::ScriptingEnvironment() {}
|
||||
ScriptingEnvironment::ScriptingEnvironment(const char *file_name)
|
||||
{
|
||||
SimpleLogger().Write() << "Using script " << file_name;
|
||||
|
||||
// Create a new lua state
|
||||
for (int i = 0; i < omp_get_max_threads(); ++i)
|
||||
{
|
||||
lua_state_vector.push_back(luaL_newstate());
|
||||
}
|
||||
|
||||
// Connect LuaBind to this lua state for all threads
|
||||
#pragma omp parallel
|
||||
{
|
||||
lua_State *lua_state = getLuaStateForThreadID(omp_get_thread_num());
|
||||
luabind::open(lua_state);
|
||||
// open utility libraries string library;
|
||||
luaL_openlibs(lua_state);
|
||||
|
||||
luaAddScriptFolderToLoadPath(lua_state, file_name);
|
||||
|
||||
// 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::module(lua_state)[luabind::class_<HashTable<std::string, std::string>>("keyVals")
|
||||
.def("Add", &HashTable<std::string, std::string>::Add)
|
||||
.def("Find", &HashTable<std::string, std::string>::Find)
|
||||
.def("Holds", &HashTable<std::string, std::string>::Holds)];
|
||||
|
||||
luabind::module(lua_state)[luabind::class_<ImportNode>("Node")
|
||||
.def(luabind::constructor<>())
|
||||
.def_readwrite("lat", &ImportNode::lat)
|
||||
.def_readwrite("lon", &ImportNode::lon)
|
||||
.def_readonly("id", &ImportNode::id)
|
||||
.def_readwrite("bollard", &ImportNode::bollard)
|
||||
.def_readwrite("traffic_light", &ImportNode::trafficLight)
|
||||
.def_readwrite("tags", &ImportNode::keyVals)];
|
||||
|
||||
luabind::module(lua_state)
|
||||
[luabind::class_<ExtractionWay>("Way")
|
||||
.def(luabind::constructor<>())
|
||||
.def_readonly("id", &ExtractionWay::id)
|
||||
.def_readwrite("name", &ExtractionWay::name)
|
||||
.def_readwrite("speed", &ExtractionWay::speed)
|
||||
.def_readwrite("backward_speed", &ExtractionWay::backward_speed)
|
||||
.def_readwrite("duration", &ExtractionWay::duration)
|
||||
.def_readwrite("type", &ExtractionWay::type)
|
||||
.def_readwrite("access", &ExtractionWay::access)
|
||||
.def_readwrite("roundabout", &ExtractionWay::roundabout)
|
||||
.def_readwrite("is_access_restricted", &ExtractionWay::isAccessRestricted)
|
||||
.def_readwrite("ignore_in_grid", &ExtractionWay::ignoreInGrid)
|
||||
.def_readwrite("tags", &ExtractionWay::keyVals)
|
||||
.def_readwrite("direction", &ExtractionWay::direction)
|
||||
.enum_("constants")[
|
||||
luabind::value("notSure", 0),
|
||||
luabind::value("oneway", 1),
|
||||
luabind::value("bidirectional", 2),
|
||||
luabind::value("opposite", 3)
|
||||
]];
|
||||
|
||||
// fails on c++11/OS X 10.9
|
||||
luabind::module(lua_state)[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))
|
||||
{
|
||||
throw OSRMException("ERROR occured in scripting block");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScriptingEnvironment::~ScriptingEnvironment()
|
||||
{
|
||||
for (unsigned i = 0; i < lua_state_vector.size(); ++i)
|
||||
{
|
||||
// lua_state_vector[i];
|
||||
}
|
||||
}
|
||||
|
||||
lua_State *ScriptingEnvironment::getLuaStateForThreadID(const int id) { return lua_state_vector[id]; }
|
||||
@@ -1,347 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "XMLParser.h"
|
||||
|
||||
#include "ExtractionWay.h"
|
||||
#include "ExtractorCallbacks.h"
|
||||
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
#include "../DataStructures/InputReaderFactory.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/ref.hpp>
|
||||
|
||||
XMLParser::XMLParser(const char *filename, ExtractorCallbacks *ec, ScriptingEnvironment &se)
|
||||
: BaseParser(ec, se)
|
||||
{
|
||||
inputReader = inputReaderFactory(filename);
|
||||
}
|
||||
|
||||
bool XMLParser::ReadHeader() { return (xmlTextReaderRead(inputReader) == 1); }
|
||||
bool XMLParser::Parse()
|
||||
{
|
||||
while (xmlTextReaderRead(inputReader) == 1)
|
||||
{
|
||||
const int type = xmlTextReaderNodeType(inputReader);
|
||||
|
||||
// 1 is Element
|
||||
if (type != 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
xmlChar *currentName = xmlTextReaderName(inputReader);
|
||||
if (currentName == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(currentName, (const xmlChar *)"node") == 1)
|
||||
{
|
||||
ImportNode n = ReadXMLNode();
|
||||
ParseNodeInLua(n, lua_state);
|
||||
extractor_callbacks->ProcessNode(n);
|
||||
}
|
||||
|
||||
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 r = ReadXMLRestriction();
|
||||
if ((UINT_MAX != r.fromWay) && !extractor_callbacks->ProcessRestriction(r))
|
||||
{
|
||||
std::cerr << "[XMLParser] restriction not parsed" << std::endl;
|
||||
}
|
||||
}
|
||||
xmlFree(currentName);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
InputRestrictionContainer XMLParser::ReadXMLRestriction()
|
||||
{
|
||||
InputRestrictionContainer restriction;
|
||||
std::string except_tag_string;
|
||||
|
||||
if (xmlTextReaderIsEmptyElement(inputReader) != 1)
|
||||
{
|
||||
const int depth = xmlTextReaderDepth(inputReader);
|
||||
while (xmlTextReaderRead(inputReader) == 1)
|
||||
{
|
||||
const int childType = xmlTextReaderNodeType(inputReader);
|
||||
if (childType != 1 && childType != 15)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const int childDepth = xmlTextReaderDepth(inputReader);
|
||||
xmlChar *childName = xmlTextReaderName(inputReader);
|
||||
if (childName == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (depth == childDepth && childType == 15 &&
|
||||
xmlStrEqual(childName, (const xmlChar *)"relation") == 1)
|
||||
{
|
||||
xmlFree(childName);
|
||||
break;
|
||||
}
|
||||
if (childType != 1)
|
||||
{
|
||||
xmlFree(childName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(childName, (const xmlChar *)"tag") == 1)
|
||||
{
|
||||
xmlChar *k = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
|
||||
xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
|
||||
if (k != NULL && value != NULL)
|
||||
{
|
||||
if (xmlStrEqual(k, (const xmlChar *)"restriction") &&
|
||||
(0 == std::string((const char *)value).find("only_")))
|
||||
{
|
||||
restriction.restriction.flags.isOnly = true;
|
||||
}
|
||||
if (xmlStrEqual(k, (const xmlChar *)"except"))
|
||||
{
|
||||
except_tag_string = (const char *)value;
|
||||
}
|
||||
}
|
||||
|
||||
if (k != NULL)
|
||||
{
|
||||
xmlFree(k);
|
||||
}
|
||||
if (value != NULL)
|
||||
{
|
||||
xmlFree(value);
|
||||
}
|
||||
}
|
||||
else if (xmlStrEqual(childName, (const xmlChar *)"member") == 1)
|
||||
{
|
||||
xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref");
|
||||
if (ref != NULL)
|
||||
{
|
||||
xmlChar *role = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"role");
|
||||
xmlChar *type = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"type");
|
||||
|
||||
if (xmlStrEqual(role, (const xmlChar *)"to") &&
|
||||
xmlStrEqual(type, (const xmlChar *)"way"))
|
||||
{
|
||||
restriction.toWay = stringToUint((const char *)ref);
|
||||
}
|
||||
if (xmlStrEqual(role, (const xmlChar *)"from") &&
|
||||
xmlStrEqual(type, (const xmlChar *)"way"))
|
||||
{
|
||||
restriction.fromWay = stringToUint((const char *)ref);
|
||||
}
|
||||
if (xmlStrEqual(role, (const xmlChar *)"via") &&
|
||||
xmlStrEqual(type, (const xmlChar *)"node"))
|
||||
{
|
||||
restriction.restriction.viaNode = stringToUint((const char *)ref);
|
||||
}
|
||||
|
||||
if (NULL != type)
|
||||
{
|
||||
xmlFree(type);
|
||||
}
|
||||
if (NULL != role)
|
||||
{
|
||||
xmlFree(role);
|
||||
}
|
||||
if (NULL != ref)
|
||||
{
|
||||
xmlFree(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlFree(childName);
|
||||
}
|
||||
}
|
||||
|
||||
if (ShouldIgnoreRestriction(except_tag_string))
|
||||
{
|
||||
restriction.fromWay = UINT_MAX; // workaround to ignore the restriction
|
||||
}
|
||||
return restriction;
|
||||
}
|
||||
|
||||
ExtractionWay XMLParser::ReadXMLWay()
|
||||
{
|
||||
ExtractionWay way;
|
||||
if (xmlTextReaderIsEmptyElement(inputReader) != 1)
|
||||
{
|
||||
const int depth = xmlTextReaderDepth(inputReader);
|
||||
while (xmlTextReaderRead(inputReader) == 1)
|
||||
{
|
||||
const int childType = xmlTextReaderNodeType(inputReader);
|
||||
if (childType != 1 && childType != 15)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const int childDepth = xmlTextReaderDepth(inputReader);
|
||||
xmlChar *childName = xmlTextReaderName(inputReader);
|
||||
if (childName == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (depth == childDepth && childType == 15 &&
|
||||
xmlStrEqual(childName, (const xmlChar *)"way") == 1)
|
||||
{
|
||||
xmlChar *id = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id");
|
||||
way.id = stringToUint((char *)id);
|
||||
xmlFree(id);
|
||||
xmlFree(childName);
|
||||
break;
|
||||
}
|
||||
if (childType != 1)
|
||||
{
|
||||
xmlFree(childName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(childName, (const xmlChar *)"tag") == 1)
|
||||
{
|
||||
xmlChar *k = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
|
||||
xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
|
||||
|
||||
if (k != NULL && value != NULL)
|
||||
{
|
||||
way.keyVals.Add(std::string((char *)k), std::string((char *)value));
|
||||
}
|
||||
if (k != NULL)
|
||||
{
|
||||
xmlFree(k);
|
||||
}
|
||||
if (value != NULL)
|
||||
{
|
||||
xmlFree(value);
|
||||
}
|
||||
}
|
||||
else if (xmlStrEqual(childName, (const xmlChar *)"nd") == 1)
|
||||
{
|
||||
xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref");
|
||||
if (ref != NULL)
|
||||
{
|
||||
way.path.push_back(stringToUint((const char *)ref));
|
||||
xmlFree(ref);
|
||||
}
|
||||
}
|
||||
xmlFree(childName);
|
||||
}
|
||||
}
|
||||
return way;
|
||||
}
|
||||
|
||||
ImportNode XMLParser::ReadXMLNode()
|
||||
{
|
||||
ImportNode node;
|
||||
|
||||
xmlChar *attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"lat");
|
||||
if (attribute != NULL)
|
||||
{
|
||||
node.lat = COORDINATE_PRECISION * StringToDouble((const char *)attribute);
|
||||
xmlFree(attribute);
|
||||
}
|
||||
attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"lon");
|
||||
if (attribute != NULL)
|
||||
{
|
||||
node.lon = COORDINATE_PRECISION * StringToDouble((const char *)attribute);
|
||||
xmlFree(attribute);
|
||||
}
|
||||
attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id");
|
||||
if (attribute != NULL)
|
||||
{
|
||||
node.id = stringToUint((const char *)attribute);
|
||||
xmlFree(attribute);
|
||||
}
|
||||
|
||||
if (xmlTextReaderIsEmptyElement(inputReader) != 1)
|
||||
{
|
||||
const int depth = xmlTextReaderDepth(inputReader);
|
||||
while (xmlTextReaderRead(inputReader) == 1)
|
||||
{
|
||||
const int childType = xmlTextReaderNodeType(inputReader);
|
||||
// 1 = Element, 15 = EndElement
|
||||
if (childType != 1 && childType != 15)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const int childDepth = xmlTextReaderDepth(inputReader);
|
||||
xmlChar *childName = xmlTextReaderName(inputReader);
|
||||
if (childName == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (depth == childDepth && childType == 15 &&
|
||||
xmlStrEqual(childName, (const xmlChar *)"node") == 1)
|
||||
{
|
||||
xmlFree(childName);
|
||||
break;
|
||||
}
|
||||
if (childType != 1)
|
||||
{
|
||||
xmlFree(childName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(childName, (const xmlChar *)"tag") == 1)
|
||||
{
|
||||
xmlChar *k = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
|
||||
xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
|
||||
if (k != NULL && value != NULL)
|
||||
{
|
||||
node.keyVals.emplace(std::string((char *)(k)), std::string((char *)(value)));
|
||||
}
|
||||
if (k != NULL)
|
||||
{
|
||||
xmlFree(k);
|
||||
}
|
||||
if (value != NULL)
|
||||
{
|
||||
xmlFree(value);
|
||||
}
|
||||
}
|
||||
|
||||
xmlFree(childName);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef XMLPARSER_H_
|
||||
#define XMLPARSER_H_
|
||||
|
||||
#include "ExtractorCallbacks.h"
|
||||
#include "BaseParser.h"
|
||||
|
||||
#include <libxml/xmlreader.h>
|
||||
|
||||
class XMLParser : public BaseParser
|
||||
{
|
||||
public:
|
||||
XMLParser(const char *filename, ExtractorCallbacks *ec, ScriptingEnvironment &se);
|
||||
bool ReadHeader();
|
||||
bool Parse();
|
||||
|
||||
private:
|
||||
InputRestrictionContainer ReadXMLRestriction();
|
||||
ExtractionWay ReadXMLWay();
|
||||
ImportNode ReadXMLNode();
|
||||
xmlTextReaderPtr inputReader;
|
||||
};
|
||||
|
||||
#endif /* XMLPARSER_H_ */
|
||||
@@ -4,4 +4,4 @@ gem "cucumber"
|
||||
gem "rake"
|
||||
gem "osmlib-base"
|
||||
gem "sys-proctable"
|
||||
gem "rspec-expectations"
|
||||
gem "rspec-expectations"
|
||||
|
||||
+16
-11
@@ -2,22 +2,27 @@ GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
builder (3.2.2)
|
||||
cucumber (1.3.8)
|
||||
cucumber (2.0.0)
|
||||
builder (>= 2.1.2)
|
||||
cucumber-core (~> 1.1.3)
|
||||
diff-lcs (>= 1.1.3)
|
||||
gherkin (~> 2.12.1)
|
||||
gherkin (~> 2.12)
|
||||
multi_json (>= 1.7.5, < 2.0)
|
||||
multi_test (>= 0.0.2)
|
||||
diff-lcs (1.2.4)
|
||||
gherkin (2.12.1)
|
||||
multi_test (>= 0.1.2)
|
||||
cucumber-core (1.1.3)
|
||||
gherkin (~> 2.12.0)
|
||||
diff-lcs (1.2.5)
|
||||
gherkin (2.12.2)
|
||||
multi_json (~> 1.3)
|
||||
multi_json (1.8.0)
|
||||
multi_test (0.0.2)
|
||||
multi_json (1.11.0)
|
||||
multi_test (0.1.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)
|
||||
rake (10.4.2)
|
||||
rspec-expectations (3.2.1)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.2.0)
|
||||
rspec-support (3.2.2)
|
||||
sys-proctable (0.9.8)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef FIXED_POINT_COORDINATE_H_
|
||||
#define FIXED_POINT_COORDINATE_H_
|
||||
|
||||
#include <iosfwd> //for std::ostream
|
||||
|
||||
constexpr double COORDINATE_PRECISION = 1000000.;
|
||||
|
||||
struct FixedPointCoordinate
|
||||
{
|
||||
int lat;
|
||||
int lon;
|
||||
|
||||
FixedPointCoordinate();
|
||||
explicit FixedPointCoordinate(int lat, int lon);
|
||||
void Reset();
|
||||
bool isSet() const;
|
||||
bool isValid() const;
|
||||
bool operator==(const FixedPointCoordinate &other) const;
|
||||
|
||||
static double
|
||||
ApproximateDistance(const int lat1, const int lon1, const int lat2, const int lon2);
|
||||
|
||||
static double ApproximateDistance(const FixedPointCoordinate &c1,
|
||||
const FixedPointCoordinate &c2);
|
||||
|
||||
static double ApproximateEuclideanDistance(const FixedPointCoordinate &c1,
|
||||
const FixedPointCoordinate &c2);
|
||||
|
||||
static double
|
||||
ApproximateEuclideanDistance(const int lat1, const int lon1, const int lat2, const int lon2);
|
||||
|
||||
static void convertInternalLatLonToString(const int value, std::string &output);
|
||||
|
||||
static void convertInternalCoordinateToString(const FixedPointCoordinate &coord,
|
||||
std::string &output);
|
||||
|
||||
static void convertInternalReversedCoordinateToString(const FixedPointCoordinate &coord,
|
||||
std::string &output);
|
||||
|
||||
static double ComputePerpendicularDistance(const FixedPointCoordinate &point,
|
||||
const FixedPointCoordinate &segA,
|
||||
const FixedPointCoordinate &segB);
|
||||
|
||||
static double ComputePerpendicularDistance(const FixedPointCoordinate &coord_a,
|
||||
const FixedPointCoordinate &coord_b,
|
||||
const FixedPointCoordinate &query_location,
|
||||
FixedPointCoordinate &nearest_location,
|
||||
double &r);
|
||||
|
||||
void Output(std::ostream &out) const;
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &o, FixedPointCoordinate const &c)
|
||||
{
|
||||
c.Output(o);
|
||||
return o;
|
||||
}
|
||||
|
||||
#endif /* FIXED_POINT_COORDINATE_H_ */
|
||||
@@ -1,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<std::string> content;
|
||||
static Reply StockReply(status_type status);
|
||||
void setSize(const unsigned size);
|
||||
void SetUncompressedSize();
|
||||
|
||||
Reply();
|
||||
|
||||
private:
|
||||
std::string ToString(Reply::status_type status);
|
||||
boost::asio::const_buffer ToBuffer(Reply::status_type status);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // REPLY_H
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "OSRM_impl.h"
|
||||
#include "OSRM.h"
|
||||
|
||||
#include "../Plugins/HelloWorldPlugin.h"
|
||||
#include "../Plugins/LocatePlugin.h"
|
||||
#include "../Plugins/NearestPlugin.h"
|
||||
#include "../Plugins/TimestampPlugin.h"
|
||||
#include "../Plugins/ViaRoutePlugin.h"
|
||||
|
||||
#include "../Server/DataStructures/BaseDataFacade.h"
|
||||
#include "../Server/DataStructures/InternalDataFacade.h"
|
||||
#include "../Server/DataStructures/SharedBarriers.h"
|
||||
#include "../Server/DataStructures/SharedDataFacade.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
OSRM_impl::OSRM_impl(const ServerPaths &server_paths, const bool use_shared_memory)
|
||||
: use_shared_memory(use_shared_memory)
|
||||
{
|
||||
if (use_shared_memory)
|
||||
{
|
||||
barrier = new SharedBarriers();
|
||||
query_data_facade = new SharedDataFacade<QueryEdge::EdgeData>();
|
||||
}
|
||||
else
|
||||
{
|
||||
query_data_facade = new InternalDataFacade<QueryEdge::EdgeData>(server_paths);
|
||||
}
|
||||
|
||||
// The following plugins handle all requests.
|
||||
RegisterPlugin(new HelloWorldPlugin());
|
||||
RegisterPlugin(new LocatePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
|
||||
RegisterPlugin(new NearestPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
|
||||
RegisterPlugin(new TimestampPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
|
||||
RegisterPlugin(new ViaRoutePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
|
||||
}
|
||||
|
||||
OSRM_impl::~OSRM_impl()
|
||||
{
|
||||
for (PluginMap::value_type &plugin_pointer : plugin_map)
|
||||
{
|
||||
delete plugin_pointer.second;
|
||||
}
|
||||
if (use_shared_memory)
|
||||
{
|
||||
delete barrier;
|
||||
}
|
||||
}
|
||||
|
||||
void OSRM_impl::RegisterPlugin(BasePlugin *plugin)
|
||||
{
|
||||
SimpleLogger().Write() << "loaded plugin: " << plugin->GetDescriptor();
|
||||
if (plugin_map.find(plugin->GetDescriptor()) != plugin_map.end())
|
||||
{
|
||||
delete plugin_map.find(plugin->GetDescriptor())->second;
|
||||
}
|
||||
plugin_map.emplace(plugin->GetDescriptor(), plugin);
|
||||
}
|
||||
|
||||
void OSRM_impl::RunQuery(RouteParameters &route_parameters, http::Reply &reply)
|
||||
{
|
||||
const PluginMap::const_iterator &iter = plugin_map.find(route_parameters.service);
|
||||
|
||||
if (plugin_map.end() != iter)
|
||||
{
|
||||
reply.status = http::Reply::ok;
|
||||
if (use_shared_memory)
|
||||
{
|
||||
// lock update pending
|
||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> pending_lock(
|
||||
barrier->pending_update_mutex);
|
||||
|
||||
// lock query
|
||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
|
||||
barrier->query_mutex);
|
||||
|
||||
// unlock update pending
|
||||
pending_lock.unlock();
|
||||
|
||||
// increment query count
|
||||
++(barrier->number_of_queries);
|
||||
|
||||
(static_cast<SharedDataFacade<QueryEdge::EdgeData> *>(query_data_facade))
|
||||
->CheckAndReloadFacade();
|
||||
}
|
||||
|
||||
iter->second->HandleRequest(route_parameters, reply);
|
||||
if (use_shared_memory)
|
||||
{
|
||||
// lock query
|
||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
|
||||
barrier->query_mutex);
|
||||
|
||||
// decrement query count
|
||||
--(barrier->number_of_queries);
|
||||
BOOST_ASSERT_MSG(0 <= barrier->number_of_queries, "invalid number of queries");
|
||||
|
||||
// notify all processes that were waiting for this condition
|
||||
if (0 == barrier->number_of_queries)
|
||||
{
|
||||
barrier->no_running_queries_condition.notify_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
}
|
||||
}
|
||||
|
||||
// proxy code for compilation firewall
|
||||
|
||||
OSRM::OSRM(const ServerPaths &paths, const bool use_shared_memory)
|
||||
: OSRM_pimpl_(new OSRM_impl(paths, use_shared_memory))
|
||||
{
|
||||
}
|
||||
|
||||
OSRM::~OSRM() { delete OSRM_pimpl_; }
|
||||
|
||||
void OSRM::RunQuery(RouteParameters &route_parameters, http::Reply &reply)
|
||||
{
|
||||
OSRM_pimpl_->RunQuery(route_parameters, reply);
|
||||
}
|
||||
@@ -1,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 HELLOWORLDPLUGIN_H_
|
||||
#define HELLOWORLDPLUGIN_H_
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class HelloWorldPlugin : public BasePlugin
|
||||
{
|
||||
private:
|
||||
std::string temp_string;
|
||||
|
||||
public:
|
||||
HelloWorldPlugin() : descriptor_string("hello") {}
|
||||
virtual ~HelloWorldPlugin() {}
|
||||
const std::string GetDescriptor() const { return descriptor_string; }
|
||||
|
||||
void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply)
|
||||
{
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.emplace_back("<html><head><title>Hello World Demonstration "
|
||||
"Document</title></head><body><h1>Hello, World!</h1>");
|
||||
reply.content.emplace_back("<pre>");
|
||||
reply.content.emplace_back("zoom level: ");
|
||||
intToString(routeParameters.zoom_level, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("\nchecksum: ");
|
||||
intToString(routeParameters.check_sum, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("\ninstructions: ");
|
||||
reply.content.emplace_back((routeParameters.print_instructions ? "yes" : "no"));
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("\ngeometry: ");
|
||||
reply.content.emplace_back((routeParameters.geometry ? "yes" : "no"));
|
||||
reply.content.emplace_back("\ncompression: ");
|
||||
reply.content.emplace_back((routeParameters.compression ? "yes" : "no"));
|
||||
reply.content.emplace_back("\noutput format: ");
|
||||
reply.content.emplace_back(routeParameters.output_format);
|
||||
reply.content.emplace_back("\njson parameter: ");
|
||||
reply.content.emplace_back(routeParameters.jsonp_parameter);
|
||||
reply.content.emplace_back("\nlanguage: ");
|
||||
reply.content.emplace_back(routeParameters.language);
|
||||
reply.content.emplace_back("\nNumber of locations: ");
|
||||
intToString(routeParameters.coordinates.size(), temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("\n");
|
||||
|
||||
unsigned counter = 0;
|
||||
for (const FixedPointCoordinate &coordinate : routeParameters.coordinates)
|
||||
{
|
||||
reply.content.emplace_back(" [");
|
||||
intToString(counter, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("] ");
|
||||
doubleToString(coordinate.lat / COORDINATE_PRECISION, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back(",");
|
||||
doubleToString(coordinate.lon / COORDINATE_PRECISION, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("\n");
|
||||
++counter;
|
||||
}
|
||||
|
||||
reply.content.emplace_back("Number of hints: ");
|
||||
intToString(routeParameters.hints.size(), temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("\n");
|
||||
|
||||
counter = 0;
|
||||
for (const std::string ¤t_string : routeParameters.hints)
|
||||
{
|
||||
reply.content.emplace_back(" [");
|
||||
intToString(counter, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("] ");
|
||||
reply.content.emplace_back(current_string);
|
||||
reply.content.emplace_back("\n");
|
||||
++counter;
|
||||
}
|
||||
reply.content.emplace_back("</pre></body></html>");
|
||||
}
|
||||
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
#endif /* HELLOWORLDPLUGIN_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 LOCATE_PLUGIN_H
|
||||
#define LOCATE_PLUGIN_H
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
// locates the nearest node in the road network for a given coordinate.
|
||||
|
||||
template <class DataFacadeT> class LocatePlugin : public BasePlugin
|
||||
{
|
||||
public:
|
||||
explicit LocatePlugin(DataFacadeT *facade) : descriptor_string("locate"), facade(facade) {}
|
||||
const std::string GetDescriptor() const { return descriptor_string; }
|
||||
|
||||
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
|
||||
{
|
||||
// check number of parameters
|
||||
if (route_parameters.coordinates.empty() || !route_parameters.coordinates.front().isValid())
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
// query to helpdesk
|
||||
FixedPointCoordinate result;
|
||||
std::string tmp;
|
||||
// json
|
||||
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(route_parameters.jsonp_parameter);
|
||||
reply.content.emplace_back("(");
|
||||
}
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.emplace_back("{");
|
||||
if (!facade->LocateClosestEndPointForCoordinate(route_parameters.coordinates.front(),
|
||||
result))
|
||||
{
|
||||
reply.content.emplace_back("\"status\":207,");
|
||||
reply.content.emplace_back("\"mapped_coordinate\":[]");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write coordinate to stream
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.emplace_back("\"status\":0,");
|
||||
reply.content.emplace_back("\"mapped_coordinate\":");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(result.lat, tmp);
|
||||
reply.content.emplace_back("[");
|
||||
reply.content.emplace_back(tmp);
|
||||
FixedPointCoordinate::convertInternalLatLonToString(result.lon, tmp);
|
||||
reply.content.emplace_back(",");
|
||||
reply.content.emplace_back(tmp);
|
||||
reply.content.emplace_back("]");
|
||||
}
|
||||
reply.content.emplace_back("}");
|
||||
reply.headers.resize(3);
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(")");
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.js\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.json\"";
|
||||
}
|
||||
reply.headers[0].name = "Content-Length";
|
||||
unsigned content_length = 0;
|
||||
for (const std::string &snippet : reply.content)
|
||||
{
|
||||
content_length += snippet.length();
|
||||
}
|
||||
intToString(content_length, tmp);
|
||||
reply.headers[0].value = tmp;
|
||||
return;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
DataFacadeT *facade;
|
||||
};
|
||||
|
||||
#endif /* LOCATE_PLUGIN_H */
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef NEAREST_PLUGIN_H
|
||||
#define NEAREST_PLUGIN_H
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "../DataStructures/PhantomNodes.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
/*
|
||||
* This Plugin locates the nearest point on a street in the road network for a given coordinate.
|
||||
*/
|
||||
|
||||
template <class DataFacadeT> class NearestPlugin : public BasePlugin
|
||||
{
|
||||
public:
|
||||
explicit NearestPlugin(DataFacadeT *facade) : facade(facade), descriptor_string("nearest")
|
||||
{
|
||||
descriptor_table.emplace("", 0); // default descriptor
|
||||
descriptor_table.emplace("json", 1);
|
||||
}
|
||||
|
||||
const std::string GetDescriptor() const { return descriptor_string; }
|
||||
|
||||
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
|
||||
{
|
||||
// check number of parameters
|
||||
if (route_parameters.coordinates.empty())
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
if (!route_parameters.coordinates.front().isValid())
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
PhantomNode result;
|
||||
facade->FindPhantomNodeForCoordinate(
|
||||
route_parameters.coordinates.front(), result, route_parameters.zoom_level);
|
||||
|
||||
// json
|
||||
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(route_parameters.jsonp_parameter);
|
||||
reply.content.emplace_back("(");
|
||||
}
|
||||
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.emplace_back("{\"status\":");
|
||||
if (SPECIAL_NODEID != result.forward_node_id)
|
||||
{
|
||||
reply.content.emplace_back("0,");
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.content.emplace_back("207,");
|
||||
}
|
||||
reply.content.emplace_back("\"mapped_coordinate\":[");
|
||||
std::string temp_string;
|
||||
|
||||
if (SPECIAL_NODEID != result.forward_node_id)
|
||||
{
|
||||
FixedPointCoordinate::convertInternalLatLonToString(result.location.lat, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
FixedPointCoordinate::convertInternalLatLonToString(result.location.lon, temp_string);
|
||||
reply.content.emplace_back(",");
|
||||
reply.content.emplace_back(temp_string);
|
||||
}
|
||||
reply.content.emplace_back("],\"name\":\"");
|
||||
if (SPECIAL_NODEID != result.forward_node_id)
|
||||
{
|
||||
facade->GetName(result.name_id, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
}
|
||||
reply.content.emplace_back("\"}");
|
||||
reply.headers.resize(3);
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(")");
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.js\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.json\"";
|
||||
}
|
||||
reply.headers[0].name = "Content-Length";
|
||||
unsigned content_length = 0;
|
||||
for (const std::string &snippet : reply.content)
|
||||
{
|
||||
content_length += snippet.length();
|
||||
}
|
||||
intToString(content_length, temp_string);
|
||||
reply.headers[0].value = temp_string;
|
||||
}
|
||||
|
||||
private:
|
||||
DataFacadeT *facade;
|
||||
std::unordered_map<std::string, unsigned> descriptor_table;
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
#endif /* NEAREST_PLUGIN_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 TIMESTAMP_PLUGIN_H
|
||||
#define TIMESTAMP_PLUGIN_H
|
||||
|
||||
#include "BasePlugin.h"
|
||||
|
||||
template <class DataFacadeT> class TimestampPlugin : public BasePlugin
|
||||
{
|
||||
public:
|
||||
explicit TimestampPlugin(const DataFacadeT *facade)
|
||||
: facade(facade), descriptor_string("timestamp")
|
||||
{
|
||||
}
|
||||
const std::string GetDescriptor() const { return descriptor_string; }
|
||||
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
|
||||
{
|
||||
std::string tmp;
|
||||
|
||||
// json
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(route_parameters.jsonp_parameter);
|
||||
reply.content.emplace_back("(");
|
||||
}
|
||||
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.emplace_back("{");
|
||||
reply.content.emplace_back("\"status\":");
|
||||
reply.content.emplace_back("0,");
|
||||
reply.content.emplace_back("\"timestamp\":\"");
|
||||
reply.content.emplace_back(facade->GetTimestamp());
|
||||
reply.content.emplace_back("\"");
|
||||
reply.content.emplace_back("}");
|
||||
reply.headers.resize(3);
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(")");
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"timestamp.js\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"timestamp.json\"";
|
||||
}
|
||||
unsigned content_length = 0;
|
||||
for (const std::string &snippet : reply.content)
|
||||
{
|
||||
content_length += snippet.length();
|
||||
}
|
||||
intToString(content_length, tmp);
|
||||
reply.headers[0].value = tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
const DataFacadeT *facade;
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
#endif /* TIMESTAMP_PLUGIN_H */
|
||||
@@ -1,241 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef VIAROUTEPLUGIN_H_
|
||||
#define VIAROUTEPLUGIN_H_
|
||||
|
||||
#include "BasePlugin.h"
|
||||
|
||||
#include "../Algorithms/ObjectToBase64.h"
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "../DataStructures/SearchEngine.h"
|
||||
#include "../Descriptors/BaseDescriptor.h"
|
||||
#include "../Descriptors/GPXDescriptor.h"
|
||||
#include "../Descriptors/JSONDescriptor.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
|
||||
{
|
||||
private:
|
||||
std::unordered_map<std::string, unsigned> descriptorTable;
|
||||
std::shared_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
|
||||
|
||||
public:
|
||||
explicit ViaRoutePlugin(DataFacadeT *facade) : descriptor_string("viaroute"), facade(facade)
|
||||
{
|
||||
search_engine_ptr = std::make_shared<SearchEngine<DataFacadeT>>(facade);
|
||||
|
||||
descriptorTable.emplace("json", 0);
|
||||
descriptorTable.emplace("gpx", 1);
|
||||
}
|
||||
|
||||
virtual ~ViaRoutePlugin() {}
|
||||
|
||||
const std::string GetDescriptor() const { return descriptor_string; }
|
||||
|
||||
void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply)
|
||||
{
|
||||
// check number of parameters
|
||||
if (2 > routeParameters.coordinates.size())
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
RawRouteData raw_route;
|
||||
raw_route.check_sum = facade->GetCheckSum();
|
||||
|
||||
if (std::any_of(begin(routeParameters.coordinates),
|
||||
end(routeParameters.coordinates),
|
||||
[&](FixedPointCoordinate coordinate)
|
||||
{ return !coordinate.isValid(); }))
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const FixedPointCoordinate &coordinate : routeParameters.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 = (routeParameters.check_sum == raw_route.check_sum);
|
||||
|
||||
for (unsigned i = 0; i < raw_route.raw_via_node_coordinates.size(); ++i)
|
||||
{
|
||||
if (checksum_OK && i < routeParameters.hints.size() &&
|
||||
!routeParameters.hints[i].empty())
|
||||
{
|
||||
DecodeObjectFromBase64(routeParameters.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],
|
||||
routeParameters.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);
|
||||
}
|
||||
|
||||
if ((routeParameters.alternate_route) && (1 == raw_route.segment_end_coordinates.size()))
|
||||
{
|
||||
search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
|
||||
raw_route);
|
||||
}
|
||||
else
|
||||
{
|
||||
search_engine_ptr->shortest_path(raw_route.segment_end_coordinates, 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;
|
||||
|
||||
if (!routeParameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(routeParameters.jsonp_parameter);
|
||||
reply.content.emplace_back("(");
|
||||
}
|
||||
|
||||
DescriptorConfig descriptor_config;
|
||||
|
||||
auto iter = descriptorTable.find(routeParameters.output_format);
|
||||
unsigned descriptor_type = (iter != descriptorTable.end() ? iter->second : 0);
|
||||
|
||||
descriptor_config.zoom_level = routeParameters.zoom_level;
|
||||
descriptor_config.instructions = routeParameters.print_instructions;
|
||||
descriptor_config.geometry = routeParameters.geometry;
|
||||
descriptor_config.encode_geometry = routeParameters.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>>();
|
||||
break;
|
||||
default:
|
||||
descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>();
|
||||
break;
|
||||
}
|
||||
|
||||
PhantomNodes phantom_nodes;
|
||||
phantom_nodes.source_phantom = raw_route.segment_end_coordinates.front().source_phantom;
|
||||
phantom_nodes.target_phantom = raw_route.segment_end_coordinates.back().target_phantom;
|
||||
descriptor->SetConfig(descriptor_config);
|
||||
descriptor->Run(raw_route, phantom_nodes, facade, reply);
|
||||
|
||||
if (!routeParameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(")\n");
|
||||
}
|
||||
reply.headers.resize(3);
|
||||
reply.headers[0].name = "Content-Length";
|
||||
|
||||
unsigned content_length = 0;
|
||||
for (const std::string &snippet : reply.content)
|
||||
{
|
||||
content_length += snippet.length();
|
||||
}
|
||||
std::string tmp_string;
|
||||
intToString(content_length, tmp_string);
|
||||
reply.headers[0].value = tmp_string;
|
||||
|
||||
switch (descriptor_type)
|
||||
{
|
||||
case 0:
|
||||
if (!routeParameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.js\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.json\"";
|
||||
}
|
||||
|
||||
break;
|
||||
case 1:
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/gpx+xml; charset=UTF-8";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.gpx\"";
|
||||
|
||||
break;
|
||||
default:
|
||||
if (!routeParameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.js\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.json\"";
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
DataFacadeT *facade;
|
||||
};
|
||||
|
||||
#endif /* VIAROUTEPLUGIN_H_ */
|
||||
@@ -1,12 +1,25 @@
|
||||
# Readme
|
||||
## About
|
||||
|
||||
For instructions on how to compile and run OSRM, please consult the Wiki at
|
||||
The Open Source Routing Machine is a high performance routing engine written in C++11 designed to run on OpenStreetMap data.
|
||||
|
||||
https://github.com/DennisOSRM/Project-OSRM/wiki
|
||||
## Current build status
|
||||
|
||||
or use our free and daily updated online service at
|
||||
| build config | branch | status |
|
||||
|:-------------|:--------|:------------|
|
||||
| Linux | master | [](https://travis-ci.org/Project-OSRM/osrm-backend) |
|
||||
| Linux | develop | [](https://travis-ci.org/Project-OSRM/osrm-backend) |
|
||||
| Windows | master/develop | [](https://ci.appveyor.com/project/DennisOSRM/osrm-backend) |
|
||||
| LUAbind fork | master | [](https://travis-ci.org/DennisOSRM/luabind) |
|
||||
|
||||
http://map.project-osrm.org
|
||||
## Building
|
||||
|
||||
For instructions on how to [build](https://github.com/Project-OSRM/osrm-backend/wiki/Building-OSRM) and [run OSRM](https://github.com/Project-OSRM/osrm-backend/wiki/Running-OSRM), please consult [the Wiki](https://github.com/Project-OSRM/osrm-backend/wiki).
|
||||
|
||||
To quickly try OSRM use our [free and daily updated online service](http://map.project-osrm.org)
|
||||
|
||||
## Documentation
|
||||
|
||||
See the Wiki's [server API documentation](https://github.com/Project-OSRM/osrm-backend/wiki/Server-api) as well as the [library API documentation](https://github.com/Project-OSRM/osrm-backend/wiki/Library-api)
|
||||
|
||||
## References in publications
|
||||
|
||||
@@ -31,10 +44,3 @@ When using the code in a (scientific) publication, please cite
|
||||
}
|
||||
```
|
||||
|
||||
## Current build status
|
||||
|
||||
| build config | branch | status |
|
||||
|:-------------|:--------|:------------|
|
||||
| Project OSRM | master | [](https://travis-ci.org/DennisOSRM/Project-OSRM) |
|
||||
| Project OSRM | develop | [](https://travis-ci.org/DennisOSRM/Project-OSRM) |
|
||||
| LUAbind fork | master | [](https://travis-ci.org/DennisOSRM/luabind) |
|
||||
|
||||
@@ -6,7 +6,7 @@ require 'sys/proctable'
|
||||
|
||||
BUILD_FOLDER = 'build'
|
||||
DATA_FOLDER = 'sandbox'
|
||||
PROFILE = 'examples/postgis'
|
||||
PROFILE = 'bicycle'
|
||||
OSRM_PORT = 5000
|
||||
PROFILES_FOLDER = '../profiles'
|
||||
|
||||
@@ -181,3 +181,10 @@ 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
|
||||
|
||||
|
||||
@@ -1,407 +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 BASIC_ROUTING_INTERFACE_H
|
||||
#define BASIC_ROUTING_INTERFACE_H
|
||||
|
||||
#include "../DataStructures/RawRouteData.h"
|
||||
#include "../DataStructures/SearchEngineData.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../Util/ContainerUtils.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <stack>
|
||||
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap2;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap2;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap3;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap3;
|
||||
|
||||
template <class DataFacadeT> class BasicRoutingInterface
|
||||
{
|
||||
private:
|
||||
typedef typename DataFacadeT::EdgeData EdgeData;
|
||||
|
||||
protected:
|
||||
DataFacadeT *facade;
|
||||
|
||||
public:
|
||||
BasicRoutingInterface() = delete;
|
||||
BasicRoutingInterface(const BasicRoutingInterface &) = delete;
|
||||
explicit BasicRoutingInterface(DataFacadeT *facade) : facade(facade) {}
|
||||
virtual ~BasicRoutingInterface() {};
|
||||
|
||||
inline void RoutingStep(SearchEngineData::QueryHeap &forward_heap,
|
||||
SearchEngineData::QueryHeap &reverse_heap,
|
||||
NodeID *middle_node_id,
|
||||
int *upper_bound,
|
||||
const bool forward_direction) const
|
||||
{
|
||||
const NodeID node = forward_heap.DeleteMin();
|
||||
const int distance = forward_heap.GetKey(node);
|
||||
if (reverse_heap.WasInserted(node))
|
||||
{
|
||||
const int new_distance = reverse_heap.GetKey(node) + distance;
|
||||
if (new_distance < *upper_bound)
|
||||
{
|
||||
if (new_distance >= 0)
|
||||
{
|
||||
*middle_node_id = node;
|
||||
*upper_bound = new_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (distance > *upper_bound)
|
||||
{
|
||||
forward_heap.DeleteAll();
|
||||
return;
|
||||
}
|
||||
|
||||
// Stalling
|
||||
for (EdgeID edge = facade->BeginEdges(node); edge < facade->EndEdges(node); ++edge)
|
||||
{
|
||||
const EdgeData &data = facade->GetEdgeData(edge);
|
||||
const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward);
|
||||
if (reverse_flag)
|
||||
{
|
||||
const NodeID to = facade->GetTarget(edge);
|
||||
const int edge_weight = data.distance;
|
||||
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
|
||||
if (forward_heap.WasInserted(to))
|
||||
{
|
||||
if (forward_heap.GetKey(to) + edge_weight < distance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (EdgeID edge = facade->BeginEdges(node), end_edge = facade->EndEdges(node);
|
||||
edge < end_edge;
|
||||
++edge)
|
||||
{
|
||||
const EdgeData &data = facade->GetEdgeData(edge);
|
||||
bool forward_directionFlag = (forward_direction ? data.forward : data.backward);
|
||||
if (forward_directionFlag)
|
||||
{
|
||||
|
||||
const NodeID to = facade->GetTarget(edge);
|
||||
const int edge_weight = data.distance;
|
||||
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
const int to_distance = distance + edge_weight;
|
||||
|
||||
// New Node discovered -> Add to Heap + Node Info Storage
|
||||
if (!forward_heap.WasInserted(to))
|
||||
{
|
||||
forward_heap.Insert(to, to_distance, node);
|
||||
}
|
||||
// Found a shorter Path -> Update distance
|
||||
else if (to_distance < forward_heap.GetKey(to))
|
||||
{
|
||||
// new parent
|
||||
forward_heap.GetData(to).parent = node;
|
||||
forward_heap.DecreaseKey(to, to_distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void UnpackPath(const std::vector<NodeID> &packed_path,
|
||||
const PhantomNodes &phantom_node_pair,
|
||||
std::vector<PathData> &unpacked_path) const
|
||||
{
|
||||
const bool start_traversed_in_reverse =
|
||||
(packed_path.front() != phantom_node_pair.source_phantom.forward_node_id);
|
||||
const bool target_traversed_in_reverse =
|
||||
(packed_path.back() != phantom_node_pair.target_phantom.forward_node_id);
|
||||
|
||||
const unsigned packed_path_size = packed_path.size();
|
||||
std::stack<std::pair<NodeID, NodeID>> recursion_stack;
|
||||
|
||||
// We have to push the path in reverse order onto the stack because it's LIFO.
|
||||
for (unsigned i = packed_path_size - 1; i > 0; --i)
|
||||
{
|
||||
recursion_stack.emplace(packed_path[i - 1], packed_path[i]);
|
||||
}
|
||||
|
||||
std::pair<NodeID, NodeID> edge;
|
||||
while (!recursion_stack.empty())
|
||||
{
|
||||
edge = recursion_stack.top();
|
||||
recursion_stack.pop();
|
||||
|
||||
// facade->FindEdge does not suffice here in case of shortcuts.
|
||||
// The above explanation unclear? Think!
|
||||
EdgeID smaller_edge_id = SPECIAL_EDGEID;
|
||||
int edge_weight = INT_MAX;
|
||||
for (EdgeID edge_id = facade->BeginEdges(edge.first);
|
||||
edge_id < facade->EndEdges(edge.first);
|
||||
++edge_id)
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).forward)
|
||||
{
|
||||
smaller_edge_id = edge_id;
|
||||
edge_weight = weight;
|
||||
}
|
||||
}
|
||||
if (SPECIAL_EDGEID == smaller_edge_id)
|
||||
{
|
||||
for (EdgeID edge_id = facade->BeginEdges(edge.second);
|
||||
edge_id < facade->EndEdges(edge.second);
|
||||
++edge_id)
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).backward)
|
||||
{
|
||||
smaller_edge_id = edge_id;
|
||||
edge_weight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT_MSG(edge_weight != INVALID_EDGE_WEIGHT, "edge id invalid");
|
||||
|
||||
const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
|
||||
if (ed.shortcut)
|
||||
{ // unpack
|
||||
const NodeID middle_node_id = ed.id;
|
||||
// again, we need to this in reversed order
|
||||
recursion_stack.emplace(middle_node_id, edge.second);
|
||||
recursion_stack.emplace(edge.first, middle_node_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT_MSG(!ed.shortcut, "original edge flagged as shortcut");
|
||||
unsigned name_index = facade->GetNameIndexFromEdgeID(ed.id);
|
||||
const TurnInstruction turn_instruction = facade->GetTurnInstructionForEdgeID(ed.id);
|
||||
|
||||
if (!facade->EdgeIsCompressed(ed.id))
|
||||
{
|
||||
BOOST_ASSERT(!facade->EdgeIsCompressed(ed.id));
|
||||
unpacked_path.emplace_back(facade->GetGeometryIndexForEdgeID(ed.id),
|
||||
name_index,
|
||||
turn_instruction,
|
||||
ed.distance);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<unsigned> id_vector;
|
||||
facade->GetUncompressedGeometry(facade->GetGeometryIndexForEdgeID(ed.id),
|
||||
id_vector);
|
||||
|
||||
const int start_index =
|
||||
(unpacked_path.empty()
|
||||
? ((start_traversed_in_reverse)
|
||||
? id_vector.size() -
|
||||
phantom_node_pair.source_phantom.fwd_segment_position - 1
|
||||
: phantom_node_pair.source_phantom.fwd_segment_position)
|
||||
: 0);
|
||||
const int end_index = id_vector.size();
|
||||
|
||||
BOOST_ASSERT(start_index >= 0);
|
||||
BOOST_ASSERT(start_index <= end_index);
|
||||
for (int i = start_index; i < end_index; ++i)
|
||||
{
|
||||
unpacked_path.emplace_back(PathData{
|
||||
id_vector[i], name_index, TurnInstruction::NoTurn, 0});
|
||||
}
|
||||
unpacked_path.back().turn_instruction = turn_instruction;
|
||||
unpacked_path.back().segment_duration = ed.distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SPECIAL_EDGEID != phantom_node_pair.target_phantom.packed_geometry_id)
|
||||
{
|
||||
std::vector<unsigned> id_vector;
|
||||
facade->GetUncompressedGeometry(phantom_node_pair.target_phantom.packed_geometry_id,
|
||||
id_vector);
|
||||
if (target_traversed_in_reverse)
|
||||
{
|
||||
std::reverse(id_vector.begin(), id_vector.end());
|
||||
}
|
||||
const bool is_local_path = (phantom_node_pair.source_phantom.packed_geometry_id ==
|
||||
phantom_node_pair.target_phantom.packed_geometry_id) &&
|
||||
unpacked_path.empty();
|
||||
|
||||
int start_index = 0;
|
||||
int end_index = phantom_node_pair.target_phantom.fwd_segment_position;
|
||||
if (target_traversed_in_reverse)
|
||||
{
|
||||
end_index =
|
||||
id_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position;
|
||||
}
|
||||
if (is_local_path)
|
||||
{
|
||||
start_index = phantom_node_pair.source_phantom.fwd_segment_position;
|
||||
end_index = phantom_node_pair.target_phantom.fwd_segment_position;
|
||||
if (target_traversed_in_reverse)
|
||||
{
|
||||
start_index =
|
||||
id_vector.size() - phantom_node_pair.source_phantom.fwd_segment_position;
|
||||
end_index =
|
||||
id_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASSERT(start_index >= 0);
|
||||
for (int i = start_index; i != end_index; (start_index < end_index ? ++i : --i))
|
||||
{
|
||||
BOOST_ASSERT(i >= -1);
|
||||
unpacked_path.emplace_back(PathData{id_vector[i],
|
||||
phantom_node_pair.target_phantom.name_id,
|
||||
TurnInstruction::NoTurn,
|
||||
0});
|
||||
}
|
||||
}
|
||||
|
||||
// there is no equivalent to a node-based node in an edge-expanded graph.
|
||||
// two equivalent routes may start (or end) at different node-based edges
|
||||
// as they are added with the offset how much "distance" on the edge
|
||||
// has already been traversed. Depending on offset one needs to remove
|
||||
// the last node.
|
||||
if (unpacked_path.size() > 1)
|
||||
{
|
||||
const unsigned last_index = unpacked_path.size() - 1;
|
||||
const unsigned second_to_last_index = last_index - 1;
|
||||
|
||||
// looks like a trivially true check but tests for underflow
|
||||
BOOST_ASSERT(last_index > second_to_last_index);
|
||||
|
||||
if (unpacked_path[last_index].node == unpacked_path[second_to_last_index].node)
|
||||
{
|
||||
unpacked_path.pop_back();
|
||||
}
|
||||
BOOST_ASSERT(!unpacked_path.empty());
|
||||
}
|
||||
}
|
||||
|
||||
inline void UnpackEdge(const NodeID s, const NodeID t, std::vector<NodeID> &unpacked_path) const
|
||||
{
|
||||
std::stack<std::pair<NodeID, NodeID>> recursion_stack;
|
||||
recursion_stack.emplace(s, t);
|
||||
|
||||
std::pair<NodeID, NodeID> edge;
|
||||
while (!recursion_stack.empty())
|
||||
{
|
||||
edge = recursion_stack.top();
|
||||
recursion_stack.pop();
|
||||
|
||||
EdgeID smaller_edge_id = SPECIAL_EDGEID;
|
||||
int edge_weight = INT_MAX;
|
||||
for (EdgeID edge_id = facade->BeginEdges(edge.first);
|
||||
edge_id < facade->EndEdges(edge.first);
|
||||
++edge_id)
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).forward)
|
||||
{
|
||||
smaller_edge_id = edge_id;
|
||||
edge_weight = weight;
|
||||
}
|
||||
}
|
||||
|
||||
if (SPECIAL_EDGEID == smaller_edge_id)
|
||||
{
|
||||
for (EdgeID edge_id = facade->BeginEdges(edge.second);
|
||||
edge_id < facade->EndEdges(edge.second);
|
||||
++edge_id)
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).backward)
|
||||
{
|
||||
smaller_edge_id = edge_id;
|
||||
edge_weight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT_MSG(edge_weight != INT_MAX, "edge weight invalid");
|
||||
|
||||
const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
|
||||
if (ed.shortcut)
|
||||
{ // unpack
|
||||
const NodeID middle_node_id = ed.id;
|
||||
// again, we need to this in reversed order
|
||||
recursion_stack.emplace(middle_node_id, edge.second);
|
||||
recursion_stack.emplace(edge.first, middle_node_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT_MSG(!ed.shortcut, "edge must be shortcut");
|
||||
unpacked_path.emplace_back(edge.first);
|
||||
}
|
||||
}
|
||||
unpacked_path.emplace_back(t);
|
||||
}
|
||||
|
||||
inline void RetrievePackedPathFromHeap(const SearchEngineData::QueryHeap &forward_heap,
|
||||
const SearchEngineData::QueryHeap &reverse_heap,
|
||||
const NodeID middle_node_id,
|
||||
std::vector<NodeID> &packed_path) const
|
||||
{
|
||||
NodeID current_node_id = middle_node_id;
|
||||
while (current_node_id != forward_heap.GetData(current_node_id).parent)
|
||||
{
|
||||
current_node_id = forward_heap.GetData(current_node_id).parent;
|
||||
packed_path.emplace_back(current_node_id);
|
||||
}
|
||||
std::reverse(packed_path.begin(), packed_path.end());
|
||||
packed_path.emplace_back(middle_node_id);
|
||||
current_node_id = middle_node_id;
|
||||
while (current_node_id != reverse_heap.GetData(current_node_id).parent)
|
||||
{
|
||||
current_node_id = reverse_heap.GetData(current_node_id).parent;
|
||||
packed_path.emplace_back(current_node_id);
|
||||
}
|
||||
}
|
||||
|
||||
inline void RetrievePackedPathFromSingleHeap(const SearchEngineData::QueryHeap &search_heap,
|
||||
const NodeID middle_node_id,
|
||||
std::vector<NodeID> &packed_path) const
|
||||
{
|
||||
NodeID current_node_id = middle_node_id;
|
||||
while (current_node_id != search_heap.GetData(current_node_id).parent)
|
||||
{
|
||||
current_node_id = search_heap.GetData(current_node_id).parent;
|
||||
packed_path.emplace_back(current_node_id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BASIC_ROUTING_INTERFACE_H
|
||||
@@ -1,324 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SHORTEST_PATH_ROUTING_H
|
||||
#define SHORTEST_PATH_ROUTING_H
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include "BasicRoutingInterface.h"
|
||||
#include "../DataStructures/SearchEngineData.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInterface<DataFacadeT>
|
||||
{
|
||||
typedef BasicRoutingInterface<DataFacadeT> super;
|
||||
typedef SearchEngineData::QueryHeap QueryHeap;
|
||||
SearchEngineData &engine_working_data;
|
||||
|
||||
public:
|
||||
ShortestPathRouting(DataFacadeT *facade, SearchEngineData &engine_working_data)
|
||||
: super(facade), engine_working_data(engine_working_data)
|
||||
{
|
||||
}
|
||||
|
||||
~ShortestPathRouting() {}
|
||||
|
||||
void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
|
||||
RawRouteData &raw_route_data) const
|
||||
{
|
||||
for (const PhantomNodes &phantom_node_pair : phantom_nodes_vector)
|
||||
{
|
||||
if (phantom_node_pair.AtLeastOnePhantomNodeIsInvalid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
int distance1 = 0;
|
||||
int distance2 = 0;
|
||||
bool search_from_1st_node = true;
|
||||
bool search_from_2nd_node = true;
|
||||
NodeID middle1 = UINT_MAX;
|
||||
NodeID middle2 = UINT_MAX;
|
||||
std::vector<std::vector<NodeID>> packed_legs1(phantom_nodes_vector.size());
|
||||
std::vector<std::vector<NodeID>> packed_legs2(phantom_nodes_vector.size());
|
||||
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes());
|
||||
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes());
|
||||
engine_working_data.InitializeOrClearThirdThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes());
|
||||
|
||||
QueryHeap &forward_heap1 = *(engine_working_data.forwardHeap);
|
||||
QueryHeap &reverse_heap1 = *(engine_working_data.backwardHeap);
|
||||
QueryHeap &forward_heap2 = *(engine_working_data.forwardHeap2);
|
||||
QueryHeap &reverse_heap2 = *(engine_working_data.backwardHeap2);
|
||||
|
||||
int current_leg = 0;
|
||||
// Get distance to next pair of target nodes.
|
||||
for (const PhantomNodes &phantom_node_pair : phantom_nodes_vector)
|
||||
{
|
||||
forward_heap1.Clear();
|
||||
forward_heap2.Clear();
|
||||
reverse_heap1.Clear();
|
||||
reverse_heap2.Clear();
|
||||
int local_upper_bound1 = INT_MAX;
|
||||
int local_upper_bound2 = INT_MAX;
|
||||
|
||||
middle1 = UINT_MAX;
|
||||
middle2 = UINT_MAX;
|
||||
|
||||
// insert new starting nodes into forward heap, adjusted by previous distances.
|
||||
if (search_from_1st_node &&
|
||||
phantom_node_pair.source_phantom.forward_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
forward_heap1.Insert(
|
||||
phantom_node_pair.source_phantom.forward_node_id,
|
||||
distance1 - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
|
||||
phantom_node_pair.source_phantom.forward_node_id);
|
||||
forward_heap2.Insert(
|
||||
phantom_node_pair.source_phantom.forward_node_id,
|
||||
distance1 - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
|
||||
phantom_node_pair.source_phantom.forward_node_id);
|
||||
}
|
||||
if (search_from_2nd_node &&
|
||||
phantom_node_pair.source_phantom.reverse_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
forward_heap1.Insert(
|
||||
phantom_node_pair.source_phantom.reverse_node_id,
|
||||
distance2 - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
|
||||
phantom_node_pair.source_phantom.reverse_node_id);
|
||||
forward_heap2.Insert(
|
||||
phantom_node_pair.source_phantom.reverse_node_id,
|
||||
distance2 - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
|
||||
phantom_node_pair.source_phantom.reverse_node_id);
|
||||
}
|
||||
|
||||
// insert new backward nodes into backward heap, unadjusted.
|
||||
if (phantom_node_pair.target_phantom.forward_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
reverse_heap1.Insert(phantom_node_pair.target_phantom.forward_node_id,
|
||||
phantom_node_pair.target_phantom.GetForwardWeightPlusOffset(),
|
||||
phantom_node_pair.target_phantom.forward_node_id);
|
||||
}
|
||||
|
||||
if (phantom_node_pair.target_phantom.reverse_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
reverse_heap2.Insert(phantom_node_pair.target_phantom.reverse_node_id,
|
||||
phantom_node_pair.target_phantom.GetReverseWeightPlusOffset(),
|
||||
phantom_node_pair.target_phantom.reverse_node_id);
|
||||
}
|
||||
|
||||
// run two-Target Dijkstra routing step.
|
||||
while (0 < (forward_heap1.Size() + reverse_heap1.Size()))
|
||||
{
|
||||
if (0 < forward_heap1.Size())
|
||||
{
|
||||
super::RoutingStep(
|
||||
forward_heap1, reverse_heap1, &middle1, &local_upper_bound1, true);
|
||||
}
|
||||
if (0 < reverse_heap1.Size())
|
||||
{
|
||||
super::RoutingStep(
|
||||
reverse_heap1, forward_heap1, &middle1, &local_upper_bound1, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!reverse_heap2.Empty())
|
||||
{
|
||||
while (0 < (forward_heap2.Size() + reverse_heap2.Size()))
|
||||
{
|
||||
if (0 < forward_heap2.Size())
|
||||
{
|
||||
super::RoutingStep(
|
||||
forward_heap2, reverse_heap2, &middle2, &local_upper_bound2, true);
|
||||
}
|
||||
if (0 < reverse_heap2.Size())
|
||||
{
|
||||
super::RoutingStep(
|
||||
reverse_heap2, forward_heap2, &middle2, &local_upper_bound2, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No path found for both target nodes?
|
||||
if ((INVALID_EDGE_WEIGHT == local_upper_bound1) &&
|
||||
(INVALID_EDGE_WEIGHT == local_upper_bound2))
|
||||
{
|
||||
raw_route_data.shortest_path_length = INVALID_EDGE_WEIGHT;
|
||||
raw_route_data.alternative_path_length = INVALID_EDGE_WEIGHT;
|
||||
return;
|
||||
}
|
||||
if (SPECIAL_NODEID == middle1)
|
||||
{
|
||||
search_from_1st_node = false;
|
||||
}
|
||||
if (SPECIAL_NODEID == middle2)
|
||||
{
|
||||
search_from_2nd_node = false;
|
||||
}
|
||||
|
||||
// Was at most one of the two paths not found?
|
||||
BOOST_ASSERT_MSG((INT_MAX != distance1 || INT_MAX != distance2), "no path found");
|
||||
|
||||
// Unpack paths if they exist
|
||||
std::vector<NodeID> temporary_packed_leg1;
|
||||
std::vector<NodeID> temporary_packed_leg2;
|
||||
|
||||
BOOST_ASSERT((unsigned)current_leg < packed_legs1.size());
|
||||
BOOST_ASSERT((unsigned)current_leg < packed_legs2.size());
|
||||
|
||||
if (INVALID_EDGE_WEIGHT != local_upper_bound1)
|
||||
{
|
||||
super::RetrievePackedPathFromHeap(
|
||||
forward_heap1, reverse_heap1, middle1, temporary_packed_leg1);
|
||||
}
|
||||
|
||||
if (INVALID_EDGE_WEIGHT != local_upper_bound2)
|
||||
{
|
||||
super::RetrievePackedPathFromHeap(
|
||||
forward_heap2, reverse_heap2, middle2, temporary_packed_leg2);
|
||||
}
|
||||
|
||||
// if one of the paths was not found, replace it with the other one.
|
||||
if (temporary_packed_leg1.empty())
|
||||
{
|
||||
temporary_packed_leg1.insert(temporary_packed_leg1.end(),
|
||||
temporary_packed_leg2.begin(),
|
||||
temporary_packed_leg2.end());
|
||||
local_upper_bound1 = local_upper_bound2;
|
||||
}
|
||||
if (temporary_packed_leg2.empty())
|
||||
{
|
||||
temporary_packed_leg2.insert(temporary_packed_leg2.end(),
|
||||
temporary_packed_leg1.begin(),
|
||||
temporary_packed_leg1.end());
|
||||
local_upper_bound2 = local_upper_bound1;
|
||||
}
|
||||
|
||||
BOOST_ASSERT_MSG(!temporary_packed_leg1.empty() || !temporary_packed_leg2.empty(),
|
||||
"tempory packed paths empty");
|
||||
|
||||
BOOST_ASSERT((0 == current_leg) || !packed_legs1[current_leg - 1].empty());
|
||||
BOOST_ASSERT((0 == current_leg) || !packed_legs2[current_leg - 1].empty());
|
||||
|
||||
if (0 < current_leg)
|
||||
{
|
||||
const NodeID end_id_of_segment1 = packed_legs1[current_leg - 1].back();
|
||||
const NodeID end_id_of_segment2 = packed_legs2[current_leg - 1].back();
|
||||
BOOST_ASSERT(!temporary_packed_leg1.empty());
|
||||
const NodeID start_id_of_leg1 = temporary_packed_leg1.front();
|
||||
const NodeID start_id_of_leg2 = temporary_packed_leg2.front();
|
||||
if ((end_id_of_segment1 != start_id_of_leg1) &&
|
||||
(end_id_of_segment2 != start_id_of_leg2))
|
||||
{
|
||||
std::swap(temporary_packed_leg1, temporary_packed_leg2);
|
||||
std::swap(local_upper_bound1, local_upper_bound2);
|
||||
}
|
||||
}
|
||||
|
||||
// remove one path if both legs end at the same segment
|
||||
if (0 < current_leg)
|
||||
{
|
||||
const NodeID start_id_of_leg1 = temporary_packed_leg1.front();
|
||||
const NodeID start_id_of_leg2 = temporary_packed_leg2.front();
|
||||
if (start_id_of_leg1 == start_id_of_leg2)
|
||||
{
|
||||
const NodeID last_id_of_packed_legs1 = packed_legs1[current_leg - 1].back();
|
||||
const NodeID last_id_of_packed_legs2 = packed_legs2[current_leg - 1].back();
|
||||
if (start_id_of_leg1 != last_id_of_packed_legs1)
|
||||
{
|
||||
packed_legs1 = packed_legs2;
|
||||
BOOST_ASSERT(start_id_of_leg1 == temporary_packed_leg1.front());
|
||||
}
|
||||
else if (start_id_of_leg2 != last_id_of_packed_legs2)
|
||||
{
|
||||
packed_legs2 = packed_legs1;
|
||||
BOOST_ASSERT(start_id_of_leg2 == temporary_packed_leg2.front());
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT(packed_legs1.size() == packed_legs2.size());
|
||||
|
||||
packed_legs1[current_leg].insert(packed_legs1[current_leg].end(),
|
||||
temporary_packed_leg1.begin(),
|
||||
temporary_packed_leg1.end());
|
||||
BOOST_ASSERT(packed_legs1[current_leg].size() == temporary_packed_leg1.size());
|
||||
packed_legs2[current_leg].insert(packed_legs2[current_leg].end(),
|
||||
temporary_packed_leg2.begin(),
|
||||
temporary_packed_leg2.end());
|
||||
BOOST_ASSERT(packed_legs2[current_leg].size() == temporary_packed_leg2.size());
|
||||
|
||||
if ((packed_legs1[current_leg].back() == packed_legs2[current_leg].back()) &&
|
||||
phantom_node_pair.target_phantom.isBidirected())
|
||||
{
|
||||
const NodeID last_node_id = packed_legs2[current_leg].back();
|
||||
search_from_1st_node &=
|
||||
!(last_node_id == phantom_node_pair.target_phantom.reverse_node_id);
|
||||
search_from_2nd_node &=
|
||||
!(last_node_id == phantom_node_pair.target_phantom.forward_node_id);
|
||||
BOOST_ASSERT(search_from_1st_node != search_from_2nd_node);
|
||||
}
|
||||
|
||||
distance1 = local_upper_bound1;
|
||||
distance2 = local_upper_bound2;
|
||||
++current_leg;
|
||||
}
|
||||
|
||||
if (distance1 > distance2)
|
||||
{
|
||||
std::swap(packed_legs1, packed_legs2);
|
||||
}
|
||||
raw_route_data.unpacked_path_segments.resize(packed_legs1.size());
|
||||
|
||||
raw_route_data.source_traversed_in_reverse =
|
||||
(packed_legs1.front().front() !=
|
||||
phantom_nodes_vector.front().source_phantom.forward_node_id);
|
||||
raw_route_data.target_traversed_in_reverse =
|
||||
(packed_legs1.back().back() !=
|
||||
phantom_nodes_vector.back().target_phantom.forward_node_id);
|
||||
|
||||
for (unsigned i = 0; i < packed_legs1.size(); ++i)
|
||||
{
|
||||
BOOST_ASSERT(!phantom_nodes_vector.empty());
|
||||
BOOST_ASSERT(packed_legs1.size() == raw_route_data.unpacked_path_segments.size());
|
||||
|
||||
PhantomNodes unpack_phantom_node_pair = phantom_nodes_vector[i];
|
||||
super::UnpackPath(
|
||||
// -- packed input
|
||||
packed_legs1[i],
|
||||
// -- start and end of (sub-)route
|
||||
unpack_phantom_node_pair,
|
||||
// -- unpacked output
|
||||
raw_route_data.unpacked_path_segments[i]);
|
||||
}
|
||||
raw_route_data.shortest_path_length = std::min(distance1, distance2);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SHORTEST_PATH_ROUTING_H */
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef APIGRAMMAR_H_
|
||||
#define APIGRAMMAR_H_
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
#include <boost/spirit/include/qi_action.hpp>
|
||||
|
||||
namespace qi = boost::spirit::qi;
|
||||
|
||||
template <typename Iterator, class HandlerT>
|
||||
struct APIGrammar : qi::grammar<Iterator>
|
||||
{
|
||||
explicit APIGrammar(HandlerT * h) : APIGrammar::base_type(api_call), handler(h)
|
||||
{
|
||||
api_call = qi::lit('/') >> string[boost::bind(&HandlerT::setService, handler, ::_1)] >> *(query);
|
||||
query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | cmp | language | instruction | geometry | alt_route | old_API) ) ;
|
||||
|
||||
zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >> qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)];
|
||||
output = (-qi::lit('&')) >> qi::lit("output") >> '=' >> string[boost::bind(&HandlerT::setOutputFormat, handler, ::_1)];
|
||||
jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >> stringwithPercent[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)];
|
||||
checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >> qi::int_[boost::bind(&HandlerT::setChecksum, handler, ::_1)];
|
||||
instruction = (-qi::lit('&')) >> qi::lit("instructions") >> '=' >> qi::bool_[boost::bind(&HandlerT::setInstructionFlag, handler, ::_1)];
|
||||
geometry = (-qi::lit('&')) >> qi::lit("geometry") >> '=' >> qi::bool_[boost::bind(&HandlerT::setGeometryFlag, handler, ::_1)];
|
||||
cmp = (-qi::lit('&')) >> qi::lit("compression") >> '=' >> qi::bool_[boost::bind(&HandlerT::setCompressionFlag, handler, ::_1)];
|
||||
location = (-qi::lit('&')) >> qi::lit("loc") >> '=' >> (qi::double_ >> qi::lit(',') >> qi::double_)[boost::bind(&HandlerT::addCoordinate, handler, ::_1)];
|
||||
hint = (-qi::lit('&')) >> qi::lit("hint") >> '=' >> stringwithDot[boost::bind(&HandlerT::addHint, handler, ::_1)];
|
||||
language = (-qi::lit('&')) >> qi::lit("hl") >> '=' >> string[boost::bind(&HandlerT::setLanguage, handler, ::_1)];
|
||||
alt_route = (-qi::lit('&')) >> qi::lit("alt") >> '=' >> qi::bool_[boost::bind(&HandlerT::setAlternateRouteFlag, handler, ::_1)];
|
||||
old_API = (-qi::lit('&')) >> qi::lit("geomformat") >> '=' >> string[boost::bind(&HandlerT::setDeprecatedAPIFlag, handler, ::_1)];
|
||||
|
||||
string = +(qi::char_("a-zA-Z"));
|
||||
stringwithDot = +(qi::char_("a-zA-Z0-9_.-"));
|
||||
stringwithPercent = +(qi::char_("a-zA-Z0-9_.-") | qi::char_('[') | qi::char_(']') | (qi::char_('%') >> qi::char_("0-9A-Z") >> qi::char_("0-9A-Z") ));
|
||||
}
|
||||
|
||||
qi::rule<Iterator> api_call, query;
|
||||
qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location, hint,
|
||||
stringwithDot, stringwithPercent, language, instruction, geometry,
|
||||
cmp, alt_route, old_API;
|
||||
|
||||
HandlerT * handler;
|
||||
};
|
||||
|
||||
#endif /* APIGRAMMAR_H_ */
|
||||
@@ -1,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 "Connection.h"
|
||||
#include "RequestHandler.h"
|
||||
#include "RequestParser.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/iostreams/filtering_stream.hpp>
|
||||
#include <boost/iostreams/filter/gzip.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace http
|
||||
{
|
||||
|
||||
Connection::Connection(boost::asio::io_service &io_service, RequestHandler &handler)
|
||||
: strand(io_service), TCP_socket(io_service), request_handler(handler),
|
||||
request_parser(new RequestParser())
|
||||
{
|
||||
}
|
||||
|
||||
Connection::~Connection() { delete request_parser; }
|
||||
|
||||
boost::asio::ip::tcp::socket &Connection::socket() { return TCP_socket; }
|
||||
|
||||
/// Start the first asynchronous operation for the connection.
|
||||
void Connection::start()
|
||||
{
|
||||
TCP_socket.async_read_some(
|
||||
boost::asio::buffer(incoming_data_buffer),
|
||||
strand.wrap(boost::bind(&Connection::handle_read,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred)));
|
||||
}
|
||||
|
||||
void Connection::handle_read(const boost::system::error_code &e, std::size_t bytes_transferred)
|
||||
{
|
||||
if (!e)
|
||||
{
|
||||
CompressionType compression_type(noCompression);
|
||||
boost::tribool result;
|
||||
boost::tie(result, boost::tuples::ignore) =
|
||||
request_parser->Parse(request,
|
||||
incoming_data_buffer.data(),
|
||||
incoming_data_buffer.data() + bytes_transferred,
|
||||
&compression_type);
|
||||
|
||||
if (result)
|
||||
{
|
||||
request.endpoint = TCP_socket.remote_endpoint().address();
|
||||
request_handler.handle_request(request, reply);
|
||||
|
||||
Header compression_header;
|
||||
std::vector<char> compressed_output;
|
||||
std::vector<boost::asio::const_buffer> output_buffer;
|
||||
switch (compression_type)
|
||||
{
|
||||
case deflateRFC1951:
|
||||
compression_header.name = "Content-Encoding";
|
||||
compression_header.value = "deflate";
|
||||
reply.headers.insert(reply.headers.begin(), compression_header);
|
||||
compressBufferCollection(reply.content, compression_type, compressed_output);
|
||||
reply.setSize(compressed_output.size());
|
||||
output_buffer = reply.HeaderstoBuffers();
|
||||
output_buffer.push_back(boost::asio::buffer(compressed_output));
|
||||
boost::asio::async_write(
|
||||
TCP_socket,
|
||||
output_buffer,
|
||||
strand.wrap(boost::bind(&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error)));
|
||||
break;
|
||||
case gzipRFC1952:
|
||||
compression_header.name = "Content-Encoding";
|
||||
compression_header.value = "gzip";
|
||||
reply.headers.insert(reply.headers.begin(), compression_header);
|
||||
compressBufferCollection(reply.content, compression_type, compressed_output);
|
||||
reply.setSize(compressed_output.size());
|
||||
output_buffer = reply.HeaderstoBuffers();
|
||||
output_buffer.push_back(boost::asio::buffer(compressed_output));
|
||||
boost::asio::async_write(
|
||||
TCP_socket,
|
||||
output_buffer,
|
||||
strand.wrap(boost::bind(&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error)));
|
||||
break;
|
||||
case noCompression:
|
||||
reply.SetUncompressedSize();
|
||||
output_buffer = reply.toBuffers();
|
||||
boost::asio::async_write(
|
||||
TCP_socket,
|
||||
output_buffer,
|
||||
strand.wrap(boost::bind(&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!result)
|
||||
{
|
||||
reply = Reply::StockReply(Reply::badRequest);
|
||||
|
||||
boost::asio::async_write(TCP_socket,
|
||||
reply.toBuffers(),
|
||||
strand.wrap(boost::bind(&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error)));
|
||||
}
|
||||
else
|
||||
{
|
||||
TCP_socket.async_read_some(
|
||||
boost::asio::buffer(incoming_data_buffer),
|
||||
strand.wrap(boost::bind(&Connection::handle_read,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle completion of a write operation.
|
||||
void Connection::handle_write(const boost::system::error_code &e)
|
||||
{
|
||||
if (!e)
|
||||
{
|
||||
// Initiate graceful connection closure.
|
||||
boost::system::error_code ignoredEC;
|
||||
TCP_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignoredEC);
|
||||
}
|
||||
}
|
||||
|
||||
void Connection::compressBufferCollection(std::vector<std::string> uncompressed_data,
|
||||
CompressionType compression_type,
|
||||
std::vector<char> &compressed_data)
|
||||
{
|
||||
boost::iostreams::gzip_params compression_parameters;
|
||||
|
||||
compression_parameters.level = boost::iostreams::zlib::best_speed;
|
||||
if (deflateRFC1951 == compression_type)
|
||||
{
|
||||
compression_parameters.noheader = true;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(compressed_data.empty());
|
||||
boost::iostreams::filtering_ostream compressing_stream;
|
||||
|
||||
compressing_stream.push(boost::iostreams::gzip_compressor(compression_parameters));
|
||||
compressing_stream.push(boost::iostreams::back_inserter(compressed_data));
|
||||
|
||||
for (const std::string &line : uncompressed_data)
|
||||
{
|
||||
compressing_stream << line;
|
||||
}
|
||||
|
||||
compressing_stream.reset();
|
||||
}
|
||||
}
|
||||
@@ -1,405 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INTERNAL_DATA_FACADE
|
||||
#define INTERNAL_DATA_FACADE
|
||||
|
||||
// implements all data storage when shared memory is _NOT_ used
|
||||
|
||||
#include "BaseDataFacade.h"
|
||||
|
||||
#include "../../DataStructures/OriginalEdgeData.h"
|
||||
#include "../../DataStructures/QueryNode.h"
|
||||
#include "../../DataStructures/QueryEdge.h"
|
||||
#include "../../DataStructures/SharedMemoryVectorWrapper.h"
|
||||
#include "../../DataStructures/StaticGraph.h"
|
||||
#include "../../DataStructures/StaticRTree.h"
|
||||
#include "../../Util/BoostFileSystemFix.h"
|
||||
#include "../../Util/GraphLoader.h"
|
||||
#include "../../Util/ProgramOptions.h"
|
||||
#include "../../Util/SimpleLogger.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<EdgeDataT>
|
||||
{
|
||||
|
||||
private:
|
||||
typedef BaseDataFacade<EdgeDataT> super;
|
||||
typedef StaticGraph<typename super::EdgeData> QueryGraph;
|
||||
typedef typename QueryGraph::InputEdge InputEdge;
|
||||
typedef typename super::RTreeLeaf RTreeLeaf;
|
||||
|
||||
InternalDataFacade() {}
|
||||
|
||||
unsigned m_check_sum;
|
||||
unsigned m_number_of_nodes;
|
||||
QueryGraph *m_query_graph;
|
||||
std::string m_timestamp;
|
||||
|
||||
std::shared_ptr<ShM<FixedPointCoordinate, false>::vector> m_coordinate_list;
|
||||
ShM<NodeID, false>::vector m_via_node_list;
|
||||
ShM<unsigned, false>::vector m_name_ID_list;
|
||||
ShM<TurnInstruction, false>::vector m_turn_instruction_list;
|
||||
ShM<char, false>::vector m_names_char_list;
|
||||
ShM<unsigned, false>::vector m_name_begin_indices;
|
||||
ShM<bool, false>::vector m_egde_is_compressed;
|
||||
ShM<unsigned, false>::vector m_geometry_indices;
|
||||
ShM<unsigned, false>::vector m_geometry_list;
|
||||
|
||||
std::shared_ptr<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false>>
|
||||
m_static_rtree;
|
||||
|
||||
void LoadTimestamp(const boost::filesystem::path ×tamp_path)
|
||||
{
|
||||
if (boost::filesystem::exists(timestamp_path))
|
||||
{
|
||||
SimpleLogger().Write() << "Loading Timestamp";
|
||||
boost::filesystem::ifstream timestampInStream(timestamp_path);
|
||||
if (!timestampInStream)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << timestamp_path << " not found";
|
||||
}
|
||||
getline(timestampInStream, m_timestamp);
|
||||
timestampInStream.close();
|
||||
}
|
||||
if (m_timestamp.empty())
|
||||
{
|
||||
m_timestamp = "n/a";
|
||||
}
|
||||
if (25 < m_timestamp.length())
|
||||
{
|
||||
m_timestamp.resize(25);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadGraph(const boost::filesystem::path &hsgr_path)
|
||||
{
|
||||
typename ShM<typename QueryGraph::NodeArrayEntry, false>::vector node_list;
|
||||
typename ShM<typename QueryGraph::EdgeArrayEntry, false>::vector edge_list;
|
||||
|
||||
SimpleLogger().Write() << "loading graph from " << hsgr_path.string();
|
||||
|
||||
m_number_of_nodes = readHSGRFromStream(hsgr_path, node_list, edge_list, &m_check_sum);
|
||||
|
||||
BOOST_ASSERT_MSG(0 != node_list.size(), "node list empty");
|
||||
// BOOST_ASSERT_MSG(0 != edge_list.size(), "edge list empty");
|
||||
SimpleLogger().Write() << "loaded " << node_list.size() << " nodes and " << edge_list.size()
|
||||
<< " edges";
|
||||
m_query_graph = new QueryGraph(node_list, edge_list);
|
||||
|
||||
BOOST_ASSERT_MSG(0 == node_list.size(), "node list not flushed");
|
||||
BOOST_ASSERT_MSG(0 == edge_list.size(), "edge list not flushed");
|
||||
SimpleLogger().Write() << "Data checksum is " << m_check_sum;
|
||||
}
|
||||
|
||||
void LoadNodeAndEdgeInformation(const boost::filesystem::path &nodes_file,
|
||||
const boost::filesystem::path &edges_file)
|
||||
{
|
||||
boost::filesystem::ifstream nodes_input_stream(nodes_file, std::ios::binary);
|
||||
|
||||
NodeInfo current_node;
|
||||
unsigned number_of_coordinates = 0;
|
||||
nodes_input_stream.read((char *)&number_of_coordinates, sizeof(unsigned));
|
||||
m_coordinate_list =
|
||||
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));
|
||||
m_coordinate_list->at(i) = FixedPointCoordinate(current_node.lat, current_node.lon);
|
||||
BOOST_ASSERT((std::abs(m_coordinate_list->at(i).lat) >> 30) == 0);
|
||||
BOOST_ASSERT((std::abs(m_coordinate_list->at(i).lon) >> 30) == 0);
|
||||
}
|
||||
nodes_input_stream.close();
|
||||
|
||||
boost::filesystem::ifstream edges_input_stream(edges_file, std::ios::binary);
|
||||
unsigned number_of_edges = 0;
|
||||
edges_input_stream.read((char *)&number_of_edges, sizeof(unsigned));
|
||||
m_via_node_list.resize(number_of_edges);
|
||||
m_name_ID_list.resize(number_of_edges);
|
||||
m_turn_instruction_list.resize(number_of_edges);
|
||||
m_egde_is_compressed.resize(number_of_edges);
|
||||
|
||||
unsigned compressed = 0;
|
||||
|
||||
OriginalEdgeData current_edge_data;
|
||||
for (unsigned i = 0; i < number_of_edges; ++i)
|
||||
{
|
||||
edges_input_stream.read((char *)&(current_edge_data), sizeof(OriginalEdgeData));
|
||||
m_via_node_list[i] = current_edge_data.via_node;
|
||||
m_name_ID_list[i] = current_edge_data.name_id;
|
||||
m_turn_instruction_list[i] = current_edge_data.turn_instruction;
|
||||
m_egde_is_compressed[i] = current_edge_data.compressed_geometry;
|
||||
if (m_egde_is_compressed[i])
|
||||
{
|
||||
++compressed;
|
||||
}
|
||||
}
|
||||
|
||||
edges_input_stream.close();
|
||||
}
|
||||
|
||||
void LoadGeometries(const boost::filesystem::path &geometry_file)
|
||||
{
|
||||
std::ifstream geometry_stream(geometry_file.c_str(), std::ios::binary);
|
||||
unsigned number_of_indices = 0;
|
||||
unsigned number_of_compressed_geometries = 0;
|
||||
|
||||
geometry_stream.read((char *)&number_of_indices, sizeof(unsigned));
|
||||
|
||||
m_geometry_indices.resize(number_of_indices);
|
||||
geometry_stream.read((char *)&(m_geometry_indices[0]),
|
||||
number_of_indices * sizeof(unsigned));
|
||||
|
||||
geometry_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
|
||||
|
||||
BOOST_ASSERT(m_geometry_indices.back() == number_of_compressed_geometries);
|
||||
m_geometry_list.resize(number_of_compressed_geometries);
|
||||
|
||||
geometry_stream.read((char *)&(m_geometry_list[0]),
|
||||
number_of_compressed_geometries * sizeof(unsigned));
|
||||
geometry_stream.close();
|
||||
}
|
||||
|
||||
void LoadRTree(const boost::filesystem::path &ram_index_path,
|
||||
const boost::filesystem::path &file_index_path)
|
||||
{
|
||||
BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
|
||||
|
||||
m_static_rtree = std::make_shared<StaticRTree<RTreeLeaf>>(
|
||||
ram_index_path, file_index_path, m_coordinate_list);
|
||||
}
|
||||
|
||||
void LoadStreetNames(const boost::filesystem::path &names_file)
|
||||
{
|
||||
boost::filesystem::ifstream name_stream(names_file, std::ios::binary);
|
||||
unsigned number_of_names = 0;
|
||||
unsigned number_of_chars = 0;
|
||||
name_stream.read((char *)&number_of_names, sizeof(unsigned));
|
||||
name_stream.read((char *)&number_of_chars, sizeof(unsigned));
|
||||
BOOST_ASSERT_MSG(0 != number_of_names, "name file broken");
|
||||
BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
|
||||
|
||||
m_name_begin_indices.resize(number_of_names);
|
||||
name_stream.read((char *)&m_name_begin_indices[0], number_of_names * sizeof(unsigned));
|
||||
|
||||
m_names_char_list.resize(number_of_chars + 1); //+1 gives sentinel element
|
||||
name_stream.read((char *)&m_names_char_list[0], number_of_chars * sizeof(char));
|
||||
BOOST_ASSERT_MSG(0 != m_names_char_list.size(), "could not load any names");
|
||||
name_stream.close();
|
||||
}
|
||||
|
||||
public:
|
||||
~InternalDataFacade()
|
||||
{
|
||||
delete m_query_graph;
|
||||
m_static_rtree.reset();
|
||||
}
|
||||
|
||||
explicit InternalDataFacade(const ServerPaths &server_paths)
|
||||
{
|
||||
// generate paths of data files
|
||||
if (server_paths.find("hsgrdata") == server_paths.end())
|
||||
{
|
||||
throw OSRMException("no hsgr file given in ini file");
|
||||
}
|
||||
if (server_paths.find("ramindex") == server_paths.end())
|
||||
{
|
||||
throw OSRMException("no ram index file given in ini file");
|
||||
}
|
||||
if (server_paths.find("fileindex") == server_paths.end())
|
||||
{
|
||||
throw OSRMException("no leaf index file given in ini file");
|
||||
}
|
||||
if (server_paths.find("geometries") == server_paths.end())
|
||||
{
|
||||
throw OSRMException("no geometries file given in ini file");
|
||||
}
|
||||
if (server_paths.find("nodesdata") == server_paths.end())
|
||||
{
|
||||
throw OSRMException("no nodes file given in ini file");
|
||||
}
|
||||
if (server_paths.find("edgesdata") == server_paths.end())
|
||||
{
|
||||
throw OSRMException("no edges file given in ini file");
|
||||
}
|
||||
if (server_paths.find("namesdata") == server_paths.end())
|
||||
{
|
||||
throw OSRMException("no names file given in ini file");
|
||||
}
|
||||
|
||||
ServerPaths::const_iterator paths_iterator = server_paths.find("hsgrdata");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path &hsgr_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("timestamp");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path ×tamp_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("ramindex");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path &ram_index_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("fileindex");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path &file_index_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("nodesdata");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path &nodes_data_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("edgesdata");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path &edges_data_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("namesdata");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path &names_data_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("geometries");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path &geometries_path = paths_iterator->second;
|
||||
|
||||
// load data
|
||||
SimpleLogger().Write() << "loading graph data";
|
||||
LoadGraph(hsgr_path);
|
||||
SimpleLogger().Write() << "loading egde information";
|
||||
LoadNodeAndEdgeInformation(nodes_data_path, edges_data_path);
|
||||
SimpleLogger().Write() << "loading geometries";
|
||||
LoadGeometries(geometries_path);
|
||||
SimpleLogger().Write() << "loading r-tree";
|
||||
LoadRTree(ram_index_path, file_index_path);
|
||||
SimpleLogger().Write() << "loading timestamp";
|
||||
LoadTimestamp(timestamp_path);
|
||||
SimpleLogger().Write() << "loading street names";
|
||||
LoadStreetNames(names_data_path);
|
||||
}
|
||||
|
||||
// search graph access
|
||||
unsigned GetNumberOfNodes() const { return m_query_graph->GetNumberOfNodes(); }
|
||||
|
||||
unsigned GetNumberOfEdges() const { return m_query_graph->GetNumberOfEdges(); }
|
||||
|
||||
unsigned GetOutDegree(const NodeID n) const { return m_query_graph->GetOutDegree(n); }
|
||||
|
||||
NodeID GetTarget(const EdgeID e) const { return m_query_graph->GetTarget(e); }
|
||||
|
||||
EdgeDataT &GetEdgeData(const EdgeID e) { return m_query_graph->GetEdgeData(e); }
|
||||
|
||||
const EdgeDataT &GetEdgeData(const EdgeID e) const { return m_query_graph->GetEdgeData(e); }
|
||||
|
||||
EdgeID BeginEdges(const NodeID n) const { return m_query_graph->BeginEdges(n); }
|
||||
|
||||
EdgeID EndEdges(const NodeID n) const { return m_query_graph->EndEdges(n); }
|
||||
|
||||
// searches for a specific edge
|
||||
EdgeID FindEdge(const NodeID from, const NodeID to) const
|
||||
{
|
||||
return m_query_graph->FindEdge(from, to);
|
||||
}
|
||||
|
||||
EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const
|
||||
{
|
||||
return m_query_graph->FindEdgeInEitherDirection(from, to);
|
||||
}
|
||||
|
||||
EdgeID FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const
|
||||
{
|
||||
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
|
||||
}
|
||||
|
||||
// node and edge information access
|
||||
FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const
|
||||
{
|
||||
return m_coordinate_list->at(id);
|
||||
};
|
||||
|
||||
bool EdgeIsCompressed(const unsigned id) const { return m_egde_is_compressed.at(id); }
|
||||
|
||||
TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const
|
||||
{
|
||||
return m_turn_instruction_list.at(id);
|
||||
}
|
||||
|
||||
bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
FixedPointCoordinate &result,
|
||||
const unsigned zoom_level = 18) const
|
||||
{
|
||||
return m_static_rtree->LocateClosestEndPointForCoordinate(
|
||||
input_coordinate, result, zoom_level);
|
||||
}
|
||||
|
||||
bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
PhantomNode &resulting_phantom_node,
|
||||
const unsigned zoom_level) const
|
||||
{
|
||||
const bool found = m_static_rtree->FindPhantomNodeForCoordinate(
|
||||
input_coordinate, resulting_phantom_node, zoom_level);
|
||||
return found;
|
||||
}
|
||||
|
||||
unsigned GetCheckSum() const { return m_check_sum; }
|
||||
|
||||
unsigned GetNameIndexFromEdgeID(const unsigned id) const
|
||||
{
|
||||
return m_name_ID_list.at(id);
|
||||
};
|
||||
|
||||
void GetName(const unsigned name_id, std::string &result) const
|
||||
{
|
||||
if (UINT_MAX == name_id)
|
||||
{
|
||||
result = "";
|
||||
return;
|
||||
}
|
||||
BOOST_ASSERT_MSG(name_id < m_name_begin_indices.size(), "name id too high");
|
||||
const unsigned begin_index = m_name_begin_indices[name_id];
|
||||
const unsigned end_index = m_name_begin_indices[name_id + 1];
|
||||
BOOST_ASSERT_MSG(begin_index < m_names_char_list.size(), "begin index of name too high");
|
||||
BOOST_ASSERT_MSG(end_index < m_names_char_list.size(), "end index of name too high");
|
||||
|
||||
BOOST_ASSERT_MSG(begin_index <= end_index, "string ends before begin");
|
||||
result.clear();
|
||||
result.resize(end_index - begin_index);
|
||||
std::copy(m_names_char_list.begin() + begin_index,
|
||||
m_names_char_list.begin() + end_index,
|
||||
result.begin());
|
||||
}
|
||||
|
||||
virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const
|
||||
{
|
||||
return m_via_node_list.at(id);
|
||||
}
|
||||
|
||||
virtual void GetUncompressedGeometry(const unsigned id, std::vector<unsigned> &result_nodes)
|
||||
const
|
||||
{
|
||||
const unsigned begin = m_geometry_indices.at(id);
|
||||
const unsigned end = m_geometry_indices.at(id + 1);
|
||||
|
||||
result_nodes.clear();
|
||||
result_nodes.insert(
|
||||
result_nodes.begin(), m_geometry_list.begin() + begin, m_geometry_list.begin() + end);
|
||||
}
|
||||
|
||||
std::string GetTimestamp() const { return m_timestamp; }
|
||||
};
|
||||
|
||||
#endif // INTERNAL_DATA_FACADE
|
||||
@@ -1,350 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SHARED_DATA_FACADE_H
|
||||
#define SHARED_DATA_FACADE_H
|
||||
|
||||
// implements all data storage when shared memory _IS_ used
|
||||
|
||||
#include "BaseDataFacade.h"
|
||||
#include "SharedDataType.h"
|
||||
|
||||
#include "../../DataStructures/StaticGraph.h"
|
||||
#include "../../DataStructures/StaticRTree.h"
|
||||
#include "../../Util/BoostFileSystemFix.h"
|
||||
#include "../../Util/ProgramOptions.h"
|
||||
#include "../../Util/SimpleLogger.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDataT>
|
||||
{
|
||||
|
||||
private:
|
||||
typedef EdgeDataT EdgeData;
|
||||
typedef BaseDataFacade<EdgeData> super;
|
||||
typedef StaticGraph<EdgeData, true> QueryGraph;
|
||||
typedef typename StaticGraph<EdgeData, true>::NodeArrayEntry GraphNode;
|
||||
typedef typename StaticGraph<EdgeData, true>::EdgeArrayEntry GraphEdge;
|
||||
typedef typename QueryGraph::InputEdge InputEdge;
|
||||
typedef typename super::RTreeLeaf RTreeLeaf;
|
||||
typedef typename StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>::TreeNode
|
||||
RTreeNode;
|
||||
|
||||
SharedDataLayout *data_layout;
|
||||
char *shared_memory;
|
||||
SharedDataTimestamp *data_timestamp_ptr;
|
||||
|
||||
SharedDataType CURRENT_LAYOUT;
|
||||
SharedDataType CURRENT_DATA;
|
||||
unsigned CURRENT_TIMESTAMP;
|
||||
|
||||
unsigned m_check_sum;
|
||||
unsigned m_number_of_nodes;
|
||||
std::shared_ptr<QueryGraph> m_query_graph;
|
||||
std::shared_ptr<SharedMemory> m_layout_memory;
|
||||
std::shared_ptr<SharedMemory> m_large_memory;
|
||||
std::string m_timestamp;
|
||||
|
||||
std::shared_ptr<ShM<FixedPointCoordinate, true>::vector> m_coordinate_list;
|
||||
ShM<NodeID, true>::vector m_via_node_list;
|
||||
ShM<unsigned, true>::vector m_name_ID_list;
|
||||
ShM<TurnInstruction, true>::vector m_turn_instruction_list;
|
||||
ShM<char, true>::vector m_names_char_list;
|
||||
ShM<unsigned, true>::vector m_name_begin_indices;
|
||||
ShM<bool, true>::vector m_egde_is_compressed;
|
||||
ShM<unsigned, true>::vector m_geometry_indices;
|
||||
ShM<unsigned, true>::vector m_geometry_list;
|
||||
|
||||
std::shared_ptr<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>>
|
||||
m_static_rtree;
|
||||
|
||||
void LoadTimestamp()
|
||||
{
|
||||
char *timestamp_ptr = shared_memory + data_layout->GetTimeStampOffset();
|
||||
m_timestamp.resize(data_layout->timestamp_length);
|
||||
std::copy(
|
||||
timestamp_ptr, timestamp_ptr + data_layout->timestamp_length, m_timestamp.begin());
|
||||
}
|
||||
|
||||
void LoadRTree(const boost::filesystem::path &file_index_path)
|
||||
{
|
||||
BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
|
||||
|
||||
RTreeNode *tree_ptr = (RTreeNode *)(shared_memory + data_layout->GetRSearchTreeOffset());
|
||||
m_static_rtree =
|
||||
std::make_shared<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>>(
|
||||
tree_ptr, data_layout->r_search_tree_size, file_index_path, m_coordinate_list);
|
||||
}
|
||||
|
||||
void LoadGraph()
|
||||
{
|
||||
m_number_of_nodes = data_layout->graph_node_list_size;
|
||||
GraphNode *graph_nodes_ptr =
|
||||
(GraphNode *)(shared_memory + data_layout->GetGraphNodeListOffset());
|
||||
|
||||
GraphEdge *graph_edges_ptr =
|
||||
(GraphEdge *)(shared_memory + data_layout->GetGraphEdgeListOffset());
|
||||
|
||||
typename ShM<GraphNode, true>::vector node_list(graph_nodes_ptr,
|
||||
data_layout->graph_node_list_size);
|
||||
typename ShM<GraphEdge, true>::vector edge_list(graph_edges_ptr,
|
||||
data_layout->graph_edge_list_size);
|
||||
m_query_graph.reset(new QueryGraph(node_list, edge_list));
|
||||
}
|
||||
|
||||
void LoadNodeAndEdgeInformation()
|
||||
{
|
||||
|
||||
FixedPointCoordinate *coordinate_list_ptr =
|
||||
(FixedPointCoordinate *)(shared_memory + data_layout->GetCoordinateListOffset());
|
||||
m_coordinate_list = std::make_shared<ShM<FixedPointCoordinate, true>::vector>(
|
||||
coordinate_list_ptr, data_layout->coordinate_list_size);
|
||||
|
||||
TurnInstruction *turn_instruction_list_ptr =
|
||||
(TurnInstruction *)(shared_memory + data_layout->GetTurnInstructionListOffset());
|
||||
typename ShM<TurnInstruction, true>::vector turn_instruction_list(
|
||||
turn_instruction_list_ptr, data_layout->turn_instruction_list_size);
|
||||
m_turn_instruction_list.swap(turn_instruction_list);
|
||||
|
||||
unsigned *name_id_list_ptr =
|
||||
(unsigned *)(shared_memory + data_layout->GetNameIDListOffset());
|
||||
typename ShM<unsigned, true>::vector name_id_list(name_id_list_ptr,
|
||||
data_layout->name_id_list_size);
|
||||
m_name_ID_list.swap(name_id_list);
|
||||
}
|
||||
|
||||
void LoadViaNodeList()
|
||||
{
|
||||
NodeID *via_node_list_ptr = (NodeID *)(shared_memory + data_layout->GetViaNodeListOffset());
|
||||
typename ShM<NodeID, true>::vector via_node_list(via_node_list_ptr,
|
||||
data_layout->via_node_list_size);
|
||||
m_via_node_list.swap(via_node_list);
|
||||
}
|
||||
|
||||
void LoadNames()
|
||||
{
|
||||
unsigned *street_names_index_ptr =
|
||||
(unsigned *)(shared_memory + data_layout->GetNameIndexOffset());
|
||||
typename ShM<unsigned, true>::vector name_begin_indices(street_names_index_ptr,
|
||||
data_layout->name_index_list_size);
|
||||
m_name_begin_indices.swap(name_begin_indices);
|
||||
|
||||
char *names_list_ptr = (char *)(shared_memory + data_layout->GetNameListOffset());
|
||||
typename ShM<char, true>::vector names_char_list(names_list_ptr,
|
||||
data_layout->name_char_list_size);
|
||||
m_names_char_list.swap(names_char_list);
|
||||
}
|
||||
|
||||
void LoadGeometries()
|
||||
{
|
||||
unsigned *geometries_compressed_ptr =
|
||||
(unsigned *)(shared_memory + data_layout->GetGeometriesIndicatorOffset());
|
||||
typename ShM<bool, true>::vector egde_is_compressed(geometries_compressed_ptr,
|
||||
data_layout->geometries_indicators);
|
||||
m_egde_is_compressed.swap(egde_is_compressed);
|
||||
|
||||
unsigned *geometries_index_ptr =
|
||||
(unsigned *)(shared_memory + data_layout->GetGeometriesIndexListOffset());
|
||||
typename ShM<unsigned, true>::vector geometry_begin_indices(
|
||||
geometries_index_ptr, data_layout->geometries_index_list_size);
|
||||
m_geometry_indices.swap(geometry_begin_indices);
|
||||
|
||||
unsigned *geometries_list_ptr =
|
||||
(unsigned *)(shared_memory + data_layout->GetGeometryListOffset());
|
||||
typename ShM<unsigned, true>::vector geometry_list(geometries_list_ptr,
|
||||
data_layout->geometries_list_size);
|
||||
m_geometry_list.swap(geometry_list);
|
||||
}
|
||||
|
||||
public:
|
||||
SharedDataFacade()
|
||||
{
|
||||
data_timestamp_ptr = (SharedDataTimestamp *)SharedMemoryFactory::Get(
|
||||
CURRENT_REGIONS, sizeof(SharedDataTimestamp), false, false)->Ptr();
|
||||
|
||||
CURRENT_LAYOUT = LAYOUT_NONE;
|
||||
CURRENT_DATA = DATA_NONE;
|
||||
CURRENT_TIMESTAMP = 0;
|
||||
|
||||
// load data
|
||||
CheckAndReloadFacade();
|
||||
}
|
||||
|
||||
void CheckAndReloadFacade()
|
||||
{
|
||||
if (CURRENT_LAYOUT != data_timestamp_ptr->layout ||
|
||||
CURRENT_DATA != data_timestamp_ptr->data ||
|
||||
CURRENT_TIMESTAMP != data_timestamp_ptr->timestamp)
|
||||
{
|
||||
// release the previous shared memory segments
|
||||
SharedMemory::Remove(CURRENT_LAYOUT);
|
||||
SharedMemory::Remove(CURRENT_DATA);
|
||||
|
||||
CURRENT_LAYOUT = data_timestamp_ptr->layout;
|
||||
CURRENT_DATA = data_timestamp_ptr->data;
|
||||
CURRENT_TIMESTAMP = data_timestamp_ptr->timestamp;
|
||||
|
||||
m_layout_memory.reset(SharedMemoryFactory::Get(CURRENT_LAYOUT));
|
||||
|
||||
data_layout = (SharedDataLayout *)(m_layout_memory->Ptr());
|
||||
boost::filesystem::path ram_index_path(data_layout->ram_index_file_name);
|
||||
if (!boost::filesystem::exists(ram_index_path))
|
||||
{
|
||||
throw OSRMException("no leaf index file given. "
|
||||
"Is any data loaded into shared memory?");
|
||||
}
|
||||
|
||||
m_large_memory.reset(SharedMemoryFactory::Get(CURRENT_DATA));
|
||||
shared_memory = (char *)(m_large_memory->Ptr());
|
||||
|
||||
LoadGraph();
|
||||
LoadNodeAndEdgeInformation();
|
||||
LoadGeometries();
|
||||
LoadRTree(ram_index_path);
|
||||
LoadTimestamp();
|
||||
LoadViaNodeList();
|
||||
LoadNames();
|
||||
|
||||
data_layout->PrintInformation();
|
||||
}
|
||||
}
|
||||
|
||||
// search graph access
|
||||
unsigned GetNumberOfNodes() const { return m_query_graph->GetNumberOfNodes(); }
|
||||
|
||||
unsigned GetNumberOfEdges() const { return m_query_graph->GetNumberOfEdges(); }
|
||||
|
||||
unsigned GetOutDegree(const NodeID n) const { return m_query_graph->GetOutDegree(n); }
|
||||
|
||||
NodeID GetTarget(const EdgeID e) const { return m_query_graph->GetTarget(e); }
|
||||
|
||||
EdgeDataT &GetEdgeData(const EdgeID e) { return m_query_graph->GetEdgeData(e); }
|
||||
|
||||
// const EdgeDataT &GetEdgeData( const EdgeID e ) const {
|
||||
// return m_query_graph->GetEdgeData(e);
|
||||
// }
|
||||
|
||||
EdgeID BeginEdges(const NodeID n) const { return m_query_graph->BeginEdges(n); }
|
||||
|
||||
EdgeID EndEdges(const NodeID n) const { return m_query_graph->EndEdges(n); }
|
||||
|
||||
// searches for a specific edge
|
||||
EdgeID FindEdge(const NodeID from, const NodeID to) const
|
||||
{
|
||||
return m_query_graph->FindEdge(from, to);
|
||||
}
|
||||
|
||||
EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const
|
||||
{
|
||||
return m_query_graph->FindEdgeInEitherDirection(from, to);
|
||||
}
|
||||
|
||||
EdgeID FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const
|
||||
{
|
||||
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
|
||||
}
|
||||
|
||||
// node and edge information access
|
||||
FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const
|
||||
{
|
||||
return m_coordinate_list->at(id);
|
||||
};
|
||||
|
||||
virtual bool EdgeIsCompressed(const unsigned id) const { return m_egde_is_compressed.at(id); }
|
||||
|
||||
virtual void GetUncompressedGeometry(const unsigned id, std::vector<unsigned> &result_nodes)
|
||||
const
|
||||
{
|
||||
const unsigned begin = m_geometry_indices.at(id);
|
||||
const unsigned end = m_geometry_indices.at(id + 1);
|
||||
|
||||
result_nodes.clear();
|
||||
result_nodes.insert(
|
||||
result_nodes.begin(), m_geometry_list.begin() + begin, m_geometry_list.begin() + end);
|
||||
}
|
||||
|
||||
virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const
|
||||
{
|
||||
return m_via_node_list.at(id);
|
||||
}
|
||||
|
||||
TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const
|
||||
{
|
||||
return m_turn_instruction_list.at(id);
|
||||
}
|
||||
|
||||
bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
FixedPointCoordinate &result,
|
||||
const unsigned zoom_level = 18) const
|
||||
{
|
||||
return m_static_rtree->LocateClosestEndPointForCoordinate(
|
||||
input_coordinate, result, zoom_level);
|
||||
}
|
||||
|
||||
bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
PhantomNode &resulting_phantom_node,
|
||||
const unsigned zoom_level) const
|
||||
{
|
||||
const bool found = m_static_rtree->FindPhantomNodeForCoordinate(
|
||||
input_coordinate, resulting_phantom_node, zoom_level);
|
||||
return found;
|
||||
}
|
||||
|
||||
unsigned GetCheckSum() const { return m_check_sum; }
|
||||
|
||||
unsigned GetNameIndexFromEdgeID(const unsigned id) const
|
||||
{
|
||||
return m_name_ID_list.at(id);
|
||||
};
|
||||
|
||||
void GetName(const unsigned name_id, std::string &result) const
|
||||
{
|
||||
if (UINT_MAX == name_id)
|
||||
{
|
||||
result = "";
|
||||
return;
|
||||
}
|
||||
BOOST_ASSERT_MSG(name_id < m_name_begin_indices.size(), "name id too high");
|
||||
const unsigned begin_index = m_name_begin_indices[name_id];
|
||||
const unsigned end_index = m_name_begin_indices[name_id + 1];
|
||||
BOOST_ASSERT_MSG(begin_index <= m_names_char_list.size(), "begin index of name too high");
|
||||
BOOST_ASSERT_MSG(end_index <= m_names_char_list.size(), "end index of name too high");
|
||||
|
||||
BOOST_ASSERT_MSG(begin_index <= end_index, "string ends before begin");
|
||||
result.clear();
|
||||
result.resize(end_index - begin_index);
|
||||
std::copy(m_names_char_list.begin() + begin_index,
|
||||
m_names_char_list.begin() + end_index,
|
||||
result.begin());
|
||||
}
|
||||
|
||||
std::string GetTimestamp() const { return m_timestamp; }
|
||||
};
|
||||
|
||||
#endif // SHARED_DATA_FACADE_H
|
||||
@@ -1,273 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SHARED_DATA_TYPE_H_
|
||||
#define SHARED_DATA_TYPE_H_
|
||||
|
||||
#include "BaseDataFacade.h"
|
||||
|
||||
#include "../../DataStructures/QueryEdge.h"
|
||||
#include "../../DataStructures/StaticGraph.h"
|
||||
#include "../../DataStructures/StaticRTree.h"
|
||||
#include "../../DataStructures/TurnInstructions.h"
|
||||
|
||||
#include "../../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
typedef BaseDataFacade<QueryEdge::EdgeData>::RTreeLeaf RTreeLeaf;
|
||||
typedef StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>::TreeNode RTreeNode;
|
||||
typedef StaticGraph<QueryEdge::EdgeData> QueryGraph;
|
||||
|
||||
struct SharedDataLayout
|
||||
{
|
||||
uint64_t name_index_list_size;
|
||||
uint64_t name_char_list_size;
|
||||
uint64_t name_id_list_size;
|
||||
uint64_t via_node_list_size;
|
||||
uint64_t graph_node_list_size;
|
||||
uint64_t graph_edge_list_size;
|
||||
uint64_t coordinate_list_size;
|
||||
uint64_t turn_instruction_list_size;
|
||||
uint64_t r_search_tree_size;
|
||||
uint64_t geometries_index_list_size;
|
||||
uint64_t geometries_list_size;
|
||||
uint64_t geometries_indicators;
|
||||
|
||||
unsigned checksum;
|
||||
unsigned timestamp_length;
|
||||
|
||||
char ram_index_file_name[1024];
|
||||
|
||||
SharedDataLayout()
|
||||
: name_index_list_size(0), name_char_list_size(0), name_id_list_size(0),
|
||||
via_node_list_size(0), graph_node_list_size(0), graph_edge_list_size(0),
|
||||
coordinate_list_size(0), turn_instruction_list_size(0), r_search_tree_size(0),
|
||||
geometries_index_list_size(0), geometries_list_size(0), geometries_indicators(0),
|
||||
checksum(0), timestamp_length(0)
|
||||
|
||||
{
|
||||
ram_index_file_name[0] = '\0';
|
||||
}
|
||||
|
||||
void PrintInformation() const
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "-";
|
||||
SimpleLogger().Write(logDEBUG) << "name_index_list_size: " << name_index_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "name_char_list_size: " << name_char_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "name_id_list_size: " << name_id_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "via_node_list_size: " << via_node_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "graph_node_list_size: " << graph_node_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "graph_edge_list_size: " << graph_edge_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "timestamp_length: " << timestamp_length;
|
||||
SimpleLogger().Write(logDEBUG) << "coordinate_list_size: " << coordinate_list_size;
|
||||
SimpleLogger().Write(logDEBUG)
|
||||
<< "turn_instruction_list_size: " << turn_instruction_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "r_search_tree_size: " << r_search_tree_size;
|
||||
SimpleLogger().Write(logDEBUG) << "geometries_indicators: " << geometries_indicators
|
||||
<< "/" << ((geometries_indicators / 8) + 1);
|
||||
SimpleLogger().Write(logDEBUG)
|
||||
<< "geometries_index_list_size: " << geometries_index_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "geometries_list_size: " << geometries_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "sizeof(checksum): " << sizeof(checksum);
|
||||
SimpleLogger().Write(logDEBUG) << "ram index file name: " << ram_index_file_name;
|
||||
}
|
||||
|
||||
uint64_t GetSizeOfLayout() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::EdgeArrayEntry)) +
|
||||
(timestamp_length * sizeof(char)) +
|
||||
(coordinate_list_size * sizeof(FixedPointCoordinate)) +
|
||||
(turn_instruction_list_size * sizeof(TurnInstructionsClass)) +
|
||||
(r_search_tree_size * sizeof(RTreeNode)) +
|
||||
(geometries_indicators / 32 + 1) * sizeof(unsigned) +
|
||||
(geometries_index_list_size * sizeof(unsigned)) +
|
||||
(geometries_list_size * sizeof(unsigned)) + sizeof(checksum) + 1024 * sizeof(char);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t GetNameIndexOffset() const { return 0; }
|
||||
uint64_t GetNameListOffset() const
|
||||
{
|
||||
uint64_t result = (name_index_list_size * sizeof(unsigned));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetNameIDListOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetViaNodeListOffset() const
|
||||
{
|
||||
uint64_t result = (name_index_list_size * sizeof(unsigned)) +
|
||||
(name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetGraphNodeListOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetGraphEdgeListOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetTimeStampOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::EdgeArrayEntry));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetCoordinateListOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::EdgeArrayEntry)) +
|
||||
(timestamp_length * sizeof(char));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetTurnInstructionListOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::EdgeArrayEntry)) +
|
||||
(timestamp_length * sizeof(char)) +
|
||||
(coordinate_list_size * sizeof(FixedPointCoordinate));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetRSearchTreeOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::EdgeArrayEntry)) +
|
||||
(timestamp_length * sizeof(char)) +
|
||||
(coordinate_list_size * sizeof(FixedPointCoordinate)) +
|
||||
(turn_instruction_list_size * sizeof(TurnInstructionsClass));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetGeometriesIndicatorOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::EdgeArrayEntry)) +
|
||||
(timestamp_length * sizeof(char)) +
|
||||
(coordinate_list_size * sizeof(FixedPointCoordinate)) +
|
||||
(turn_instruction_list_size * sizeof(TurnInstructionsClass)) +
|
||||
(r_search_tree_size * sizeof(RTreeNode));
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t GetGeometriesIndexListOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::EdgeArrayEntry)) +
|
||||
(timestamp_length * sizeof(char)) +
|
||||
(coordinate_list_size * sizeof(FixedPointCoordinate)) +
|
||||
(turn_instruction_list_size * sizeof(TurnInstructionsClass)) +
|
||||
(r_search_tree_size * sizeof(RTreeNode)) +
|
||||
(geometries_indicators / 32 + 1) * sizeof(unsigned);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t GetGeometryListOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::EdgeArrayEntry)) +
|
||||
(timestamp_length * sizeof(char)) +
|
||||
(coordinate_list_size * sizeof(FixedPointCoordinate)) +
|
||||
(turn_instruction_list_size * sizeof(TurnInstructionsClass)) +
|
||||
(r_search_tree_size * sizeof(RTreeNode)) +
|
||||
(geometries_indicators / 32 + 1) * sizeof(unsigned) +
|
||||
(geometries_index_list_size * sizeof(unsigned));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetChecksumOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::EdgeArrayEntry)) +
|
||||
(timestamp_length * sizeof(char)) +
|
||||
(coordinate_list_size * sizeof(FixedPointCoordinate)) +
|
||||
(turn_instruction_list_size * sizeof(TurnInstructionsClass)) +
|
||||
(r_search_tree_size * sizeof(RTreeNode)) +
|
||||
(geometries_indicators / 32 + 1) * sizeof(unsigned) +
|
||||
(geometries_index_list_size * sizeof(unsigned)) +
|
||||
(geometries_list_size * sizeof(unsigned));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
enum SharedDataType
|
||||
{ CURRENT_REGIONS,
|
||||
LAYOUT_1,
|
||||
DATA_1,
|
||||
LAYOUT_2,
|
||||
DATA_2,
|
||||
LAYOUT_NONE,
|
||||
DATA_NONE };
|
||||
|
||||
struct SharedDataTimestamp
|
||||
{
|
||||
SharedDataType layout;
|
||||
SharedDataType data;
|
||||
unsigned timestamp;
|
||||
};
|
||||
|
||||
#endif /* SHARED_DATA_TYPE_H_ */
|
||||
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include <osrm/Reply.h>
|
||||
|
||||
#include "../../Util/StringUtil.h"
|
||||
|
||||
namespace http
|
||||
{
|
||||
|
||||
void Reply::setSize(const unsigned size)
|
||||
{
|
||||
for (Header &h : headers)
|
||||
{
|
||||
if ("Content-Length" == h.name)
|
||||
{
|
||||
intToString(size, h.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sets the size of the uncompressed output.
|
||||
void Reply::SetUncompressedSize()
|
||||
{
|
||||
unsigned uncompressed_size = 0;
|
||||
for (const std::string ¤t_line : content)
|
||||
{
|
||||
uncompressed_size += current_line.size();
|
||||
}
|
||||
setSize(uncompressed_size);
|
||||
}
|
||||
|
||||
std::vector<boost::asio::const_buffer> Reply::toBuffers()
|
||||
{
|
||||
std::vector<boost::asio::const_buffer> buffers;
|
||||
buffers.push_back(ToBuffer(status));
|
||||
for (const Header &h : headers)
|
||||
{
|
||||
buffers.push_back(boost::asio::buffer(h.name));
|
||||
buffers.push_back(boost::asio::buffer(seperators));
|
||||
buffers.push_back(boost::asio::buffer(h.value));
|
||||
buffers.push_back(boost::asio::buffer(crlf));
|
||||
}
|
||||
buffers.push_back(boost::asio::buffer(crlf));
|
||||
for (const std::string &line : content)
|
||||
{
|
||||
buffers.push_back(boost::asio::buffer(line));
|
||||
}
|
||||
return buffers;
|
||||
}
|
||||
|
||||
std::vector<boost::asio::const_buffer> Reply::HeaderstoBuffers()
|
||||
{
|
||||
std::vector<boost::asio::const_buffer> buffers;
|
||||
buffers.push_back(ToBuffer(status));
|
||||
for (std::size_t i = 0; i < headers.size(); ++i)
|
||||
{
|
||||
Header ¤t_header = headers[i];
|
||||
buffers.push_back(boost::asio::buffer(current_header.name));
|
||||
buffers.push_back(boost::asio::buffer(seperators));
|
||||
buffers.push_back(boost::asio::buffer(current_header.value));
|
||||
buffers.push_back(boost::asio::buffer(crlf));
|
||||
}
|
||||
buffers.push_back(boost::asio::buffer(crlf));
|
||||
return buffers;
|
||||
}
|
||||
|
||||
Reply Reply::StockReply(Reply::status_type status)
|
||||
{
|
||||
Reply rep;
|
||||
rep.status = status;
|
||||
rep.content.clear();
|
||||
rep.content.push_back(rep.ToString(status));
|
||||
rep.headers.resize(3);
|
||||
rep.headers[0].name = "Access-Control-Allow-Origin";
|
||||
rep.headers[0].value = "*";
|
||||
rep.headers[1].name = "Content-Length";
|
||||
|
||||
std::string size_string;
|
||||
intToString(rep.content.size(), size_string);
|
||||
|
||||
rep.headers[1].value = size_string;
|
||||
rep.headers[2].name = "Content-Type";
|
||||
rep.headers[2].value = "text/html";
|
||||
return rep;
|
||||
}
|
||||
|
||||
std::string Reply::ToString(Reply::status_type status)
|
||||
{
|
||||
if (Reply::ok == status)
|
||||
{
|
||||
return okHTML;
|
||||
}
|
||||
if (Reply::badRequest == status)
|
||||
{
|
||||
return badRequestHTML;
|
||||
}
|
||||
return internalServerErrorHTML;
|
||||
}
|
||||
|
||||
boost::asio::const_buffer Reply::ToBuffer(Reply::status_type status)
|
||||
{
|
||||
if (Reply::ok == status)
|
||||
{
|
||||
return boost::asio::buffer(okString);
|
||||
}
|
||||
if (Reply::internalServerError == status)
|
||||
{
|
||||
return boost::asio::buffer(internalServerErrorString);
|
||||
}
|
||||
return boost::asio::buffer(badRequestString);
|
||||
}
|
||||
|
||||
Reply::Reply() : status(ok) {}
|
||||
}
|
||||
@@ -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 "APIGrammar.h"
|
||||
#include "RequestHandler.h"
|
||||
#include "Http/Request.h"
|
||||
|
||||
#include "../Library/OSRM.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Reply.h>
|
||||
#include <osrm/RouteParameters.h>
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
RequestHandler::RequestHandler() : routing_machine(nullptr) {}
|
||||
|
||||
void RequestHandler::handle_request(const http::Request &req, http::Reply &reply)
|
||||
{
|
||||
// parse command
|
||||
try
|
||||
{
|
||||
std::string request;
|
||||
URIDecode(req.uri, request);
|
||||
|
||||
// deactivated as GCC apparently does not implement that, not even in 4.9
|
||||
// std::time_t t = std::time(nullptr);
|
||||
// SimpleLogger().Write() << std::put_time(std::localtime(&t), "%m-%d-%Y %H:%M:%S") <<
|
||||
// " " << req.endpoint.to_string() << " " <<
|
||||
// req.referrer << ( 0 == req.referrer.length() ? "- " :" ") <<
|
||||
// req.agent << ( 0 == req.agent.length() ? "- " :" ") << request;
|
||||
|
||||
time_t ltime;
|
||||
struct tm *Tm;
|
||||
|
||||
ltime = time(nullptr);
|
||||
Tm = localtime(<ime);
|
||||
|
||||
SimpleLogger().Write() << (Tm->tm_mday < 10 ? "0" : "") << Tm->tm_mday << "-"
|
||||
<< (Tm->tm_mon + 1 < 10 ? "0" : "") << (Tm->tm_mon + 1) << "-"
|
||||
<< 1900 + Tm->tm_year << " " << (Tm->tm_hour < 10 ? "0" : "")
|
||||
<< Tm->tm_hour << ":" << (Tm->tm_min < 10 ? "0" : "") << Tm->tm_min
|
||||
<< ":" << (Tm->tm_sec < 10 ? "0" : "") << Tm->tm_sec << " "
|
||||
<< req.endpoint.to_string() << " " << req.referrer
|
||||
<< (0 == req.referrer.length() ? "- " : " ") << req.agent
|
||||
<< (0 == req.agent.length() ? "- " : " ") << request;
|
||||
|
||||
RouteParameters route_parameters;
|
||||
APIGrammarParser api_parser(&route_parameters);
|
||||
|
||||
auto it = request.begin();
|
||||
const bool result = boost::spirit::qi::parse(it, request.end(), api_parser);
|
||||
|
||||
if (!result || (it != request.end()))
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
reply.content.clear();
|
||||
const int position = std::distance(request.begin(), it);
|
||||
reply.content.push_back(
|
||||
"{\"status\":400,\"status_message\":\"Query string malformed close to position ");
|
||||
std::string tmp_position_string;
|
||||
intToString(position, tmp_position_string);
|
||||
reply.content.push_back(tmp_position_string);
|
||||
reply.content.push_back("\"}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// parsing done, lets call the right plugin to handle the request
|
||||
BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed");
|
||||
routing_machine->RunQuery(route_parameters, reply);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::internalServerError);
|
||||
SimpleLogger().Write(logWARNING) << "[server error] code: " << e.what()
|
||||
<< ", uri: " << req.uri;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void RequestHandler::RegisterRoutingMachine(OSRM *osrm) { routing_machine = osrm; }
|
||||
@@ -1,306 +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 "Http/Request.h"
|
||||
#include "RequestParser.h"
|
||||
|
||||
namespace http
|
||||
{
|
||||
|
||||
RequestParser::RequestParser() : state_(method_start) {}
|
||||
|
||||
void RequestParser::Reset() { state_ = method_start; }
|
||||
|
||||
boost::tuple<boost::tribool, char *>
|
||||
RequestParser::Parse(Request &req, char *begin, char *end, http::CompressionType *compressionType)
|
||||
{
|
||||
while (begin != end)
|
||||
{
|
||||
boost::tribool result = consume(req, *begin++, compressionType);
|
||||
if (result || !result)
|
||||
{
|
||||
return boost::make_tuple(result, begin);
|
||||
}
|
||||
}
|
||||
boost::tribool result = boost::indeterminate;
|
||||
return boost::make_tuple(result, begin);
|
||||
}
|
||||
|
||||
boost::tribool
|
||||
RequestParser::consume(Request &req, char input, http::CompressionType *compressionType)
|
||||
{
|
||||
switch (state_)
|
||||
{
|
||||
case method_start:
|
||||
if (!isChar(input) || isCTL(input) || isTSpecial(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
state_ = method;
|
||||
return boost::indeterminate;
|
||||
case method:
|
||||
if (input == ' ')
|
||||
{
|
||||
state_ = uri;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
if (!isChar(input) || isCTL(input) || isTSpecial(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return boost::indeterminate;
|
||||
case uri_start:
|
||||
if (isCTL(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
state_ = uri;
|
||||
req.uri.push_back(input);
|
||||
return boost::indeterminate;
|
||||
case uri:
|
||||
if (input == ' ')
|
||||
{
|
||||
state_ = http_version_h;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
if (isCTL(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
req.uri.push_back(input);
|
||||
return boost::indeterminate;
|
||||
case http_version_h:
|
||||
if (input == 'H')
|
||||
{
|
||||
state_ = http_version_t_1;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
return false;
|
||||
case http_version_t_1:
|
||||
if (input == 'T')
|
||||
{
|
||||
state_ = http_version_t_2;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
return false;
|
||||
case http_version_t_2:
|
||||
if (input == 'T')
|
||||
{
|
||||
state_ = http_version_p;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
return false;
|
||||
case http_version_p:
|
||||
if (input == 'P')
|
||||
{
|
||||
state_ = http_version_slash;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
return false;
|
||||
case http_version_slash:
|
||||
if (input == '/')
|
||||
{
|
||||
state_ = http_version_major_start;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
return false;
|
||||
case http_version_major_start:
|
||||
if (isDigit(input))
|
||||
{
|
||||
state_ = http_version_major;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
return false;
|
||||
case http_version_major:
|
||||
if (input == '.')
|
||||
{
|
||||
state_ = http_version_minor_start;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
if (isDigit(input))
|
||||
{
|
||||
return boost::indeterminate;
|
||||
}
|
||||
return false;
|
||||
case http_version_minor_start:
|
||||
if (isDigit(input))
|
||||
{
|
||||
state_ = http_version_minor;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
return false;
|
||||
case http_version_minor:
|
||||
if (input == '\r')
|
||||
{
|
||||
state_ = expecting_newline_1;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
if (isDigit(input))
|
||||
{
|
||||
return boost::indeterminate;
|
||||
}
|
||||
return false;
|
||||
case expecting_newline_1:
|
||||
if (input == '\n')
|
||||
{
|
||||
state_ = header_line_start;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
return false;
|
||||
case header_line_start:
|
||||
if (header.name == "Accept-Encoding")
|
||||
{
|
||||
/* giving gzip precedence over deflate */
|
||||
if (header.value.find("deflate") != std::string::npos)
|
||||
{
|
||||
*compressionType = deflateRFC1951;
|
||||
}
|
||||
if (header.value.find("gzip") != std::string::npos)
|
||||
{
|
||||
*compressionType = gzipRFC1952;
|
||||
}
|
||||
}
|
||||
|
||||
if ("Referer" == header.name)
|
||||
{
|
||||
req.referrer = header.value;
|
||||
}
|
||||
|
||||
if ("User-Agent" == header.name)
|
||||
{
|
||||
req.agent = header.value;
|
||||
}
|
||||
|
||||
if (input == '\r')
|
||||
{
|
||||
state_ = expecting_newline_3;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
if (!isChar(input) || isCTL(input) || isTSpecial(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
state_ = header_name;
|
||||
header.Clear();
|
||||
header.name.push_back(input);
|
||||
return boost::indeterminate;
|
||||
case header_lws:
|
||||
if (input == '\r')
|
||||
{
|
||||
state_ = expecting_newline_2;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
if (input == ' ' || input == '\t')
|
||||
{
|
||||
return boost::indeterminate;
|
||||
}
|
||||
if (isCTL(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
state_ = header_value;
|
||||
return boost::indeterminate;
|
||||
case header_name:
|
||||
if (input == ':')
|
||||
{
|
||||
state_ = space_before_header_value;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
if (!isChar(input) || isCTL(input) || isTSpecial(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
header.name.push_back(input);
|
||||
return boost::indeterminate;
|
||||
case space_before_header_value:
|
||||
if (input == ' ')
|
||||
{
|
||||
state_ = header_value;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
return false;
|
||||
case header_value:
|
||||
if (input == '\r')
|
||||
{
|
||||
state_ = expecting_newline_2;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
if (isCTL(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
header.value.push_back(input);
|
||||
return boost::indeterminate;
|
||||
case expecting_newline_2:
|
||||
if (input == '\n')
|
||||
{
|
||||
state_ = header_line_start;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
return false;
|
||||
case expecting_newline_3:
|
||||
return (input == '\n');
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool RequestParser::isChar(int c) { return c >= 0 && c <= 127; }
|
||||
|
||||
inline bool RequestParser::isCTL(int c) { return (c >= 0 && c <= 31) || (c == 127); }
|
||||
|
||||
inline bool RequestParser::isTSpecial(int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '(':
|
||||
case ')':
|
||||
case '<':
|
||||
case '>':
|
||||
case '@':
|
||||
case ',':
|
||||
case ';':
|
||||
case ':':
|
||||
case '\\':
|
||||
case '"':
|
||||
case '/':
|
||||
case '[':
|
||||
case ']':
|
||||
case '?':
|
||||
case '=':
|
||||
case '{':
|
||||
case '}':
|
||||
case ' ':
|
||||
case '\t':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool RequestParser::isDigit(int c) { return c >= '0' && c <= '9'; }
|
||||
}
|
||||
@@ -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 REQUEST_PARSER_H
|
||||
#define REQUEST_PARSER_H
|
||||
|
||||
#include "Http/CompressionType.h"
|
||||
#include <osrm/Header.h>
|
||||
|
||||
#include <boost/logic/tribool.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
namespace http
|
||||
{
|
||||
|
||||
struct Request;
|
||||
|
||||
class RequestParser
|
||||
{
|
||||
public:
|
||||
RequestParser();
|
||||
void Reset();
|
||||
|
||||
boost::tuple<boost::tribool, char *>
|
||||
Parse(Request &req, char *begin, char *end, CompressionType *compressionType);
|
||||
|
||||
private:
|
||||
boost::tribool consume(Request &req, char input, CompressionType *compressionType);
|
||||
|
||||
inline bool isChar(int c);
|
||||
|
||||
inline bool isCTL(int c);
|
||||
|
||||
inline bool isTSpecial(int c);
|
||||
|
||||
inline bool isDigit(int c);
|
||||
|
||||
enum state
|
||||
{ method_start,
|
||||
method,
|
||||
uri_start,
|
||||
uri,
|
||||
http_version_h,
|
||||
http_version_t_1,
|
||||
http_version_t_2,
|
||||
http_version_p,
|
||||
http_version_slash,
|
||||
http_version_major_start,
|
||||
http_version_major,
|
||||
http_version_minor_start,
|
||||
http_version_minor,
|
||||
expecting_newline_1,
|
||||
header_line_start,
|
||||
header_lws,
|
||||
header_name,
|
||||
space_before_header_value,
|
||||
header_value,
|
||||
expecting_newline_2,
|
||||
expecting_newline_3 } state_;
|
||||
|
||||
Header header;
|
||||
};
|
||||
|
||||
} // namespace http
|
||||
|
||||
#endif // REQUEST_PARSER_H
|
||||
@@ -1,133 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../Algorithms/StronglyConnectedComponents.h"
|
||||
#include "../DataStructures/DynamicGraph.h"
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../Util/GraphLoader.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/UUID.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
typedef QueryEdge::EdgeData EdgeData;
|
||||
typedef DynamicGraph<EdgeData>::InputEdge InputEdge;
|
||||
|
||||
std::vector<NodeInfo> internal_to_external_node_map;
|
||||
std::vector<TurnRestriction> restrictions_vector;
|
||||
std::vector<NodeID> bollard_node_IDs_vector;
|
||||
std::vector<NodeID> traffic_light_node_IDs_vector;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
LogPolicy::GetInstance().Unmute();
|
||||
if (argc < 3)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "usage:\n" << argv[0] << " <osrm> <osrm.restrictions>";
|
||||
return -1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
SimpleLogger().Write() << "Using restrictions from file: " << argv[2];
|
||||
std::ifstream restriction_ifstream(argv[2], std::ios::binary);
|
||||
const UUID uuid_orig;
|
||||
UUID uuid_loaded;
|
||||
restriction_ifstream.read((char *)&uuid_loaded, sizeof(UUID));
|
||||
|
||||
if (!uuid_loaded.TestGraphUtil(uuid_orig))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << argv[2] << " was prepared with a different build. "
|
||||
"Reprocess to get rid of this warning.";
|
||||
}
|
||||
|
||||
if (!restriction_ifstream.good())
|
||||
{
|
||||
throw OSRMException("Could not access <osrm-restrictions> files");
|
||||
}
|
||||
uint32_t usable_restriction_count = 0;
|
||||
restriction_ifstream.read((char *)&usable_restriction_count, sizeof(uint32_t));
|
||||
restrictions_vector.resize(usable_restriction_count);
|
||||
|
||||
restriction_ifstream.read((char *)&(restrictions_vector[0]),
|
||||
usable_restriction_count * sizeof(TurnRestriction));
|
||||
restriction_ifstream.close();
|
||||
|
||||
std::ifstream input_stream;
|
||||
input_stream.open(argv[1], std::ifstream::in | std::ifstream::binary);
|
||||
|
||||
if (!input_stream.is_open())
|
||||
{
|
||||
throw OSRMException("Cannot open osrm file");
|
||||
}
|
||||
|
||||
std::vector<ImportEdge> edge_list;
|
||||
const NodeID number_of_nodes = readBinaryOSRMGraphFromStream(input_stream,
|
||||
edge_list,
|
||||
bollard_node_IDs_vector,
|
||||
traffic_light_node_IDs_vector,
|
||||
&internal_to_external_node_map,
|
||||
restrictions_vector);
|
||||
input_stream.close();
|
||||
|
||||
BOOST_ASSERT_MSG(restrictions_vector.size() == usable_restriction_count,
|
||||
"size of restrictions_vector changed");
|
||||
|
||||
SimpleLogger().Write() << restrictions_vector.size() << " restrictions, "
|
||||
<< bollard_node_IDs_vector.size() << " bollard nodes, "
|
||||
<< traffic_light_node_IDs_vector.size() << " traffic lights";
|
||||
|
||||
/***
|
||||
* Building an edge-expanded graph from node-based input an turn
|
||||
* restrictions
|
||||
*/
|
||||
|
||||
SimpleLogger().Write() << "Starting SCC graph traversal";
|
||||
std::shared_ptr<TarjanSCC> tarjan =
|
||||
std::make_shared<TarjanSCC>(number_of_nodes,
|
||||
edge_list,
|
||||
bollard_node_IDs_vector,
|
||||
traffic_light_node_IDs_vector,
|
||||
restrictions_vector,
|
||||
internal_to_external_node_map);
|
||||
std::vector<ImportEdge>().swap(edge_list);
|
||||
|
||||
tarjan->Run();
|
||||
SimpleLogger().Write() << "finished component analysis";
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,138 +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 BOOST_FILE_SYSTEM_FIX_H
|
||||
#define BOOST_FILE_SYSTEM_FIX_H
|
||||
|
||||
#include "OSRMException.h"
|
||||
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
// This is one big workaround for latest boost renaming woes.
|
||||
|
||||
#if BOOST_FILESYSTEM_VERSION < 3
|
||||
#warning Boost Installation with Filesystem3 missing, activating workaround
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
|
||||
// Validator for boost::filesystem::path, that verifies that the file
|
||||
// exists. The validate() function must be defined in the same namespace
|
||||
// as the target type, (boost::filesystem::path in this case), otherwise
|
||||
// it is not called
|
||||
// inline void validate(
|
||||
// boost::any & v,
|
||||
// const std::vector<std::string> & values,
|
||||
// boost::filesystem::path *,
|
||||
// int
|
||||
// ) {
|
||||
// boost::program_options::validators::check_first_occurrence(v);
|
||||
// const std::string & input_string =
|
||||
// boost::program_options::validators::get_single_string(values);
|
||||
// // SimpleLogger().Write() << "validator called for " << input_string;
|
||||
// // SimpleLogger().Write() << "validator called for " << input_string;
|
||||
// if(boost::filesystem::is_regular_file(input_string)) {
|
||||
// v = boost::any(boost::filesystem::path(input_string));
|
||||
// } else {
|
||||
// throw OSRMException(input_string + " not found");
|
||||
// }
|
||||
// }
|
||||
|
||||
// adapted from:
|
||||
// http://stackoverflow.com/questions/1746136/how-do-i-normalize-a-pathname-using-boostfilesystem
|
||||
inline boost::filesystem::path
|
||||
portable_canonical(const boost::filesystem::path &relative_path,
|
||||
const boost::filesystem::path ¤t_path = boost::filesystem::current_path())
|
||||
{
|
||||
const boost::filesystem::path absolute_path =
|
||||
boost::filesystem::absolute(relative_path, current_path);
|
||||
|
||||
boost::filesystem::path canonical_path;
|
||||
for (auto path_iterator = absolute_path.begin(); path_iterator != absolute_path.end();
|
||||
++path_iterator)
|
||||
{
|
||||
if (".." == path_iterator->string())
|
||||
{
|
||||
// /a/b/.. is not necessarily /a if b is a symbolic link
|
||||
if (boost::filesystem::is_symlink(canonical_path))
|
||||
{
|
||||
canonical_path /= *path_iterator;
|
||||
}
|
||||
else if (".." == canonical_path.filename())
|
||||
{
|
||||
// /a/b/../.. is not /a/b/.. under most circumstances
|
||||
// We can end up with ..s in our result because of symbolic links
|
||||
canonical_path /= *path_iterator;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise it should be safe to resolve the parent
|
||||
canonical_path = canonical_path.parent_path();
|
||||
}
|
||||
}
|
||||
else if ("." == path_iterator->string())
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just cat other path entries
|
||||
canonical_path /= *path_iterator;
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT(canonical_path.is_absolute());
|
||||
BOOST_ASSERT(boost::filesystem::exists(canonical_path));
|
||||
return canonical_path;
|
||||
}
|
||||
|
||||
#if BOOST_FILESYSTEM_VERSION < 3
|
||||
|
||||
inline path temp_directory_path()
|
||||
{
|
||||
char *buffer;
|
||||
buffer = tmpnam(NULL);
|
||||
|
||||
return path(buffer);
|
||||
}
|
||||
|
||||
inline path unique_path(const path &) { return temp_directory_path(); }
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_FILESYSTEM_VERSION
|
||||
#define BOOST_FILESYSTEM_VERSION 3
|
||||
#endif
|
||||
|
||||
#endif /* BOOST_FILE_SYSTEM_FIX_H */
|
||||
@@ -1,335 +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 DATA_STORE_OPTIONS_H
|
||||
#define DATA_STORE_OPTIONS_H
|
||||
|
||||
#include "BoostFileSystemFix.h"
|
||||
#include "GitDescription.h"
|
||||
#include "OSRMException.h"
|
||||
#include "SimpleLogger.h"
|
||||
|
||||
#include <osrm/ServerPaths.h>
|
||||
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
void AssertPathExists(const boost::filesystem::path& path)
|
||||
{
|
||||
if (!boost::filesystem::is_regular_file(path))
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << path << " check failed";
|
||||
throw OSRMException(path.string() + " not found.");
|
||||
} else {
|
||||
SimpleLogger().Write(logDEBUG) << path << " exists";
|
||||
}
|
||||
}
|
||||
|
||||
// support old capitalized option names by down-casing them with a regex replace
|
||||
inline void PrepareConfigFile(
|
||||
const boost::filesystem::path & path,
|
||||
std::string & output
|
||||
) {
|
||||
boost::filesystem::fstream config_stream(path);
|
||||
std::string input_str(
|
||||
(std::istreambuf_iterator<char>(config_stream)),
|
||||
std::istreambuf_iterator<char>()
|
||||
);
|
||||
boost::regex regex("^([^=]*)"); //match from start of line to '='
|
||||
std::string format("\\L$1\\E"); //replace with downcased substring
|
||||
output = boost::regex_replace( input_str, regex, format );
|
||||
}
|
||||
|
||||
// generate boost::program_options object for the routing part
|
||||
inline bool GenerateDataStoreOptions(const int argc, const char * argv[], ServerPaths & paths)
|
||||
{
|
||||
// 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>(
|
||||
&paths["config"]
|
||||
)->default_value("server.ini"),
|
||||
"Path to a configuration file"
|
||||
);
|
||||
|
||||
// declare a group of options that will be allowed both on command line
|
||||
// as well as in a config file
|
||||
boost::program_options::options_description config_options("Configuration");
|
||||
config_options.add_options()
|
||||
(
|
||||
"hsgrdata",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["hsgrdata"]),
|
||||
".hsgr file"
|
||||
)
|
||||
(
|
||||
"nodesdata",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["nodesdata"]),
|
||||
".nodes file"
|
||||
)
|
||||
(
|
||||
"edgesdata",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["edgesdata"]),
|
||||
".edges file"
|
||||
)
|
||||
(
|
||||
"geometry",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["geometry"]),
|
||||
".geometry file"
|
||||
)
|
||||
(
|
||||
"ramindex",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["ramindex"]),
|
||||
".ramIndex file"
|
||||
)
|
||||
(
|
||||
"fileindex",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["fileindex"]),
|
||||
".fileIndex file"
|
||||
)
|
||||
(
|
||||
"namesdata",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["namesdata"]),
|
||||
".names file"
|
||||
)
|
||||
(
|
||||
"timestamp",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["timestamp"]),
|
||||
".timestamp file"
|
||||
);
|
||||
|
||||
// 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()
|
||||
(
|
||||
"base,b",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["base"]),
|
||||
"base path to .osrm file"
|
||||
);
|
||||
|
||||
// positional option
|
||||
boost::program_options::positional_options_description positional_options;
|
||||
positional_options.add("base", 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]) + " [<options>] <configuration>"
|
||||
);
|
||||
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);
|
||||
|
||||
const bool parameter_present =
|
||||
(paths.find("hsgrdata") != paths.end() && !paths.find("hsgrdata" )->second.string().empty()) ||
|
||||
(paths.find("nodesdata") != paths.end() && !paths.find("nodesdata")->second.string().empty()) ||
|
||||
(paths.find("edgesdata") != paths.end() && !paths.find("edgesdata")->second.string().empty()) ||
|
||||
(paths.find("geometry") != paths.end() && !paths.find("geometry" )->second.string().empty()) ||
|
||||
(paths.find("ramindex") != paths.end() && !paths.find("ramindex" )->second.string().empty()) ||
|
||||
(paths.find("fileindex") != paths.end() && !paths.find("fileindex")->second.string().empty()) ||
|
||||
(paths.find("timestamp") != paths.end() && !paths.find("timestamp")->second.string().empty());
|
||||
|
||||
if (parameter_present)
|
||||
{
|
||||
if (
|
||||
( paths.find("config") != paths.end() &&
|
||||
boost::filesystem::is_regular_file(paths.find("config")->second)
|
||||
) || option_variables.count("base")
|
||||
)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "conflicting parameters";
|
||||
SimpleLogger().Write() << visible_options;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// parse config file
|
||||
ServerPaths::iterator path_iterator = paths.find("config");
|
||||
if (
|
||||
path_iterator != paths.end() &&
|
||||
boost::filesystem::is_regular_file(path_iterator->second) &&
|
||||
!option_variables.count("base")
|
||||
)
|
||||
{
|
||||
SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string();
|
||||
std::string config_str;
|
||||
PrepareConfigFile( path_iterator->second, config_str );
|
||||
std::stringstream config_stream( config_str );
|
||||
boost::program_options::store(
|
||||
parse_config_file(config_stream, config_file_options),
|
||||
option_variables
|
||||
);
|
||||
boost::program_options::notify(option_variables);
|
||||
}
|
||||
else if (option_variables.count("base"))
|
||||
{
|
||||
path_iterator = paths.find("base");
|
||||
BOOST_ASSERT( paths.end() != path_iterator );
|
||||
std::string base_string = path_iterator->second.string();
|
||||
|
||||
path_iterator = paths.find("hsgrdata");
|
||||
if (path_iterator != paths.end())
|
||||
{
|
||||
path_iterator->second = base_string + ".hsgr";
|
||||
}
|
||||
|
||||
path_iterator = paths.find("nodesdata");
|
||||
if (path_iterator != paths.end())
|
||||
{
|
||||
path_iterator->second = base_string + ".nodes";
|
||||
}
|
||||
|
||||
path_iterator = paths.find("edgesdata");
|
||||
if (path_iterator != paths.end())
|
||||
{
|
||||
path_iterator->second = base_string + ".edges";
|
||||
}
|
||||
|
||||
path_iterator = paths.find("geometry");
|
||||
if (path_iterator != paths.end())
|
||||
{
|
||||
path_iterator->second = base_string + ".geometry";
|
||||
}
|
||||
|
||||
path_iterator = paths.find("ramindex");
|
||||
if (path_iterator != paths.end())
|
||||
{
|
||||
path_iterator->second = base_string + ".ramIndex";
|
||||
}
|
||||
|
||||
path_iterator = paths.find("fileindex");
|
||||
if (path_iterator != paths.end())
|
||||
{
|
||||
path_iterator->second = base_string + ".fileIndex";
|
||||
}
|
||||
|
||||
path_iterator = paths.find("namesdata");
|
||||
if (path_iterator != paths.end())
|
||||
{
|
||||
path_iterator->second = base_string + ".names";
|
||||
}
|
||||
|
||||
path_iterator = paths.find("timestamp");
|
||||
if (path_iterator != paths.end())
|
||||
{
|
||||
path_iterator->second = base_string + ".timestamp";
|
||||
}
|
||||
}
|
||||
|
||||
path_iterator = paths.find("hsgrdata");
|
||||
if (path_iterator == paths.end() || path_iterator->second.string().empty())
|
||||
{
|
||||
throw OSRMException(".hsgr file must be specified");
|
||||
}
|
||||
AssertPathExists(path_iterator->second);
|
||||
|
||||
path_iterator = paths.find("nodesdata");
|
||||
if (path_iterator == paths.end() || path_iterator->second.string().empty())
|
||||
{
|
||||
throw OSRMException(".nodes file must be specified");
|
||||
}
|
||||
AssertPathExists(path_iterator->second);
|
||||
|
||||
path_iterator = paths.find("edgesdata");
|
||||
if (path_iterator == paths.end() || path_iterator->second.string().empty())
|
||||
{
|
||||
throw OSRMException(".edges file must be specified");
|
||||
}
|
||||
AssertPathExists(path_iterator->second);
|
||||
|
||||
path_iterator = paths.find("geometry");
|
||||
if (path_iterator == paths.end() || path_iterator->second.string().empty())
|
||||
{
|
||||
throw OSRMException(".geometry file must be specified");
|
||||
}
|
||||
AssertPathExists(path_iterator->second);
|
||||
|
||||
path_iterator = paths.find("ramindex");
|
||||
if (path_iterator == paths.end() || path_iterator->second.string().empty())
|
||||
{
|
||||
throw OSRMException(".ramindex file must be specified");
|
||||
}
|
||||
AssertPathExists(path_iterator->second);
|
||||
|
||||
path_iterator = paths.find("fileindex");
|
||||
if (path_iterator == paths.end() || path_iterator->second.string().empty())
|
||||
{
|
||||
throw OSRMException(".fileindex file must be specified");
|
||||
}
|
||||
AssertPathExists(path_iterator->second);
|
||||
|
||||
path_iterator = paths.find("namesdata");
|
||||
if (path_iterator == paths.end() || path_iterator->second.string().empty())
|
||||
{
|
||||
throw OSRMException(".names file must be specified");
|
||||
}
|
||||
AssertPathExists(path_iterator->second);
|
||||
|
||||
path_iterator = paths.find("timestamp");
|
||||
if (path_iterator == paths.end() || path_iterator->second.string().empty())
|
||||
{
|
||||
throw OSRMException(".timestamp file must be specified");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* DATA_STORE_OPTIONS_H */
|
||||
@@ -1,315 +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 GRAPHLOADER_H
|
||||
#define GRAPHLOADER_H
|
||||
|
||||
#include "OSRMException.h"
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
#include "../DataStructures/ImportEdge.h"
|
||||
#include "../DataStructures/QueryNode.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/UUID.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
template <typename EdgeT>
|
||||
NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
|
||||
std::vector<EdgeT> &edge_list,
|
||||
std::vector<NodeID> &barrier_node_list,
|
||||
std::vector<NodeID> &traffic_light_node_list,
|
||||
std::vector<NodeInfo> *int_to_ext_node_id_map,
|
||||
std::vector<TurnRestriction> &restriction_list)
|
||||
{
|
||||
const UUID uuid_orig;
|
||||
UUID uuid_loaded;
|
||||
input_stream.read((char *)&uuid_loaded, sizeof(UUID));
|
||||
|
||||
if (!uuid_loaded.TestGraphUtil(uuid_orig))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << ".osrm was prepared with different build."
|
||||
"Reprocess to get rid of this warning.";
|
||||
}
|
||||
|
||||
NodeID n, source, target;
|
||||
EdgeID m;
|
||||
short dir; // direction (0 = open, 1 = forward, 2+ = open)
|
||||
std::unordered_map<NodeID, NodeID> ext_to_int_id_map;
|
||||
input_stream.read((char *)&n, sizeof(NodeID));
|
||||
SimpleLogger().Write() << "Importing n = " << n << " nodes ";
|
||||
ExternalMemoryNode node;
|
||||
for (NodeID i = 0; i < n; ++i)
|
||||
{
|
||||
input_stream.read((char *)&node, sizeof(ExternalMemoryNode));
|
||||
int_to_ext_node_id_map->emplace_back(node.lat, node.lon, node.id);
|
||||
ext_to_int_id_map.emplace(node.id, i);
|
||||
if (node.bollard)
|
||||
{
|
||||
barrier_node_list.emplace_back(i);
|
||||
}
|
||||
if (node.trafficLight)
|
||||
{
|
||||
traffic_light_node_list.emplace_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
// tighten vector sizes
|
||||
barrier_node_list.shrink_to_fit();
|
||||
traffic_light_node_list.shrink_to_fit();
|
||||
input_stream.read((char *)&m, sizeof(unsigned));
|
||||
SimpleLogger().Write() << " and " << m << " edges ";
|
||||
for (TurnRestriction ¤t_restriction : restriction_list)
|
||||
{
|
||||
auto internal_id_iter = ext_to_int_id_map.find(current_restriction.fromNode);
|
||||
if (internal_id_iter == ext_to_int_id_map.end())
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "Unmapped from Node of restriction";
|
||||
continue;
|
||||
}
|
||||
current_restriction.fromNode = internal_id_iter->second;
|
||||
|
||||
internal_id_iter = ext_to_int_id_map.find(current_restriction.viaNode);
|
||||
if (internal_id_iter == ext_to_int_id_map.end())
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "Unmapped via node of restriction";
|
||||
continue;
|
||||
}
|
||||
current_restriction.viaNode = internal_id_iter->second;
|
||||
|
||||
internal_id_iter = ext_to_int_id_map.find(current_restriction.toNode);
|
||||
if (internal_id_iter == ext_to_int_id_map.end())
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "Unmapped to node of restriction";
|
||||
continue;
|
||||
}
|
||||
current_restriction.toNode = internal_id_iter->second;
|
||||
}
|
||||
|
||||
edge_list.reserve(m);
|
||||
EdgeWeight weight;
|
||||
short type;
|
||||
NodeID nameID;
|
||||
int length;
|
||||
bool is_roundabout, ignore_in_grid, is_access_restricted, is_contra_flow, is_split;
|
||||
|
||||
for (EdgeID i = 0; i < m; ++i)
|
||||
{
|
||||
input_stream.read((char *)&source, sizeof(unsigned));
|
||||
input_stream.read((char *)&target, sizeof(unsigned));
|
||||
input_stream.read((char *)&length, sizeof(int));
|
||||
input_stream.read((char *)&dir, sizeof(short));
|
||||
input_stream.read((char *)&weight, sizeof(int));
|
||||
input_stream.read((char *)&type, sizeof(short));
|
||||
input_stream.read((char *)&nameID, sizeof(unsigned));
|
||||
input_stream.read((char *)&is_roundabout, sizeof(bool));
|
||||
input_stream.read((char *)&ignore_in_grid, sizeof(bool));
|
||||
input_stream.read((char *)&is_access_restricted, sizeof(bool));
|
||||
input_stream.read((char *)&is_contra_flow, sizeof(bool));
|
||||
input_stream.read((char *)&is_split, sizeof(bool));
|
||||
|
||||
BOOST_ASSERT_MSG(length > 0, "loaded null length edge");
|
||||
BOOST_ASSERT_MSG(weight > 0, "loaded null weight");
|
||||
BOOST_ASSERT_MSG(0 <= dir && dir <= 2, "loaded bogus direction");
|
||||
|
||||
bool forward = true;
|
||||
bool backward = true;
|
||||
if (1 == dir)
|
||||
{
|
||||
backward = false;
|
||||
}
|
||||
if (2 == dir)
|
||||
{
|
||||
forward = false;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(type >= 0);
|
||||
|
||||
// translate the external NodeIDs to internal IDs
|
||||
auto internal_id_iter = ext_to_int_id_map.find(source);
|
||||
if (ext_to_int_id_map.find(source) == ext_to_int_id_map.end())
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
SimpleLogger().Write(logWARNING) << " unresolved source NodeID: " << source;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
source = internal_id_iter->second;
|
||||
internal_id_iter = ext_to_int_id_map.find(target);
|
||||
if (ext_to_int_id_map.find(target) == ext_to_int_id_map.end())
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
SimpleLogger().Write(logWARNING) << "unresolved target NodeID : " << target;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
target = internal_id_iter->second;
|
||||
BOOST_ASSERT_MSG(source != UINT_MAX && target != UINT_MAX, "nonexisting source or target");
|
||||
|
||||
if (source > target)
|
||||
{
|
||||
std::swap(source, target);
|
||||
std::swap(forward, backward);
|
||||
}
|
||||
|
||||
edge_list.emplace_back(source,
|
||||
target,
|
||||
nameID,
|
||||
weight,
|
||||
forward,
|
||||
backward,
|
||||
type,
|
||||
is_roundabout,
|
||||
ignore_in_grid,
|
||||
is_access_restricted,
|
||||
is_contra_flow,
|
||||
is_split);
|
||||
}
|
||||
|
||||
std::sort(edge_list.begin(), edge_list.end());
|
||||
for (unsigned i = 1; i < edge_list.size(); ++i)
|
||||
{
|
||||
if ((edge_list[i - 1].target() == edge_list[i].target()) &&
|
||||
(edge_list[i - 1].source() == edge_list[i].source()))
|
||||
{
|
||||
const bool edge_flags_equivalent =
|
||||
(edge_list[i - 1].isForward() == edge_list[i].isForward()) &&
|
||||
(edge_list[i - 1].isBackward() == edge_list[i].isBackward());
|
||||
const bool edge_flags_are_superset1 =
|
||||
(edge_list[i - 1].isForward() && edge_list[i - 1].isBackward()) &&
|
||||
(edge_list[i].isBackward() != edge_list[i].isBackward());
|
||||
const bool edge_flags_are_superset_2 =
|
||||
(edge_list[i].isForward() && edge_list[i].isBackward()) &&
|
||||
(edge_list[i - 1].isBackward() != edge_list[i - 1].isBackward());
|
||||
|
||||
if (edge_flags_equivalent)
|
||||
{
|
||||
edge_list[i]._weight = std::min(edge_list[i - 1].weight(), edge_list[i].weight());
|
||||
edge_list[i - 1]._source = UINT_MAX;
|
||||
}
|
||||
else if (edge_flags_are_superset1)
|
||||
{
|
||||
if (edge_list[i - 1].weight() <= edge_list[i].weight())
|
||||
{
|
||||
// edge i-1 is smaller and goes in both directions. Throw away the other edge
|
||||
edge_list[i]._source = UINT_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
// edge i-1 is open in both directions, but edge i is smaller in one direction.
|
||||
// Close edge i-1 in this direction
|
||||
edge_list[i - 1].forward = !edge_list[i].isForward();
|
||||
edge_list[i - 1].backward = !edge_list[i].isBackward();
|
||||
}
|
||||
}
|
||||
else if (edge_flags_are_superset_2)
|
||||
{
|
||||
if (edge_list[i - 1].weight() <= edge_list[i].weight())
|
||||
{
|
||||
// edge i-1 is smaller for one direction. edge i is open in both. close edge i
|
||||
// in the other direction
|
||||
edge_list[i].forward = !edge_list[i - 1].isForward();
|
||||
edge_list[i].backward = !edge_list[i - 1].isBackward();
|
||||
}
|
||||
else
|
||||
{
|
||||
// edge i is smaller and goes in both direction. Throw away edge i-1
|
||||
edge_list[i - 1]._source = UINT_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto new_end_iter = std::remove_if(edge_list.begin(),
|
||||
edge_list.end(),
|
||||
[](const EdgeT &edge)
|
||||
{ return edge.source() == UINT_MAX; });
|
||||
ext_to_int_id_map.clear();
|
||||
edge_list.erase(new_end_iter, edge_list.end()); // remove excess candidates.
|
||||
edge_list.shrink_to_fit();
|
||||
SimpleLogger().Write() << "Graph loaded ok and has " << edge_list.size() << " edges";
|
||||
return n;
|
||||
}
|
||||
|
||||
template <typename NodeT, typename EdgeT>
|
||||
unsigned readHSGRFromStream(const boost::filesystem::path &hsgr_file,
|
||||
std::vector<NodeT> &node_list,
|
||||
std::vector<EdgeT> &edge_list,
|
||||
unsigned *check_sum)
|
||||
{
|
||||
if (!boost::filesystem::exists(hsgr_file))
|
||||
{
|
||||
throw OSRMException("hsgr file does not exist");
|
||||
}
|
||||
if (0 == boost::filesystem::file_size(hsgr_file))
|
||||
{
|
||||
throw OSRMException("hsgr file is empty");
|
||||
}
|
||||
|
||||
boost::filesystem::ifstream hsgr_input_stream(hsgr_file, std::ios::binary);
|
||||
|
||||
UUID uuid_loaded, uuid_orig;
|
||||
hsgr_input_stream.read((char *)&uuid_loaded, sizeof(UUID));
|
||||
if (!uuid_loaded.TestGraphUtil(uuid_orig))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build. "
|
||||
"Reprocess to get rid of this warning.";
|
||||
}
|
||||
|
||||
unsigned number_of_nodes = 0;
|
||||
unsigned number_of_edges = 0;
|
||||
hsgr_input_stream.read((char *)check_sum, sizeof(unsigned));
|
||||
hsgr_input_stream.read((char *)&number_of_nodes, sizeof(unsigned));
|
||||
BOOST_ASSERT_MSG(0 != number_of_nodes, "number of nodes is zero");
|
||||
hsgr_input_stream.read((char *)&number_of_edges, sizeof(unsigned));
|
||||
|
||||
SimpleLogger().Write() << "number_of_nodes: " << number_of_nodes
|
||||
<< ", number_of_edges: " << number_of_edges;
|
||||
|
||||
// BOOST_ASSERT_MSG( 0 != number_of_edges, "number of edges is zero");
|
||||
node_list.resize(number_of_nodes + 1);
|
||||
hsgr_input_stream.read((char *)&(node_list[0]), number_of_nodes * sizeof(NodeT));
|
||||
|
||||
edge_list.resize(number_of_edges);
|
||||
hsgr_input_stream.read((char *)&(edge_list[0]), number_of_edges * sizeof(EdgeT));
|
||||
hsgr_input_stream.close();
|
||||
|
||||
return number_of_nodes;
|
||||
}
|
||||
|
||||
#endif // GRAPHLOADER_H
|
||||
@@ -1,41 +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 OPENMP_WRAPPER_H
|
||||
#define OPENMP_WRAPPER_H
|
||||
|
||||
#ifdef _OPENMP
|
||||
extern "C" {
|
||||
#include <omp.h>
|
||||
}
|
||||
#else
|
||||
inline int omp_get_num_procs() { return 1; }
|
||||
inline int omp_get_max_threads() { return 1; }
|
||||
inline int omp_get_thread_num() { return 0; }
|
||||
inline void omp_set_num_threads(int i) {}
|
||||
#endif // _OPENMP
|
||||
#endif // OPENMP_WRAPPER_H
|
||||
@@ -1,282 +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 PROGAM_OPTIONS_H
|
||||
#define PROGAM_OPTIONS_H
|
||||
|
||||
#include "GitDescription.h"
|
||||
#include "OSRMException.h"
|
||||
#include "SimpleLogger.h"
|
||||
|
||||
#include <osrm/ServerPaths.h>
|
||||
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
const static unsigned INIT_OK_START_ENGINE = 0;
|
||||
const static unsigned INIT_OK_DO_NOT_START_ENGINE = 1;
|
||||
const static unsigned INIT_FAILED = -1;
|
||||
|
||||
// support old capitalized option names by down-casing them with a regex replace
|
||||
inline void PrepareConfigFile(const boost::filesystem::path &path, std::string &output)
|
||||
{
|
||||
std::ifstream config_stream(path.string().c_str());
|
||||
std::string input_str((std::istreambuf_iterator<char>(config_stream)),
|
||||
std::istreambuf_iterator<char>());
|
||||
std::regex regex("^([^=]*)"); // match from start of line to '='
|
||||
std::string format("\\L$1\\E"); // replace with downcased substring
|
||||
output = std::regex_replace(input_str, regex, format);
|
||||
}
|
||||
|
||||
// generate boost::program_options object for the routing part
|
||||
inline unsigned GenerateServerProgramOptions(const int argc,
|
||||
const char *argv[],
|
||||
ServerPaths &paths,
|
||||
std::string &ip_address,
|
||||
int &ip_port,
|
||||
int &requested_num_threads,
|
||||
bool &use_shared_memory,
|
||||
bool &trial)
|
||||
{
|
||||
|
||||
// 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>(&paths["config"])
|
||||
->default_value("server.ini"),
|
||||
"Path to a configuration file")(
|
||||
"trial",
|
||||
boost::program_options::value<bool>(&trial)->implicit_value(true),
|
||||
"Quit after initialization");
|
||||
|
||||
// declare a group of options that will be allowed both on command line
|
||||
// as well as in a config file
|
||||
boost::program_options::options_description config_options("Configuration");
|
||||
config_options.add_options()(
|
||||
"hsgrdata",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["hsgrdata"]),
|
||||
".hsgr file")("nodesdata",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["nodesdata"]),
|
||||
".nodes file")(
|
||||
"edgesdata",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["edgesdata"]),
|
||||
".edges file")("geometry",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["geometries"]),
|
||||
".geometry file")(
|
||||
"ramindex",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["ramindex"]),
|
||||
".ramIndex file")(
|
||||
"fileindex",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["fileindex"]),
|
||||
"File index file")(
|
||||
"namesdata",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["namesdata"]),
|
||||
".names file")("timestamp",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["timestamp"]),
|
||||
".timestamp file")(
|
||||
"ip,i",
|
||||
boost::program_options::value<std::string>(&ip_address)->default_value("0.0.0.0"),
|
||||
"IP address")(
|
||||
"port,p", boost::program_options::value<int>(&ip_port)->default_value(5000), "TCP/IP port")(
|
||||
"threads,t",
|
||||
boost::program_options::value<int>(&requested_num_threads)->default_value(8),
|
||||
"Number of threads to use")(
|
||||
"sharedmemory,s",
|
||||
boost::program_options::value<bool>(&use_shared_memory)->implicit_value(true),
|
||||
"Load data from shared memory");
|
||||
|
||||
// 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()(
|
||||
"base,b",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["base"]),
|
||||
"base path to .osrm file");
|
||||
|
||||
// positional option
|
||||
boost::program_options::positional_options_description positional_options;
|
||||
positional_options.add("base", 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]) + " <base.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 INIT_OK_DO_NOT_START_ENGINE;
|
||||
}
|
||||
|
||||
if (option_variables.count("help"))
|
||||
{
|
||||
SimpleLogger().Write() << visible_options;
|
||||
return INIT_OK_DO_NOT_START_ENGINE;
|
||||
}
|
||||
|
||||
boost::program_options::notify(option_variables);
|
||||
|
||||
// parse config file
|
||||
ServerPaths::iterator path_iterator = paths.find("config");
|
||||
if (path_iterator != paths.end() && boost::filesystem::is_regular_file(path_iterator->second) &&
|
||||
!option_variables.count("base"))
|
||||
{
|
||||
SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string();
|
||||
std::string config_str;
|
||||
PrepareConfigFile(path_iterator->second, config_str);
|
||||
std::stringstream config_stream(config_str);
|
||||
boost::program_options::store(parse_config_file(config_stream, config_file_options),
|
||||
option_variables);
|
||||
boost::program_options::notify(option_variables);
|
||||
}
|
||||
|
||||
if (1 > requested_num_threads)
|
||||
{
|
||||
throw OSRMException("Number of threads must be a positive number");
|
||||
}
|
||||
|
||||
if (!use_shared_memory && option_variables.count("base"))
|
||||
{
|
||||
path_iterator = paths.find("base");
|
||||
BOOST_ASSERT(paths.end() != path_iterator);
|
||||
std::string base_string = path_iterator->second.string();
|
||||
|
||||
path_iterator = paths.find("hsgrdata");
|
||||
if (path_iterator != paths.end() &&
|
||||
!boost::filesystem::is_regular_file(path_iterator->second))
|
||||
{
|
||||
path_iterator->second = base_string + ".hsgr";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw OSRMException(base_string + ".hsgr not found");
|
||||
}
|
||||
|
||||
path_iterator = paths.find("nodesdata");
|
||||
if (path_iterator != paths.end() &&
|
||||
!boost::filesystem::is_regular_file(path_iterator->second))
|
||||
{
|
||||
path_iterator->second = base_string + ".nodes";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw OSRMException(base_string + ".nodes not found");
|
||||
}
|
||||
|
||||
path_iterator = paths.find("edgesdata");
|
||||
if (path_iterator != paths.end() &&
|
||||
!boost::filesystem::is_regular_file(path_iterator->second))
|
||||
{
|
||||
path_iterator->second = base_string + ".edges";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw OSRMException(base_string + ".edges not found");
|
||||
}
|
||||
|
||||
path_iterator = paths.find("geometries");
|
||||
if (path_iterator != paths.end() &&
|
||||
!boost::filesystem::is_regular_file(path_iterator->second))
|
||||
{
|
||||
path_iterator->second = base_string + ".geometry";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw OSRMException(base_string + ".geometry not found");
|
||||
}
|
||||
|
||||
path_iterator = paths.find("ramindex");
|
||||
if (path_iterator != paths.end() &&
|
||||
!boost::filesystem::is_regular_file(path_iterator->second))
|
||||
{
|
||||
path_iterator->second = base_string + ".ramIndex";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw OSRMException(base_string + ".ramIndex not found");
|
||||
}
|
||||
|
||||
path_iterator = paths.find("fileindex");
|
||||
if (path_iterator != paths.end() &&
|
||||
!boost::filesystem::is_regular_file(path_iterator->second))
|
||||
{
|
||||
path_iterator->second = base_string + ".fileIndex";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw OSRMException(base_string + ".fileIndex not found");
|
||||
}
|
||||
|
||||
path_iterator = paths.find("namesdata");
|
||||
if (path_iterator != paths.end() &&
|
||||
!boost::filesystem::is_regular_file(path_iterator->second))
|
||||
{
|
||||
path_iterator->second = base_string + ".names";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw OSRMException(base_string + ".namesIndex not found");
|
||||
}
|
||||
|
||||
path_iterator = paths.find("timestamp");
|
||||
if (path_iterator != paths.end() &&
|
||||
!boost::filesystem::is_regular_file(path_iterator->second))
|
||||
{
|
||||
path_iterator->second = base_string + ".timestamp";
|
||||
}
|
||||
|
||||
return INIT_OK_START_ENGINE;
|
||||
}
|
||||
if (use_shared_memory && !option_variables.count("base"))
|
||||
{
|
||||
return INIT_OK_START_ENGINE;
|
||||
}
|
||||
SimpleLogger().Write() << visible_options;
|
||||
return INIT_OK_DO_NOT_START_ENGINE;
|
||||
}
|
||||
|
||||
#endif /* PROGRAM_OPTIONS_H */
|
||||
@@ -1,151 +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 SIMPLE_LOGGER_H
|
||||
#define SIMPLE_LOGGER_H
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
|
||||
enum LogLevel
|
||||
{ logINFO,
|
||||
logWARNING,
|
||||
logDEBUG };
|
||||
|
||||
const char COL_RESET[] = "\x1b[0m";
|
||||
const char RED[] = "\x1b[31m";
|
||||
const char GREEN[] = "\x1b[32m";
|
||||
const char YELLOW[] = "\x1b[33m";
|
||||
const char BLUE[] = "\x1b[34m";
|
||||
const char MAGENTA[] = "\x1b[35m";
|
||||
const char CYAN[] = "\x1b[36m";
|
||||
|
||||
class LogPolicy
|
||||
{
|
||||
public:
|
||||
void Unmute() { m_is_mute = false; }
|
||||
|
||||
void Mute() { m_is_mute = true; }
|
||||
|
||||
bool IsMute() const { return m_is_mute; }
|
||||
|
||||
static LogPolicy &GetInstance()
|
||||
{
|
||||
static LogPolicy runningInstance;
|
||||
return runningInstance;
|
||||
}
|
||||
|
||||
LogPolicy(const LogPolicy &) = delete;
|
||||
|
||||
private:
|
||||
LogPolicy() : m_is_mute(true) {}
|
||||
bool m_is_mute;
|
||||
};
|
||||
|
||||
class SimpleLogger
|
||||
{
|
||||
public:
|
||||
SimpleLogger() : level(logINFO) {}
|
||||
|
||||
std::mutex& get_mutex()
|
||||
{
|
||||
static std::mutex m;
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
std::ostringstream &Write(LogLevel l = logINFO)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(get_mutex());
|
||||
try
|
||||
{
|
||||
level = l;
|
||||
os << "[";
|
||||
switch (level)
|
||||
{
|
||||
case logINFO:
|
||||
os << "info";
|
||||
break;
|
||||
case logWARNING:
|
||||
os << "warn";
|
||||
break;
|
||||
case logDEBUG:
|
||||
#ifndef NDEBUG
|
||||
os << "debug";
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
BOOST_ASSERT_MSG(false, "should not happen");
|
||||
break;
|
||||
}
|
||||
os << "] ";
|
||||
}
|
||||
catch (...) {}
|
||||
return os;
|
||||
}
|
||||
|
||||
virtual ~SimpleLogger()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(get_mutex());
|
||||
if (!LogPolicy::GetInstance().IsMute())
|
||||
{
|
||||
const bool is_terminal = isatty(fileno(stdout));
|
||||
switch (level)
|
||||
{
|
||||
case logINFO:
|
||||
std::cout << os.str() << (is_terminal ? COL_RESET : "") << std::endl;
|
||||
break;
|
||||
case logWARNING:
|
||||
std::cerr << (is_terminal ? RED : "") << os.str() << (is_terminal ? COL_RESET : "")
|
||||
<< std::endl;
|
||||
break;
|
||||
case logDEBUG:
|
||||
#ifndef NDEBUG
|
||||
std::cout << (is_terminal ? YELLOW : "") << os.str()
|
||||
<< (is_terminal ? COL_RESET : "") << std::endl;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
BOOST_ASSERT_MSG(false, "should not happen");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
LogLevel level;
|
||||
std::ostringstream os;
|
||||
};
|
||||
|
||||
#endif /* SIMPLE_LOGGER_H */
|
||||
@@ -1,283 +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 STRINGUTIL_H
|
||||
#define STRINGUTIL_H
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/spirit/include/karma.hpp>
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// precision: position after decimal point
|
||||
// length: maximum number of digits including comma and decimals
|
||||
template <int length, int precision> static inline char *printInt(char *buffer, int value)
|
||||
{
|
||||
bool minus = false;
|
||||
if (value < 0)
|
||||
{
|
||||
minus = true;
|
||||
value = -value;
|
||||
}
|
||||
buffer += length - 1;
|
||||
for (int i = 0; i < precision; i++)
|
||||
{
|
||||
*buffer = '0' + (value % 10);
|
||||
value /= 10;
|
||||
buffer--;
|
||||
}
|
||||
*buffer = '.';
|
||||
buffer--;
|
||||
for (int i = precision + 1; i < length; i++)
|
||||
{
|
||||
*buffer = '0' + (value % 10);
|
||||
value /= 10;
|
||||
if (value == 0)
|
||||
break;
|
||||
buffer--;
|
||||
}
|
||||
if (minus)
|
||||
{
|
||||
buffer--;
|
||||
*buffer = '-';
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// convert scoped enums to integers
|
||||
template <typename Enumeration>
|
||||
auto as_integer(Enumeration const value)
|
||||
-> typename std::underlying_type<Enumeration>::type
|
||||
{
|
||||
return static_cast<typename std::underlying_type<Enumeration>::type>(value);
|
||||
}
|
||||
|
||||
static inline void intToString(const int value, std::string &output)
|
||||
{
|
||||
output.clear();
|
||||
std::back_insert_iterator<std::string> sink(output);
|
||||
boost::spirit::karma::generate(sink, boost::spirit::karma::int_, value);
|
||||
}
|
||||
|
||||
static inline void int64ToString(const int64_t value, std::string &output)
|
||||
{
|
||||
output.clear();
|
||||
std::back_insert_iterator<std::string> sink(output);
|
||||
boost::spirit::karma::generate(sink, boost::spirit::karma::long_long, value);
|
||||
}
|
||||
|
||||
static inline int stringToInt(const std::string &input)
|
||||
{
|
||||
auto first_digit = input.begin();
|
||||
// Delete any trailing white-spaces
|
||||
while (first_digit != input.end() && std::isspace(*first_digit))
|
||||
{
|
||||
++first_digit;
|
||||
}
|
||||
int value = 0;
|
||||
boost::spirit::qi::parse(first_digit, input.end(), boost::spirit::int_, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline unsigned stringToUint(const std::string &input)
|
||||
{
|
||||
auto first_digit = input.begin();
|
||||
// Delete any trailing white-spaces
|
||||
while (first_digit != input.end() && std::isspace(*first_digit))
|
||||
{
|
||||
++first_digit;
|
||||
}
|
||||
int value = 0;
|
||||
boost::spirit::qi::parse(first_digit, input.end(), boost::spirit::uint_, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline uint64_t stringToInt64(const std::string &input)
|
||||
{
|
||||
auto first_digit = input.begin();
|
||||
// Delete any trailing white-spaces
|
||||
while (first_digit != input.end() && std::isspace(*first_digit))
|
||||
{
|
||||
++first_digit;
|
||||
}
|
||||
uint64_t value = 0;
|
||||
boost::spirit::qi::parse(first_digit, input.end(), boost::spirit::long_long, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
// source: http://tinodidriksen.com/2011/05/28/cpp-convert-string-to-double-speed/
|
||||
static inline double StringToDouble(const char *p)
|
||||
{
|
||||
double r = 0.0;
|
||||
bool neg = false;
|
||||
if (*p == '-')
|
||||
{
|
||||
neg = true;
|
||||
++p;
|
||||
}
|
||||
while (*p >= '0' && *p <= '9')
|
||||
{
|
||||
r = (r * 10.0) + (*p - '0');
|
||||
++p;
|
||||
}
|
||||
if (*p == '.')
|
||||
{
|
||||
double f = 0.0;
|
||||
int n = 0;
|
||||
++p;
|
||||
while (*p >= '0' && *p <= '9')
|
||||
{
|
||||
f = (f * 10.0) + (*p - '0');
|
||||
++p;
|
||||
++n;
|
||||
}
|
||||
r += f / std::pow(10.0, n);
|
||||
}
|
||||
if (neg)
|
||||
{
|
||||
r = -r;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline void doubleToString(const double value, std::string &output)
|
||||
{
|
||||
output.clear();
|
||||
std::back_insert_iterator<std::string> sink(output);
|
||||
boost::spirit::karma::generate(sink, boost::spirit::karma::double_, value);
|
||||
}
|
||||
|
||||
static inline void doubleToStringWithTwoDigitsBehindComma(const double value, std::string &output)
|
||||
{
|
||||
// The largest 32-bit integer is 4294967295, that is 10 chars
|
||||
// On the safe side, add 1 for sign, and 1 for trailing zero
|
||||
char buffer[12];
|
||||
sprintf(buffer, "%g", value);
|
||||
output = buffer;
|
||||
}
|
||||
|
||||
inline void replaceAll(std::string &s, const std::string &sub, const std::string &other)
|
||||
{
|
||||
boost::replace_all(s, sub, other);
|
||||
}
|
||||
|
||||
inline std::string EscapeJSONString(const std::string &input)
|
||||
{
|
||||
std::string output;
|
||||
output.reserve(input.size());
|
||||
for (auto iter = input.begin(); iter != input.end(); ++iter)
|
||||
{
|
||||
switch (iter[0])
|
||||
{
|
||||
case '\\':
|
||||
output += "\\\\";
|
||||
break;
|
||||
case '"':
|
||||
output += "\\\"";
|
||||
break;
|
||||
case '/':
|
||||
output += "\\/";
|
||||
break;
|
||||
case '\b':
|
||||
output += "\\b";
|
||||
break;
|
||||
case '\f':
|
||||
output += "\\f";
|
||||
break;
|
||||
case '\n':
|
||||
output += "\\n";
|
||||
break;
|
||||
case '\r':
|
||||
output += "\\r";
|
||||
break;
|
||||
case '\t':
|
||||
output += "\\t";
|
||||
break;
|
||||
default:
|
||||
output += *iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
static std::string originals[] = {"&", "\"", "<", ">", "'", "[", "]", "\\"};
|
||||
static std::string entities[] = {"&", """, "<", ">",
|
||||
"'", "&91;", "&93;", " \"};
|
||||
|
||||
inline std::size_t URIDecode(const std::string &input, std::string &output)
|
||||
{
|
||||
auto src_iter = input.begin();
|
||||
output.resize(input.size() + 1);
|
||||
std::size_t decoded_length = 0;
|
||||
for (decoded_length = 0; src_iter != input.end(); ++decoded_length)
|
||||
{
|
||||
if (src_iter[0] == '%' && src_iter[1] && src_iter[2] && isxdigit(src_iter[1]) &&
|
||||
isxdigit(src_iter[2]))
|
||||
{
|
||||
std::string::value_type a = src_iter[1];
|
||||
std::string::value_type b = src_iter[2];
|
||||
a -= src_iter[1] < 58 ? 48 : src_iter[1] < 71 ? 55 : 87;
|
||||
b -= src_iter[2] < 58 ? 48 : src_iter[2] < 71 ? 55 : 87;
|
||||
output[decoded_length] = 16 * a + b;
|
||||
src_iter += 3;
|
||||
continue;
|
||||
}
|
||||
output[decoded_length] = *src_iter++;
|
||||
}
|
||||
output.resize(decoded_length);
|
||||
return decoded_length;
|
||||
}
|
||||
|
||||
inline std::size_t URIDecodeInPlace(std::string &URI) { return URIDecode(URI, URI); }
|
||||
|
||||
inline bool StringStartsWith(const std::string &input, const std::string &prefix)
|
||||
{
|
||||
return boost::starts_with(input, prefix);
|
||||
}
|
||||
|
||||
inline std::string GetRandomString()
|
||||
{
|
||||
std::string s;
|
||||
s.resize(128);
|
||||
static const char alphanum[] = "0123456789"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
for (int i = 0; i < 127; ++i)
|
||||
{
|
||||
s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
|
||||
}
|
||||
s[127] = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif // STRINGUTIL_H
|
||||
@@ -1,39 +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 TIMINGUTIL_H
|
||||
#define TIMINGUTIL_H
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#define TIMER_START(_X) std::chrono::time_point<std::chrono::steady_clock> _X##_start, _X##_stop; _X##_start = std::chrono::steady_clock::now()
|
||||
#define TIMER_STOP(_X) _X##_stop = std::chrono::steady_clock::now()
|
||||
#define TIMER_MSEC(_X) std::chrono::duration_cast<std::chrono::milliseconds>(_X##_stop - _X##_start).count()
|
||||
#define TIMER_SEC(_X) std::chrono::duration_cast<std::chrono::seconds>(_X##_stop - _X##_start).count()
|
||||
#define TIMER_MIN(_X) std::chrono::duration_cast<std::chrono::minutes>(_X##_stop - _X##_start).count()
|
||||
|
||||
#endif // TIMINGUTIL_H
|
||||
@@ -1,109 +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 "UUID.h"
|
||||
|
||||
#include "OSRMException.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/uuid/uuid_generators.hpp> // generators
|
||||
#include <boost/uuid/uuid_io.hpp> // streaming operators etc.
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#cmakedefine01 HAS64BITS
|
||||
#cmakedefine MD5PREPARE "${MD5PREPARE}"
|
||||
#cmakedefine MD5RTREE "${MD5RTREE}"
|
||||
#cmakedefine MD5GRAPH "${MD5GRAPH}"
|
||||
#cmakedefine MD5OBJECTS "${MD5OBJECTS}"
|
||||
|
||||
UUID::UUID() : magic_number(1297240911)
|
||||
{
|
||||
md5_prepare[32] = md5_tree[32] = md5_graph[32] = md5_objects[32] = '\0';
|
||||
|
||||
boost::uuids::name_generator gen(named_uuid);
|
||||
std::string temp_string(__DATE__);
|
||||
temp_string += __TIME__;
|
||||
|
||||
std::copy(MD5PREPARE, MD5PREPARE + strlen(MD5PREPARE), md5_prepare);
|
||||
temp_string += md5_prepare;
|
||||
std::copy(MD5RTREE, MD5RTREE + 32, md5_tree);
|
||||
temp_string += md5_tree;
|
||||
std::copy(MD5GRAPH, MD5GRAPH + 32, md5_graph);
|
||||
temp_string += md5_graph;
|
||||
std::copy(MD5OBJECTS, MD5OBJECTS + 32, md5_objects);
|
||||
temp_string += md5_objects;
|
||||
|
||||
named_uuid = gen(temp_string);
|
||||
has_64_bits = HAS64BITS;
|
||||
}
|
||||
|
||||
UUID::~UUID() {}
|
||||
|
||||
const boost::uuids::uuid &UUID::GetUUID() const { return named_uuid; }
|
||||
|
||||
bool UUID::IsMagicNumberOK() const { return 1297240911 == magic_number; }
|
||||
|
||||
bool UUID::TestGraphUtil(const UUID &other) const
|
||||
{
|
||||
if (!other.IsMagicNumberOK())
|
||||
{
|
||||
throw OSRMException("hsgr input file misses magic number. Check or reprocess the file");
|
||||
}
|
||||
return std::equal(md5_graph, md5_graph + 32, other.md5_graph);
|
||||
}
|
||||
|
||||
bool UUID::TestPrepare(const UUID &other) const
|
||||
{
|
||||
if (!other.IsMagicNumberOK())
|
||||
{
|
||||
throw OSRMException("osrm input file misses magic number. Check or reprocess the file");
|
||||
}
|
||||
return std::equal(md5_prepare, md5_prepare + 32, other.md5_prepare);
|
||||
}
|
||||
|
||||
bool UUID::TestRTree(const UUID &other) const
|
||||
{
|
||||
if (!other.IsMagicNumberOK())
|
||||
{
|
||||
throw OSRMException("r-tree input file misses magic number. Check or reprocess the file");
|
||||
}
|
||||
return std::equal(md5_tree, md5_tree + 32, other.md5_tree);
|
||||
}
|
||||
|
||||
bool UUID::TestQueryObjects(const UUID &other) const
|
||||
{
|
||||
if (!other.IsMagicNumberOK())
|
||||
{
|
||||
throw OSRMException("missing magic number. Check or reprocess the file");
|
||||
}
|
||||
return std::equal(md5_objects, md5_objects + 32, other.md5_objects);
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
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 BAYES_CLASSIFIER_HPP
|
||||
#define BAYES_CLASSIFIER_HPP
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
struct NormalDistribution
|
||||
{
|
||||
NormalDistribution(const double mean, const double standard_deviation)
|
||||
: mean(mean), standard_deviation(standard_deviation)
|
||||
{
|
||||
}
|
||||
|
||||
// FIXME implement log-probability version since its faster
|
||||
double density_function(const double val) const
|
||||
{
|
||||
const double x = val - mean;
|
||||
return 1.0 / (std::sqrt(2. * M_PI) * standard_deviation) *
|
||||
std::exp(-x * x / (standard_deviation * standard_deviation));
|
||||
}
|
||||
|
||||
double mean;
|
||||
double standard_deviation;
|
||||
};
|
||||
|
||||
struct LaplaceDistribution
|
||||
{
|
||||
LaplaceDistribution(const double location, const double scale)
|
||||
: location(location), scale(scale)
|
||||
{
|
||||
}
|
||||
|
||||
// FIXME implement log-probability version since its faster
|
||||
double density_function(const double val) const
|
||||
{
|
||||
const double x = std::abs(val - location);
|
||||
return 1.0 / (2. * scale) * std::exp(-x / scale);
|
||||
}
|
||||
|
||||
double location;
|
||||
double scale;
|
||||
};
|
||||
|
||||
template <typename PositiveDistributionT, typename NegativeDistributionT, typename ValueT>
|
||||
class BayesClassifier
|
||||
{
|
||||
public:
|
||||
enum class ClassLabel : unsigned
|
||||
{
|
||||
NEGATIVE,
|
||||
POSITIVE
|
||||
};
|
||||
using ClassificationT = std::pair<ClassLabel, double>;
|
||||
|
||||
BayesClassifier(PositiveDistributionT positive_distribution,
|
||||
NegativeDistributionT negative_distribution,
|
||||
const double positive_apriori_probability)
|
||||
: positive_distribution(std::move(positive_distribution)),
|
||||
negative_distribution(std::move(negative_distribution)),
|
||||
positive_apriori_probability(positive_apriori_probability),
|
||||
negative_apriori_probability(1. - positive_apriori_probability)
|
||||
{
|
||||
}
|
||||
|
||||
// Returns label and the probability of the label.
|
||||
ClassificationT classify(const ValueT &v) const
|
||||
{
|
||||
const double positive_postpriori =
|
||||
positive_apriori_probability * positive_distribution.density_function(v);
|
||||
const double negative_postpriori =
|
||||
negative_apriori_probability * negative_distribution.density_function(v);
|
||||
const double norm = positive_postpriori + negative_postpriori;
|
||||
|
||||
if (positive_postpriori > negative_postpriori)
|
||||
{
|
||||
return std::make_pair(ClassLabel::POSITIVE, positive_postpriori / norm);
|
||||
}
|
||||
|
||||
return std::make_pair(ClassLabel::NEGATIVE, negative_postpriori / norm);
|
||||
}
|
||||
|
||||
private:
|
||||
PositiveDistributionT positive_distribution;
|
||||
NegativeDistributionT negative_distribution;
|
||||
double positive_apriori_probability;
|
||||
double negative_apriori_probability;
|
||||
};
|
||||
|
||||
#endif // BAYES_CLASSIFIER_HPP
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
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 BFS_COMPONENTS_HPP_
|
||||
#define BFS_COMPONENTS_HPP_
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../data_structures/restriction_map.hpp"
|
||||
|
||||
#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;
|
||||
if (m_barrier_nodes.find(v) != m_barrier_nodes.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
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_COMPONENTS_HPP_
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
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 "coordinate_calculation.hpp"
|
||||
|
||||
#include "../util/mercator.hpp"
|
||||
#include "../util/string_util.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <osrm/coordinate.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr static const float RAD = 0.017453292519943295769236907684886f;
|
||||
// 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)
|
||||
constexpr static const float earth_radius = 6372797.560856f;
|
||||
}
|
||||
|
||||
namespace coordinate_calculation
|
||||
{
|
||||
|
||||
double haversine_distance(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 double lt1 = lat1 / COORDINATE_PRECISION;
|
||||
const double ln1 = lon1 / COORDINATE_PRECISION;
|
||||
const double lt2 = lat2 / COORDINATE_PRECISION;
|
||||
const double ln2 = lon2 / COORDINATE_PRECISION;
|
||||
const double dlat1 = lt1 * (RAD);
|
||||
|
||||
const double dlong1 = ln1 * (RAD);
|
||||
const double dlat2 = lt2 * (RAD);
|
||||
const double dlong2 = ln2 * (RAD);
|
||||
|
||||
const double dLong = dlong1 - dlong2;
|
||||
const double dLat = dlat1 - dlat2;
|
||||
|
||||
const double aHarv = std::pow(std::sin(dLat / 2.0), 2.0) +
|
||||
std::cos(dlat1) * std::cos(dlat2) * std::pow(std::sin(dLong / 2.), 2);
|
||||
const double cHarv = 2. * std::atan2(std::sqrt(aHarv), std::sqrt(1.0 - aHarv));
|
||||
return earth_radius * cHarv;
|
||||
}
|
||||
|
||||
double haversine_distance(const FixedPointCoordinate &coordinate_1,
|
||||
const FixedPointCoordinate &coordinate_2)
|
||||
{
|
||||
return haversine_distance(coordinate_1.lat, coordinate_1.lon, coordinate_2.lat,
|
||||
coordinate_2.lon);
|
||||
}
|
||||
|
||||
float great_circle_distance(const FixedPointCoordinate &coordinate_1,
|
||||
const FixedPointCoordinate &coordinate_2)
|
||||
{
|
||||
return great_circle_distance(coordinate_1.lat, coordinate_1.lon, coordinate_2.lat,
|
||||
coordinate_2.lon);
|
||||
}
|
||||
|
||||
float great_circle_distance(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 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) * std::cos((float_lat1 + float_lat2) / 2.f);
|
||||
const float y_value = float_lat2 - float_lat1;
|
||||
return std::hypot(x_value, y_value) * earth_radius;
|
||||
}
|
||||
|
||||
float perpendicular_distance(const FixedPointCoordinate &source_coordinate,
|
||||
const FixedPointCoordinate &target_coordinate,
|
||||
const FixedPointCoordinate &query_location)
|
||||
{
|
||||
float ratio;
|
||||
FixedPointCoordinate nearest_location;
|
||||
|
||||
return perpendicular_distance(source_coordinate, target_coordinate, query_location,
|
||||
nearest_location, ratio);
|
||||
}
|
||||
|
||||
float perpendicular_distance(const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location,
|
||||
FixedPointCoordinate &nearest_location,
|
||||
float &ratio)
|
||||
{
|
||||
return perpendicular_distance_from_projected_coordinate(
|
||||
segment_source, segment_target, query_location,
|
||||
{mercator::lat2y(query_location.lat / COORDINATE_PRECISION),
|
||||
query_location.lon / COORDINATE_PRECISION},
|
||||
nearest_location, ratio);
|
||||
}
|
||||
|
||||
float perpendicular_distance_from_projected_coordinate(
|
||||
const FixedPointCoordinate &source_coordinate,
|
||||
const FixedPointCoordinate &target_coordinate,
|
||||
const FixedPointCoordinate &query_location,
|
||||
const std::pair<double, double> &projected_coordinate)
|
||||
{
|
||||
float ratio;
|
||||
FixedPointCoordinate nearest_location;
|
||||
|
||||
return perpendicular_distance_from_projected_coordinate(source_coordinate, target_coordinate,
|
||||
query_location, projected_coordinate,
|
||||
nearest_location, ratio);
|
||||
}
|
||||
|
||||
float perpendicular_distance_from_projected_coordinate(
|
||||
const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location,
|
||||
const std::pair<double, double> &projected_coordinate,
|
||||
FixedPointCoordinate &nearest_location,
|
||||
float &ratio)
|
||||
{
|
||||
BOOST_ASSERT(query_location.is_valid());
|
||||
|
||||
// initialize values
|
||||
const double x = projected_coordinate.first;
|
||||
const double y = projected_coordinate.second;
|
||||
const double a = mercator::lat2y(segment_source.lat / COORDINATE_PRECISION);
|
||||
const double b = segment_source.lon / COORDINATE_PRECISION;
|
||||
const double c = mercator::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 =
|
||||
static_cast<float>((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<float>::epsilon())
|
||||
{
|
||||
ratio = 0.f;
|
||||
}
|
||||
else if (std::abs(ratio - 1.f) <= std::numeric_limits<float>::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>(mercator::y2lat(p) * COORDINATE_PRECISION);
|
||||
nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
|
||||
}
|
||||
BOOST_ASSERT(nearest_location.is_valid());
|
||||
|
||||
const float approximate_distance =
|
||||
great_circle_distance(query_location, nearest_location);
|
||||
BOOST_ASSERT(0.f <= approximate_distance);
|
||||
return approximate_distance;
|
||||
}
|
||||
|
||||
void lat_or_lon_to_string(const int value, std::string &output)
|
||||
{
|
||||
char buffer[12];
|
||||
buffer[11] = 0; // zero termination
|
||||
output = printInt<11, 6>(buffer, value);
|
||||
}
|
||||
|
||||
float deg_to_rad(const float degree)
|
||||
{
|
||||
return degree * (static_cast<float>(M_PI) / 180.f);
|
||||
}
|
||||
|
||||
float rad_to_deg(const float radian)
|
||||
{
|
||||
return radian * (180.f * static_cast<float>(M_1_PI));
|
||||
}
|
||||
|
||||
float bearing(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 = deg_to_rad(lon_diff);
|
||||
const float lat1 = deg_to_rad(first_coordinate.lat / COORDINATE_PRECISION);
|
||||
const float lat2 = deg_to_rad(second_coordinate.lat / COORDINATE_PRECISION);
|
||||
const float y = std::sin(lon_delta) * std::cos(lat2);
|
||||
const float x =
|
||||
std::cos(lat1) * std::sin(lat2) - std::sin(lat1) * std::cos(lat2) * std::cos(lon_delta);
|
||||
float result = rad_to_deg(std::atan2(y, x));
|
||||
while (result < 0.f)
|
||||
{
|
||||
result += 360.f;
|
||||
}
|
||||
|
||||
while (result >= 360.f)
|
||||
{
|
||||
result -= 360.f;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
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 COORDINATE_CALCULATION
|
||||
#define COORDINATE_CALCULATION
|
||||
|
||||
struct FixedPointCoordinate;
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace coordinate_calculation
|
||||
{
|
||||
double
|
||||
haversine_distance(const int lat1, const int lon1, const int lat2, const int lon2);
|
||||
|
||||
double haversine_distance(const FixedPointCoordinate &first_coordinate,
|
||||
const FixedPointCoordinate &second_coordinate);
|
||||
|
||||
float great_circle_distance(const FixedPointCoordinate &first_coordinate,
|
||||
const FixedPointCoordinate &second_coordinate);
|
||||
|
||||
float great_circle_distance(const int lat1, const int lon1, const int lat2, const int lon2);
|
||||
|
||||
void lat_or_lon_to_string(const int value, std::string &output);
|
||||
|
||||
float perpendicular_distance(const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location);
|
||||
|
||||
float perpendicular_distance(const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location,
|
||||
FixedPointCoordinate &nearest_location,
|
||||
float &ratio);
|
||||
|
||||
float perpendicular_distance_from_projected_coordinate(
|
||||
const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location,
|
||||
const std::pair<double, double> &projected_coordinate);
|
||||
|
||||
float perpendicular_distance_from_projected_coordinate(
|
||||
const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location,
|
||||
const std::pair<double, double> &projected_coordinate,
|
||||
FixedPointCoordinate &nearest_location,
|
||||
float &ratio);
|
||||
|
||||
float deg_to_rad(const float degree);
|
||||
float rad_to_deg(const float radian);
|
||||
|
||||
float bearing(const FixedPointCoordinate &first_coordinate,
|
||||
const FixedPointCoordinate &second_coordinate);
|
||||
}
|
||||
|
||||
#endif // COORDINATE_CALCULATION
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -28,44 +28,59 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef ITERATOR_BASED_CRC32_H
|
||||
#define ITERATOR_BASED_CRC32_H
|
||||
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#if defined(__x86_64__) && !defined(__MINGW64__)
|
||||
#include <cpuid.h>
|
||||
#else
|
||||
#endif
|
||||
|
||||
#include <boost/crc.hpp> // for boost::crc_32_type
|
||||
|
||||
inline void __get_cpuid(int param, unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx)
|
||||
#include <iterator>
|
||||
|
||||
class IteratorbasedCRC32
|
||||
{
|
||||
*ecx = 0;
|
||||
}
|
||||
#endif
|
||||
public:
|
||||
bool using_hardware() const { return use_hardware_implementation; }
|
||||
|
||||
template <class ContainerT> class IteratorbasedCRC32
|
||||
{
|
||||
private:
|
||||
typedef typename ContainerT::iterator IteratorType;
|
||||
unsigned crc;
|
||||
IteratorbasedCRC32() : crc(0) { use_hardware_implementation = detect_hardware_support(); }
|
||||
|
||||
bool use_SSE42_CRC_function;
|
||||
|
||||
#if !defined(__x86_64__)
|
||||
boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> CRC32_processor;
|
||||
#endif
|
||||
unsigned SoftwareBasedCRC32(char *str, unsigned len)
|
||||
template <class Iterator> unsigned operator()(Iterator iter, const Iterator end)
|
||||
{
|
||||
#if !defined(__x86_64__)
|
||||
CRC32_processor.process_bytes(str, len);
|
||||
return CRC32_processor.checksum();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
unsigned crc = 0;
|
||||
while (iter != end)
|
||||
{
|
||||
using value_type = typename std::iterator_traits<Iterator>::value_type;
|
||||
const char *data = reinterpret_cast<const char *>(&(*iter));
|
||||
|
||||
if (use_hardware_implementation)
|
||||
{
|
||||
crc = compute_in_hardware(data, sizeof(value_type));
|
||||
}
|
||||
else
|
||||
{
|
||||
crc = compute_in_software(data, sizeof(value_type));
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
private:
|
||||
bool detect_hardware_support() const
|
||||
{
|
||||
static const int sse42_bit = 0x00100000;
|
||||
const unsigned ecx = cpuid();
|
||||
const bool sse42_found = (ecx & sse42_bit) != 0;
|
||||
return sse42_found;
|
||||
}
|
||||
|
||||
unsigned compute_in_software(const char *str, unsigned len)
|
||||
{
|
||||
crc_processor.process_bytes(str, len);
|
||||
return crc_processor.checksum();
|
||||
}
|
||||
|
||||
// adapted from http://byteworm.com/2010/10/13/crc32/
|
||||
unsigned SSE42BasedCRC32(char *str, unsigned len)
|
||||
unsigned compute_in_hardware(const char *str, unsigned len)
|
||||
{
|
||||
#if defined(__x86_64__)
|
||||
unsigned q = len / sizeof(unsigned);
|
||||
@@ -81,7 +96,7 @@ template <class ContainerT> class IteratorbasedCRC32
|
||||
++p;
|
||||
}
|
||||
|
||||
str = (char *)p;
|
||||
str = reinterpret_cast<char *>(p);
|
||||
while (r--)
|
||||
{
|
||||
__asm__ __volatile__(".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
|
||||
@@ -101,44 +116,30 @@ template <class ContainerT> class IteratorbasedCRC32
|
||||
return ecx;
|
||||
}
|
||||
|
||||
bool DetectNativeCRC32Support()
|
||||
#if defined(__MINGW64__) || defined(_MSC_VER) || !defined(__x86_64__)
|
||||
inline void
|
||||
__get_cpuid(int param, unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx) const
|
||||
{
|
||||
static const int SSE42_BIT = 0x00100000;
|
||||
const unsigned ecx = cpuid();
|
||||
const bool has_SSE42 = ecx & SSE42_BIT;
|
||||
if (has_SSE42)
|
||||
{
|
||||
SimpleLogger().Write() << "using hardware based CRC32 computation";
|
||||
}
|
||||
else
|
||||
{
|
||||
SimpleLogger().Write() << "using software based CRC32 computation";
|
||||
}
|
||||
return has_SSE42;
|
||||
*ecx = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> crc_processor;
|
||||
unsigned crc;
|
||||
bool use_hardware_implementation;
|
||||
};
|
||||
|
||||
struct RangebasedCRC32
|
||||
{
|
||||
template <typename Iteratable> unsigned operator()(const Iteratable &iterable)
|
||||
{
|
||||
return crc32(std::begin(iterable), std::end(iterable));
|
||||
}
|
||||
|
||||
public:
|
||||
IteratorbasedCRC32() : crc(0) { use_SSE42_CRC_function = DetectNativeCRC32Support(); }
|
||||
bool using_hardware() const { return crc32.using_hardware(); }
|
||||
|
||||
unsigned operator()(IteratorType iter, const IteratorType end)
|
||||
{
|
||||
unsigned crc = 0;
|
||||
while (iter != end)
|
||||
{
|
||||
char *data = reinterpret_cast<char *>(&(*iter));
|
||||
|
||||
if (use_SSE42_CRC_function)
|
||||
{
|
||||
crc = SSE42BasedCRC32(data, sizeof(typename ContainerT::value_type));
|
||||
}
|
||||
else
|
||||
{
|
||||
crc = SoftwareBasedCRC32(data, sizeof(typename ContainerT::value_type));
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
private:
|
||||
IteratorbasedCRC32 crc32;
|
||||
};
|
||||
|
||||
#endif /* ITERATOR_BASED_CRC32_H */
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
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 "douglas_peucker.hpp"
|
||||
|
||||
#include "../data_structures/segment_information.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <osrm/coordinate.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
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 = std::hypot(x_value_1, y_value_1) * 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 = std::hypot(x_value_2, y_value_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;
|
||||
};
|
||||
}
|
||||
|
||||
void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level)
|
||||
{
|
||||
Run(std::begin(input_geometry), std::end(input_geometry), zoom_level);
|
||||
}
|
||||
|
||||
void DouglasPeucker::Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level)
|
||||
{
|
||||
const auto size = std::distance(begin, end);
|
||||
if (size < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
begin->necessary = true;
|
||||
std::prev(end)->necessary = true;
|
||||
|
||||
{
|
||||
BOOST_ASSERT_MSG(zoom_level < DOUGLAS_PEUCKER_THRESHOLDS.size(), "unsupported zoom level");
|
||||
auto left_border = begin;
|
||||
auto right_border = std::next(begin);
|
||||
// Sweep over array and identify those ranges that need to be checked
|
||||
do
|
||||
{
|
||||
// traverse list until new border element found
|
||||
if (right_border->necessary)
|
||||
{
|
||||
// sanity checks
|
||||
BOOST_ASSERT(left_border->necessary);
|
||||
BOOST_ASSERT(right_border->necessary);
|
||||
recursion_stack.emplace(left_border, right_border);
|
||||
left_border = right_border;
|
||||
}
|
||||
++right_border;
|
||||
} while (right_border != end);
|
||||
}
|
||||
|
||||
// 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(pair.first->necessary, "left border must be necessary");
|
||||
BOOST_ASSERT_MSG(pair.second->necessary, "right border must be necessary");
|
||||
BOOST_ASSERT_MSG(std::distance(pair.second, end) > 0, "right border outside of geometry");
|
||||
BOOST_ASSERT_MSG(std::distance(pair.first, pair.second) >= 0,
|
||||
"left border on the wrong side");
|
||||
|
||||
int max_int_distance = 0;
|
||||
auto farthest_entry_it = pair.second;
|
||||
const CoordinatePairCalculator dist_calc(pair.first->location, pair.second->location);
|
||||
|
||||
// sweep over range to find the maximum
|
||||
for (auto it = std::next(pair.first); it != pair.second; ++it)
|
||||
{
|
||||
const int distance = dist_calc(it->location);
|
||||
// found new feasible maximum?
|
||||
if (distance > max_int_distance && distance > DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
|
||||
{
|
||||
farthest_entry_it = it;
|
||||
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
|
||||
farthest_entry_it->necessary = true;
|
||||
if (1 < std::distance(pair.first, farthest_entry_it))
|
||||
{
|
||||
recursion_stack.emplace(pair.first, farthest_entry_it);
|
||||
}
|
||||
if (1 < std::distance(farthest_entry_it, pair.second))
|
||||
{
|
||||
recursion_stack.emplace(farthest_entry_it, pair.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
Copyright (c) 2013, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -25,10 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DOUGLASPEUCKER_H_
|
||||
#define DOUGLASPEUCKER_H_
|
||||
#ifndef DOUGLAS_PEUCKER_HPP_
|
||||
#define DOUGLAS_PEUCKER_HPP_
|
||||
|
||||
#include "../data_structures/segment_information.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <stack>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
/* This class object computes the bitvector of indicating generalized input
|
||||
@@ -38,25 +42,40 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* bit indicating if the points is present in the generalization.
|
||||
* Note: points may also be pre-selected*/
|
||||
|
||||
struct FixedPointCoordinate;
|
||||
struct SegmentInformation;
|
||||
static const std::array<int, 19> 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
|
||||
}};
|
||||
|
||||
class DouglasPeucker
|
||||
{
|
||||
private:
|
||||
std::vector<double> douglas_peucker_thresholds;
|
||||
public:
|
||||
using RandomAccessIt = std::vector<SegmentInformation>::iterator;
|
||||
|
||||
typedef std::pair<unsigned, unsigned> GeometryRange;
|
||||
using GeometryRange = std::pair<RandomAccessIt, RandomAccessIt>;
|
||||
// Stack to simulate the recursion
|
||||
std::stack<GeometryRange> recursion_stack;
|
||||
|
||||
double ComputeDistance(const FixedPointCoordinate &point,
|
||||
const FixedPointCoordinate &segA,
|
||||
const FixedPointCoordinate &segB) const;
|
||||
|
||||
public:
|
||||
DouglasPeucker();
|
||||
void Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level);
|
||||
void Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level);
|
||||
};
|
||||
|
||||
#endif /* DOUGLASPEUCKER_H_ */
|
||||
#endif /* DOUGLAS_PEUCKER_HPP_ */
|
||||
@@ -0,0 +1,180 @@
|
||||
#ifndef GEOSPATIAL_QUERY_HPP
|
||||
#define GEOSPATIAL_QUERY_HPP
|
||||
|
||||
#include "coordinate_calculation.hpp"
|
||||
#include "../typedefs.h"
|
||||
#include "../data_structures/phantom_node.hpp"
|
||||
#include "../util/bearing.hpp"
|
||||
|
||||
#include <osrm/coordinate.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
|
||||
// Implements complex queries on top of an RTree and builds PhantomNodes from it.
|
||||
//
|
||||
// Only holds a weak reference on the RTree!
|
||||
template <typename RTreeT> class GeospatialQuery
|
||||
{
|
||||
using EdgeData = typename RTreeT::EdgeData;
|
||||
using CoordinateList = typename RTreeT::CoordinateList;
|
||||
|
||||
public:
|
||||
GeospatialQuery(RTreeT &rtree_, std::shared_ptr<CoordinateList> coordinates_)
|
||||
: rtree(rtree_), coordinates(coordinates_)
|
||||
{
|
||||
}
|
||||
|
||||
// Returns nearest PhantomNodes in the given bearing range within max_distance.
|
||||
// Does not filter by small/big component!
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const FixedPointCoordinate &input_coordinate,
|
||||
const float max_distance,
|
||||
const int bearing = 0,
|
||||
const int bearing_range = 180)
|
||||
{
|
||||
auto results =
|
||||
rtree.Nearest(input_coordinate,
|
||||
[this, bearing, bearing_range, max_distance](const EdgeData &data)
|
||||
{
|
||||
return checkSegmentBearing(data, bearing, bearing_range);
|
||||
},
|
||||
[max_distance](const std::size_t, const float min_dist)
|
||||
{
|
||||
return min_dist > max_distance;
|
||||
});
|
||||
|
||||
return MakePhantomNodes(input_coordinate, results);
|
||||
}
|
||||
|
||||
// Returns max_results nearest PhantomNodes in the given bearing range.
|
||||
// Does not filter by small/big component!
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const FixedPointCoordinate &input_coordinate,
|
||||
const unsigned max_results,
|
||||
const int bearing = 0,
|
||||
const int bearing_range = 180)
|
||||
{
|
||||
auto results = rtree.Nearest(input_coordinate,
|
||||
[this, bearing, bearing_range](const EdgeData &data)
|
||||
{
|
||||
return checkSegmentBearing(data, bearing, bearing_range);
|
||||
},
|
||||
[max_results](const std::size_t num_results, const float)
|
||||
{
|
||||
return num_results >= max_results;
|
||||
});
|
||||
|
||||
return MakePhantomNodes(input_coordinate, results);
|
||||
}
|
||||
|
||||
// Returns the nearest phantom node. If this phantom node is not from a big component
|
||||
// a second phantom node is return that is the nearest coordinate in a big component.
|
||||
std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const FixedPointCoordinate &input_coordinate,
|
||||
const int bearing = 0,
|
||||
const int bearing_range = 180)
|
||||
{
|
||||
bool has_small_component = false;
|
||||
bool has_big_component = false;
|
||||
auto results = rtree.Nearest(
|
||||
input_coordinate,
|
||||
[this, bearing, bearing_range, &has_big_component,
|
||||
&has_small_component](const EdgeData &data)
|
||||
{
|
||||
auto use_segment =
|
||||
(!has_small_component || (!has_big_component && !data.component.is_tiny));
|
||||
auto use_directions = std::make_pair(use_segment, use_segment);
|
||||
|
||||
if (use_segment)
|
||||
{
|
||||
use_directions = checkSegmentBearing(data, bearing, bearing_range);
|
||||
if (use_directions.first || use_directions.second)
|
||||
{
|
||||
has_big_component = has_big_component || !data.component.is_tiny;
|
||||
has_small_component = has_small_component || data.component.is_tiny;
|
||||
}
|
||||
}
|
||||
|
||||
return use_directions;
|
||||
},
|
||||
[&has_big_component](const std::size_t num_results, const float)
|
||||
{
|
||||
return num_results > 0 && has_big_component;
|
||||
});
|
||||
|
||||
if (results.size() == 0)
|
||||
{
|
||||
return std::make_pair(PhantomNode{}, PhantomNode{});
|
||||
}
|
||||
|
||||
BOOST_ASSERT(results.size() > 0);
|
||||
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
|
||||
MakePhantomNode(input_coordinate, results.back()).phantom_node);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
MakePhantomNodes(const FixedPointCoordinate &input_coordinate,
|
||||
const std::vector<EdgeData> &results) const
|
||||
{
|
||||
std::vector<PhantomNodeWithDistance> distance_and_phantoms(results.size());
|
||||
std::transform(results.begin(), results.end(), distance_and_phantoms.begin(),
|
||||
[this, &input_coordinate](const EdgeData &data)
|
||||
{
|
||||
return MakePhantomNode(input_coordinate, data);
|
||||
});
|
||||
return distance_and_phantoms;
|
||||
}
|
||||
|
||||
PhantomNodeWithDistance MakePhantomNode(const FixedPointCoordinate &input_coordinate,
|
||||
const EdgeData &data) const
|
||||
{
|
||||
FixedPointCoordinate point_on_segment;
|
||||
float ratio;
|
||||
const auto current_perpendicular_distance = coordinate_calculation::perpendicular_distance(
|
||||
coordinates->at(data.u), coordinates->at(data.v), input_coordinate, point_on_segment,
|
||||
ratio);
|
||||
|
||||
auto transformed =
|
||||
PhantomNodeWithDistance { PhantomNode{data, point_on_segment}, current_perpendicular_distance };
|
||||
|
||||
ratio = std::min(1.f, std::max(0.f, ratio));
|
||||
|
||||
if (SPECIAL_NODEID != transformed.phantom_node.forward_node_id)
|
||||
{
|
||||
transformed.phantom_node.forward_weight *= ratio;
|
||||
}
|
||||
if (SPECIAL_NODEID != transformed.phantom_node.reverse_node_id)
|
||||
{
|
||||
transformed.phantom_node.reverse_weight *= 1.f - ratio;
|
||||
}
|
||||
return transformed;
|
||||
}
|
||||
|
||||
std::pair<bool, bool> checkSegmentBearing(const EdgeData &segment,
|
||||
const float filter_bearing,
|
||||
const float filter_bearing_range)
|
||||
{
|
||||
const float forward_edge_bearing =
|
||||
coordinate_calculation::bearing(coordinates->at(segment.u), coordinates->at(segment.v));
|
||||
|
||||
const float backward_edge_bearing = (forward_edge_bearing + 180) > 360
|
||||
? (forward_edge_bearing - 180)
|
||||
: (forward_edge_bearing + 180);
|
||||
|
||||
const bool forward_bearing_valid =
|
||||
bearing::CheckInBounds(forward_edge_bearing, filter_bearing, filter_bearing_range) &&
|
||||
segment.forward_edge_based_node_id != SPECIAL_NODEID;
|
||||
const bool backward_bearing_valid =
|
||||
bearing::CheckInBounds(backward_edge_bearing, filter_bearing, filter_bearing_range) &&
|
||||
segment.reverse_edge_based_node_id != SPECIAL_NODEID;
|
||||
return std::make_pair(forward_bearing_valid, backward_bearing_valid);
|
||||
}
|
||||
|
||||
RTreeT &rtree;
|
||||
const std::shared_ptr<CoordinateList> coordinates;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,188 @@
|
||||
#include "graph_compressor.hpp"
|
||||
|
||||
#include "../data_structures/compressed_edge_container.hpp"
|
||||
#include "../data_structures/dynamic_graph.hpp"
|
||||
#include "../data_structures/node_based_graph.hpp"
|
||||
#include "../data_structures/restriction_map.hpp"
|
||||
#include "../data_structures/percent.hpp"
|
||||
|
||||
#include "../util/simple_logger.hpp"
|
||||
|
||||
GraphCompressor::GraphCompressor(SpeedProfileProperties speed_profile)
|
||||
: speed_profile(std::move(speed_profile))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void GraphCompressor::Compress(const std::unordered_set<NodeID>& barrier_nodes,
|
||||
const std::unordered_set<NodeID>& traffic_lights,
|
||||
RestrictionMap& restriction_map,
|
||||
NodeBasedDynamicGraph& graph,
|
||||
CompressedEdgeContainer& geometry_compressor)
|
||||
{
|
||||
const unsigned original_number_of_nodes = graph.GetNumberOfNodes();
|
||||
const unsigned original_number_of_edges = graph.GetNumberOfEdges();
|
||||
|
||||
Percent progress(original_number_of_nodes);
|
||||
|
||||
for (const NodeID node_v : osrm::irange(0u, original_number_of_nodes))
|
||||
{
|
||||
progress.printStatus(node_v);
|
||||
|
||||
// only contract degree 2 vertices
|
||||
if (2 != graph.GetOutDegree(node_v))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// don't contract barrier node
|
||||
if (barrier_nodes.end() != barrier_nodes.find(node_v))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if v is a via node for a turn restriction, i.e. a 'directed' barrier node
|
||||
if (restriction_map.IsViaNode(node_v))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// reverse_e2 forward_e2
|
||||
// u <---------- v -----------> w
|
||||
// ----------> <-----------
|
||||
// forward_e1 reverse_e1
|
||||
//
|
||||
// Will be compressed to:
|
||||
//
|
||||
// reverse_e1
|
||||
// u <---------- w
|
||||
// ---------->
|
||||
// forward_e1
|
||||
//
|
||||
// If the edges are compatible.
|
||||
|
||||
const bool reverse_edge_order = graph.GetEdgeData(graph.BeginEdges(node_v)).reversed;
|
||||
const EdgeID forward_e2 = graph.BeginEdges(node_v) + reverse_edge_order;
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != forward_e2);
|
||||
BOOST_ASSERT(forward_e2 >= graph.BeginEdges(node_v) &&
|
||||
forward_e2 < graph.EndEdges(node_v));
|
||||
const EdgeID reverse_e2 = graph.BeginEdges(node_v) + 1 - reverse_edge_order;
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != reverse_e2);
|
||||
BOOST_ASSERT(reverse_e2 >= graph.BeginEdges(node_v) &&
|
||||
reverse_e2 < graph.EndEdges(node_v));
|
||||
|
||||
const EdgeData &fwd_edge_data2 = graph.GetEdgeData(forward_e2);
|
||||
const EdgeData &rev_edge_data2 = graph.GetEdgeData(reverse_e2);
|
||||
|
||||
const NodeID node_w = graph.GetTarget(forward_e2);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != node_w);
|
||||
BOOST_ASSERT(node_v != node_w);
|
||||
const NodeID node_u = graph.GetTarget(reverse_e2);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != node_u);
|
||||
BOOST_ASSERT(node_u != node_v);
|
||||
|
||||
const EdgeID forward_e1 = graph.FindEdge(node_u, node_v);
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != forward_e1);
|
||||
BOOST_ASSERT(node_v == graph.GetTarget(forward_e1));
|
||||
const EdgeID reverse_e1 = graph.FindEdge(node_w, node_v);
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != reverse_e1);
|
||||
BOOST_ASSERT(node_v == graph.GetTarget(reverse_e1));
|
||||
|
||||
const EdgeData &fwd_edge_data1 = graph.GetEdgeData(forward_e1);
|
||||
const EdgeData &rev_edge_data1 = graph.GetEdgeData(reverse_e1);
|
||||
|
||||
if (graph.FindEdgeInEitherDirection(node_u, node_w) != SPECIAL_EDGEID)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// this case can happen if two ways with different names overlap
|
||||
if (fwd_edge_data1.name_id != rev_edge_data1.name_id ||
|
||||
fwd_edge_data2.name_id != rev_edge_data2.name_id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fwd_edge_data1.IsCompatibleTo(fwd_edge_data2) && rev_edge_data1.IsCompatibleTo(rev_edge_data2))
|
||||
{
|
||||
BOOST_ASSERT(graph.GetEdgeData(forward_e1).name_id ==
|
||||
graph.GetEdgeData(reverse_e1).name_id);
|
||||
BOOST_ASSERT(graph.GetEdgeData(forward_e2).name_id ==
|
||||
graph.GetEdgeData(reverse_e2).name_id);
|
||||
|
||||
// Get distances before graph is modified
|
||||
const int forward_weight1 = graph.GetEdgeData(forward_e1).distance;
|
||||
const int forward_weight2 = graph.GetEdgeData(forward_e2).distance;
|
||||
|
||||
BOOST_ASSERT(0 != forward_weight1);
|
||||
BOOST_ASSERT(0 != forward_weight2);
|
||||
|
||||
const int reverse_weight1 = graph.GetEdgeData(reverse_e1).distance;
|
||||
const int reverse_weight2 = graph.GetEdgeData(reverse_e2).distance;
|
||||
|
||||
BOOST_ASSERT(0 != reverse_weight1);
|
||||
BOOST_ASSERT(0 != reverse_weight2);
|
||||
|
||||
const bool has_node_penalty = traffic_lights.find(node_v) != traffic_lights.end();
|
||||
|
||||
// add weight of e2's to e1
|
||||
graph.GetEdgeData(forward_e1).distance += fwd_edge_data2.distance;
|
||||
graph.GetEdgeData(reverse_e1).distance += rev_edge_data2.distance;
|
||||
if (has_node_penalty)
|
||||
{
|
||||
graph.GetEdgeData(forward_e1).distance +=
|
||||
speed_profile.traffic_signal_penalty;
|
||||
graph.GetEdgeData(reverse_e1).distance +=
|
||||
speed_profile.traffic_signal_penalty;
|
||||
}
|
||||
|
||||
// extend e1's to targets of e2's
|
||||
graph.SetTarget(forward_e1, node_w);
|
||||
graph.SetTarget(reverse_e1, node_u);
|
||||
|
||||
// remove e2's (if bidir, otherwise only one)
|
||||
graph.DeleteEdge(node_v, forward_e2);
|
||||
graph.DeleteEdge(node_v, reverse_e2);
|
||||
|
||||
// update any involved turn restrictions
|
||||
restriction_map.FixupStartingTurnRestriction(node_u, node_v, node_w);
|
||||
restriction_map.FixupArrivingTurnRestriction(node_u, node_v, node_w, graph);
|
||||
|
||||
restriction_map.FixupStartingTurnRestriction(node_w, node_v, node_u);
|
||||
restriction_map.FixupArrivingTurnRestriction(node_w, node_v, node_u, graph);
|
||||
|
||||
// store compressed geometry in container
|
||||
geometry_compressor.CompressEdge(
|
||||
forward_e1, forward_e2, node_v, node_w,
|
||||
forward_weight1 + (has_node_penalty ? speed_profile.traffic_signal_penalty : 0),
|
||||
forward_weight2);
|
||||
geometry_compressor.CompressEdge(
|
||||
reverse_e1, reverse_e2, node_v, node_u, reverse_weight1,
|
||||
reverse_weight2 + (has_node_penalty ? speed_profile.traffic_signal_penalty : 0));
|
||||
}
|
||||
}
|
||||
|
||||
PrintStatistics(original_number_of_nodes, original_number_of_edges, graph);
|
||||
}
|
||||
|
||||
void GraphCompressor::PrintStatistics(unsigned original_number_of_nodes,
|
||||
unsigned original_number_of_edges,
|
||||
const NodeBasedDynamicGraph& graph) const
|
||||
{
|
||||
|
||||
unsigned new_node_count = 0;
|
||||
unsigned new_edge_count = 0;
|
||||
|
||||
for (const auto i : osrm::irange(0u, graph.GetNumberOfNodes()))
|
||||
{
|
||||
if (graph.GetOutDegree(i) > 0)
|
||||
{
|
||||
++new_node_count;
|
||||
new_edge_count += (graph.EndEdges(i) - graph.BeginEdges(i));
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
|
||||
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 GEOMETRY_COMPRESSOR_HPP
|
||||
#define GEOMETRY_COMPRESSOR_HPP
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include "../extractor/speed_profile.hpp"
|
||||
#include "../data_structures/node_based_graph.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
|
||||
class CompressedEdgeContainer;
|
||||
class RestrictionMap;
|
||||
|
||||
class GraphCompressor
|
||||
{
|
||||
using EdgeData = NodeBasedDynamicGraph::EdgeData;
|
||||
|
||||
public:
|
||||
GraphCompressor(SpeedProfileProperties speed_profile);
|
||||
|
||||
void Compress(const std::unordered_set<NodeID>& barrier_nodes,
|
||||
const std::unordered_set<NodeID>& traffic_lights,
|
||||
RestrictionMap& restriction_map,
|
||||
NodeBasedDynamicGraph& graph,
|
||||
CompressedEdgeContainer& geometry_compressor);
|
||||
private:
|
||||
|
||||
void PrintStatistics(unsigned original_number_of_nodes,
|
||||
unsigned original_number_of_edges,
|
||||
const NodeBasedDynamicGraph& graph) const;
|
||||
|
||||
SpeedProfileProperties speed_profile;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
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_ENCODER_HPP
|
||||
#define OBJECT_ENCODER_HPP
|
||||
|
||||
#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 <iterator>
|
||||
#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 = reinterpret_cast<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)));
|
||||
std::replace(begin(encoded), end(encoded), '+', '-');
|
||||
std::replace(begin(encoded), end(encoded), '/', '_');
|
||||
}
|
||||
|
||||
template <class ObjectT> static void DecodeFromBase64(const std::string &input, ObjectT &object)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string encoded(input);
|
||||
std::replace(begin(encoded), end(encoded), '-', '+');
|
||||
std::replace(begin(encoded), end(encoded), '_', '/');
|
||||
|
||||
std::copy(binary_t(encoded.begin()), binary_t(encoded.begin() + encoded.length()),
|
||||
reinterpret_cast<char *>(&object));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* OBJECT_ENCODER_HPP */
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
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 "polyline_compressor.hpp"
|
||||
#include "../data_structures/segment_information.hpp"
|
||||
|
||||
#include <osrm/coordinate.hpp>
|
||||
|
||||
std::string PolylineCompressor::encode_vector(std::vector<int> &numbers) const
|
||||
{
|
||||
std::string output;
|
||||
const auto end = numbers.size();
|
||||
for (std::size_t i = 0; i < end; ++i)
|
||||
{
|
||||
numbers[i] <<= 1;
|
||||
if (numbers[i] < 0)
|
||||
{
|
||||
numbers[i] = ~(numbers[i]);
|
||||
}
|
||||
}
|
||||
for (const int number : numbers)
|
||||
{
|
||||
output += encode_number(number);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
std::string PolylineCompressor::encode_number(int number_to_encode) const
|
||||
{
|
||||
std::string output;
|
||||
while (number_to_encode >= 0x20)
|
||||
{
|
||||
const int next_value = (0x20 | (number_to_encode & 0x1f)) + 63;
|
||||
output += static_cast<char>(next_value);
|
||||
number_to_encode >>= 5;
|
||||
}
|
||||
|
||||
number_to_encode += 63;
|
||||
output += static_cast<char>(number_to_encode);
|
||||
return output;
|
||||
}
|
||||
|
||||
std::string
|
||||
PolylineCompressor::get_encoded_string(const std::vector<SegmentInformation> &polyline) const
|
||||
{
|
||||
if (polyline.empty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<int> delta_numbers;
|
||||
delta_numbers.reserve((polyline.size() - 1) * 2);
|
||||
FixedPointCoordinate previous_coordinate = {0, 0};
|
||||
for (const auto &segment : polyline)
|
||||
{
|
||||
if (segment.necessary)
|
||||
{
|
||||
const int lat_diff = segment.location.lat - previous_coordinate.lat;
|
||||
const int lon_diff = segment.location.lon - previous_coordinate.lon;
|
||||
delta_numbers.emplace_back(lat_diff);
|
||||
delta_numbers.emplace_back(lon_diff);
|
||||
previous_coordinate = segment.location;
|
||||
}
|
||||
}
|
||||
return encode_vector(delta_numbers);
|
||||
}
|
||||
|
||||
std::vector<FixedPointCoordinate> PolylineCompressor::decode_string(const std::string &geometry_string) const
|
||||
{
|
||||
std::vector<FixedPointCoordinate> new_coordinates;
|
||||
int index = 0, len = geometry_string.size();
|
||||
int lat = 0, lng = 0;
|
||||
|
||||
while (index < len)
|
||||
{
|
||||
int b, shift = 0, result = 0;
|
||||
do
|
||||
{
|
||||
b = geometry_string.at(index++) - 63;
|
||||
result |= (b & 0x1f) << shift;
|
||||
shift += 5;
|
||||
} while (b >= 0x20);
|
||||
int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
|
||||
lat += dlat;
|
||||
|
||||
shift = 0;
|
||||
result = 0;
|
||||
do
|
||||
{
|
||||
b = geometry_string.at(index++) - 63;
|
||||
result |= (b & 0x1f) << shift;
|
||||
shift += 5;
|
||||
} while (b >= 0x20);
|
||||
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
|
||||
lng += dlng;
|
||||
|
||||
FixedPointCoordinate p;
|
||||
p.lat = COORDINATE_PRECISION * (((double) lat / 1E6));
|
||||
p.lon = COORDINATE_PRECISION * (((double) lng / 1E6));
|
||||
new_coordinates.push_back(p);
|
||||
}
|
||||
|
||||
return new_coordinates;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
Copyright (c) 2013, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -25,26 +25,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BASEPLUGIN_H_
|
||||
#define BASEPLUGIN_H_
|
||||
#ifndef POLYLINECOMPRESSOR_H_
|
||||
#define POLYLINECOMPRESSOR_H_
|
||||
|
||||
#include "../Util/StringUtil.h"
|
||||
struct SegmentInformation;
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
#include <osrm/Reply.h>
|
||||
#include <osrm/RouteParameters.h>
|
||||
#include <osrm/coordinate.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class BasePlugin
|
||||
class PolylineCompressor
|
||||
{
|
||||
private:
|
||||
std::string encode_vector(std::vector<int> &numbers) const;
|
||||
|
||||
std::string encode_number(const int number_to_encode) const;
|
||||
|
||||
public:
|
||||
BasePlugin() {}
|
||||
// Maybe someone can explain the pure virtual destructor thing to me (dennis)
|
||||
virtual ~BasePlugin() {}
|
||||
virtual const std::string GetDescriptor() const = 0;
|
||||
virtual void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply) = 0;
|
||||
std::string get_encoded_string(const std::vector<SegmentInformation> &polyline) const;
|
||||
|
||||
std::vector<FixedPointCoordinate> decode_string(const std::string &geometry_string) const;
|
||||
};
|
||||
|
||||
#endif /* BASEPLUGIN_H_ */
|
||||
#endif /* POLYLINECOMPRESSOR_H_ */
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -25,49 +25,32 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef AZIMUTH_H
|
||||
#define AZIMUTH_H
|
||||
#include "polyline_formatter.hpp"
|
||||
|
||||
#include <string>
|
||||
#include "polyline_compressor.hpp"
|
||||
#include "../data_structures/segment_information.hpp"
|
||||
|
||||
struct Azimuth
|
||||
#include <osrm/coordinate.hpp>
|
||||
|
||||
osrm::json::String
|
||||
PolylineFormatter::printEncodedString(const std::vector<SegmentInformation> &polyline) const
|
||||
{
|
||||
static std::string Get(const double heading)
|
||||
{
|
||||
if (heading <= 202.5)
|
||||
{
|
||||
if (heading >= 0 && heading <= 22.5)
|
||||
{
|
||||
return "N";
|
||||
}
|
||||
if (heading > 22.5 && heading <= 67.5)
|
||||
{
|
||||
return "NE";
|
||||
}
|
||||
if (heading > 67.5 && heading <= 112.5)
|
||||
{
|
||||
return "E";
|
||||
}
|
||||
if (heading > 112.5 && heading <= 157.5)
|
||||
{
|
||||
return "SE";
|
||||
}
|
||||
return "S";
|
||||
}
|
||||
if (heading > 202.5 && heading <= 247.5)
|
||||
{
|
||||
return "SW";
|
||||
}
|
||||
if (heading > 247.5 && heading <= 292.5)
|
||||
{
|
||||
return "W";
|
||||
}
|
||||
if (heading > 292.5 && heading <= 337.5)
|
||||
{
|
||||
return "NW";
|
||||
}
|
||||
return "N";
|
||||
}
|
||||
};
|
||||
return osrm::json::String(PolylineCompressor().get_encoded_string(polyline));
|
||||
}
|
||||
|
||||
#endif // AZIMUTH_H
|
||||
osrm::json::Array
|
||||
PolylineFormatter::printUnencodedString(const std::vector<SegmentInformation> &polyline) const
|
||||
{
|
||||
osrm::json::Array json_geometry_array;
|
||||
for (const auto &segment : polyline)
|
||||
{
|
||||
if (segment.necessary)
|
||||
{
|
||||
osrm::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,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -25,23 +25,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SCRIPTINGENVIRONMENT_H_
|
||||
#define SCRIPTINGENVIRONMENT_H_
|
||||
#ifndef POLYLINE_FORMATTER_HPP
|
||||
#define POLYLINE_FORMATTER_HPP
|
||||
|
||||
struct SegmentInformation;
|
||||
|
||||
#include <osrm/json_container.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct lua_State;
|
||||
|
||||
class ScriptingEnvironment
|
||||
struct PolylineFormatter
|
||||
{
|
||||
public:
|
||||
ScriptingEnvironment();
|
||||
explicit ScriptingEnvironment(const char *file_name);
|
||||
virtual ~ScriptingEnvironment();
|
||||
osrm::json::String printEncodedString(const std::vector<SegmentInformation> &polyline) const;
|
||||
|
||||
lua_State *getLuaStateForThreadID(const int);
|
||||
|
||||
std::vector<lua_State *> lua_state_vector;
|
||||
osrm::json::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const;
|
||||
};
|
||||
|
||||
#endif /* SCRIPTINGENVIRONMENT_H_ */
|
||||
#endif /* POLYLINE_FORMATTER_HPP */
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
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->get_name_for_id(shortest_segment_1.name_id);
|
||||
route_names.shortest_path_name_2 = facade->get_name_for_id(shortest_segment_2.name_id);
|
||||
|
||||
route_names.alternative_path_name_1 =
|
||||
facade->get_name_for_id(alternative_segment_1.name_id);
|
||||
route_names.alternative_path_name_2 =
|
||||
facade->get_name_for_id(alternative_segment_2.name_id);
|
||||
|
||||
return route_names;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // EXTRACT_ROUTE_NAMES_H
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
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 TARJAN_SCC_HPP
|
||||
#define TARJAN_SCC_HPP
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../data_structures/deallocating_vector.hpp"
|
||||
#include "../data_structures/import_edge.hpp"
|
||||
#include "../data_structures/query_node.hpp"
|
||||
#include "../data_structures/percent.hpp"
|
||||
|
||||
#include "../util/integer_range.hpp"
|
||||
#include "../util/simple_logger.hpp"
|
||||
#include "../util/std_hash.hpp"
|
||||
#include "../util/timing_util.hpp"
|
||||
|
||||
#include <osrm/coordinate.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
template <typename GraphT> class TarjanSCC
|
||||
{
|
||||
struct TarjanStackFrame
|
||||
{
|
||||
explicit TarjanStackFrame(NodeID v, NodeID parent) : v(v), parent(parent) {}
|
||||
NodeID v;
|
||||
NodeID parent;
|
||||
};
|
||||
|
||||
struct TarjanNode
|
||||
{
|
||||
TarjanNode() : index(SPECIAL_NODEID), low_link(SPECIAL_NODEID), on_stack(false) {}
|
||||
unsigned index;
|
||||
unsigned low_link;
|
||||
bool on_stack;
|
||||
};
|
||||
|
||||
std::vector<unsigned> components_index;
|
||||
std::vector<NodeID> component_size_vector;
|
||||
std::shared_ptr<const GraphT> m_graph;
|
||||
std::size_t size_one_counter;
|
||||
|
||||
public:
|
||||
TarjanSCC(std::shared_ptr<const GraphT> graph)
|
||||
: components_index(graph->GetNumberOfNodes(), SPECIAL_NODEID), m_graph(graph),
|
||||
size_one_counter(0)
|
||||
{
|
||||
BOOST_ASSERT(m_graph->GetNumberOfNodes() > 0);
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
TIMER_START(SCC_RUN);
|
||||
const NodeID max_node_id = m_graph->GetNumberOfNodes();
|
||||
|
||||
// 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<TarjanNode> tarjan_node_list(max_node_id);
|
||||
unsigned component_index = 0, size_of_current_component = 0;
|
||||
unsigned index = 0;
|
||||
std::vector<bool> processing_node_before_recursion(max_node_id, true);
|
||||
for (const NodeID node : osrm::irange(0u, max_node_id))
|
||||
{
|
||||
if (SPECIAL_NODEID == components_index[node])
|
||||
{
|
||||
recursion_stack.emplace(TarjanStackFrame(node, node));
|
||||
}
|
||||
|
||||
while (!recursion_stack.empty())
|
||||
{
|
||||
TarjanStackFrame currentFrame = recursion_stack.top();
|
||||
const NodeID u = currentFrame.parent;
|
||||
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;
|
||||
|
||||
for (const auto current_edge : m_graph->GetAdjacentEdgeRange(v))
|
||||
{
|
||||
const auto vprime = m_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[u].low_link =
|
||||
std::min(tarjan_node_list[u].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";
|
||||
|
||||
size_one_counter = std::count_if(component_size_vector.begin(), component_size_vector.end(),
|
||||
[](unsigned value)
|
||||
{
|
||||
return 1 == value;
|
||||
});
|
||||
}
|
||||
|
||||
std::size_t get_number_of_components() const { return component_size_vector.size(); }
|
||||
|
||||
std::size_t get_size_one_count() const { return size_one_counter; }
|
||||
|
||||
unsigned get_component_size(const unsigned component_id) const
|
||||
{
|
||||
return component_size_vector[component_id];
|
||||
}
|
||||
|
||||
unsigned get_component_id(const NodeID node) const { return components_index[node]; }
|
||||
};
|
||||
|
||||
#endif /* TARJAN_SCC_HPP */
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
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 TRIP_BRUTE_FORCE_HPP
|
||||
#define TRIP_BRUTE_FORCE_HPP
|
||||
|
||||
#include "../data_structures/search_engine.hpp"
|
||||
#include "../util/dist_table_wrapper.hpp"
|
||||
#include "../util/simple_logger.hpp"
|
||||
|
||||
#include <osrm/json_container.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace trip
|
||||
{
|
||||
|
||||
// computes the distance of a given permutation
|
||||
EdgeWeight ReturnDistance(const DistTableWrapper<EdgeWeight> &dist_table,
|
||||
const std::vector<NodeID> &location_order,
|
||||
const EdgeWeight min_route_dist,
|
||||
const std::size_t component_size)
|
||||
{
|
||||
EdgeWeight route_dist = 0;
|
||||
std::size_t i = 0;
|
||||
while (i < location_order.size() && (route_dist < min_route_dist))
|
||||
{
|
||||
route_dist += dist_table(location_order[i], location_order[(i + 1) % component_size]);
|
||||
BOOST_ASSERT_MSG(dist_table(location_order[i], location_order[(i + 1) % component_size]) !=
|
||||
INVALID_EDGE_WEIGHT,
|
||||
"invalid route found");
|
||||
++i;
|
||||
}
|
||||
|
||||
return route_dist;
|
||||
}
|
||||
|
||||
// computes the route by computing all permutations and selecting the shortest
|
||||
template <typename NodeIDIterator>
|
||||
std::vector<NodeID> BruteForceTrip(const NodeIDIterator start,
|
||||
const NodeIDIterator end,
|
||||
const std::size_t number_of_locations,
|
||||
const DistTableWrapper<EdgeWeight> &dist_table)
|
||||
{
|
||||
(void)number_of_locations; // unused
|
||||
|
||||
const auto component_size = std::distance(start, end);
|
||||
|
||||
std::vector<NodeID> perm(start, end);
|
||||
std::vector<NodeID> route;
|
||||
route.reserve(component_size);
|
||||
|
||||
EdgeWeight min_route_dist = INVALID_EDGE_WEIGHT;
|
||||
|
||||
// check length of all possible permutation of the component ids
|
||||
|
||||
BOOST_ASSERT_MSG(perm.size() > 0, "no permutation given");
|
||||
BOOST_ASSERT_MSG(*(std::max_element(std::begin(perm), std::end(perm))) < number_of_locations,
|
||||
"invalid node id");
|
||||
BOOST_ASSERT_MSG(*(std::min_element(std::begin(perm), std::end(perm))) >= 0, "invalid node id");
|
||||
|
||||
do
|
||||
{
|
||||
const auto new_distance = ReturnDistance(dist_table, perm, min_route_dist, component_size);
|
||||
if (new_distance <= min_route_dist)
|
||||
{
|
||||
min_route_dist = new_distance;
|
||||
route = perm;
|
||||
}
|
||||
} while (std::next_permutation(std::begin(perm), std::end(perm)));
|
||||
|
||||
return route;
|
||||
}
|
||||
|
||||
} // end namespace trip
|
||||
} // end namespace osrm
|
||||
#endif // TRIP_BRUTE_FORCE_HPP
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
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 TRIP_FARTHEST_INSERTION_HPP
|
||||
#define TRIP_FARTHEST_INSERTION_HPP
|
||||
|
||||
#include "../data_structures/search_engine.hpp"
|
||||
#include "../util/dist_table_wrapper.hpp"
|
||||
|
||||
#include <osrm/json_container.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace trip
|
||||
{
|
||||
|
||||
// given a route and a new location, find the best place of insertion and
|
||||
// check the distance of roundtrip when the new location is additionally visited
|
||||
using NodeIDIter = std::vector<NodeID>::iterator;
|
||||
std::pair<EdgeWeight, NodeIDIter>
|
||||
GetShortestRoundTrip(const NodeID new_loc,
|
||||
const DistTableWrapper<EdgeWeight> &dist_table,
|
||||
const std::size_t number_of_locations,
|
||||
std::vector<NodeID> &route)
|
||||
{
|
||||
(void)number_of_locations; // unused
|
||||
|
||||
auto min_trip_distance = INVALID_EDGE_WEIGHT;
|
||||
NodeIDIter next_insert_point_candidate;
|
||||
|
||||
// for all nodes in the current trip find the best insertion resulting in the shortest path
|
||||
// assert min 2 nodes in route
|
||||
const auto start = std::begin(route);
|
||||
const auto end = std::end(route);
|
||||
for (auto from_node = start; from_node != end; ++from_node)
|
||||
{
|
||||
auto to_node = std::next(from_node);
|
||||
if (to_node == end)
|
||||
{
|
||||
to_node = start;
|
||||
}
|
||||
|
||||
const auto dist_from = dist_table(*from_node, new_loc);
|
||||
const auto dist_to = dist_table(new_loc, *to_node);
|
||||
const auto trip_dist = dist_from + dist_to - dist_table(*from_node, *to_node);
|
||||
|
||||
BOOST_ASSERT_MSG(dist_from != INVALID_EDGE_WEIGHT, "distance has invalid edge weight");
|
||||
BOOST_ASSERT_MSG(dist_to != INVALID_EDGE_WEIGHT, "distance has invalid edge weight");
|
||||
// This is not neccessarily true:
|
||||
// Lets say you have an edge (u, v) with duration 100. If you place a coordinate exactly in
|
||||
// the middle of the segment yielding (u, v'), the adjusted duration will be 100 * 0.5 = 50.
|
||||
// Now imagine two coordinates. One placed at 0.99 and one at 0.999. This means (u, v') now
|
||||
// has a duration of 100 * 0.99 = 99, but (u, v'') also has a duration of 100 * 0.995 = 99.
|
||||
// In which case (v', v'') has a duration of 0.
|
||||
// BOOST_ASSERT_MSG(trip_dist >= 0, "previous trip was not minimal. something's wrong");
|
||||
|
||||
// from all possible insertions to the current trip, choose the shortest of all insertions
|
||||
if (trip_dist < min_trip_distance)
|
||||
{
|
||||
min_trip_distance = trip_dist;
|
||||
next_insert_point_candidate = to_node;
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT_MSG(min_trip_distance != INVALID_EDGE_WEIGHT, "trip has invalid edge weight");
|
||||
|
||||
return std::make_pair(min_trip_distance, next_insert_point_candidate);
|
||||
}
|
||||
|
||||
template <typename NodeIDIterator>
|
||||
// given two initial start nodes, find a roundtrip route using the farthest insertion algorithm
|
||||
std::vector<NodeID> FindRoute(const std::size_t &number_of_locations,
|
||||
const std::size_t &component_size,
|
||||
const NodeIDIterator &start,
|
||||
const NodeIDIterator &end,
|
||||
const DistTableWrapper<EdgeWeight> &dist_table,
|
||||
const NodeID &start1,
|
||||
const NodeID &start2)
|
||||
{
|
||||
BOOST_ASSERT_MSG(number_of_locations >= component_size,
|
||||
"component size bigger than total number of locations");
|
||||
|
||||
std::vector<NodeID> route;
|
||||
route.reserve(number_of_locations);
|
||||
|
||||
// tracks which nodes have been already visited
|
||||
std::vector<bool> visited(number_of_locations, false);
|
||||
|
||||
visited[start1] = true;
|
||||
visited[start2] = true;
|
||||
route.push_back(start1);
|
||||
route.push_back(start2);
|
||||
|
||||
// add all other nodes missing (two nodes are already in the initial start trip)
|
||||
for (std::size_t j = 2; j < component_size; ++j)
|
||||
{
|
||||
|
||||
auto farthest_distance = std::numeric_limits<int>::min();
|
||||
auto next_node = -1;
|
||||
NodeIDIter next_insert_point;
|
||||
|
||||
// find unvisited loc i that is the farthest away from all other visited locs
|
||||
for (auto i = start; i != end; ++i)
|
||||
{
|
||||
// find the shortest distance from i to all visited nodes
|
||||
if (!visited[*i])
|
||||
{
|
||||
const auto insert_candidate =
|
||||
GetShortestRoundTrip(*i, dist_table, number_of_locations, route);
|
||||
|
||||
BOOST_ASSERT_MSG(insert_candidate.first != INVALID_EDGE_WEIGHT,
|
||||
"shortest round trip is invalid");
|
||||
|
||||
// add the location to the current trip such that it results in the shortest total
|
||||
// tour
|
||||
if (insert_candidate.first >= farthest_distance)
|
||||
{
|
||||
farthest_distance = insert_candidate.first;
|
||||
next_node = *i;
|
||||
next_insert_point = insert_candidate.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASSERT_MSG(next_node >= 0, "next node to visit is invalid");
|
||||
|
||||
// mark as visited and insert node
|
||||
visited[next_node] = true;
|
||||
route.insert(next_insert_point, next_node);
|
||||
}
|
||||
return route;
|
||||
}
|
||||
|
||||
template <typename NodeIDIterator>
|
||||
std::vector<NodeID> FarthestInsertionTrip(const NodeIDIterator &start,
|
||||
const NodeIDIterator &end,
|
||||
const std::size_t number_of_locations,
|
||||
const DistTableWrapper<EdgeWeight> &dist_table)
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// START FARTHEST INSERTION HERE
|
||||
// 1. start at a random round trip of 2 locations
|
||||
// 2. find the location that is the farthest away from the visited locations and whose insertion
|
||||
// will make the round trip the longest
|
||||
// 3. add the found location to the current round trip such that round trip is the shortest
|
||||
// 4. repeat 2-3 until all locations are visited
|
||||
// 5. DONE!
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const auto component_size = std::distance(start, end);
|
||||
BOOST_ASSERT(component_size >= 0);
|
||||
|
||||
auto max_from = -1;
|
||||
auto max_to = -1;
|
||||
|
||||
if (static_cast<std::size_t>(component_size) == number_of_locations)
|
||||
{
|
||||
// find the pair of location with the biggest distance and make the pair the initial start
|
||||
// trip
|
||||
const auto index = std::distance(
|
||||
std::begin(dist_table), std::max_element(std::begin(dist_table), std::end(dist_table)));
|
||||
max_from = index / number_of_locations;
|
||||
max_to = index % number_of_locations;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto max_dist = 0;
|
||||
for (auto x = start; x != end; ++x)
|
||||
{
|
||||
for (auto y = start; y != end; ++y)
|
||||
{
|
||||
const auto xy_dist = dist_table(*x, *y);
|
||||
if (xy_dist > max_dist)
|
||||
{
|
||||
max_dist = xy_dist;
|
||||
max_from = *x;
|
||||
max_to = *y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT(max_from >= 0);
|
||||
BOOST_ASSERT(max_to >= 0);
|
||||
BOOST_ASSERT_MSG(static_cast<std::size_t>(max_from) < number_of_locations, "start node");
|
||||
BOOST_ASSERT_MSG(static_cast<std::size_t>(max_to) < number_of_locations, "start node");
|
||||
return FindRoute(number_of_locations, component_size, start, end, dist_table, max_from, max_to);
|
||||
}
|
||||
|
||||
} // end namespace trip
|
||||
} // end namespace osrm
|
||||
|
||||
#endif // TRIP_FARTHEST_INSERTION_HPP
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user