Compare commits
2530 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| bec585e382 | |||
| 2cc8ae875a | |||
| db8252e650 | |||
| e3cb26a1c4 | |||
| 44036ae26d | |||
| 5b5f871a6e | |||
| 9a8f9cae6d | |||
| 8f804581c0 | |||
| e26ef17545 | |||
| 800bb223b5 | |||
| 75606f2100 | |||
| a28928e6ca | |||
| 8700007025 | |||
| 520f7fa2de | |||
| 096208a154 | |||
| 27caab69ec | |||
| 3fe2b587cb | |||
| c791188811 | |||
| b227c90c18 | |||
| 8a5538356b | |||
| b257c881b5 | |||
| 0f5dffb1c3 | |||
| d2bd238274 | |||
| fed700440d | |||
| 32a9d42412 | |||
| efc938d870 | |||
| 369f669227 | |||
| 1c56671f01 | |||
| 4dbc1e0e96 | |||
| 94288843f1 | |||
| b12decc865 | |||
| 0fc944abf3 | |||
| 9f96c98f02 | |||
| 9805b05738 | |||
| 13ed186469 | |||
| 00a43221ac | |||
| edc39112e2 | |||
| 3b727dea99 | |||
| f16b2adec7 | |||
| 7d425aa76f | |||
| 651c07c724 | |||
| 4d27b75897 | |||
| 6f75d68d07 | |||
| ae269e12bb | |||
| 3a48929fe6 | |||
| be970326b6 | |||
| 463511871f | |||
| 002da1e02d | |||
| b095aae5ce | |||
| 511c21029e | |||
| 81b0447024 | |||
| d42772a261 | |||
| c1136099a9 | |||
| 06f8a975c0 | |||
| c8cd8775f6 | |||
| f9900c91bd | |||
| accaf6e77e | |||
| 8490e297a9 | |||
| 6d3a4b5f6c | |||
| 1f36206f45 | |||
| 952e10936c | |||
| 2b3093a687 | |||
| d7e25772b0 | |||
| c66c9b0353 | |||
| bbde0d75da | |||
| c3aec4f627 | |||
| 113852eed4 | |||
| 6b9b2c1468 | |||
| 2c87b295ff | |||
| 93767d68f8 | |||
| cc3646ca16 | |||
| 48333f73d5 | |||
| 1f4241a63d | |||
| 8eccfaa034 | |||
| 438d1af12a | |||
| 5be6ef380f | |||
| 76419ed2fc | |||
| 4684921e51 | |||
| edd8caa2bf | |||
| cb5575ae89 | |||
| 42e726dec5 | |||
| e3d33aa171 | |||
| f2ceeb35da | |||
| 577cf5ddc4 | |||
| 91ced39233 | |||
| 4b6cb0b8b8 | |||
| fb81302382 | |||
| dfc81f65ee | |||
| 909db4c861 | |||
| 4277eed1b6 | |||
| 6f5703a5fe | |||
| f7469f298d | |||
| b29d5df7a2 | |||
| 549ba65861 | |||
| a9d99cbe54 | |||
| 8438024370 | |||
| e6a00ddcfd | |||
| 71b967d243 | |||
| 1fc1e9590a | |||
| 0a0099fb41 | |||
| b890d394ad | |||
| a7fd37ae76 | |||
| 41fafae21d | |||
| a38c007f51 | |||
| c7ee402b0e | |||
| 1c19796e3e | |||
| 76fb0cb965 | |||
| 23c79f5cc9 | |||
| 14eac50261 | |||
| cf3eae1c91 | |||
| db06cdb4ce | |||
| 7ba8e51fa9 | |||
| bc6466cc36 | |||
| 4fbefaef9a | |||
| be11d3325d | |||
| 274140d309 | |||
| ed960ccc8d | |||
| f2b72113c1 | |||
| 67a8d30e87 | |||
| dafd0e5db7 | |||
| d6d10cbf06 | |||
| 3d3ba86be4 | |||
| 52ed8a7ed0 | |||
| 9449c99e25 | |||
| 4c0846734e | |||
| 4c64f5fe62 | |||
| 9455ea0547 | |||
| c3b54a63c3 | |||
| b9e1d3116c | |||
| 5bb7e62a7c | |||
| a443f3a0bb | |||
| 440244eed8 | |||
| 2b9e25300f | |||
| de264dbf94 | |||
| 848b773e24 | |||
| d92f022041 | |||
| 57fab61789 | |||
| ec8f977ebe | |||
| 8dc85e7641 | |||
| 4e00ebcd74 | |||
| 335e719b5d | |||
| 415f8ef2d8 | |||
| 17615d1d4a | |||
| 5072252c72 | |||
| 46e93770c9 | |||
| fe43734811 | |||
| 0df81c49d5 | |||
| 5653516b32 | |||
| 22da5be08e | |||
| 862656aecc | |||
| ec119a6d52 | |||
| 6b98b5f4c7 | |||
| 5effe95f2c | |||
| f22e3fd3ff | |||
| 0047040af9 | |||
| 60987e6b9b | |||
| 27d5e2b219 | |||
| 53fd0c3a55 | |||
| 63456a6d4f | |||
| d4cd3c2f7b | |||
| dbf7137a1a | |||
| 785891c315 | |||
| b7417ec954 | |||
| 61b861f0e5 | |||
| 0fea0738bf | |||
| 4f25d29815 | |||
| 28302a5040 | |||
| 9cc5ca5c58 | |||
| 4c4e60b3c9 | |||
| 5689a96602 | |||
| 8b57db467a | |||
| 50339e53e2 | |||
| bc9f5189a5 | |||
| fee83fee40 | |||
| cd5112ab0e | |||
| a43b88f9a2 | |||
| c20fd5dcaa | |||
| f12e296c09 | |||
| 9c3a572646 | |||
| 6175faa9a4 | |||
| af02fc6bbe | |||
| cc0bbc42a2 | |||
| fd747c7340 | |||
| bd33202972 | |||
| f6f0de0e38 | |||
| 881041800b | |||
| 11f3ac16f6 | |||
| 969bf95230 | |||
| abc6b4180c | |||
| f74d762a92 | |||
| f00892ed66 | |||
| f14c6e6845 | |||
| b1bbf2ef84 | |||
| 201062cade | |||
| 8cb9198bcf | |||
| f5e53c0452 | |||
| 41d9c00f70 | |||
| b52f392c92 | |||
| efaa3b5ab2 | |||
| 36f3d8d6ac | |||
| e469afa4a9 | |||
| 9d4b0caa5b | |||
| 392c07951e | |||
| 8e72c3d81e | |||
| 02428f1e06 | |||
| b3aa513563 | |||
| b8b08cb114 | |||
| ebbbf1059d | |||
| 37297076f8 | |||
| a75b2df6fe | |||
| 9ccd0f0282 | |||
| e57d9f2e2e | |||
| cf593ba9f9 | |||
| 9eb862a6a4 | |||
| bc84e08da5 | |||
| 24dae2f096 | |||
| ab24d6bd96 | |||
| 7782c80c4f | |||
| 994bd0a910 | |||
| bc9dcba4d4 | |||
| 85c244ed08 | |||
| 495196193c | |||
| def1e5e1d8 | |||
| 2727091e47 | |||
| d7fbd416ba | |||
| 6a09ce1613 | |||
| 774e6346e7 | |||
| 05b939760c | |||
| d6c6fbfe03 | |||
| bb3cbf2dda | |||
| 39d96a45aa | |||
| 6a8c5c8869 | |||
| 96318bbe11 | |||
| 00dd2463fd | |||
| bcd55626ef | |||
| 8f8cb6a52f | |||
| 2e3d33dfcd | |||
| 1e40cd6f0b | |||
| 6e2608b2f2 | |||
| 60d80cf261 | |||
| 9c23fd4a31 | |||
| fccb1aad32 | |||
| 2780ff31b5 | |||
| c37c8dc21d | |||
| 6ee7a81f10 | |||
| 3d94638d86 | |||
| 418ff95543 | |||
| 221113cbb7 | |||
| 13ea12cf6e | |||
| 1945aae4dc | |||
| 30362cfc0c | |||
| 6cdc590db5 | |||
| eb122a2b8c | |||
| feaf8711d3 | |||
| 6e364ff0ba | |||
| 6f6aff7493 | |||
| 207cddd50b | |||
| 35988d8f09 | |||
| bea63028c7 | |||
| 0244060806 | |||
| bfdc296f43 | |||
| 8e625a5d07 | |||
| 3460bd0ba9 | |||
| 4dd0377eb8 | |||
| 6e1ab9fe3a | |||
| 7a2d214cc4 | |||
| 62495a6de4 | |||
| 8ea88468f3 | |||
| 687892890b | |||
| ff0dfacc48 | |||
| 235a52032a | |||
| a5ee7e78f6 | |||
| 181dbe8493 | |||
| dae9c9a7ed | |||
| 6d6d299ea4 | |||
| 6fd615b9cd | |||
| d09394ed52 | |||
| 3e6f27d173 | |||
| 82c2ae5441 | |||
| 7edf2bb2c2 | |||
| c9607b99a3 | |||
| 2fe1a84dd4 | |||
| c63218a889 | |||
| 5efa9664db | |||
| dc75469e78 | |||
| 9d1e21b5ad | |||
| 27a367c733 | |||
| ffa0ace2a7 | |||
| 074e1e992c | |||
| cdd72c7e56 | |||
| a5e99a95a3 | |||
| 1de736019d | |||
| d6b2712070 | |||
| eda8f4ccec | |||
| 7e3f476407 | |||
| e10f36d5f0 | |||
| 1bfd9abda3 | |||
| 4a1a10fde8 | |||
| 4c3cb76ced | |||
| e2794e9f06 | |||
| 7d2c627ad2 | |||
| b310e0f718 | |||
| 18915ae2bd | |||
| 5dbda8f519 | |||
| 82ce9dfc04 | |||
| ad5cd564ab | |||
| 6f01f580ca | |||
| d5130d9fe4 | |||
| 0341a0d5e7 | |||
| 32191fb05a | |||
| 1592fe377a | |||
| 5add28410f | |||
| d54a55c12b | |||
| aab5e8430f | |||
| 2e20fdb462 | |||
| 2ac3da7a90 | |||
| 399b79bab2 | |||
| b9eb936cac | |||
| 38117df11b | |||
| 27d729baf0 | |||
| d408a64c8c | |||
| 9aeb28066d | |||
| 6fb7c8687e | |||
| d9666008e3 | |||
| e132230651 | |||
| c2877a0c22 | |||
| 251fc3ec68 | |||
| 287f0a3b68 | |||
| b03d9fe987 | |||
| 98372ef33f | |||
| d00f4afb84 | |||
| d4bf02c882 | |||
| 284e671163 | |||
| 0f112e5c9d | |||
| 759449b4be | |||
| 9c03f919a3 | |||
| c9afd9a281 | |||
| a999cb9db9 | |||
| fdc5bd6195 | |||
| e1d94eee21 | |||
| 885f237217 | |||
| 5860a4e28e | |||
| 2bebed44ff | |||
| 4990e544cf | |||
| 8010506d4e | |||
| f2f7abb9a8 | |||
| 85f6ab869e | |||
| fc87b0a11e | |||
| 79bc071754 | |||
| 797243fc9c | |||
| cc7c6b9ece | |||
| 279071e5bb | |||
| 426374ff8a | |||
| 1508874ebc | |||
| bbe440cacd | |||
| e647e73af9 | |||
| 696ddfde0e | |||
| 37d6257524 | |||
| faee894052 | |||
| 61f16b8c5e | |||
| 85eb38e755 | |||
| a87cf60dfc | |||
| 3b135447f3 | |||
| 0c3713f7e5 | |||
| 4d0571fd73 | |||
| 4722988bf0 | |||
| 61151535e6 | |||
| bcff6c192c | |||
| 020d0cfb49 | |||
| d38e3bd729 | |||
| 84a604f70b | |||
| 782baf54a3 | |||
| d754e4eeca | |||
| db98f6191e | |||
| b453a42f77 | |||
| 2a6585e664 | |||
| bc013925b8 | |||
| 8108ecc4d3 | |||
| 1c80584206 | |||
| a3dd9c3e57 | |||
| 8f05fc0a84 | |||
| 3c4feecda0 | |||
| e776a51c73 | |||
| 129e8ef98a | |||
| 69134f6d6a | |||
| b32062f875 | |||
| 8d46ee85f1 | |||
| 9f9fde1f2b | |||
| 2b041e09ac | |||
| 73b32bb45e | |||
| 11e6e74f09 | |||
| bf3e3f0c3d | |||
| 2656acc321 | |||
| e46c9be79f | |||
| 507167d5c1 | |||
| fc90162f69 | |||
| 1e8fb7a38c | |||
| afb6c5a09d | |||
| 2255ab0a37 | |||
| a6ab042078 | |||
| 480f70c049 | |||
| 0592897859 | |||
| d5a9f8e177 | |||
| 5840829cdc | |||
| fd0946b770 | |||
| 293b462fd2 | |||
| 3db50fdd54 | |||
| 1540e6518c | |||
| 8b30c13cd9 | |||
| a7eb89b2f0 | |||
| 53c102e1e9 | |||
| 7d90737921 | |||
| e281f88f2e | |||
| 16c5c7bbb4 | |||
| 7d4dfd87f1 | |||
| 6156bf0f9d | |||
| ee1fdca52e | |||
| 95b5bcbd49 | |||
| 0c529361a3 | |||
| 7110acc94f | |||
| 1188002bcb | |||
| b47a3f15ce | |||
| 695a2a2b6e | |||
| c8b4ef3eed | |||
| 6091248493 | |||
| 32fd507ad9 | |||
| 0ee77a37d1 | |||
| 05241544c5 | |||
| 495c872489 | |||
| 8c09edfdbd | |||
| 67722cf788 | |||
| 8e3484b873 | |||
| 4622aebabb | |||
| 96f29c27cd | |||
| 3de98f7a9d | |||
| 2b33fcd92d | |||
| b1ffcd4350 | |||
| fd500001fb | |||
| 54a757a917 | |||
| 98dfc218d9 | |||
| f6f0f1fb72 | |||
| 218c810860 | |||
| c836b6df3b | |||
| 637bab29c6 | |||
| 0061b3fcbf | |||
| 2a19ded9d5 | |||
| bda9de0775 | |||
| 7047610a45 | |||
| 903d6f9e12 | |||
| 7d61bb2868 | |||
| def7164cad | |||
| fc399e01fe | |||
| ffdc3eee2d | |||
| 1f6f44ab01 | |||
| 19740758c9 | |||
| f618660d24 | |||
| f50dbe298a | |||
| c324fbace4 | |||
| d05152af71 | |||
| bf228b4ae4 | |||
| ba0c17e287 | |||
| 6cfbd4cefe | |||
| e17a2e79a0 | |||
| 72d709ae6c | |||
| 08ca450c40 | |||
| a2951659ac | |||
| 3a6af3810f | |||
| 3973554f07 | |||
| 718cba2e36 | |||
| d2a70d1504 | |||
| 4bc847ac42 | |||
| c3621edf9c | |||
| a64f2de9e1 | |||
| ce684cf9d4 | |||
| 1d1be10f16 | |||
| a09f97c9d5 | |||
| 48da2d2dfb | |||
| 36c0edea2a | |||
| 3568dc2083 | |||
| 51ad72a432 | |||
| 9ce970df8f | |||
| cfa4d80dd7 | |||
| 885cd05f1a | |||
| 21188725d5 | |||
| 70f257b62f | |||
| e8fb8e13df | |||
| 7b7b93e9ba | |||
| 4014da3cc5 | |||
| 410120adee | |||
| a98e65aa1e | |||
| dba9998118 | |||
| 1c75ce5911 | |||
| 33b30aeb95 | |||
| abd8d3459a | |||
| 471698c59f | |||
| e67cf578ae | |||
| 186ad5d444 | |||
| 7eb810c34a | |||
| 7817384e3c | |||
| 34256ba358 | |||
| 08eb5aa7d1 | |||
| 1d3932e8c5 | |||
| 3f85b30d4a | |||
| e4c398aa23 | |||
| f9417555d0 | |||
| 5d3123b97f | |||
| 25080aaf1d | |||
| 05ac4b5ab6 | |||
| 07e13e2499 | |||
| 2d9645b9b0 | |||
| 65ccbedab2 | |||
| 631567864b | |||
| 39d479128c | |||
| 4c0b315c07 | |||
| 264e83a1f3 | |||
| 2b2ed50721 | |||
| 31fbf99109 | |||
| 63381ad221 | |||
| 6ee2d1103e | |||
| bee18dba54 | |||
| 481e445e8a | |||
| 129f7b7441 | |||
| d6bc3c5175 | |||
| de7c56c6bc | |||
| 0c59ecfa14 | |||
| f67241a3cb | |||
| 3b2893944c | |||
| dd7d6df4c6 | |||
| efbda436f3 | |||
| 2064934939 | |||
| b36cf7c450 | |||
| a24dd3dee2 | |||
| 7b22f08869 | |||
| 840929754a | |||
| 51fd332806 | |||
| 4d7e0f6b79 | |||
| b74a573ec5 | |||
| 5faf88afdb | |||
| 5e1110930e | |||
| f11adf5f80 | |||
| 40a71e09a6 | |||
| 1231847a3c | |||
| b06a73e893 | |||
| f99f194927 | |||
| eac7d07ef6 | |||
| 60d70a9f4c | |||
| c944783590 | |||
| 8104a8aea1 | |||
| a4db678895 | |||
| da33d02461 | |||
| 9b4071006e | |||
| b3cdd5b3bf | |||
| 93e53ec612 | |||
| ea8319e2b9 | |||
| 2fae253c62 | |||
| e204b257ad | |||
| dd83d8ed61 | |||
| 61f3d85af1 | |||
| 804e515847 | |||
| 35977b6c7f | |||
| 23f1d3d83b | |||
| b8ea935424 | |||
| 7c0866f626 | |||
| 0f2062b739 | |||
| e91454eeee | |||
| 58134200df | |||
| f6bab21928 | |||
| 011910811b | |||
| bbc0ba147a | |||
| 922a4331db | |||
| 8f7f1e2683 | |||
| 1980cc007f | |||
| 39611f7477 | |||
| e3d659576f | |||
| 46d4670b74 | |||
| 15ca6d5ca9 | |||
| 58f23cda4a | |||
| a58d8420a2 | |||
| 96f834fb81 | |||
| 86617eccb1 | |||
| f2936d1c2d | |||
| 0fc8e04ab5 | |||
| a65e2d3115 | |||
| ca6e25b11c | |||
| 3ec6a6f5bc | |||
| c12fae47e7 | |||
| 604d2c698b | |||
| 5d14016366 | |||
| b112becbba | |||
| e68a09fb3c | |||
| 30e9b4513a | |||
| 671b14dac0 | |||
| 82e99988e8 | |||
| 313a7ed7fa | |||
| cf3365574e | |||
| 0e1f6f50ea | |||
| 5b6518d4a9 | |||
| c009dce591 | |||
| 40e2d7932b | |||
| e29b7a6eae | |||
| a3e9cbc000 | |||
| aedcc2ff40 | |||
| 4c17aeb180 | |||
| ef60ae652c | |||
| 1d62ed028e | |||
| 50bf7694c2 | |||
| 807f1d7c1c | |||
| 7a7d0c09d9 | |||
| f90ce77da4 | |||
| d27ac27bc7 | |||
| 44c6a64bf4 | |||
| 2d6eae9391 | |||
| ba440550a6 | |||
| 8e24fee9da | |||
| 1148652101 | |||
| ed01eeaeb3 | |||
| 096f187d6f | |||
| fa35eb1959 | |||
| 8d89d30c74 | |||
| f1bde40939 | |||
| 4e7ccaa298 | |||
| d0284991ed | |||
| c4998990e5 | |||
| 42d3ee9b94 | |||
| be5c3e41e1 | |||
| 3282d410c4 | |||
| 75303c95f8 | |||
| 0209272831 | |||
| 0e16c4ed97 | |||
| e49720f34a | |||
| 8aee371d81 | |||
| 71c4f81b59 | |||
| 3127fafc88 | |||
| 4e6bdf28cc | |||
| 621a5a86a0 | |||
| d80c8cbd2f | |||
| 686f1aeeb2 | |||
| e27a69bab7 | |||
| 4ee2e1d049 | |||
| 2102648102 | |||
| 8611e40172 | |||
| 7d5b88fff8 | |||
| cfd9aa31a9 | |||
| 62aea4c321 | |||
| f75fcb3041 | |||
| 971c557d85 | |||
| ea05aa225e | |||
| 56cdabff6a | |||
| 15f62e680a | |||
| 0af4e16c21 | |||
| c7b90bac1a | |||
| 4b81331d53 | |||
| 47ab0cbf62 | |||
| f5b079b8e7 | |||
| 21c4691d40 | |||
| 3726706608 | |||
| 28a53aa147 | |||
| 2ad572490c | |||
| 0ed9caf969 | |||
| 63ee376f71 | |||
| 67bcb98a84 | |||
| 9cd91ae99c | |||
| d111a0e5e6 | |||
| 11d4c04cea | |||
| 01773c2a00 | |||
| 1079bf7843 | |||
| 05bcfd2c1c | |||
| 5357a6a4fd | |||
| b6787b0014 | |||
| a32116d24c | |||
| a03b698e5a | |||
| fa0c5db18c | |||
| bc063ded7a | |||
| 846505cbc8 | |||
| 964118d1d6 | |||
| c43b67ea2e | |||
| f68af08931 | |||
| cdd5a41965 | |||
| e13ee59af3 | |||
| 9eb183e01d | |||
| 1163417722 | |||
| 3edc48cda5 | |||
| 2c01425ee5 | |||
| ed9c72814f | |||
| adbbe2b097 | |||
| 7335e0809a | |||
| 75dabb75e2 | |||
| 15adcd24be | |||
| e98ba99331 | |||
| 11459d38d0 | |||
| baf4ea2e8c | |||
| 6a29168c14 | |||
| a4689c7a27 | |||
| 8fda5a187b | |||
| 7b78270f4b | |||
| afd3599a9c | |||
| 4bc8562cd0 | |||
| 11fed4c06c | |||
| 9416a983c6 | |||
| 8108c6320d | |||
| b40b931568 | |||
| 282f70ea91 | |||
| a671f63a3e | |||
| f3ad14cb7f | |||
| 21eb5b661d | |||
| 87fe073118 | |||
| 507dadebf4 | |||
| 7dac8c621c | |||
| 19f4ebf3c5 | |||
| c21b40bebc | |||
| 0766c3c62d | |||
| cc40eb709c | |||
| 3625308585 | |||
| df3a7676eb | |||
| 8f6077e973 | |||
| e6689144c4 | |||
| a67de410bf | |||
| 54ec1a89de | |||
| 4b5f744c6f | |||
| df978345d7 | |||
| facc07c60d | |||
| 2f203ac22c | |||
| cc864191b8 | |||
| 547455245e | |||
| b0d7449bb4 | |||
| aed04c7d55 | |||
| bb5973f2fd | |||
| f801fd1f0d | |||
| 44ca12ead6 | |||
| 9c48389f74 | |||
| acefb5a5f3 | |||
| 3d691a3aec | |||
| 38ebdbb563 | |||
| 1090325c31 | |||
| f8ba4b9312 | |||
| 49a1dfff60 | |||
| 5f4d342d45 | |||
| e1c1f79068 | |||
| a716fa252f | |||
| 0b12e4d8be | |||
| 6ad6c94355 | |||
| 78270c8155 | |||
| 4573ae21e6 | |||
| 0ab6220635 | |||
| 3b51976b96 | |||
| c35211b2f6 | |||
| f62515e13b | |||
| 7f2daf8926 | |||
| 0325861ef3 | |||
| 37f8285a6e | |||
| d3906cffdc | |||
| bee1c77efe | |||
| 7250a82286 | |||
| 984457f9c6 | |||
| 5db23f7e46 | |||
| f4f49b2b46 | |||
| 58b35f6e2d | |||
| b51ad16756 | |||
| d790bda7d2 | |||
| 15ce232f61 | |||
| d999a47600 | |||
| 644286111f | |||
| 917b1cbd6c | |||
| 6d1b585212 | |||
| 6ca35a6264 | |||
| 0290b1b4e0 | |||
| 1d86bf3e56 | |||
| 3fd8ab8d3a | |||
| d240ae3b03 | |||
| b875765c52 | |||
| 2bdec31219 | |||
| a9eebdb1fa | |||
| b25f3a9e91 | |||
| 06f3375a97 | |||
| 5057ae920c | |||
| 6a03f13d55 | |||
| 20cbfd95d6 | |||
| 885dbe1e65 | |||
| 7d7cce5c72 | |||
| 0c66f84555 | |||
| 044e41c079 | |||
| 8dc631e13c | |||
| d93b4feb99 | |||
| 0b873f590c | |||
| f52d637f58 | |||
| e2daf5c2fc | |||
| bef113001a | |||
| f0b403bc2e | |||
| a21fb5fc89 | |||
| bbc0424563 | |||
| f487845e9d | |||
| 77641a9fce | |||
| 56d93eb18b | |||
| da1fd96d4e | |||
| d1fdc7061f | |||
| 2822382797 | |||
| 35c9021bdf | |||
| 493b13364f | |||
| a8ff3231a8 | |||
| c2a750a690 | |||
| 6a9541833a | |||
| 9117b45899 | |||
| 812cf36d52 | |||
| 4aa7420d6a | |||
| 1802839a22 | |||
| 9a2d701e2e | |||
| 69ad3f3365 | |||
| d53eb881c2 | |||
| e28e45f38e | |||
| bf6ca22b00 | |||
| b8acbae3e8 | |||
| 4ec9f2c00f | |||
| 4fc329a1eb | |||
| 0574a60bc2 | |||
| e490c4afed | |||
| d028a30f87 | |||
| 75a2d4d00a | |||
| a122a1e8c7 | |||
| 8fe09c85b6 | |||
| bc951de2a5 | |||
| c970cd13cc | |||
| 8983c0f927 | |||
| a47467f29b | |||
| ef206eb4d9 | |||
| da5eec1c5f | |||
| a69b3535a5 | |||
| f4c23f3259 | |||
| e36e9fd629 | |||
| d2f19353ed | |||
| 2d498cb88b | |||
| a80815d57a | |||
| acab77f4f8 | |||
| bddad0c57c | |||
| 3968349480 | |||
| 3ae17761b3 | |||
| 9a28bdbf76 | |||
| e769821e0f | |||
| 9b68821f05 | |||
| b2adb22b2d | |||
| 981941edf4 | |||
| 111dea89a9 | |||
| 2720f4de9c | |||
| 21645643b0 | |||
| c6a07acd90 | |||
| 1816e6607e | |||
| 37dd05a9b5 | |||
| 529997de9b | |||
| 4f37270300 | |||
| faf9c96442 | |||
| f7e09686e5 | |||
| 8eef8204e7 | |||
| 8b8e08f0f5 | |||
| a6bfec22b5 | |||
| d05c4fa9ed | |||
| 07231d3706 | |||
| 584ba10726 | |||
| 24a61dc650 | |||
| 7e7aa6aaee | |||
| 35c5be6475 | |||
| fcf3eb6193 | |||
| 5226b200e7 | |||
| 5f57152156 | |||
| 633ef26054 | |||
| 285bd4f542 | |||
| e706fb973f | |||
| 8dc7afed4e | |||
| 0c7f996de6 | |||
| 985a8e9f97 | |||
| 5e26e4c22d | |||
| 00e27e4b5c | |||
| b3ec9c9323 | |||
| 84ffedd95d | |||
| 455dc26a5d | |||
| 0fccd0f0d2 | |||
| 7e639d6bc1 | |||
| 694ce9d04f | |||
| aebe8572f9 | |||
| c98eed612a | |||
| 5f0ee417b1 | |||
| a6b4658138 | |||
| 1a57aff0f4 | |||
| afc0bac232 | |||
| ac1c59b724 | |||
| 1f9806386e | |||
| 1b67120704 | |||
| 5579388896 | |||
| 49c972983d | |||
| 3cb34f8036 | |||
| 3c5b2286a3 | |||
| 845972daa5 | |||
| e00ef38305 | |||
| 22d0861f6d | |||
| 5265f38c35 | |||
| d13cd4d4b3 | |||
| 79d33d669c | |||
| 439f6e62bc | |||
| 3ef054bbac | |||
| 5a13c6cc3f | |||
| b7750ff742 | |||
| 2c0fa2a9f6 | |||
| 881a57bf8d | |||
| c924b2067c | |||
| fdd0c8470f | |||
| 1960c38468 | |||
| 3074a0146e | |||
| f060dfda40 | |||
| b0ead129ca | |||
| abe9c4d53c | |||
| 15a95ff425 | |||
| 37b8f97d60 | |||
| 88a4bb4d12 | |||
| 50594febc7 | |||
| 9587923e55 | |||
| 2850a074ea | |||
| bed5c8002f | |||
| cc982a578d | |||
| e12ad48822 | |||
| 6abbb06ff6 | |||
| 3d68769503 | |||
| bd316e7e98 | |||
| 3f4c4d675b | |||
| 4b7e5b7445 | |||
| 996dbdde00 | |||
| db67f2ddf1 | |||
| 7b9b2fd23a | |||
| 700747801c | |||
| cb30f4668e | |||
| 9710f39cad | |||
| e3244dd649 | |||
| abd20776a2 | |||
| 5d8b4cb261 | |||
| 9ee615020f | |||
| acef734643 | |||
| 0ff7ac6aad | |||
| 859502c504 | |||
| 9c2926ef8a | |||
| 3188bc5aba | |||
| bf9d9512a0 | |||
| ba03f99e09 | |||
| 8e89f80588 | |||
| 07e245eb02 | |||
| ea12c6fde6 | |||
| 38c7d07e50 | |||
| a0a835bbe6 | |||
| c09e897dab | |||
| c5a3937c80 | |||
| 8e6cc09d2f | |||
| dee3529f14 | |||
| bf5d83d228 | |||
| c2b7336817 | |||
| fc6017c0dd | |||
| 821cc3a177 | |||
| 8939cef020 | |||
| fb17653651 | |||
| f8a07c7a03 | |||
| eb89436df3 | |||
| c1e7ba7118 | |||
| ffddea75a4 | |||
| 380111a604 | |||
| dd4461d473 | |||
| 2706a0bec1 | |||
| 46b207e08e | |||
| d3eda80969 | |||
| 66fb5fc9c8 | |||
| 2d3fb858ad | |||
| 7bf74c0917 | |||
| 5b22dffa6f | |||
| 3ca9420801 | |||
| 3c948a82c0 | |||
| c33c6188a8 | |||
| 0d8f2e1b18 | |||
| 17ed4f908c | |||
| 946bfb9a26 | |||
| 6c2c48a611 | |||
| 1f36cf9242 | |||
| 3ddac9ac5d | |||
| 1b22b348b0 | |||
| f68721af07 | |||
| d53b7de5ec | |||
| b25f3891c8 | |||
| ca58c9ce09 | |||
| 7a2a535f87 | |||
| 17d220187a | |||
| d3a4857826 | |||
| e64fec15b0 | |||
| 3d5f566d86 | |||
| c87b63cb24 | |||
| cd95f9310b | |||
| 297128c19c | |||
| 25a385c940 | |||
| 181e814139 | |||
| 52e5483dfb | |||
| 56f6c795ed | |||
| 5d8cfa465b | |||
| b6ca4a7a46 | |||
| a45508a96b | |||
| a45d274847 | |||
| e3cc896a42 | |||
| 99a47ae87b | |||
| b1388b6f30 | |||
| 2cddf90e49 | |||
| 85148d1283 | |||
| 7b0b378abc | |||
| a1ecab2f95 | |||
| b7704f0c7f | |||
| d6962f3a09 | |||
| e44ebe0743 | |||
| f02ec41fbc | |||
| d0b4ffd154 | |||
| 265af1f790 | |||
| 241d6b482e | |||
| 45f0af2afc | |||
| 7955066d5c | |||
| ec3f9695cd | |||
| 018c144c76 | |||
| 56e88b2a56 | |||
| a2bdc5d8d9 | |||
| 1b257f7547 | |||
| 5d6b05979d | |||
| 538f8d040a | |||
| 7d52aa1272 | |||
| d316202834 | |||
| 0167dfc3c9 | |||
| 02dc3dee04 | |||
| a5d3bc9578 | |||
| cfbc6b0441 | |||
| 8c5f8e995e | |||
| b77dd6699d | |||
| 9a153708e6 | |||
| e0027a78e1 | |||
| 51e8113a69 | |||
| 78f5753a3a | |||
| 16ca8da438 | |||
| ca6515c58a | |||
| 2ec952032a | |||
| b0b67a0cdc | |||
| 0eed39cdf1 | |||
| ace59411cb | |||
| ef7619d664 | |||
| 0f8a32f38c | |||
| c6a58ff1b4 | |||
| 45f751720a | |||
| ca016e2818 | |||
| 5da01946b8 | |||
| 8b3002a685 | |||
| ede5cca2e7 | |||
| d0e158ca07 | |||
| 09dc21af31 | |||
| 2435fadfbd | |||
| edef9c11f7 | |||
| 2c9edcaf23 | |||
| 18861d58b5 | |||
| 9b3dab8055 | |||
| 7a6a5f6612 | |||
| f468fcc2b6 | |||
| 5d93c68790 | |||
| fa04706484 | |||
| d09be5a80e | |||
| a4d6e5c9cc | |||
| 4f85fd28cf | |||
| 39914cd933 | |||
| 038e8cc8b8 | |||
| db5fd5506d | |||
| f2be495e95 | |||
| 6d8465a04d | |||
| 4bb5270f25 | |||
| 0f06c71796 | |||
| 5b8d8a83dd | |||
| 8ec3d549a6 | |||
| 394e369b54 | |||
| 899ab9ddc0 | |||
| 8ae467985f | |||
| 9ccc8a7404 | |||
| 0b89a9d554 | |||
| 752fb880be | |||
| 549bcb502b | |||
| 44077cb007 | |||
| 7b5902a580 | |||
| 2861bacd2a | |||
| 776ac3bb2a | |||
| b429d9f509 | |||
| 26397e4692 | |||
| 48d23194af | |||
| bcaea1a617 | |||
| 12b43d206c | |||
| 9cc49f6ff3 | |||
| 87f036e538 | |||
| fdebec6448 | |||
| ba37836e24 | |||
| b60cfd9294 | |||
| bc0665cd9f | |||
| 0dbe5e6593 | |||
| 9b33aaa11a | |||
| 024b78da7c | |||
| 2a64297506 | |||
| 09c76939f1 | |||
| 0b3f3bdf92 | |||
| 3b29eeb6b6 | |||
| 985270bb02 | |||
| 6b91d6692f | |||
| eca09e6c81 | |||
| 874c579f86 | |||
| a0bddab169 | |||
| b679a94930 | |||
| 5bde545ce3 | |||
| e68c750389 | |||
| f16cb3c52d | |||
| f7d5b0db9c | |||
| ba0b664e3f | |||
| 149d037824 | |||
| d0349d9b0d | |||
| c71c8b0047 | |||
| 3be644265b | |||
| cd6874ca60 | |||
| 7083978f9d | |||
| 4d132489c1 | |||
| b5170ed1fd | |||
| cc915dbef2 | |||
| 9a5bf1ee95 | |||
| a14b6af5c0 | |||
| ec372ad01d | |||
| 8a412ef69e | |||
| c978364f49 | |||
| 61d2a99dd4 | |||
| fdba916d83 | |||
| a12209e61d | |||
| fc6607ce9e | |||
| 62ccbc7490 | |||
| b2b36984e1 | |||
| c10208407d | |||
| 64720c2d2e | |||
| da81e4839a | |||
| 25013afdd2 | |||
| 678829ab28 | |||
| d8dffa9d71 | |||
| be8810077a | |||
| ee4ecb9783 | |||
| eaed8572f0 | |||
| e91e6fb068 | |||
| cb17a0a49b | |||
| 248df9ca2d | |||
| fa615ed9f4 | |||
| 65aa4af6d9 | |||
| df56ad476e | |||
| 8e20fa89e8 | |||
| 76058729e0 | |||
| 88a0cc8c9c | |||
| 2ea45c0c58 | |||
| bf27f41f52 | |||
| 853f6012d5 | |||
| 14ad02777f | |||
| c1eb00f6d5 | |||
| e5adaf974d | |||
| 727a29600d | |||
| a5ebdb9243 | |||
| 2ef37ee798 | |||
| c23575786c | |||
| 5a0d693c93 | |||
| c6902528b3 | |||
| f90993be86 | |||
| e7db076648 | |||
| 6d52a7d3d4 | |||
| 3368b492b9 | |||
| 1222aa6d25 | |||
| 67efd150d4 | |||
| 9894f2e053 | |||
| 3a1a51ac46 | |||
| a1b5429f4e | |||
| b11e39554f | |||
| a92c764945 | |||
| f581396f1d | |||
| 6814926f05 | |||
| b8f882dba4 | |||
| 783e8edf71 | |||
| 966f1d654e | |||
| 02adaac468 | |||
| 2b2a0d685f | |||
| 6f2ec17640 | |||
| 6c158f5a1b | |||
| df83dfdfe8 | |||
| 165c252fc8 | |||
| d21f63d327 | |||
| 05c33bee78 | |||
| 762dd17512 | |||
| 5f7065848e | |||
| 65e020a627 | |||
| 793e477898 | |||
| a5232f857e | |||
| 0ef7a72b33 | |||
| 717787ff62 | |||
| 2d599a5190 | |||
| e73145d558 | |||
| 220e7748a9 | |||
| 72f41c5b4f | |||
| 775627473a | |||
| ba2356d2ba | |||
| 179f53b21b | |||
| 3ccd3b5650 | |||
| 224655f8cb | |||
| fd96c7c488 | |||
| 45c96f73c2 | |||
| c5893ef6e8 | |||
| 8b1f09d302 | |||
| cb1b824a75 | |||
| b0ce9e4af7 | |||
| aae3637e0c | |||
| 33faa2f252 | |||
| 482d79ef4b | |||
| 6bdd517c43 | |||
| a337109618 | |||
| 0ae5ace520 | |||
| a4306cddef | |||
| 1f97c5518e | |||
| 1823a4da36 | |||
| d60caf7095 | |||
| 9e10b94339 | |||
| 7048dd754d | |||
| de29e17d95 | |||
| c299989ff7 | |||
| 0b655ea6a1 | |||
| 538827942a | |||
| 8bd5f69e04 | |||
| c470ea9fa1 | |||
| c1806476af | |||
| af41c9f6e4 | |||
| 823e8d24b5 | |||
| 4028c0b24f | |||
| 2e4ff30103 | |||
| 121dcca7e3 | |||
| 5adfe2d46b | |||
| 03f4aaa2d6 | |||
| d67c3f36ff | |||
| e199d30beb | |||
| 27e2de2b1f | |||
| 8a6d07342e | |||
| ab39457fe1 | |||
| e6933ea413 | |||
| 422e0c44d5 | |||
| ad03b409ab | |||
| 38ae213260 | |||
| 6a0a59896e | |||
| 187cb56364 | |||
| 1fe96d0d22 | |||
| 52b859b3e6 | |||
| 9483b781e2 | |||
| 791f475168 | |||
| 6b69d6dce2 | |||
| 720abbc81e | |||
| e3183cfd16 | |||
| e07423f260 | |||
| ecfda146b2 | |||
| f923f508f5 | |||
| b465dabe77 | |||
| d8d6b91257 | |||
| 0946fac11f | |||
| c50b69c654 | |||
| 32bf99ba40 | |||
| 0baa8215ef | |||
| 85a007d87b | |||
| 7b14de13ec | |||
| 117ebe1c32 | |||
| 2b010811d8 | |||
| 4b94f1fa83 | |||
| d73f3ebd1b | |||
| 4c48cda4cd | |||
| 9e64ccdbf2 | |||
| aedf9d3a91 | |||
| 0ee94a5729 | |||
| 2130630293 | |||
| 445cf5d42c | |||
| 08f13a1776 | |||
| f406dc51fa | |||
| 7580777e43 | |||
| ea30005762 | |||
| 7794cd6274 | |||
| 45a4fe44f7 | |||
| 1d225078eb | |||
| 533caf8c0f | |||
| e6c25ae290 | |||
| 264077acac | |||
| 0ff18881b6 | |||
| 9e0e536dbc | |||
| 1a9e54ba33 | |||
| 9378af1057 | |||
| cd6075a884 | |||
| 1da3a00b92 | |||
| 275961f088 | |||
| f14fac3f7d | |||
| ce784e0491 | |||
| 65ad3bb941 | |||
| b5b4280c3b | |||
| 0649f6e607 | |||
| 22c2efded9 | |||
| 7825279405 | |||
| 2623c7023c | |||
| 2138fdfadf | |||
| 40517e3010 | |||
| 1341214044 | |||
| 34e2ef13cf | |||
| 058219528d | |||
| f4bd175616 | |||
| fea0c07e1c | |||
| f684fa9a7b | |||
| 2855b94aa8 | |||
| 9958aaae4f | |||
| 289e5ada2c | |||
| 648eed6532 | |||
| d94955d51e | |||
| 046fe93f1f | |||
| ce60af5029 | |||
| dbe70ffc8a | |||
| 8acf081be3 | |||
| c5f6065280 | |||
| 07509ba5c9 | |||
| 8b3c8f7093 | |||
| c3e0b68399 | |||
| f0dd1fdfc7 | |||
| 5fd8c0938a | |||
| b3f4aa4504 | |||
| 4718cf6cc0 | |||
| ac07c78664 | |||
| 4a3db7e2c3 | |||
| a23158f986 | |||
| 838322299a | |||
| 41f3f53540 | |||
| a26d982f52 | |||
| 5e4121ac58 | |||
| 81d8c8f9bf | |||
| 0c34addfa7 | |||
| 6a68fe6a4f | |||
| 0d246a4422 | |||
| 991c9f2f8b | |||
| ffd36b5489 | |||
| b9149658a8 | |||
| 21ff3fbccd | |||
| 90efbefbec | |||
| 8f89d75edc | |||
| 5d082f53ae | |||
| 591d79ba49 | |||
| 5ee6ede824 | |||
| 095a58b1bd | |||
| fd2f000075 | |||
| bb244646df | |||
| 238dd07cf6 | |||
| aea5e446e5 | |||
| 203beff4d2 | |||
| cb6f4ad646 | |||
| f7b72dd136 | |||
| 96aff57275 | |||
| 4b46d07380 | |||
| 204f7c918e | |||
| b1c83e6588 | |||
| c55bd11377 | |||
| 885a9df356 | |||
| 0a373018c6 | |||
| 8c4c1a56fd | |||
| de790c7c19 | |||
| 3c2bf76103 | |||
| 13bc41fc36 | |||
| 758027e2e0 | |||
| 25b352aeab | |||
| b030fe7db2 | |||
| 9b09c9f0c3 | |||
| de73809bb9 | |||
| 7144f69683 | |||
| c3396fa6fd | |||
| 924a41a2f4 | |||
| a492bf3885 | |||
| 662714fca3 | |||
| 4fc4e93ab5 | |||
| d0b5929a9e | |||
| 58dc98460b | |||
| e0dd4848b0 | |||
| cef01f5dbc | |||
| 88af9c545b | |||
| cd1f45e248 | |||
| d5eee3138f | |||
| fdfe0ce63d | |||
| ba6641ed9a | |||
| fb13e3ddb8 | |||
| ca17efd764 | |||
| dd104a49f6 | |||
| b849d008d2 | |||
| 1e09935501 | |||
| d7e558350b | |||
| 04afe8fbf1 | |||
| 392726bad3 | |||
| 19285d61ab | |||
| 015b29e8a3 | |||
| aff61dbc3e | |||
| 37f5d755f1 | |||
| 98cd3465d3 | |||
| 009f08dca3 | |||
| 2edf4906a4 | |||
| ee6c15b997 | |||
| 03df07e4b6 | |||
| 501f2f8267 | |||
| e949677c48 | |||
| b2512915ae | |||
| dc9db06cc8 | |||
| cb5931aaeb | |||
| da17e55657 | |||
| f47d944349 | |||
| 682079adc6 | |||
| f0fb97e67c | |||
| 6e5058f95f | |||
| 31b8997518 | |||
| 76a9723268 | |||
| 5fe79764de | |||
| 186859fcf0 | |||
| b545d60453 | |||
| f68a046080 | |||
| f77fa5b34c | |||
| 38bf0c276c | |||
| ef5c8c24a8 | |||
| 4e8fb92e07 | |||
| 4f1ff5b24c | |||
| 22abc27b6b | |||
| 19f6d885fe | |||
| b19a633441 | |||
| 997dcad799 | |||
| e35efd001c | |||
| 50d6b10be4 | |||
| 5ef7ea794a | |||
| e70485f1fd | |||
| f55f8a3629 | |||
| fbbd6caf97 | |||
| bde3f95ae9 | |||
| a5c406a4dd | |||
| 58a57543ce | |||
| e32bc5e186 | |||
| 7a5f45ac94 | |||
| 657f7577bf | |||
| 48355447f9 | |||
| c8f7e6331b | |||
| 40bb27c95f | |||
| 78f8124c63 | |||
| 94d5bcbf1c | |||
| ad5d8c6f9a | |||
| 4911601b24 | |||
| cb86d3d829 | |||
| 24c6314f1a | |||
| 02e2b3bd47 | |||
| ec84b3a0ca | |||
| 4455e816aa | |||
| 3df89c0dfe | |||
| f5d22c904f | |||
| 2233c44d36 | |||
| d5f6c1c15c | |||
| e36a27307b | |||
| cf527ed819 | |||
| a8e8833a8d | |||
| 349df0dc94 | |||
| 0e33f638e6 | |||
| 50ccfbf554 | |||
| e2c093856c | |||
| 992458ae4b | |||
| 8c16686150 | |||
| 7cbadfbd12 | |||
| 0e43697ee0 | |||
| 7de27df309 | |||
| b06db1ba39 | |||
| 5fe24cb689 | |||
| 733d1384a4 | |||
| 99e9d0d023 | |||
| 2bd1e46ab9 | |||
| cabaad4b17 | |||
| 8b6fe691ed | |||
| ccf9efdaa5 | |||
| bf66bec4c7 | |||
| 3319709526 | |||
| 7ceab5c88c | |||
| 94d4789e68 | |||
| b13985d550 | |||
| dc4a3e9b89 | |||
| d538c35532 | |||
| cfd26321b5 | |||
| 61d955f3de | |||
| a9f54c44e9 | |||
| 125877035f | |||
| 8f4b0c8078 | |||
| 1863e85bf5 | |||
| 488c6099fc | |||
| 67abc6d2cf | |||
| c56a57c0ba | |||
| 30b2c1ad61 | |||
| 5e279363e4 | |||
| abb7509f03 | |||
| 1cd60c05f3 | |||
| 510cc22484 | |||
| 3da664236c | |||
| 7e35a7fe0c | |||
| 58ef7db5d6 | |||
| f9de4a394c | |||
| dced5816df | |||
| 690ac740d2 | |||
| 89d0412e22 | |||
| a305752faf | |||
| 469b139e89 | |||
| 8f5d9c4816 | |||
| 7102c77e0b | |||
| 115ae21f1f | |||
| 8d3fdf45b9 | |||
| 1e7e5ea57c | |||
| 7c8b91456f | |||
| dc960f30f5 | |||
| ba12e31280 | |||
| 027a4081a2 | |||
| 190def17e5 | |||
| 9730526d33 | |||
| c87c843308 | |||
| 6453cdf0d6 | |||
| 5f80c33b24 | |||
| a33542c9b5 | |||
| 3a1d98648f | |||
| 4ec79d61d0 | |||
| b4f055f80c | |||
| 6bf35c679f | |||
| 3349d43c00 | |||
| ced961d24c | |||
| 419f708d87 | |||
| bbc1c04042 | |||
| 7a6865637d | |||
| ae96420925 | |||
| 2822812d0d | |||
| c8ab430491 | |||
| bb87f28e80 | |||
| 6db671215a | |||
| 64566ec6cf | |||
| faaf97ef62 | |||
| 67d6efed21 | |||
| 571d9bd610 | |||
| 4144698540 | |||
| 9bf6bf2c78 | |||
| cc9236b8db | |||
| 0103b59e61 | |||
| e9f6531db7 | |||
| 62c2c750ea | |||
| 3e5e3175e0 | |||
| 54c5af30d9 | |||
| ca4a3361c0 | |||
| 47d302221d | |||
| ed215657e6 | |||
| 3e63b14192 | |||
| 86433ab3a8 | |||
| 7214800d93 | |||
| 29f298fa4a | |||
| ef35bc77cb | |||
| 6ae880f61e | |||
| 0d1149310c | |||
| 51d32bb8d3 | |||
| 49a8980dea | |||
| 9fe1680c56 | |||
| b7db65a023 | |||
| 4c02002265 | |||
| d0198649f2 | |||
| 32c1fd082d | |||
| 363bf42b95 | |||
| a1ab2232f3 | |||
| cf69f43166 | |||
| 9833438733 | |||
| 67c5e3966a | |||
| aa0927911d | |||
| 13c9e1ed58 | |||
| 19a457ab7d | |||
| 0926bff0cc | |||
| 53a0bc963a | |||
| a2819d822a | |||
| 175112d97d | |||
| dced47024f | |||
| ffc361406e | |||
| 852c648235 | |||
| 1197b96c49 | |||
| f21fe81e16 | |||
| 593dfd0108 | |||
| aaf0fb9d12 | |||
| 02e9f8aef3 | |||
| 424055c04e | |||
| 02daf17326 | |||
| a666f0d52e | |||
| 27a760c58c | |||
| 0ba12f48c6 | |||
| eaaf54d886 | |||
| 4b3d634fe9 | |||
| f77a699ea4 | |||
| e989e38cc2 | |||
| 6a900ed6e7 | |||
| 29e6b85f79 | |||
| 2641408d53 | |||
| 5b79226183 | |||
| 98f9f0cd48 | |||
| cf7e107ad1 | |||
| ab66c1aa1b | |||
| 5b03366909 | |||
| 7824e1446a | |||
| 59cf1a4937 | |||
| 252113c838 | |||
| e2f84d1acd | |||
| 204dcecb28 | |||
| 70bbfbea12 | |||
| 2221a0a908 | |||
| 203b215093 | |||
| 76ee84dae8 | |||
| 79e1c87a01 | |||
| ed208114be | |||
| 7dd711b37c | |||
| 4852802d66 | |||
| c495b1faab | |||
| eb5bd8e6ac | |||
| ff7dcf9c17 | |||
| 2b12a16c84 | |||
| 4d00b2ebbb | |||
| 1ba5abbaef | |||
| b87a98bbda | |||
| f76361a345 | |||
| f25bab9555 | |||
| ed78b8429f | |||
| 94e9dd8f28 | |||
| 90215ca0dd | |||
| 34eb647fcb | |||
| 83205290de | |||
| 02fd528c32 | |||
| e05193f46d | |||
| 14e2d900b5 | |||
| ba4290340d | |||
| 5a04700bae | |||
| 999f50dce9 | |||
| 9522e6e714 | |||
| 7836ea4479 | |||
| 37e8ab8de1 | |||
| 34048497e7 | |||
| 5197422482 | |||
| d9987c2734 | |||
| c9671b4712 | |||
| bbf03e3060 | |||
| e35a78e3cf | |||
| e318be6a88 | |||
| 1dab0ebc25 | |||
| 687e58e9d4 | |||
| 993a4aa675 | |||
| c991510b0f | |||
| c8025bf004 | |||
| 9f5767a80c | |||
| ffb05d6271 | |||
| 2dd2d3dd7b | |||
| be29c7fca0 | |||
| 2c23a3c0b3 | |||
| 37e3ead8e9 | |||
| b018ea7b1b | |||
| d6cdca35d4 | |||
| a09d150b47 | |||
| 7cf46afc48 | |||
| 056c95670f | |||
| 35dffe43d9 | |||
| 19c26f0733 | |||
| 388ff10ff5 | |||
| 8c7be8e45f | |||
| 579aa67cde | |||
| 725f86a0d2 | |||
| 50a6ef18d2 | |||
| 1b3e924450 | |||
| a33e08e299 | |||
| 45dee5a666 | |||
| 642473244e | |||
| e92f344335 | |||
| 7951795ea4 | |||
| 101fbcca90 | |||
| d562132a4a | |||
| 7152ab39ff | |||
| 39c5279f5d | |||
| fef0e16f9c | |||
| fb1361b00d | |||
| 64c75c8b57 | |||
| f4e015a255 | |||
| 242b68c488 | |||
| 9452c7e0c7 | |||
| ab1d3d1ced | |||
| 41df92bb93 | |||
| 427db3f29a | |||
| b5600bdd7f | |||
| a2153b668a | |||
| 7d52c82c3b | |||
| 092f1a4959 | |||
| 21bee7e40c | |||
| a9ac0ac725 | |||
| 5dc1ed6696 | |||
| b55f66e69c | |||
| ab637e22b1 | |||
| fa665c5494 | |||
| e91b75a1bb | |||
| 4c6f85fd25 | |||
| f09e9b7790 | |||
| b51d3da7e5 | |||
| 861dbd5977 | |||
| 5001fcdd53 | |||
| eeb47dc724 | |||
| 5556dff11e | |||
| 18b57fa6aa | |||
| 12bb4d75fd | |||
| 411d8d4d98 | |||
| 748df0b21a | |||
| 8d98316a89 | |||
| c6b45a8e09 | |||
| d42920674a | |||
| c66fced161 | |||
| d3dee115ab | |||
| 77aa965533 | |||
| 29499f21c5 | |||
| 18d8968ae7 | |||
| 467cf73635 | |||
| 457519eae3 | |||
| 2a1c24763d | |||
| 92196dc207 | |||
| f73723f9af | |||
| 26ab8755b6 | |||
| d91382208d | |||
| 5f90ed8b3e | |||
| 644fad8355 | |||
| c4904cc365 | |||
| 613e38d7f8 | |||
| dee7c339b3 | |||
| b80cda66a9 | |||
| 411bcbcbde | |||
| 352bf8839b | |||
| 18f438a528 | |||
| 076944da5d | |||
| acbba95032 | |||
| 75f77783ff | |||
| 87e0f074e8 | |||
| 2211c69455 | |||
| a7449c913c | |||
| aaec0e641b | |||
| 5afed2d396 | |||
| 843348338a | |||
| 061ebc7942 | |||
| 822c1c97e3 | |||
| 65df6aa4a0 | |||
| 32719690ac | |||
| f83748fdc2 | |||
| a354d7c00b | |||
| 41f7312263 | |||
| d3804d2c2c | |||
| 96184b83a3 | |||
| 9bcc057176 | |||
| 20f3213477 | |||
| bf8505a285 | |||
| 770a07cc28 | |||
| 3f80f52ca5 | |||
| 52f6e149ec | |||
| 6893df9103 | |||
| 60546c9788 | |||
| 12f91564fb | |||
| ca448e682a | |||
| 2b077d140f | |||
| 0f58ff8356 | |||
| 940b740b24 | |||
| 0f258f94a8 | |||
| fd7b22f639 | |||
| ca3464512d | |||
| f59cb6417f | |||
| 74ccb53607 | |||
| e4c6e98099 | |||
| cfab0fa245 | |||
| 08d861e87c | |||
| 73234e7782 | |||
| de8d28ea5f | |||
| ed7b478ee0 | |||
| ff9a216990 | |||
| 58c94159b1 | |||
| 7a1bd4d53a | |||
| 5d7c23c62a | |||
| d91d911051 | |||
| cd0cab465d | |||
| a45b887c5b | |||
| f965b7129b | |||
| e894ce00c9 | |||
| 333aba8be6 | |||
| e9d93ae210 | |||
| 043c8be747 | |||
| 1be67518df | |||
| 4bf1987bb7 | |||
| ae45eed2b1 | |||
| 572a9393aa | |||
| 7579c41a35 | |||
| 4e589c2575 | |||
| 026da34ce9 | |||
| 0daf49a1da | |||
| f57e4c6c14 | |||
| 14bd1d01f2 | |||
| 918e20b164 | |||
| 6a0e90ef90 | |||
| 71fe8ed80d | |||
| 581c9c570b | |||
| b25fe3d127 | |||
| fc4aef6d89 | |||
| 6b4fa6a40d | |||
| 6756eea209 | |||
| bf3cd37b49 | |||
| cc7caa9e16 | |||
| 633060562f | |||
| cc48546f62 | |||
| 96cc44e521 | |||
| f2d9e4b2df | |||
| 049c7ad1f0 | |||
| 226dad651b | |||
| 0977cabc79 | |||
| 0b5e8a086e | |||
| e024ea5ee1 | |||
| 6f71092aa4 | |||
| edce44df97 | |||
| 54551d9f37 | |||
| 8521b5501f | |||
| 396dc21903 | |||
| 5e2b0ba46c | |||
| cce5d775de | |||
| 248a239c7b | |||
| 83655e9aef | |||
| 973d115edf | |||
| aaa9f89550 | |||
| 8afad5614a | |||
| a9fdabf926 | |||
| b5b262c722 | |||
| d1e1190cbd | |||
| 9812eaaca7 | |||
| 4520e04d37 | |||
| 5679b5862f | |||
| e72dc38d77 | |||
| 71fcfa4935 | |||
| c4463036c3 | |||
| b343a17b29 | |||
| 0b0fb249bf | |||
| 8d689974a7 | |||
| 375c81d38d | |||
| 0ef4f36d44 | |||
| c85f6c1228 | |||
| 0cabc81693 | |||
| 12b4fff81e | |||
| 27b6627110 | |||
| 387014dd37 | |||
| d5c91b9bda | |||
| 370f4f6257 | |||
| 49a665488e | |||
| 29da133726 | |||
| 1194bb8ae3 | |||
| 7599124aa0 | |||
| 01d2d91ecc | |||
| 6980d19214 | |||
| ac14a7b0da | |||
| 23f00ab533 | |||
| 39122bd61d | |||
| c5824765f9 | |||
| 547e942c66 | |||
| 2ab04e7e2f | |||
| a08fef172e | |||
| a04f77e7e0 | |||
| 4900f3e54d | |||
| 34ee6411d5 | |||
| 5abe7bc7e5 | |||
| a48aef4039 | |||
| e1198f29ce | |||
| 329e619c8c | |||
| 9a9e1b46ef | |||
| cc94ab6411 | |||
| e67541e82f | |||
| d907be264b | |||
| 003c1df53e | |||
| 6470838065 | |||
| a178555838 | |||
| f844e9e702 | |||
| 8753dbdb0f | |||
| 1bd24f7042 | |||
| 66d58bf047 | |||
| 1e5c4b0d79 | |||
| 711d402f17 | |||
| e19f54a378 | |||
| 5294fc4767 | |||
| 7ed3a1df04 | |||
| 2d45354f50 | |||
| 9f6d13f4c3 | |||
| 57a31d0ec9 | |||
| da277d9816 | |||
| 22dabc5180 | |||
| 47f11fc3a6 | |||
| 91a2e56215 | |||
| e6681af9d0 | |||
| d9e3c43c91 | |||
| f84de4ac21 | |||
| 3089231476 | |||
| 0f94fb9d6d | |||
| 01097f7225 | |||
| a25e4e1ed8 | |||
| 9e75595754 | |||
| f6d5945b59 | |||
| 250eb20851 | |||
| d2b00c4995 | |||
| 89c73d89b4 | |||
| fcd63bf9eb | |||
| 9a0cf6a609 | |||
| 6c32d97b23 | |||
| c9e40d3e59 | |||
| dc920a7e39 | |||
| 07262387e0 | |||
| 97e2ac689e | |||
| 286a80d03b | |||
| 3aaf31fdb9 | |||
| 71ae5764cc | |||
| 2e41ed153b | |||
| 9ee422e6ba | |||
| 8a008d1808 | |||
| d78faea737 | |||
| 3cf72e93e6 | |||
| caa02bbca1 | |||
| 33e64aee6f | |||
| d17150270e | |||
| 463a297f0c | |||
| 407d73a735 | |||
| b5bfdb56dc | |||
| 58b7ef8431 | |||
| 2211dfb741 | |||
| 1d6e602473 | |||
| a6c52fd154 | |||
| 7a5bceae4c | |||
| 6f3e7f9e56 | |||
| fb9822b507 | |||
| d0db09cb92 | |||
| 189fbb3f7e | |||
| 887c95fe2a | |||
| fdbeb951eb | |||
| 9d23dee3fc | |||
| 70b8cef318 | |||
| e1620b8fa2 | |||
| dabc9589e9 | |||
| da98900e3a | |||
| b584ba9149 | |||
| d24ba6d13d | |||
| aba078a9d8 | |||
| 161487d6c2 | |||
| d851dd7196 | |||
| cf29621aa7 | |||
| 9e46577f43 | |||
| b7980b83df | |||
| 0a0bed7ae0 | |||
| e42b8fc37d | |||
| b01e30acfd | |||
| 311c50df9f | |||
| c2f9467f61 | |||
| 06c8656b9e | |||
| 4748bca8a4 | |||
| 916387748c | |||
| 216d7dcb86 | |||
| 23f2c7e6f5 | |||
| c8e0e5eca2 | |||
| 3167d3f451 | |||
| beb9c1ba74 | |||
| dcd88260e9 | |||
| 5f4f631fc5 | |||
| dc6fda03a1 | |||
| 764ad81537 | |||
| e26c41095f | |||
| d7bd78d612 | |||
| c50b4c72d7 | |||
| 124e555ed0 | |||
| aeba3aa209 | |||
| e50b5202b8 | |||
| 32c7578629 | |||
| 5bc5e0e8e9 | |||
| 7ee4692e84 | |||
| 679688705d | |||
| 83f0a2c094 | |||
| 504817058b | |||
| 45754b27de | |||
| a75ae8bbef | |||
| c3e6dc69bb | |||
| 0285bb6ea5 | |||
| a542292ce2 | |||
| 0765ebf735 | |||
| e86e8c37a8 | |||
| 149a42cc94 | |||
| 8de4613a3e | |||
| 60950c57e3 | |||
| 4727bb5c9b | |||
| 1e1e254897 | |||
| df5455121c | |||
| 0e2570b204 | |||
| f57519b909 | |||
| 088393ca12 | |||
| 375dc63db3 | |||
| 503324162f | |||
| 5445b64376 | |||
| 7fe997d38c | |||
| d7673dad7b | |||
| 44eed9282b | |||
| 0eeb94b24c | |||
| ef221e1c6c | |||
| 75cdefa4fe | |||
| a609a1c6c2 | |||
| f4906a97b9 | |||
| 21ffd441fa | |||
| a82383d78e | |||
| b405029f0f | |||
| db7d4f56b3 | |||
| 3151197471 | |||
| e06fe6935a | |||
| e7cec83a4c | |||
| e5f0ad4f0b | |||
| cabbe70e47 | |||
| b86c3681bb | |||
| 0f8239bc8e | |||
| 13f5baf608 | |||
| 4f5d7f79bd | |||
| 23899613c3 | |||
| db46a915cc | |||
| b591aa013d | |||
| c0db8b71dd | |||
| 444bf41fa4 | |||
| 54302a53e1 | |||
| 63059cfab3 | |||
| ec7d3a9885 | |||
| 960b55fd6c | |||
| 3067ba60ae | |||
| c9a756eddc | |||
| d4ea5fc74f | |||
| 92e52f1a5d | |||
| ef1d75db83 | |||
| f03d1a5d27 | |||
| 8a55b706ca | |||
| 357133677a | |||
| 1b6c660a8f | |||
| 111e68831e | |||
| d9f6732ce2 | |||
| f2b81ba86c | |||
| 2542112301 | |||
| a45215ddf2 | |||
| cb28b2de07 | |||
| bf0b43aa24 | |||
| 811d6deb41 | |||
| bcdd9374c7 | |||
| f70174d1d1 | |||
| 4a39a4af1c | |||
| 0367399c89 | |||
| c5db4dc15f | |||
| 31fbfa3a70 | |||
| 3515ddcfe6 | |||
| 90303d5952 | |||
| 9a02421091 | |||
| 4961b819f3 | |||
| 61c2ea9225 | |||
| f5f7269f70 | |||
| 03f1430ddc | |||
| c3dab15eb6 | |||
| a4f6ec516b | |||
| 1ca213cec6 | |||
| b782c8560c | |||
| d2e68068bf | |||
| 129a846393 | |||
| 15308931e9 | |||
| 4dffeedd1c | |||
| d0c4111429 | |||
| f579b6f971 | |||
| f5124de327 | |||
| 9ab86ae2bf | |||
| 51a7d3ff50 | |||
| 80b9afc14d | |||
| 92ae8f37ba | |||
| df1f828488 | |||
| d8c97da087 | |||
| 9d29e5d87a | |||
| bf62147802 | |||
| 34735b8aad | |||
| 932b2b9acf | |||
| 7ab4472865 | |||
| e1e79206f9 | |||
| 7ebe6de022 | |||
| b234760e92 | |||
| 3119e4b82b | |||
| 2c3f05e6f1 | |||
| 5b5da8698e | |||
| c3c0c8d881 | |||
| 9de5e31a7a | |||
| dbf15c2db2 | |||
| c9c900b364 | |||
| 5c07204351 | |||
| 828b370ea1 | |||
| de947d8b17 | |||
| 8cb5e68b1a | |||
| 99aef2a178 | |||
| fff1460dfb | |||
| e3b619fd54 | |||
| 29e363e7fb | |||
| c209245b0e | |||
| 4194ce3095 | |||
| a0e9f59e04 | |||
| c940c2722e | |||
| 5c84c12f40 | |||
| 1bcacfab74 | |||
| 1f5f8a76fb | |||
| cfa8b1f0dd | |||
| aecbcdd390 | |||
| 74729a372b | |||
| 63d8abe32f | |||
| 2c397bfa0b | |||
| bfef8f39b7 | |||
| 4430cbc3cb | |||
| ae20bac3c5 | |||
| d9a26c4062 | |||
| 48cb374d94 | |||
| 9d6bd91279 | |||
| 163cfda282 | |||
| 72cda375c8 | |||
| ecb4a08655 | |||
| 05c50bc64f | |||
| 747e4a7061 | |||
| 2b8b876713 | |||
| f13694b539 | |||
| 648f9c9723 | |||
| 0a6c37b726 | |||
| b43a51f912 | |||
| fa328c5a78 | |||
| 728bcc2b10 | |||
| 941903a243 | |||
| 4c8579b340 | |||
| 17416a09f1 | |||
| fdda21b114 | |||
| c75ae957f1 | |||
| 8c678126f1 | |||
| 2b0590f9bd | |||
| a31992aac7 | |||
| 829d2505e3 | |||
| df30498365 | |||
| 5d553bf9f2 | |||
| 03e3673dbb | |||
| 25b8b37f00 | |||
| 665f97e782 | |||
| 48a007febd | |||
| 155e0fada6 | |||
| fe2f1d32b5 | |||
| 2fcbb19e72 | |||
| 06a50d637a | |||
| 811b33e31a | |||
| 54c83ee940 | |||
| 7406e83dde | |||
| dc2c7d5339 | |||
| aaa25e5d48 | |||
| b757bd0ea2 | |||
| dd971d6b7d | |||
| c07966408b | |||
| 2557956b68 | |||
| 735260d21b | |||
| e5b0e43e18 | |||
| aa42b2494c | |||
| f057054172 | |||
| c39314c643 | |||
| ae018b759c | |||
| 556b498e06 | |||
| 19f1110421 | |||
| cc73ed19b3 | |||
| ccb7cc40df | |||
| 6d61e950d6 | |||
| 438c6e616c | |||
| 8d2396b81f | |||
| 9588ef00a5 | |||
| 411603ea03 | |||
| 67addfdb37 | |||
| 3afcd31f61 | |||
| 7ac901cb08 | |||
| fcdee8f5d5 | |||
| a7c32dfa95 | |||
| 36f3c0f77a | |||
| dad4981a57 | |||
| df53357ef1 | |||
| 85e333127a | |||
| d52d86ae82 | |||
| f62293275f | |||
| af490bae8e | |||
| edf5a0f677 | |||
| 5eecd0a57d | |||
| 1fc11a6b06 | |||
| 3516538813 | |||
| e3af8cb2e8 | |||
| 16cd822555 | |||
| 5938368a09 | |||
| 50f865b81c | |||
| 96cd09471b | |||
| cf6c1e97bb | |||
| f557e1efb4 | |||
| 8893fd1656 | |||
| 081831e6ea | |||
| 46c3ce0e34 | |||
| 6031a45c68 | |||
| ca64887cba | |||
| 3f1d67ca4c | |||
| ff09af2812 | |||
| 42b68fa834 | |||
| 2cc2c967d1 | |||
| bec4e4437d | |||
| f9abfbf68a | |||
| 53af4ee39f | |||
| af5f2f85da | |||
| ea83231da5 | |||
| c4693602ef | |||
| 3c8dd85966 | |||
| 0399022d25 | |||
| c6840496c0 | |||
| f7657280b6 | |||
| f88a4baf79 | |||
| b051f715e6 | |||
| 81a05c89e4 | |||
| cc55b016e9 | |||
| ae8e51074e | |||
| 313b93169d | |||
| db148741e9 | |||
| 1ecad20a0d | |||
| 22c5c539c2 | |||
| d59e526e1e | |||
| 94fa0047db | |||
| 26e2f9ddd1 | |||
| 23254b4f24 | |||
| 9a44f16846 | |||
| cad0069be2 | |||
| f315a013b8 | |||
| f780aa6160 | |||
| 0f03beb2b5 | |||
| 7e39c43896 | |||
| 906d28fa5d | |||
| 4d017f5d49 | |||
| 6410314b0b | |||
| 1c0202e790 | |||
| 918c978551 | |||
| 3d1a85bbea | |||
| 1a442c36e9 | |||
| a4e322f085 | |||
| 0b1d268b09 | |||
| c2be6bc019 | |||
| 9e11e832da | |||
| 348e656671 | |||
| 54cdf6d6f2 | |||
| 7c5ca8f199 | |||
| ee42d94e2d | |||
| 91baa9dfd7 | |||
| 572b176401 | |||
| 97f1dc0749 | |||
| d67ac1a708 | |||
| 2707001a3a | |||
| bb1064ac42 | |||
| 436cc692da | |||
| 76decf2e8b | |||
| ccdd0f599a | |||
| c65fed1d38 | |||
| c36ec7c95b | |||
| 305ce04284 | |||
| 034ce137a9 | |||
| 73c81a0a6c | |||
| 7544727f7a | |||
| 961a379f79 | |||
| 9ffcaa5550 | |||
| 2dbae6ce51 | |||
| f7505e8877 | |||
| c453f8e7a9 | |||
| 3a4695713d | |||
| 7d9d0878de | |||
| 26729ca482 | |||
| 405600783e | |||
| 5b5e9296b3 | |||
| dd5d520b53 | |||
| b3d517943a | |||
| 59ca59d431 | |||
| 78c92be14b | |||
| adf0c726ef | |||
| 9ecfed4e56 | |||
| 9db884f371 | |||
| e0c211085c | |||
| 555bfaf37a | |||
| bcf4af4a2f | |||
| 6a71163912 | |||
| cb2fcf4f52 | |||
| 061d78c681 | |||
| 0ffa973ec6 | |||
| 03de87c213 | |||
| 59481dd762 | |||
| 86f4aebead | |||
| a92950d234 | |||
| ccdc6f1a63 | |||
| 62cc8f456c | |||
| f7c6b9a0f7 | |||
| 01a6e3c619 | |||
| 6948d56e5d | |||
| 6373b3e49c | |||
| 91dc1b6639 | |||
| 6317b08090 | |||
| aae0547cca | |||
| 4f9c422e2f | |||
| 3595ac08f7 | |||
| 5339f440bd | |||
| 86d7442a5f | |||
| e6e5626a2c | |||
| 4a52dd1c5b | |||
| dd1302e8b1 | |||
| 7b4b7232fc | |||
| b069725df0 | |||
| aa9d8c773f | |||
| c68a03d05c | |||
| cbea651cf8 | |||
| b4ee345966 | |||
| 296e7ccb08 | |||
| 43bb53e789 | |||
| 384be58230 | |||
| 46d1a87b89 | |||
| 7c8bf18cc6 | |||
| 35255d052d | |||
| cf5c776990 | |||
| 9961172d70 | |||
| c1c46544a6 | |||
| fc24dbf9b7 | |||
| 7f311551dd | |||
| 1a6c01769e | |||
| 9da4e18099 | |||
| b19e2fbafe | |||
| 7f69857376 | |||
| a64420d700 | |||
| 2ccd3da5b3 | |||
| 845c73af73 | |||
| f7d79209dc | |||
| 0017aef89a | |||
| 7449f81ed4 | |||
| 724e96f0c1 | |||
| 8158e7f1c5 | |||
| 7d7baa70a9 | |||
| 2e3947cc6d | |||
| 54774726b2 | |||
| 2af9fcad68 | |||
| fd79e81fe5 | |||
| 2b5e110719 | |||
| 864c2d9f49 | |||
| 764fe533e8 | |||
| f1f59d770e | |||
| 950baaa9fc | |||
| 5b3aacb4b2 | |||
| d6adc56b3a | |||
| dbe1a4255c | |||
| eed20b2271 | |||
| e70adbb1cb | |||
| 06c22a478f | |||
| 565b0e97d1 | |||
| 00168cb12f | |||
| ffdaa71086 | |||
| 5de2aa1cbf | |||
| 64988ed831 | |||
| fa050ad616 | |||
| d2458f3169 | |||
| 551af0e45a | |||
| 4ac5440a4a | |||
| 7c54d4e62f | |||
| 8ab5915983 | |||
| 877865a4b1 | |||
| 7cf4d37595 | |||
| 80add9f820 | |||
| 12a35c1214 | |||
| 9379d2462e | |||
| c5e8bed1fb | |||
| 4aa7ade32c | |||
| c4ed218a7a | |||
| ff417fac01 | |||
| 0f4207f85e | |||
| f4431ed837 | |||
| 0235cf5d8e | |||
| 8fc8a4e303 | |||
| 943c15927a | |||
| 28f0782b17 | |||
| 09e331a76b | |||
| ce43b09991 |
@@ -0,0 +1,54 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -2
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
AlignEscapedNewlinesLeft: false
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: true
|
||||
AlwaysBreakTemplateDeclarations: false
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
BreakBeforeBinaryOperators: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BinPackParameters: false
|
||||
ColumnLimit: 100
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
DerivePointerBinding: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
IndentCaseLabels: false
|
||||
MaxEmptyLinesToKeep: 1
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
NamespaceIndentation: None
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyExcessCharacter: 1000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerBindsToType: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
Cpp11BracedListStyle: true
|
||||
Standard: Cpp11
|
||||
IndentWidth: 4
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
BreakBeforeBraces: Allman
|
||||
IndentFunctionDeclarationAfterType: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInAngles: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
ContinuationIndentWidth: 4
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
||||
SpaceBeforeParens: ControlStatements
|
||||
...
|
||||
|
||||
+29
-17
@@ -33,11 +33,12 @@ ehthumbs.db
|
||||
Icon?
|
||||
Thumbs.db
|
||||
|
||||
# SCons related files #
|
||||
# build related files #
|
||||
#######################
|
||||
SconsBuilder*
|
||||
.scon*
|
||||
.build
|
||||
/build/
|
||||
/Util/finger_print.cpp
|
||||
/Util/GitDescription.cpp
|
||||
/cmake/postinst
|
||||
|
||||
# Eclipse related files #
|
||||
#########################
|
||||
@@ -54,30 +55,41 @@ stxxl.errlog
|
||||
|
||||
# compiled protobuffers #
|
||||
#########################
|
||||
DataStructures/pbf-proto/*.pb.h
|
||||
DataStructures/pbf-proto/*.pb.cc
|
||||
/DataStructures/pbf-proto/*.pb.h
|
||||
/DataStructures/pbf-proto/*.pb.cc
|
||||
|
||||
# External Libs #
|
||||
#################
|
||||
lib/
|
||||
win/lib
|
||||
/lib/
|
||||
/win/lib
|
||||
|
||||
# Visual Studio Temp + build Files #
|
||||
####################################
|
||||
win/*.user
|
||||
win/*.ncb
|
||||
win/*.suo
|
||||
win/Debug/
|
||||
win/Release/
|
||||
win/bin/
|
||||
win/bin-debug/
|
||||
/win/*.user
|
||||
/win/*.ncb
|
||||
/win/*.suo
|
||||
/win/Debug/
|
||||
/win/Release/
|
||||
/win/bin/
|
||||
/win/bin-debug/
|
||||
/osrm-extract
|
||||
/osrm-io-benchmark
|
||||
/osrm-components
|
||||
/osrm-routed
|
||||
/osrm-datastore
|
||||
/osrm-prepare
|
||||
/osrm-unlock-all
|
||||
/osrm-cli
|
||||
/osrm-check-hsgr
|
||||
/osrm-springclean
|
||||
/nohup.out
|
||||
|
||||
# Sandbox folder #
|
||||
###################
|
||||
sandbox/
|
||||
/sandbox/
|
||||
|
||||
test/profile.lua
|
||||
/test/profile.lua
|
||||
|
||||
# Deprecated config file #
|
||||
##########################
|
||||
/server.ini
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
# - clang
|
||||
# Make sure CMake is installed
|
||||
install:
|
||||
- sudo apt-add-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- sudo add-apt-repository -y ppa:boost-latest/ppa
|
||||
- sudo apt-get update >/dev/null
|
||||
- sudo apt-get -q install protobuf-compiler libprotoc-dev libprotobuf7 libprotobuf-dev libbz2-dev libstxxl-dev libstxxl1 libxml2-dev libzip-dev lua5.1 liblua5.1-0-dev rubygems libtbb-dev
|
||||
- sudo apt-get -q install g++-4.8
|
||||
- sudo apt-get install libboost1.54-all-dev
|
||||
# luabind
|
||||
- curl https://gist.githubusercontent.com/DennisOSRM/f2eb7b948e6fe1ae319e/raw/install-luabind.sh | sudo bash
|
||||
# osmosis
|
||||
- curl -s https://gist.githubusercontent.com/DennisOSRM/803a64a9178ec375069f/raw/ | sudo bash
|
||||
# cmake
|
||||
- curl -s https://gist.githubusercontent.com/DennisOSRM/5fad9bee5c7f09fd7fc9/raw/ | sudo bash
|
||||
# osmpbf library
|
||||
- curl -s https://gist.githubusercontent.com/DennisOSRM/13b1b4fe38a57ead850e/raw/install_osmpbf.sh | sudo bash
|
||||
before_script:
|
||||
- rvm use 1.9.3
|
||||
- gem install bundler
|
||||
- bundle install
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake .. $CMAKEOPTIONS
|
||||
script:
|
||||
- make -j 2
|
||||
- make -j 2 tests
|
||||
- ./datastructure-tests
|
||||
- cd ..
|
||||
- cucumber -p verify
|
||||
after_script:
|
||||
# - cd ..
|
||||
# - cucumber -p verify
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- develop
|
||||
cache:
|
||||
- bundler
|
||||
- apt
|
||||
env:
|
||||
- CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++-4.8" OSRM_PORT=5000 OSRM_TIMEOUT=60
|
||||
- CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=g++-4.8" OSRM_PORT=5010 OSRM_TIMEOUT=60
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- irc.oftc.net#osrm
|
||||
on_success: change
|
||||
on_failure: always
|
||||
use_notice: true
|
||||
skip_join: false
|
||||
|
||||
recipients:
|
||||
- dennis@mapbox.com
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: always
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
The following people contributed code to the Open Source Routing Machine:
|
||||
|
||||
Christian Vetter
|
||||
Dennis Luxen
|
||||
Ruslan Krenzler
|
||||
Frederik Ramm
|
||||
Bharath Vissapragada
|
||||
Pascal Neis
|
||||
Sasa Ivetic
|
||||
Emil Tin
|
||||
Henning Moll
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef BRESENHAM_H_
|
||||
#define BRESENHAM_H_
|
||||
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
typedef std::pair<unsigned, unsigned> BresenhamPixel;
|
||||
|
||||
inline void Bresenham (int x0, int y0, int x1, int y1, std::vector<BresenhamPixel> &resultList) {
|
||||
int dx = std::abs(x1-x0);
|
||||
int dy = std::abs(y1-y0);
|
||||
int sx = (x0 < x1 ? 1 : -1);
|
||||
int sy = (y0 < y1 ? 1 : -1);
|
||||
int err = dx - dy;
|
||||
while(true) {
|
||||
resultList.push_back(std::make_pair(x0,y0));
|
||||
if(x0 == x1 && y0 == y1) break;
|
||||
int e2 = 2* err;
|
||||
if ( e2 > -dy) {
|
||||
err -= dy;
|
||||
x0 += sx;
|
||||
}
|
||||
if(e2 < dx) {
|
||||
err+= dx;
|
||||
y0 += sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* BRESENHAM_H_ */
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#include "CRC32.h"
|
||||
|
||||
CRC32::CRC32() : crc(0) {
|
||||
crcFunction = detectBestCRC32C();
|
||||
}
|
||||
|
||||
unsigned CRC32::SoftwareBasedCRC32(char *str, unsigned len, unsigned ) {
|
||||
boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> CRC32_Processor;
|
||||
CRC32_Processor.process_bytes( str, len);
|
||||
return CRC32_Processor.checksum();
|
||||
}
|
||||
|
||||
unsigned CRC32::SSEBasedCRC32( char *str, unsigned len, unsigned crc) {
|
||||
unsigned q=len/sizeof(unsigned),
|
||||
r=len%sizeof(unsigned),
|
||||
*p=(unsigned*)str/*, crc*/;
|
||||
|
||||
//crc=0;
|
||||
while (q--) {
|
||||
__asm__ __volatile__(
|
||||
".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
|
||||
:"=S"(crc)
|
||||
:"0"(crc), "c"(*p)
|
||||
);
|
||||
++p;
|
||||
}
|
||||
|
||||
str=(char*)p;
|
||||
while (r--) {
|
||||
__asm__ __volatile__(
|
||||
".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
|
||||
:"=S"(crc)
|
||||
:"0"(crc), "c"(*str)
|
||||
);
|
||||
++str;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
CRC32::CRC32CFunctionPtr CRC32::detectBestCRC32C() {
|
||||
static const int SSE42_BIT = 20;
|
||||
unsigned ecx = cpuid(1);
|
||||
bool hasSSE42 = ecx & (1 << SSE42_BIT);
|
||||
if (hasSSE42) {
|
||||
std::cout << "using hardware base sse computation" << std::endl;
|
||||
return &CRC32::SSEBasedCRC32; //crc32 hardware accelarated;
|
||||
} else {
|
||||
std::cout << "using software base sse computation" << std::endl;
|
||||
return &CRC32::SoftwareBasedCRC32; //crc32cSlicingBy8;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned CRC32::cpuid(unsigned functionInput) {
|
||||
unsigned eax;
|
||||
unsigned ebx;
|
||||
unsigned ecx;
|
||||
unsigned edx;
|
||||
asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (functionInput));
|
||||
return ecx;
|
||||
}
|
||||
|
||||
unsigned CRC32::operator()(char *str, unsigned len){
|
||||
crc =((*this).*(crcFunction))(str, len, crc);
|
||||
return crc;
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef CRC32_H_
|
||||
#define CRC32_H_
|
||||
|
||||
#include <boost/crc.hpp> // for boost::crc_32_type
|
||||
#include <iostream>
|
||||
|
||||
class CRC32 {
|
||||
private:
|
||||
unsigned crc;
|
||||
unsigned slowcrc_table[1<<8];
|
||||
|
||||
typedef boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> my_crc_32_type;
|
||||
typedef unsigned (CRC32::*CRC32CFunctionPtr)(char *str, unsigned len, unsigned crc);
|
||||
|
||||
unsigned SoftwareBasedCRC32(char *str, unsigned len, unsigned crc);
|
||||
unsigned SSEBasedCRC32( char *str, unsigned len, unsigned crc);
|
||||
unsigned cpuid(unsigned functionInput);
|
||||
CRC32CFunctionPtr detectBestCRC32C();
|
||||
CRC32CFunctionPtr crcFunction;
|
||||
public:
|
||||
CRC32();
|
||||
unsigned operator()(char *str, unsigned len);
|
||||
virtual ~CRC32() {};
|
||||
};
|
||||
|
||||
#endif /* CRC32_H_ */
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef DOUGLASPEUCKER_H_
|
||||
#define DOUGLASPEUCKER_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
#include <stack>
|
||||
|
||||
#include "../DataStructures/Coordinate.h"
|
||||
|
||||
/*This class object computes the bitvector of indicating generalized input points
|
||||
* according to the (Ramer-)Douglas-Peucker algorithm.
|
||||
*
|
||||
* Input is vector of pairs. Each pair consists of the point information and a bit
|
||||
* indicating if the points is present in the generalization.
|
||||
* Note: points may also be pre-selected*/
|
||||
|
||||
//These thresholds are more or less heuristically chosen.
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
||||
static double DouglasPeuckerThresholds[19] = { 32000000., 16240000., 80240000., 40240000., 20000000., 10000000., 500000., 240000., 120000., 60000., 30000., 19000., 5000., 2000., 200, 16, 6, 3. , 3. };
|
||||
|
||||
template<class PointT>
|
||||
class DouglasPeucker {
|
||||
private:
|
||||
typedef std::pair<std::size_t, std::size_t> PairOfPoints;
|
||||
//Stack to simulate the recursion
|
||||
std::stack<PairOfPoints > recursionStack;
|
||||
|
||||
/**
|
||||
* This distance computation does integer arithmetic only and is about twice as fast as
|
||||
* the other distance function. It is an approximation only, but works more or less ok.
|
||||
*/
|
||||
template<class CoordT>
|
||||
inline int fastDistance(const CoordT& point, const CoordT& segA, const CoordT& segB) const {
|
||||
const int p2x = (segB.lon - segA.lat);
|
||||
const int p2y = (segB.lon - segA.lat);
|
||||
const int something = p2x*p2x + p2y*p2y;
|
||||
int u = (something < FLT_EPSILON ? 0 : ((point.lon - segA.lon) * p2x + (point.lat - segA.lat) * p2y) / something);
|
||||
|
||||
if (u > 1)
|
||||
u = 1;
|
||||
else if (u < 0)
|
||||
u = 0;
|
||||
|
||||
const int x = segA.lon + u * p2x;
|
||||
const int y = segA.lat + u * p2y;
|
||||
|
||||
const int dx = x - point.lon;
|
||||
const int dy = y - point.lat;
|
||||
|
||||
const int dist = (dx*dx + dy*dy);
|
||||
|
||||
return dist;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
void Run(std::vector<PointT> & inputVector, const unsigned zoomLevel) {
|
||||
{
|
||||
assert(zoomLevel < 19);
|
||||
assert(1 < inputVector.size());
|
||||
std::size_t leftBorderOfRange = 0;
|
||||
std::size_t rightBorderOfRange = 1;
|
||||
//Sweep linerarily over array and identify those ranges that need to be checked
|
||||
// recursionStack.hint(inputVector.size());
|
||||
do {
|
||||
assert(inputVector[leftBorderOfRange].necessary);
|
||||
assert(inputVector.back().necessary);
|
||||
|
||||
if(inputVector[rightBorderOfRange].necessary) {
|
||||
recursionStack.push(std::make_pair(leftBorderOfRange, rightBorderOfRange));
|
||||
leftBorderOfRange = rightBorderOfRange;
|
||||
}
|
||||
++rightBorderOfRange;
|
||||
} while( rightBorderOfRange < inputVector.size());
|
||||
}
|
||||
while(!recursionStack.empty()) {
|
||||
//pop next element
|
||||
const PairOfPoints pair = recursionStack.top();
|
||||
recursionStack.pop();
|
||||
assert(inputVector[pair.first].necessary);
|
||||
assert(inputVector[pair.second].necessary);
|
||||
assert(pair.second < inputVector.size());
|
||||
assert(pair.first < pair.second);
|
||||
int maxDistance = INT_MIN;
|
||||
|
||||
std::size_t indexOfFarthestElement = pair.second;
|
||||
//find index idx of element with maxDistance
|
||||
for(std::size_t i = pair.first+1; i < pair.second; ++i){
|
||||
const double distance = std::fabs(fastDistance(inputVector[i].location, inputVector[pair.first].location, inputVector[pair.second].location));
|
||||
if(distance > DouglasPeuckerThresholds[zoomLevel] && distance > maxDistance) {
|
||||
indexOfFarthestElement = i;
|
||||
maxDistance = distance;
|
||||
}
|
||||
}
|
||||
if (maxDistance > DouglasPeuckerThresholds[zoomLevel]) {
|
||||
// mark idx as necessary
|
||||
inputVector[indexOfFarthestElement].necessary = true;
|
||||
if (1 < indexOfFarthestElement - pair.first) {
|
||||
recursionStack.push(std::make_pair(pair.first, indexOfFarthestElement) );
|
||||
}
|
||||
if (1 < pair.second - indexOfFarthestElement)
|
||||
recursionStack.push(std::make_pair(indexOfFarthestElement, pair.second) );
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* DOUGLASPEUCKER_H_ */
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ITERATORBASEDCRC32_H_
|
||||
#define ITERATORBASEDCRC32_H_
|
||||
|
||||
#include <boost/crc.hpp> // for boost::crc_32_type
|
||||
#include <iostream>
|
||||
|
||||
template<class ContainerT>
|
||||
class IteratorbasedCRC32 {
|
||||
private:
|
||||
typedef typename ContainerT::iterator ContainerT_iterator;
|
||||
unsigned crc;
|
||||
unsigned slowcrc_table[1<<8];
|
||||
|
||||
typedef boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> my_crc_32_type;
|
||||
typedef unsigned (IteratorbasedCRC32::*CRC32CFunctionPtr)(char *str, unsigned len, unsigned crc);
|
||||
|
||||
unsigned SoftwareBasedCRC32(char *str, unsigned len, unsigned ){
|
||||
boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> CRC32_Processor;
|
||||
CRC32_Processor.process_bytes( str, len);
|
||||
return CRC32_Processor.checksum();
|
||||
}
|
||||
unsigned SSEBasedCRC32( char *str, unsigned len, unsigned crc){
|
||||
unsigned q=len/sizeof(unsigned),
|
||||
r=len%sizeof(unsigned),
|
||||
*p=(unsigned*)str/*, crc*/;
|
||||
|
||||
//crc=0;
|
||||
while (q--) {
|
||||
__asm__ __volatile__(
|
||||
".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
|
||||
:"=S"(crc)
|
||||
:"0"(crc), "c"(*p)
|
||||
);
|
||||
++p;
|
||||
}
|
||||
|
||||
str=(char*)p;
|
||||
while (r--) {
|
||||
__asm__ __volatile__(
|
||||
".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
|
||||
:"=S"(crc)
|
||||
:"0"(crc), "c"(*str)
|
||||
);
|
||||
++str;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
unsigned cpuid(unsigned functionInput){
|
||||
unsigned eax;
|
||||
unsigned ebx;
|
||||
unsigned ecx;
|
||||
unsigned edx;
|
||||
asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (functionInput));
|
||||
return ecx;
|
||||
}
|
||||
|
||||
CRC32CFunctionPtr detectBestCRC32C(){
|
||||
static const int SSE42_BIT = 20;
|
||||
unsigned ecx = cpuid(1);
|
||||
bool hasSSE42 = ecx & (1 << SSE42_BIT);
|
||||
if (hasSSE42) {
|
||||
std::cout << "using hardware base sse computation" << std::endl;
|
||||
return &IteratorbasedCRC32::SSEBasedCRC32; //crc32 hardware accelarated;
|
||||
} else {
|
||||
std::cout << "using software base sse computation" << std::endl;
|
||||
return &IteratorbasedCRC32::SoftwareBasedCRC32; //crc32cSlicingBy8;
|
||||
}
|
||||
}
|
||||
CRC32CFunctionPtr crcFunction;
|
||||
public:
|
||||
IteratorbasedCRC32(): crc(0) {
|
||||
crcFunction = detectBestCRC32C();
|
||||
}
|
||||
|
||||
virtual ~IteratorbasedCRC32() {};
|
||||
|
||||
unsigned operator()( ContainerT_iterator iter, const ContainerT_iterator end) {
|
||||
unsigned crc = 0;
|
||||
while(iter != end) {
|
||||
char * data = reinterpret_cast<char*>(&(*iter) );
|
||||
crc =((*this).*(crcFunction))(data, sizeof(typename ContainerT::value_type*), crc);
|
||||
++iter;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* ITERATORBASEDCRC32_H_ */
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef OBJECTTOBASE64_H_
|
||||
#define OBJECTTOBASE64_H_
|
||||
|
||||
#include <boost/archive/iterators/base64_from_binary.hpp>
|
||||
#include <boost/archive/iterators/binary_from_base64.hpp>
|
||||
#include <boost/archive/iterators/transform_width.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
typedef
|
||||
boost::archive::iterators::base64_from_binary<
|
||||
boost::archive::iterators::transform_width<string::const_iterator, 6, 8>
|
||||
> base64_t;
|
||||
|
||||
typedef
|
||||
boost::archive::iterators::transform_width<
|
||||
boost::archive::iterators::binary_from_base64<string::const_iterator>, 8, 6
|
||||
> binary_t;
|
||||
|
||||
template<class ToEncodeT>
|
||||
static void EncodeObjectToBase64(const ToEncodeT & object, std::string& encoded) {
|
||||
encoded.clear();
|
||||
char * pointerToOriginalObject = (char *)&object;
|
||||
encoded = std::string(base64_t(pointerToOriginalObject), base64_t(pointerToOriginalObject+sizeof(ToEncodeT)));
|
||||
//replace "+" with "-" and "/" with "_"
|
||||
replaceAll(encoded, "+", "-");
|
||||
replaceAll(encoded, "/", "_");
|
||||
}
|
||||
|
||||
template<class ToEncodeT>
|
||||
static void DecodeObjectFromBase64(ToEncodeT & object, const std::string& _encoded) {
|
||||
try {
|
||||
string encoded(_encoded);
|
||||
//replace "-" with "+" and "_" with "/"
|
||||
replaceAll(encoded, "-", "+");
|
||||
replaceAll(encoded, "_", "/");
|
||||
char * pointerToDecodedObject = (char *)&object;
|
||||
std::string dec(binary_t(encoded.begin()), binary_t(encoded.begin() + encoded.length() - 1));
|
||||
std::copy ( dec.begin(), dec.end(), pointerToDecodedObject );
|
||||
} catch(...) {}
|
||||
}
|
||||
|
||||
#endif /* OBJECTTOBASE64_H_ */
|
||||
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef POLYLINECOMPRESSOR_H_
|
||||
#define POLYLINECOMPRESSOR_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
//#include "../DataStructures/ExtractorStructs.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
class PolylineCompressor {
|
||||
private:
|
||||
inline void encodeVectorSignedNumber(std::vector<int> & numbers, std::string & output) const {
|
||||
for(unsigned i = 0; i < numbers.size(); ++i) {
|
||||
numbers[i] <<= 1;
|
||||
if (numbers[i] < 0) {
|
||||
numbers[i] = ~(numbers[i]);
|
||||
}
|
||||
}
|
||||
for(unsigned i = 0; i < numbers.size(); ++i) {
|
||||
encodeNumber(numbers[i], output);
|
||||
}
|
||||
}
|
||||
|
||||
inline void encodeNumber(int numberToEncode, std::string & output) const {
|
||||
while (numberToEncode >= 0x20) {
|
||||
int nextValue = (0x20 | (numberToEncode & 0x1f)) + 63;
|
||||
output += (static_cast<char> (nextValue));
|
||||
if(92 == nextValue)
|
||||
output += (static_cast<char> (nextValue));
|
||||
numberToEncode >>= 5;
|
||||
}
|
||||
|
||||
numberToEncode += 63;
|
||||
output += (static_cast<char> (numberToEncode));
|
||||
if(92 == numberToEncode)
|
||||
output += (static_cast<char> (numberToEncode));
|
||||
}
|
||||
|
||||
public:
|
||||
inline void printEncodedString(const std::vector<SegmentInformation>& polyline, std::string &output) const {
|
||||
std::vector<int> deltaNumbers;
|
||||
output += "\"";
|
||||
if(!polyline.empty()) {
|
||||
_Coordinate lastCoordinate = polyline[0].location;
|
||||
deltaNumbers.push_back( lastCoordinate.lat );
|
||||
deltaNumbers.push_back( lastCoordinate.lon );
|
||||
for(unsigned i = 1; i < polyline.size(); ++i) {
|
||||
if(!polyline[i].necessary)
|
||||
continue;
|
||||
deltaNumbers.push_back(polyline[i].location.lat - lastCoordinate.lat);
|
||||
deltaNumbers.push_back(polyline[i].location.lon - lastCoordinate.lon);
|
||||
lastCoordinate = polyline[i].location;
|
||||
}
|
||||
encodeVectorSignedNumber(deltaNumbers, output);
|
||||
}
|
||||
output += "\"";
|
||||
|
||||
}
|
||||
|
||||
inline void printEncodedString(const std::vector<_Coordinate>& polyline, std::string &output) const {
|
||||
std::vector<int> deltaNumbers(2*polyline.size());
|
||||
output += "\"";
|
||||
if(!polyline.empty()) {
|
||||
deltaNumbers[0] = polyline[0].lat;
|
||||
deltaNumbers[1] = polyline[0].lon;
|
||||
for(unsigned i = 1; i < polyline.size(); ++i) {
|
||||
deltaNumbers[(2*i)] = (polyline[i].lat - polyline[i-1].lat);
|
||||
deltaNumbers[(2*i)+1] = (polyline[i].lon - polyline[i-1].lon);
|
||||
}
|
||||
encodeVectorSignedNumber(deltaNumbers, output);
|
||||
}
|
||||
output += "\"";
|
||||
}
|
||||
|
||||
inline void printUnencodedString(std::vector<_Coordinate> & polyline, std::string & output) const {
|
||||
output += "[";
|
||||
std::string tmp;
|
||||
for(unsigned i = 0; i < polyline.size(); i++) {
|
||||
convertInternalLatLonToString(polyline[i].lat, tmp);
|
||||
output += "[";
|
||||
output += tmp;
|
||||
convertInternalLatLonToString(polyline[i].lon, tmp);
|
||||
output += ", ";
|
||||
output += tmp;
|
||||
output += "]";
|
||||
if( i < polyline.size()-1 ) {
|
||||
output += ",";
|
||||
}
|
||||
}
|
||||
output += "]";
|
||||
}
|
||||
|
||||
inline void printUnencodedString(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;
|
||||
convertInternalLatLonToString(polyline[i].location.lat, tmp);
|
||||
output += "[";
|
||||
output += tmp;
|
||||
convertInternalLatLonToString(polyline[i].location.lon, tmp);
|
||||
output += ", ";
|
||||
output += tmp;
|
||||
output += "]";
|
||||
if( i < polyline.size()-1 ) {
|
||||
output += ",";
|
||||
}
|
||||
}
|
||||
output += "]";
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* POLYLINECOMPRESSOR_H_ */
|
||||
@@ -1,382 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef STRONGLYCONNECTEDCOMPONENTS_H_
|
||||
#define STRONGLYCONNECTEDCOMPONENTS_H_
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include <gdal/gdal.h>
|
||||
#include <gdal/ogrsf_frmts.h>
|
||||
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
#include "../DataStructures/DynamicGraph.h"
|
||||
#include "../DataStructures/ImportEdge.h"
|
||||
#include "../DataStructures/NodeCoords.h"
|
||||
#include "../DataStructures/Percent.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
|
||||
// Strongly connected components using Tarjan's Algorithm
|
||||
|
||||
class TarjanSCC {
|
||||
private:
|
||||
struct _NodeBasedEdgeData {
|
||||
int distance;
|
||||
unsigned edgeBasedNodeID;
|
||||
unsigned nameID:31;
|
||||
bool shortcut:1;
|
||||
bool forward:1;
|
||||
bool backward:1;
|
||||
bool roundabout:1;
|
||||
bool ignoreInGrid:1;
|
||||
short type;
|
||||
bool isAccessRestricted;
|
||||
};
|
||||
|
||||
struct _EdgeBasedEdgeData {
|
||||
int distance;
|
||||
unsigned via;
|
||||
unsigned nameID;
|
||||
bool forward;
|
||||
bool backward;
|
||||
TurnInstruction turnInstruction;
|
||||
};
|
||||
|
||||
typedef DynamicGraph< _NodeBasedEdgeData > _NodeBasedDynamicGraph;
|
||||
typedef _NodeBasedDynamicGraph::InputEdge _NodeBasedEdge;
|
||||
std::vector<NodeInfo> inputNodeInfoList;
|
||||
unsigned numberOfTurnRestrictions;
|
||||
boost::shared_ptr<_NodeBasedDynamicGraph> _nodeBasedGraph;
|
||||
boost::unordered_map<NodeID, bool> _barrierNodes;
|
||||
boost::unordered_map<NodeID, bool> _trafficLights;
|
||||
|
||||
typedef std::pair<NodeID, NodeID> RestrictionSource;
|
||||
typedef std::pair<NodeID, bool> RestrictionTarget;
|
||||
typedef std::vector<RestrictionTarget> EmanatingRestrictionsVector;
|
||||
typedef boost::unordered_map<RestrictionSource, unsigned > RestrictionMap;
|
||||
std::vector<EmanatingRestrictionsVector> _restrictionBucketVector;
|
||||
RestrictionMap _restrictionMap;
|
||||
|
||||
|
||||
public:
|
||||
struct EdgeBasedNode {
|
||||
bool operator<(const EdgeBasedNode & other) const {
|
||||
return other.id < id;
|
||||
}
|
||||
bool operator==(const EdgeBasedNode & other) const {
|
||||
return id == other.id;
|
||||
}
|
||||
NodeID id;
|
||||
int lat1;
|
||||
int lat2;
|
||||
int lon1;
|
||||
int lon2:31;
|
||||
bool belongsToTinyComponent:1;
|
||||
NodeID nameID;
|
||||
unsigned weight:31;
|
||||
bool ignoreInGrid:1;
|
||||
};
|
||||
|
||||
private:
|
||||
DeallocatingVector<EdgeBasedNode> edgeBasedNodes;
|
||||
|
||||
struct TarjanNode {
|
||||
TarjanNode() : index(UINT_MAX), lowlink(UINT_MAX), onStack(false) {}
|
||||
unsigned index;
|
||||
unsigned lowlink;
|
||||
bool onStack;
|
||||
};
|
||||
|
||||
struct TarjanStackFrame {
|
||||
explicit TarjanStackFrame(NodeID _v, NodeID p) : v(_v), parent(p) {}
|
||||
NodeID v;
|
||||
NodeID parent;
|
||||
};
|
||||
public:
|
||||
TarjanSCC(int nodes, std::vector<NodeBasedEdge> & inputEdges, std::vector<NodeID> & bn, std::vector<NodeID> & tl, std::vector<_Restriction> & irs, std::vector<NodeInfo> & nI) : inputNodeInfoList(nI), numberOfTurnRestrictions(irs.size()) {
|
||||
BOOST_FOREACH(_Restriction & restriction, irs) {
|
||||
std::pair<NodeID, NodeID> restrictionSource = std::make_pair(restriction.fromNode, restriction.viaNode);
|
||||
unsigned index;
|
||||
RestrictionMap::iterator restrIter = _restrictionMap.find(restrictionSource);
|
||||
if(restrIter == _restrictionMap.end()) {
|
||||
index = _restrictionBucketVector.size();
|
||||
_restrictionBucketVector.resize(index+1);
|
||||
_restrictionMap[restrictionSource] = index;
|
||||
} else {
|
||||
index = restrIter->second;
|
||||
//Map already contains an is_only_*-restriction
|
||||
if(_restrictionBucketVector.at(index).begin()->second)
|
||||
continue;
|
||||
else if(restriction.flags.isOnly){
|
||||
//We are going to insert an is_only_*-restriction. There can be only one.
|
||||
_restrictionBucketVector.at(index).clear();
|
||||
}
|
||||
}
|
||||
|
||||
_restrictionBucketVector.at(index).push_back(std::make_pair(restriction.toNode, restriction.flags.isOnly));
|
||||
}
|
||||
|
||||
BOOST_FOREACH(NodeID id, bn) {
|
||||
_barrierNodes[id] = true;
|
||||
}
|
||||
BOOST_FOREACH(NodeID id, tl) {
|
||||
_trafficLights[id] = true;
|
||||
}
|
||||
|
||||
DeallocatingVector< _NodeBasedEdge > edges;
|
||||
for ( std::vector< NodeBasedEdge >::const_iterator i = inputEdges.begin(); i != inputEdges.end(); ++i ) {
|
||||
|
||||
_NodeBasedEdge edge;
|
||||
if(!i->isForward()) {
|
||||
edge.source = i->target();
|
||||
edge.target = i->source();
|
||||
edge.data.backward = i->isForward();
|
||||
edge.data.forward = i->isBackward();
|
||||
} else {
|
||||
edge.source = i->source();
|
||||
edge.target = i->target();
|
||||
edge.data.forward = i->isForward();
|
||||
edge.data.backward = i->isBackward();
|
||||
}
|
||||
if(edge.source == edge.target)
|
||||
continue;
|
||||
|
||||
edge.data.distance = (std::max)((int)i->weight(), 1 );
|
||||
assert( edge.data.distance > 0 );
|
||||
edge.data.shortcut = false;
|
||||
edge.data.roundabout = i->isRoundabout();
|
||||
edge.data.ignoreInGrid = i->ignoreInGrid();
|
||||
edge.data.nameID = i->name();
|
||||
edge.data.type = i->type();
|
||||
edge.data.isAccessRestricted = i->isAccessRestricted();
|
||||
edge.data.edgeBasedNodeID = edges.size();
|
||||
edges.push_back( edge );
|
||||
if( edge.data.backward ) {
|
||||
std::swap( edge.source, edge.target );
|
||||
edge.data.forward = i->isBackward();
|
||||
edge.data.backward = i->isForward();
|
||||
edge.data.edgeBasedNodeID = edges.size();
|
||||
edges.push_back( edge );
|
||||
}
|
||||
}
|
||||
std::vector<NodeBasedEdge>().swap(inputEdges);
|
||||
std::sort( edges.begin(), edges.end() );
|
||||
_nodeBasedGraph = boost::make_shared<_NodeBasedDynamicGraph>( nodes, edges );
|
||||
}
|
||||
|
||||
void Run() {
|
||||
Percent p(_nodeBasedGraph->GetNumberOfNodes());
|
||||
|
||||
const char *pszDriverName = "ESRI Shapefile";
|
||||
OGRSFDriver *poDriver;
|
||||
|
||||
OGRRegisterAll();
|
||||
|
||||
poDriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(
|
||||
pszDriverName );
|
||||
if( poDriver == NULL )
|
||||
{
|
||||
printf( "%s driver not available.\n", pszDriverName );
|
||||
exit( 1 );
|
||||
}
|
||||
OGRDataSource *poDS;
|
||||
|
||||
poDS = poDriver->CreateDataSource( "component.shp", NULL );
|
||||
if( poDS == NULL ) {
|
||||
printf( "Creation of output file failed.\n" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
OGRLayer *poLayer;
|
||||
|
||||
poLayer = poDS->CreateLayer( "component", NULL, wkbLineString, NULL );
|
||||
if( poLayer == NULL ) {
|
||||
printf( "Layer creation failed.\n" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
|
||||
//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> > recursionStack; //true = stuff before, false = stuff after call
|
||||
std::stack<NodeID> tarjanStack;
|
||||
std::vector<unsigned> componentsIndex(_nodeBasedGraph->GetNumberOfNodes(), UINT_MAX);
|
||||
std::vector<NodeID> vectorOfComponentSizes;
|
||||
std::vector<TarjanNode> tarjanNodes(_nodeBasedGraph->GetNumberOfNodes());
|
||||
unsigned currentComponent = 0, sizeOfCurrentComponent = 0;
|
||||
int index = 0;
|
||||
for(NodeID node = 0, endNodes = _nodeBasedGraph->GetNumberOfNodes(); node < endNodes; ++node) {
|
||||
if(UINT_MAX == componentsIndex[node]) {
|
||||
recursionStack.push(std::make_pair(true, TarjanStackFrame(node,node)) );
|
||||
}
|
||||
|
||||
while(!recursionStack.empty()) {
|
||||
bool beforeRecursion = recursionStack.top().first;
|
||||
TarjanStackFrame currentFrame = recursionStack.top().second;
|
||||
NodeID v = currentFrame.v;
|
||||
// INFO("popping node " << v << (beforeRecursion ? " before " : " after ") << "recursion");
|
||||
recursionStack.pop();
|
||||
|
||||
if(beforeRecursion) {
|
||||
//Mark frame to handle tail of recursion
|
||||
recursionStack.push(std::make_pair(false, currentFrame));
|
||||
|
||||
//Mark essential information for SCC
|
||||
tarjanNodes[v].index = index;
|
||||
tarjanNodes[v].lowlink = index;
|
||||
tarjanStack.push(v);
|
||||
tarjanNodes[v].onStack = true;
|
||||
++index;
|
||||
// INFO("pushing " << v << " onto tarjan stack, idx[" << v << "]=" << tarjanNodes[v].index << ", lowlink["<< v << "]=" << tarjanNodes[v].lowlink);
|
||||
|
||||
//Traverse outgoing edges
|
||||
for(_NodeBasedDynamicGraph::EdgeIterator e2 = _nodeBasedGraph->BeginEdges(v); e2 < _nodeBasedGraph->EndEdges(v); ++e2) {
|
||||
_NodeBasedDynamicGraph::NodeIterator vprime = _nodeBasedGraph->GetTarget(e2);
|
||||
// INFO("traversing edge (" << v << "," << vprime << ")");
|
||||
if(UINT_MAX == tarjanNodes[vprime].index) {
|
||||
|
||||
recursionStack.push(std::make_pair(true,TarjanStackFrame(vprime, v)));
|
||||
} else {
|
||||
// INFO("Node " << vprime << " is already explored");
|
||||
if(tarjanNodes[vprime].onStack) {
|
||||
unsigned newLowlink = std::min(tarjanNodes[v].lowlink, tarjanNodes[vprime].index);
|
||||
// INFO("Setting lowlink[" << v << "] from " << tarjanNodes[v].lowlink << " to " << newLowlink);
|
||||
tarjanNodes[v].lowlink = newLowlink;
|
||||
// } else {
|
||||
// INFO("But node " << vprime << " is not on stack");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// INFO("we are at the end of recursion and checking node " << v);
|
||||
{ // setting lowlink in its own scope so it does not pollute namespace
|
||||
// NodeID parent = (UINT_MAX == tarjanNodes[v].parent ? v : tarjanNodes[v].parent );
|
||||
// INFO("parent=" << currentFrame.parent);
|
||||
// INFO("tarjanNodes[" << v << "].lowlink=" << tarjanNodes[v].lowlink << ", tarjanNodes[" << currentFrame.parent << "].lowlink=" << tarjanNodes[currentFrame.parent].lowlink);
|
||||
//Note the index shift by 1 compared to the recursive version
|
||||
tarjanNodes[currentFrame.parent].lowlink = std::min(tarjanNodes[currentFrame.parent].lowlink, tarjanNodes[v].lowlink);
|
||||
// INFO("Setting tarjanNodes[" << currentFrame.parent <<"].lowlink=" << tarjanNodes[currentFrame.parent].lowlink);
|
||||
}
|
||||
// INFO("tarjanNodes[" << v << "].lowlink=" << tarjanNodes[v].lowlink << ", tarjanNodes[" << v << "].index=" << tarjanNodes[v].index);
|
||||
|
||||
//after recursion, lets do cycle checking
|
||||
//Check if we found a cycle. This is the bottom part of the recursion
|
||||
if(tarjanNodes[v].lowlink == tarjanNodes[v].index) {
|
||||
NodeID vprime;
|
||||
do {
|
||||
// INFO("identified component " << currentComponent << ": " << tarjanStack.top());
|
||||
vprime = tarjanStack.top(); tarjanStack.pop();
|
||||
tarjanNodes[vprime].onStack = false;
|
||||
componentsIndex[vprime] = currentComponent;
|
||||
++sizeOfCurrentComponent;
|
||||
} while( v != vprime);
|
||||
vectorOfComponentSizes.push_back(sizeOfCurrentComponent);
|
||||
if(sizeOfCurrentComponent > 1000)
|
||||
INFO("large component [" << currentComponent << "]=" << sizeOfCurrentComponent);
|
||||
++currentComponent;
|
||||
sizeOfCurrentComponent = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INFO("identified: " << vectorOfComponentSizes.size() << " many components, marking small components");
|
||||
|
||||
int singleCounter = 0;
|
||||
for(unsigned i = 0; i < vectorOfComponentSizes.size(); ++i){
|
||||
if(1 == vectorOfComponentSizes[i])
|
||||
++singleCounter;
|
||||
}
|
||||
INFO("identified " << singleCounter << " SCCs of size 1");
|
||||
|
||||
p.reinit(_nodeBasedGraph->GetNumberOfNodes());
|
||||
for(_NodeBasedDynamicGraph::NodeIterator u = 0; u < _nodeBasedGraph->GetNumberOfNodes(); ++u ) {
|
||||
for(_NodeBasedDynamicGraph::EdgeIterator e1 = _nodeBasedGraph->BeginEdges(u); e1 < _nodeBasedGraph->EndEdges(u); ++e1) {
|
||||
_NodeBasedDynamicGraph::NodeIterator v = _nodeBasedGraph->GetTarget(e1);
|
||||
|
||||
if(_nodeBasedGraph->GetEdgeData(e1).type != SHRT_MAX) {
|
||||
assert(e1 != UINT_MAX);
|
||||
assert(u != UINT_MAX);
|
||||
assert(v != UINT_MAX);
|
||||
//edges that end on bollard nodes may actually be in two distinct components
|
||||
if(std::min(vectorOfComponentSizes[componentsIndex[u]], vectorOfComponentSizes[componentsIndex[v]]) < 10) {
|
||||
|
||||
//INFO("(" << inputNodeInfoList[u].lat/100000. << ";" << inputNodeInfoList[u].lon/100000. << ") -> (" << inputNodeInfoList[v].lat/100000. << ";" << inputNodeInfoList[v].lon/100000. << ")");
|
||||
OGRLineString lineString;
|
||||
lineString.addPoint(inputNodeInfoList[u].lon/100000., inputNodeInfoList[u].lat/100000.);
|
||||
lineString.addPoint(inputNodeInfoList[v].lon/100000., inputNodeInfoList[v].lat/100000.);
|
||||
|
||||
OGRFeature *poFeature;
|
||||
poFeature = OGRFeature::CreateFeature( poLayer->GetLayerDefn() );
|
||||
poFeature->SetGeometry( &lineString );
|
||||
if( poLayer->CreateFeature( poFeature ) != OGRERR_NONE )
|
||||
{
|
||||
ERR( "Failed to create feature in shapefile.\n" );
|
||||
}
|
||||
OGRFeature::DestroyFeature( poFeature );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
OGRDataSource::DestroyDataSource( poDS );
|
||||
std::vector<NodeID>().swap(vectorOfComponentSizes);
|
||||
std::vector<NodeID>().swap(componentsIndex);
|
||||
|
||||
}
|
||||
private:
|
||||
unsigned CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const {
|
||||
std::pair < NodeID, NodeID > restrictionSource = std::make_pair(u, v);
|
||||
RestrictionMap::const_iterator restrIter = _restrictionMap.find(restrictionSource);
|
||||
if (restrIter != _restrictionMap.end()) {
|
||||
unsigned index = restrIter->second;
|
||||
BOOST_FOREACH(RestrictionSource restrictionTarget, _restrictionBucketVector.at(index)) {
|
||||
if(restrictionTarget.second) {
|
||||
return restrictionTarget.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 > restrictionSource = std::make_pair(u, v);
|
||||
RestrictionMap::const_iterator restrIter = _restrictionMap.find(restrictionSource);
|
||||
if (restrIter != _restrictionMap.end()) {
|
||||
unsigned index = restrIter->second;
|
||||
BOOST_FOREACH(RestrictionTarget restrictionTarget, _restrictionBucketVector.at(index)) {
|
||||
if(w == restrictionTarget.first)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* STRONGLYCONNECTEDCOMPONENTS_H_ */
|
||||
+346
@@ -0,0 +1,346 @@
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
|
||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_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)
|
||||
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(bitness 32)
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(bitness 64)
|
||||
message(STATUS "Building on a 64 bit system")
|
||||
else()
|
||||
message(WARNING "Building on a 32 bit system is unsupported")
|
||||
endif()
|
||||
|
||||
if (WIN32 AND MSVC_VERSION LESS 1800)
|
||||
message(FATAL_ERROR "Building with Microsoft compiler needs Visual Studio 2013 or later (Express version works too)")
|
||||
endif()
|
||||
|
||||
OPTION(WITH_TOOLS "Build OSRM tools" OFF)
|
||||
OPTION(BUILD_TOOLS "Build OSRM tools" OFF)
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/Include/)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/third_party/)
|
||||
|
||||
add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/Util/finger_print.cpp finger_print.cpp.alwaysbuild
|
||||
COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR}
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FingerPrint-Config.cmake
|
||||
DEPENDS
|
||||
${CMAKE_SOURCE_DIR}/Util/finger_print.cpp.in
|
||||
COMMENT "Configuring finger_print.cpp"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target(FingerPrintConfigure DEPENDS ${CMAKE_SOURCE_DIR}/Util/finger_print.cpp)
|
||||
add_custom_target(tests DEPENDS datastructure-tests algorithm-tests)
|
||||
add_custom_target(benchmarks DEPENDS rtree-bench)
|
||||
|
||||
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
|
||||
)
|
||||
file(GLOB ExtractorGlob extractor/*.cpp)
|
||||
file(GLOB ImporterGlob data_structures/import_edge.cpp data_structures/external_memory_node.cpp)
|
||||
add_library(IMPORT OBJECT ${ImporterGlob})
|
||||
add_library(LOGGER OBJECT Util/simple_logger.cpp)
|
||||
add_library(PHANTOMNODE OBJECT data_structures/phantom_node.cpp)
|
||||
|
||||
set(ExtractorSources extract.cpp ${ExtractorGlob})
|
||||
add_executable(osrm-extract ${ExtractorSources} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:LOGGER>)
|
||||
|
||||
file(GLOB PrepareGlob contractor/*.cpp data_structures/hilbert_value.cpp data_structures/restriction_map.cpp Util/compute_angle.cpp)
|
||||
set(PrepareSources prepare.cpp ${PrepareGlob})
|
||||
add_executable(osrm-prepare ${PrepareSources} $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:LOGGER>)
|
||||
|
||||
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)
|
||||
list(REMOVE_ITEM DatastructureGlob data_structures/Coordinate.cpp)
|
||||
file(GLOB CoordinateGlob data_structures/Coordinate.cpp)
|
||||
file(GLOB AlgorithmGlob algorithms/*.cpp)
|
||||
file(GLOB HttpGlob Server/Http/*.cpp)
|
||||
file(GLOB LibOSRMGlob Library/*.cpp)
|
||||
file(GLOB DataStructureTestsGlob UnitTests/data_structures/*.cpp data_structures/hilbert_value.cpp)
|
||||
file(GLOB AlgorithmTestsGlob UnitTests/Algorithms/*.cpp)
|
||||
|
||||
set(
|
||||
OSRMSources
|
||||
${LibOSRMGlob}
|
||||
${DescriptorGlob}
|
||||
${DatastructureGlob}
|
||||
${CoordinateGlob}
|
||||
${AlgorithmGlob}
|
||||
${HttpGlob}
|
||||
)
|
||||
add_library(COORDINATE OBJECT ${CoordinateGlob})
|
||||
add_library(FINGERPRINT OBJECT Util/finger_print.cpp)
|
||||
add_library(GITDESCRIPTION OBJECT Util/GitDescription.cpp)
|
||||
add_library(OSRM ${OSRMSources} $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE>)
|
||||
add_dependencies(FINGERPRINT FingerPrintConfigure)
|
||||
|
||||
add_executable(osrm-routed routed.cpp ${ServerGlob})
|
||||
add_executable(osrm-datastore datastore.cpp $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:LOGGER>)
|
||||
|
||||
# Unit tests
|
||||
add_executable(datastructure-tests EXCLUDE_FROM_ALL UnitTests/datastructure_tests.cpp ${DataStructureTestsGlob} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE>)
|
||||
add_executable(algorithm-tests EXCLUDE_FROM_ALL UnitTests/algorithm_tests.cpp ${AlgorithmTestsGlob} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE>)
|
||||
|
||||
# Benchmarks
|
||||
add_executable(rtree-bench EXCLUDE_FROM_ALL benchmarks/static_rtree.cpp $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE>)
|
||||
|
||||
# Check the release mode
|
||||
if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
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")
|
||||
endif()
|
||||
endif()
|
||||
if(CMAKE_BUILD_TYPE MATCHES Release)
|
||||
message(STATUS "Configuring OSRM in release mode")
|
||||
# Check if LTO is available
|
||||
set(LTO_FLAGS "")
|
||||
CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG)
|
||||
if (HAS_LTO_FLAG)
|
||||
set(LTO_FLAGS "${LTO_FLAGS} -flto")
|
||||
|
||||
# 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()
|
||||
endif (HAS_LTO_FLAG)
|
||||
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 -pedantic -fPIC")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
# using GCC
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -fPIC")
|
||||
if (WIN32) # using mingw
|
||||
add_definitions(-D_USE_MATH_DEFINES) # define M_PI, M_1_PI etc.
|
||||
add_definitions(-DWIN32)
|
||||
SET(OPTIONAL_SOCKET_LIBS ws2_32 wsock32)
|
||||
endif()
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
|
||||
# using Intel C++
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-intel -wd10237 -Wall -ipo -fPIC")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
# 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()
|
||||
|
||||
# Activate C++11
|
||||
if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
ADD_DEFINITIONS(-std=c++11)
|
||||
endif()
|
||||
|
||||
# Configuring other platform dependencies
|
||||
if(APPLE)
|
||||
set(CMAKE_OSX_ARCHITECTURES "x86_64")
|
||||
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(OSXLIBSTD)
|
||||
message(STATUS "linking against ${OSXLIBSTD}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=${OSXLIBSTD}")
|
||||
elseif(DARWIN_VERSION GREATER 12)
|
||||
message(STATUS "linking against libc++")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
endif()
|
||||
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)
|
||||
if(NOT Boost_FOUND)
|
||||
message(FATAL_ERROR "Fatal error: Boost (version >= 1.49.0) required.\n")
|
||||
endif()
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
|
||||
target_link_libraries(OSRM ${Boost_LIBRARIES})
|
||||
target_link_libraries(osrm-extract ${Boost_LIBRARIES})
|
||||
target_link_libraries(osrm-prepare ${Boost_LIBRARIES})
|
||||
target_link_libraries(osrm-routed ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM)
|
||||
target_link_libraries(osrm-datastore ${Boost_LIBRARIES})
|
||||
target_link_libraries(datastructure-tests ${Boost_LIBRARIES})
|
||||
target_link_libraries(algorithm-tests ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM)
|
||||
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(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(${TBB_INCLUDE_DIR})
|
||||
|
||||
find_package( Luabind REQUIRED )
|
||||
include(check_luabind)
|
||||
|
||||
include_directories(${LUABIND_INCLUDE_DIR})
|
||||
target_link_libraries(osrm-extract ${LUABIND_LIBRARY})
|
||||
target_link_libraries(osrm-prepare ${LUABIND_LIBRARY})
|
||||
|
||||
if( LUAJIT_FOUND )
|
||||
target_link_libraries(osrm-extract ${LUAJIT_LIBRARIES})
|
||||
target_link_libraries(osrm-prepare ${LUAJIT_LIBRARIES})
|
||||
else()
|
||||
target_link_libraries(osrm-extract ${LUA_LIBRARY})
|
||||
target_link_libraries(osrm-prepare ${LUA_LIBRARY})
|
||||
endif()
|
||||
include_directories(${LUA_INCLUDE_DIR})
|
||||
|
||||
find_package(EXPAT REQUIRED)
|
||||
include_directories(${EXPAT_INCLUDE_DIRS})
|
||||
target_link_libraries(osrm-extract ${EXPAT_LIBRARIES})
|
||||
|
||||
find_package( STXXL REQUIRED )
|
||||
include_directories(${STXXL_INCLUDE_DIR})
|
||||
target_link_libraries(OSRM ${STXXL_LIBRARY})
|
||||
target_link_libraries(osrm-extract ${STXXL_LIBRARY})
|
||||
target_link_libraries(osrm-prepare ${STXXL_LIBRARY})
|
||||
|
||||
if(MINGW)
|
||||
# STXXL needs OpenMP library
|
||||
target_link_libraries(osrm-extract gomp)
|
||||
endif()
|
||||
|
||||
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})
|
||||
|
||||
find_package(BZip2 REQUIRED)
|
||||
include_directories(${BZIP_INCLUDE_DIRS})
|
||||
target_link_libraries(osrm-extract ${BZIP2_LIBRARIES})
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
include_directories(${ZLIB_INCLUDE_DIRS})
|
||||
target_link_libraries(osrm-extract ${ZLIB_LIBRARY})
|
||||
target_link_libraries(osrm-routed ${ZLIB_LIBRARY})
|
||||
|
||||
if(WITH_TOOLS OR BUILD_TOOLS)
|
||||
message(STATUS "Activating OSRM internal tools")
|
||||
find_package(GDAL)
|
||||
if(GDAL_FOUND)
|
||||
add_executable(osrm-components tools/components.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER>)
|
||||
target_link_libraries(osrm-components ${TBB_LIBRARIES})
|
||||
include_directories(${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_OBJECTS:LOGGER>)
|
||||
target_link_libraries(osrm-cli ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM)
|
||||
target_link_libraries(osrm-cli ${TBB_LIBRARIES})
|
||||
add_executable(osrm-io-benchmark tools/io-benchmark.cpp $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:LOGGER>)
|
||||
target_link_libraries(osrm-io-benchmark ${Boost_LIBRARIES})
|
||||
add_executable(osrm-unlock-all tools/unlock_all_mutexes.cpp $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:LOGGER>)
|
||||
target_link_libraries(osrm-unlock-all ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(osrm-unlock-all rt)
|
||||
endif()
|
||||
add_executable(osrm-check-hsgr tools/check-hsgr.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER>)
|
||||
target_link_libraries(osrm-check-hsgr ${Boost_LIBRARIES})
|
||||
add_executable(osrm-springclean tools/springclean.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:GITDESCRIPTION>)
|
||||
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)
|
||||
|
||||
# Add RPATH info to executables so that when they are run after being installed
|
||||
# (i.e., from /usr/local/bin/) the linker can find library dependencies. For
|
||||
# more info see http://www.cmake.org/Wiki/CMake_RPATH_handling
|
||||
set_property(TARGET osrm-extract PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
set_property(TARGET osrm-prepare PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
set_property(TARGET osrm-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(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})
|
||||
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 ()
|
||||
|
||||
configure_file(${CMAKE_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()
|
||||
@@ -1,261 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef CONTRACTIONCLEANUP_H_INCLUDED
|
||||
#define CONTRACTIONCLEANUP_H_INCLUDED
|
||||
|
||||
#include <algorithm>
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include "Contractor.h"
|
||||
|
||||
class ContractionCleanup {
|
||||
private:
|
||||
|
||||
struct _CleanupHeapData {
|
||||
NodeID parent;
|
||||
_CleanupHeapData( NodeID p ) {
|
||||
parent = p;
|
||||
}
|
||||
};
|
||||
typedef BinaryHeap< NodeID, NodeID, int, _CleanupHeapData > _Heap;
|
||||
|
||||
struct _ThreadData {
|
||||
_Heap* _heapForward;
|
||||
_Heap* _heapBackward;
|
||||
_ThreadData( NodeID nodes ) {
|
||||
_heapBackward = new _Heap(nodes);
|
||||
_heapForward = new _Heap(nodes);
|
||||
}
|
||||
~_ThreadData() {
|
||||
delete _heapBackward;
|
||||
delete _heapForward;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
struct Edge {
|
||||
NodeID source;
|
||||
NodeID target;
|
||||
struct EdgeData {
|
||||
NodeID via;
|
||||
unsigned nameID;
|
||||
int distance;
|
||||
TurnInstruction turnInstruction;
|
||||
bool shortcut:1;
|
||||
bool forward:1;
|
||||
bool backward:1;
|
||||
} data;
|
||||
bool operator<( const Edge& right ) const {
|
||||
if ( source != right.source )
|
||||
return source < right.source;
|
||||
return target < right.target;
|
||||
}
|
||||
|
||||
//sorts by source and other attributes
|
||||
static bool CompareBySource( const Edge& left, const Edge& right ) {
|
||||
if ( left.source != right.source )
|
||||
return left.source < right.source;
|
||||
int l = ( left.data.forward ? -1 : 0 ) + ( left.data.backward ? -1 : 0 );
|
||||
int r = ( right.data.forward ? -1 : 0 ) + ( right.data.backward ? -1 : 0 );
|
||||
if ( l != r )
|
||||
return l < r;
|
||||
if ( left.target != right.target )
|
||||
return left.target < right.target;
|
||||
return left.data.distance < right.data.distance;
|
||||
}
|
||||
|
||||
bool operator== ( const Edge& right ) const {
|
||||
return ( source == right.source && target == right.target && data.distance == right.data.distance &&
|
||||
data.shortcut == right.data.shortcut && data.forward == right.data.forward && data.backward == right.data.backward
|
||||
&& data.via == right.data.via && data.nameID == right.data.nameID
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
ContractionCleanup( int numNodes, const std::vector< Edge >& edges ) {
|
||||
_graph = edges;
|
||||
_numNodes = numNodes;
|
||||
}
|
||||
|
||||
~ContractionCleanup() {
|
||||
|
||||
}
|
||||
|
||||
void Run() {
|
||||
RemoveUselessShortcuts();
|
||||
}
|
||||
|
||||
template< class EdgeT >
|
||||
void GetData( std::vector< EdgeT >& edges ) {
|
||||
for ( int edge = 0, endEdges = ( int ) _graph.size(); edge != endEdges; ++edge ) {
|
||||
if(_graph[edge].data.forward || _graph[edge].data.backward) {
|
||||
EdgeT newEdge;
|
||||
newEdge.source = _graph[edge].source;
|
||||
newEdge.target = _graph[edge].target;
|
||||
newEdge.data = _graph[edge].data;
|
||||
edges.push_back( newEdge );
|
||||
}
|
||||
}
|
||||
sort( edges.begin(), edges.end() );
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
double _Timestamp() {
|
||||
struct timeval tp;
|
||||
gettimeofday(&tp, NULL);
|
||||
return double(tp.tv_sec) + tp.tv_usec / 1000000.;
|
||||
}
|
||||
|
||||
void BuildOutgoingGraph() {
|
||||
//sort edges by source
|
||||
sort( _graph.begin(), _graph.end(), Edge::CompareBySource );
|
||||
try {
|
||||
_firstEdge.resize( _numNodes + 1 );
|
||||
} catch(...) {
|
||||
ERR("Not enough RAM on machine");
|
||||
return;
|
||||
}
|
||||
_firstEdge[0] = 0;
|
||||
for ( NodeID i = 0, node = 0; i < ( NodeID ) _graph.size(); i++ ) {
|
||||
while ( _graph[i].source != node )
|
||||
_firstEdge[++node] = i;
|
||||
if ( i == ( NodeID ) _graph.size() - 1 )
|
||||
while ( node < _numNodes )
|
||||
_firstEdge[++node] = ( int ) _graph.size();
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveUselessShortcuts() {
|
||||
int maxThreads = omp_get_max_threads();
|
||||
std::vector < _ThreadData* > threadData;
|
||||
for ( int threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
||||
threadData.push_back( new _ThreadData( _numNodes ) );
|
||||
}
|
||||
|
||||
INFO("Scanning for useless shortcuts");
|
||||
BuildOutgoingGraph();
|
||||
/*
|
||||
#pragma omp parallel for
|
||||
for ( int i = 0; i < ( int ) _graph.size(); i++ ) {
|
||||
//only remove shortcuts
|
||||
if ( !_graph[i].data.shortcut )
|
||||
continue;
|
||||
|
||||
if ( _graph[i].data.forward ) {
|
||||
int result = _ComputeDistance( _graph[i].source, _graph[i].target, threadData[omp_get_thread_num()] );
|
||||
if ( result < _graph[i].data.distance ) {
|
||||
_graph[i].data.forward = false;
|
||||
}
|
||||
}
|
||||
if ( _graph[i].data.backward ) {
|
||||
int result = _ComputeDistance( _graph[i].target, _graph[i].source, threadData[omp_get_thread_num()] );
|
||||
if ( result < _graph[i].data.distance ) {
|
||||
_graph[i].data.backward = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
INFO("Removing edges");
|
||||
int useful = 0;
|
||||
for ( int i = 0; i < ( int ) _graph.size(); i++ ) {
|
||||
if ( !_graph[i].data.forward && !_graph[i].data.backward && _graph[i].data.shortcut ) {
|
||||
continue;
|
||||
}
|
||||
_graph[useful] = _graph[i];
|
||||
useful++;
|
||||
}
|
||||
INFO("Removed " << _graph.size() - useful << " useless shortcuts");
|
||||
_graph.resize( useful );
|
||||
|
||||
for ( int threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
||||
delete threadData[threadNum];
|
||||
}
|
||||
}
|
||||
|
||||
void _ComputeStep( _Heap* heapForward, _Heap* heapBackward, bool forwardDirection, NodeID* middle, int* targetDistance ) {
|
||||
|
||||
const NodeID node = heapForward->DeleteMin();
|
||||
const int distance = heapForward->GetKey( node );
|
||||
|
||||
if ( distance > *targetDistance ) {
|
||||
heapForward->DeleteAll();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( heapBackward->WasInserted( node ) ) {
|
||||
const int newDistance = heapBackward->GetKey( node ) + distance;
|
||||
if ( newDistance < *targetDistance ) {
|
||||
*middle = node;
|
||||
*targetDistance = newDistance;
|
||||
}
|
||||
}
|
||||
|
||||
for ( int edge = _firstEdge[node], endEdges = _firstEdge[node + 1]; edge != endEdges; ++edge ) {
|
||||
const NodeID to = _graph[edge].target;
|
||||
const int edgeWeight = _graph[edge].data.distance;
|
||||
assert( edgeWeight > 0 );
|
||||
const int toDistance = distance + edgeWeight;
|
||||
|
||||
if ( (forwardDirection ? _graph[edge].data.forward : _graph[edge].data.backward ) ) {
|
||||
//New Node discovered -> Add to Heap + Node Info Storage
|
||||
if ( !heapForward->WasInserted( to ) )
|
||||
heapForward->Insert( to, toDistance, node );
|
||||
|
||||
//Found a shorter Path -> Update distance
|
||||
else if ( toDistance < heapForward->GetKey( to ) ) {
|
||||
heapForward->DecreaseKey( to, toDistance );
|
||||
//new parent
|
||||
heapForward->GetData( to ) = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int _ComputeDistance( NodeID source, NodeID target, _ThreadData * data ) {
|
||||
data->_heapForward->Clear();
|
||||
data->_heapBackward->Clear();
|
||||
//insert source into heap
|
||||
data->_heapForward->Insert( source, 0, source );
|
||||
data->_heapBackward->Insert( target, 0, target );
|
||||
|
||||
int targetDistance = std::numeric_limits< int >::max();
|
||||
NodeID middle = std::numeric_limits<NodeID>::max();
|
||||
|
||||
while ( data->_heapForward->Size() + data->_heapBackward->Size() > 0 ) {
|
||||
if ( data->_heapForward->Size() > 0 ) {
|
||||
_ComputeStep( data->_heapForward, data->_heapBackward, true, &middle, &targetDistance );
|
||||
}
|
||||
|
||||
if ( data->_heapBackward->Size() > 0 ) {
|
||||
_ComputeStep( data->_heapBackward, data->_heapForward, false, &middle, &targetDistance );
|
||||
}
|
||||
}
|
||||
return targetDistance;
|
||||
}
|
||||
NodeID _numNodes;
|
||||
std::vector< Edge > _graph;
|
||||
std::vector< unsigned > _firstEdge;
|
||||
};
|
||||
|
||||
#endif // CONTRACTIONCLEANUP_H_INCLUDED
|
||||
@@ -1,760 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef CONTRACTOR_H_INCLUDED
|
||||
#define CONTRACTOR_H_INCLUDED
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
#include <cfloat>
|
||||
#include <ctime>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "TemporaryStorage.h"
|
||||
#include "../DataStructures/BinaryHeap.h"
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
#include "../DataStructures/DynamicGraph.h"
|
||||
#include "../DataStructures/Percent.h"
|
||||
#include "../DataStructures/XORFastHash.h"
|
||||
#include "../DataStructures/XORFastHashStorage.h"
|
||||
#include "../Util/OpenMPWrapper.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
class Contractor {
|
||||
|
||||
private:
|
||||
struct _ContractorEdgeData {
|
||||
_ContractorEdgeData() :
|
||||
distance(0), id(0), originalEdges(0), shortcut(0), forward(0), backward(0), originalViaNodeID(false) {}
|
||||
_ContractorEdgeData( unsigned _distance, unsigned _originalEdges, unsigned _id, bool _shortcut, bool _forward, bool _backward) :
|
||||
distance(_distance), id(_id), originalEdges(std::min((unsigned)1<<28, _originalEdges) ), shortcut(_shortcut), forward(_forward), backward(_backward), originalViaNodeID(false) {}
|
||||
unsigned distance;
|
||||
unsigned id;
|
||||
unsigned originalEdges:28;
|
||||
bool shortcut:1;
|
||||
bool forward:1;
|
||||
bool backward:1;
|
||||
bool originalViaNodeID:1;
|
||||
} data;
|
||||
|
||||
struct _HeapData {
|
||||
short hop;
|
||||
bool target;
|
||||
_HeapData() : hop(0), target(false) {}
|
||||
_HeapData( short h, bool t ) : hop(h), target(t) {}
|
||||
};
|
||||
|
||||
typedef DynamicGraph< _ContractorEdgeData > _DynamicGraph;
|
||||
// typedef BinaryHeap< NodeID, NodeID, int, _HeapData, ArrayStorage<NodeID, NodeID> > _Heap;
|
||||
typedef BinaryHeap< NodeID, NodeID, int, _HeapData, XORFastHashStorage<NodeID, NodeID> > _Heap;
|
||||
typedef _DynamicGraph::InputEdge _ContractorEdge;
|
||||
|
||||
struct _ThreadData {
|
||||
_Heap heap;
|
||||
std::vector< _ContractorEdge > insertedEdges;
|
||||
std::vector< NodeID > neighbours;
|
||||
_ThreadData( NodeID nodes ): heap( nodes ) { }
|
||||
};
|
||||
|
||||
struct _PriorityData {
|
||||
int depth;
|
||||
_PriorityData() : depth(0) { }
|
||||
};
|
||||
|
||||
struct _ContractionInformation {
|
||||
int edgesDeleted;
|
||||
int edgesAdded;
|
||||
int originalEdgesDeleted;
|
||||
int originalEdgesAdded;
|
||||
_ContractionInformation() : edgesDeleted(0), edgesAdded(0), originalEdgesDeleted(0), originalEdgesAdded(0) {}
|
||||
};
|
||||
|
||||
struct _RemainingNodeData {
|
||||
_RemainingNodeData() : id (0), isIndependent(false) {}
|
||||
NodeID id:31;
|
||||
bool isIndependent:1;
|
||||
};
|
||||
|
||||
struct _NodePartitionor {
|
||||
inline bool operator()(_RemainingNodeData & nodeData ) const {
|
||||
return !nodeData.isIndependent;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
template<class ContainerT >
|
||||
Contractor( int nodes, ContainerT& inputEdges) {
|
||||
std::vector< _ContractorEdge > edges;
|
||||
edges.reserve(inputEdges.size()*2);
|
||||
|
||||
typename ContainerT::deallocation_iterator diter = inputEdges.dbegin();
|
||||
typename ContainerT::deallocation_iterator dend = inputEdges.dend();
|
||||
|
||||
_ContractorEdge newEdge;
|
||||
while(diter!=dend) {
|
||||
newEdge.source = diter->source();
|
||||
newEdge.target = diter->target();
|
||||
newEdge.data = _ContractorEdgeData( (std::max)((int)diter->weight(), 1 ), 1, diter->id(), false, diter->isForward(), diter->isBackward());
|
||||
|
||||
assert( newEdge.data.distance > 0 );
|
||||
#ifndef NDEBUG
|
||||
if ( newEdge.data.distance > 24 * 60 * 60 * 10 ) {
|
||||
WARN("Edge weight large -> " << newEdge.data.distance);
|
||||
}
|
||||
#endif
|
||||
edges.push_back( newEdge );
|
||||
std::swap( newEdge.source, newEdge.target );
|
||||
newEdge.data.forward = diter->isBackward();
|
||||
newEdge.data.backward = diter->isForward();
|
||||
edges.push_back( newEdge );
|
||||
++diter;
|
||||
}
|
||||
//clear input vector and trim the current set of edges with the well-known swap trick
|
||||
inputEdges.clear();
|
||||
sort( edges.begin(), edges.end() );
|
||||
NodeID edge = 0;
|
||||
for ( NodeID i = 0; i < edges.size(); ) {
|
||||
const NodeID source = edges[i].source;
|
||||
const NodeID target = edges[i].target;
|
||||
const NodeID id = edges[i].data.id;
|
||||
//remove eigenloops
|
||||
if ( source == target ) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
_ContractorEdge forwardEdge;
|
||||
_ContractorEdge backwardEdge;
|
||||
forwardEdge.source = backwardEdge.source = source;
|
||||
forwardEdge.target = backwardEdge.target = target;
|
||||
forwardEdge.data.forward = backwardEdge.data.backward = true;
|
||||
forwardEdge.data.backward = backwardEdge.data.forward = false;
|
||||
forwardEdge.data.shortcut = backwardEdge.data.shortcut = false;
|
||||
forwardEdge.data.id = backwardEdge.data.id = id;
|
||||
forwardEdge.data.originalEdges = backwardEdge.data.originalEdges = 1;
|
||||
forwardEdge.data.distance = backwardEdge.data.distance = std::numeric_limits< int >::max();
|
||||
//remove parallel edges
|
||||
while ( i < edges.size() && edges[i].source == source && edges[i].target == target ) {
|
||||
if ( edges[i].data.forward )
|
||||
forwardEdge.data.distance = std::min( edges[i].data.distance, forwardEdge.data.distance );
|
||||
if ( edges[i].data.backward )
|
||||
backwardEdge.data.distance = std::min( edges[i].data.distance, backwardEdge.data.distance );
|
||||
i++;
|
||||
}
|
||||
//merge edges (s,t) and (t,s) into bidirectional edge
|
||||
if ( forwardEdge.data.distance == backwardEdge.data.distance ) {
|
||||
if ( (int)forwardEdge.data.distance != std::numeric_limits< int >::max() ) {
|
||||
forwardEdge.data.backward = true;
|
||||
edges[edge++] = forwardEdge;
|
||||
}
|
||||
} else { //insert seperate edges
|
||||
if ( ((int)forwardEdge.data.distance) != std::numeric_limits< int >::max() ) {
|
||||
edges[edge++] = forwardEdge;
|
||||
}
|
||||
if ( (int)backwardEdge.data.distance != std::numeric_limits< int >::max() ) {
|
||||
edges[edge++] = backwardEdge;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << "merged " << edges.size() - edge << " edges out of " << edges.size() << std::endl;
|
||||
edges.resize( edge );
|
||||
_graph = boost::make_shared<_DynamicGraph>( nodes, edges );
|
||||
edges.clear();
|
||||
std::vector<_ContractorEdge>().swap(edges);
|
||||
// unsigned maxdegree = 0;
|
||||
// NodeID highestNode = 0;
|
||||
//
|
||||
// for(unsigned i = 0; i < _graph->GetNumberOfNodes(); ++i) {
|
||||
// unsigned degree = _graph->EndEdges(i) - _graph->BeginEdges(i);
|
||||
// if(degree > maxdegree) {
|
||||
// maxdegree = degree;
|
||||
// highestNode = i;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// INFO("edges at node with id " << highestNode << " has degree " << maxdegree);
|
||||
// for(unsigned i = _graph->BeginEdges(highestNode); i < _graph->EndEdges(highestNode); ++i) {
|
||||
// INFO(" ->(" << highestNode << "," << _graph->GetTarget(i) << "); via: " << _graph->GetEdgeData(i).via);
|
||||
// }
|
||||
|
||||
//Create temporary file
|
||||
|
||||
// GetTemporaryFileName(temporaryEdgeStorageFilename);
|
||||
temporaryStorageSlotID = TemporaryStorage::GetInstance().allocateSlot();
|
||||
std::cout << "contractor finished initalization" << std::endl;
|
||||
}
|
||||
|
||||
~Contractor() {
|
||||
//Delete temporary file
|
||||
// remove(temporaryEdgeStorageFilename.c_str());
|
||||
TemporaryStorage::GetInstance().deallocateSlot(temporaryStorageSlotID);
|
||||
}
|
||||
|
||||
void Run() {
|
||||
const NodeID numberOfNodes = _graph->GetNumberOfNodes();
|
||||
Percent p (numberOfNodes);
|
||||
|
||||
const unsigned maxThreads = omp_get_max_threads();
|
||||
std::vector < _ThreadData* > threadData;
|
||||
for ( unsigned threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
||||
threadData.push_back( new _ThreadData( numberOfNodes ) );
|
||||
}
|
||||
std::cout << "Contractor is using " << maxThreads << " threads" << std::endl;
|
||||
|
||||
NodeID numberOfContractedNodes = 0;
|
||||
std::vector< _RemainingNodeData > remainingNodes( numberOfNodes );
|
||||
std::vector< float > nodePriority( numberOfNodes );
|
||||
std::vector< _PriorityData > nodeData( numberOfNodes );
|
||||
|
||||
//initialize the variables
|
||||
#pragma omp parallel for schedule ( guided )
|
||||
for ( int x = 0; x < ( int ) numberOfNodes; ++x )
|
||||
remainingNodes[x].id = x;
|
||||
|
||||
std::cout << "initializing elimination PQ ..." << std::flush;
|
||||
#pragma omp parallel
|
||||
{
|
||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||
#pragma omp parallel for schedule ( guided )
|
||||
for ( int x = 0; x < ( int ) numberOfNodes; ++x ) {
|
||||
nodePriority[x] = _Evaluate( data, &nodeData[x], x );
|
||||
}
|
||||
}
|
||||
std::cout << "ok" << std::endl << "preprocessing ..." << std::flush;
|
||||
|
||||
bool flushedContractor = false;
|
||||
while ( numberOfContractedNodes < numberOfNodes ) {
|
||||
if(!flushedContractor && (numberOfContractedNodes > (numberOfNodes*0.65) ) ){
|
||||
DeallocatingVector<_ContractorEdge> newSetOfEdges; //this one is not explicitely cleared since it goes out of scope anywa
|
||||
std::cout << " [flush " << numberOfContractedNodes << " nodes] " << std::flush;
|
||||
|
||||
//Delete old heap data to free memory that we need for the coming operations
|
||||
BOOST_FOREACH(_ThreadData * data, threadData)
|
||||
delete data;
|
||||
threadData.clear();
|
||||
|
||||
|
||||
//Create new priority array
|
||||
std::vector<float> newNodePriority(remainingNodes.size());
|
||||
//this map gives the old IDs from the new ones, necessary to get a consistent graph at the end of contraction
|
||||
oldNodeIDFromNewNodeIDMap.resize(remainingNodes.size());
|
||||
//this map gives the new IDs from the old ones, necessary to remap targets from the remaining graph
|
||||
std::vector<NodeID> newNodeIDFromOldNodeIDMap(numberOfNodes, UINT_MAX);
|
||||
|
||||
//build forward and backward renumbering map and remap ids in remainingNodes and Priorities.
|
||||
for(unsigned newNodeID = 0; newNodeID < remainingNodes.size(); ++newNodeID) {
|
||||
//create renumbering maps in both directions
|
||||
oldNodeIDFromNewNodeIDMap[newNodeID] = remainingNodes[newNodeID].id;
|
||||
newNodeIDFromOldNodeIDMap[remainingNodes[newNodeID].id] = newNodeID;
|
||||
newNodePriority[newNodeID] = nodePriority[remainingNodes[newNodeID].id];
|
||||
remainingNodes[newNodeID].id = newNodeID;
|
||||
}
|
||||
TemporaryStorage & tempStorage = TemporaryStorage::GetInstance();
|
||||
//Write dummy number of edges to temporary file
|
||||
// std::ofstream temporaryEdgeStorage(temporaryEdgeStorageFilename.c_str(), std::ios::binary);
|
||||
long initialFilePosition = tempStorage.tell(temporaryStorageSlotID);
|
||||
unsigned numberOfTemporaryEdges = 0;
|
||||
tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&numberOfTemporaryEdges, sizeof(unsigned));
|
||||
|
||||
//walk over all nodes
|
||||
for(unsigned i = 0; i < _graph->GetNumberOfNodes(); ++i) {
|
||||
//INFO("Restructuring node " << i << "|" << _graph->GetNumberOfNodes());
|
||||
const NodeID start = i;
|
||||
for(_DynamicGraph::EdgeIterator currentEdge = _graph->BeginEdges(start); currentEdge < _graph->EndEdges(start); ++currentEdge) {
|
||||
_DynamicGraph::EdgeData & data = _graph->GetEdgeData(currentEdge);
|
||||
const NodeID target = _graph->GetTarget(currentEdge);
|
||||
if(UINT_MAX == newNodeIDFromOldNodeIDMap[i] ){
|
||||
//Save edges of this node w/o renumbering.
|
||||
tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&start, sizeof(NodeID));
|
||||
tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&target, sizeof(NodeID));
|
||||
tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&data, sizeof(_DynamicGraph::EdgeData));
|
||||
++numberOfTemporaryEdges;
|
||||
}else {
|
||||
//node is not yet contracted.
|
||||
//add (renumbered) outgoing edges to new DynamicGraph.
|
||||
_ContractorEdge newEdge;
|
||||
newEdge.source = newNodeIDFromOldNodeIDMap[start];
|
||||
newEdge.target = newNodeIDFromOldNodeIDMap[target];
|
||||
newEdge.data = data;
|
||||
newEdge.data.originalViaNodeID = true;
|
||||
assert(UINT_MAX != newNodeIDFromOldNodeIDMap[start] );
|
||||
assert(UINT_MAX != newNodeIDFromOldNodeIDMap[target]);
|
||||
newSetOfEdges.push_back(newEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Note the number of temporarily stored edges
|
||||
tempStorage.seek(temporaryStorageSlotID, initialFilePosition);
|
||||
tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&numberOfTemporaryEdges, sizeof(unsigned));
|
||||
|
||||
// INFO("Flushed " << numberOfTemporaryEdges << " edges to disk");
|
||||
|
||||
//Delete map from old NodeIDs to new ones.
|
||||
std::vector<NodeID>().swap(newNodeIDFromOldNodeIDMap);
|
||||
|
||||
//Replace old priorities array by new one
|
||||
nodePriority.swap(newNodePriority);
|
||||
//Delete old nodePriority vector
|
||||
std::vector<float>().swap(newNodePriority);
|
||||
//old Graph is removed
|
||||
_graph.reset();
|
||||
|
||||
//create new graph
|
||||
std::sort(newSetOfEdges.begin(), newSetOfEdges.end());
|
||||
_graph = boost::make_shared<_DynamicGraph>(remainingNodes.size(), newSetOfEdges);
|
||||
|
||||
newSetOfEdges.clear();
|
||||
flushedContractor = true;
|
||||
|
||||
//INFO: MAKE SURE THIS IS THE LAST OPERATION OF THE FLUSH!
|
||||
//reinitialize heaps and ThreadData objects with appropriate size
|
||||
for ( unsigned threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
||||
threadData.push_back( new _ThreadData( _graph->GetNumberOfNodes() ) );
|
||||
}
|
||||
}
|
||||
|
||||
const int last = ( int ) remainingNodes.size();
|
||||
#pragma omp parallel
|
||||
{
|
||||
//determine independent node set
|
||||
_ThreadData* const data = threadData[omp_get_thread_num()];
|
||||
#pragma omp for schedule ( guided )
|
||||
for ( int i = 0; i < last; ++i ) {
|
||||
const NodeID node = remainingNodes[i].id;
|
||||
remainingNodes[i].isIndependent = _IsIndependent( nodePriority/*, nodeData*/, data, node );
|
||||
}
|
||||
}
|
||||
_NodePartitionor functor;
|
||||
const std::vector < _RemainingNodeData >::const_iterator first = stable_partition( remainingNodes.begin(), remainingNodes.end(), functor );
|
||||
const int firstIndependent = first - remainingNodes.begin();
|
||||
//contract independent nodes
|
||||
#pragma omp parallel
|
||||
{
|
||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||
#pragma omp for schedule ( guided ) nowait
|
||||
for ( int position = firstIndependent ; position < last; ++position ) {
|
||||
NodeID x = remainingNodes[position].id;
|
||||
_Contract< false > ( data, x );
|
||||
//nodePriority[x] = -1;
|
||||
}
|
||||
|
||||
std::sort( data->insertedEdges.begin(), data->insertedEdges.end() );
|
||||
}
|
||||
#pragma omp parallel
|
||||
{
|
||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||
#pragma omp for schedule ( guided ) nowait
|
||||
for ( int position = firstIndependent ; position < last; ++position ) {
|
||||
NodeID x = remainingNodes[position].id;
|
||||
_DeleteIncomingEdges( data, x );
|
||||
}
|
||||
}
|
||||
//insert new edges
|
||||
for ( unsigned threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
||||
_ThreadData& data = *threadData[threadNum];
|
||||
BOOST_FOREACH(const _ContractorEdge& edge, data.insertedEdges) {
|
||||
_DynamicGraph::EdgeIterator currentEdgeID = _graph->FindEdge(edge.source, edge.target);
|
||||
if(currentEdgeID < _graph->EndEdges(edge.source) ) {
|
||||
_DynamicGraph::EdgeData & currentEdgeData = _graph->GetEdgeData(currentEdgeID);
|
||||
if( currentEdgeData.shortcut
|
||||
&& edge.data.forward == currentEdgeData.forward
|
||||
&& edge.data.backward == currentEdgeData.backward ) {
|
||||
currentEdgeData.distance = std::min(currentEdgeData.distance, edge.data.distance);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_graph->InsertEdge( edge.source, edge.target, edge.data );
|
||||
}
|
||||
data.insertedEdges.clear();
|
||||
}
|
||||
//update priorities
|
||||
#pragma omp parallel
|
||||
{
|
||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||
#pragma omp for schedule ( guided ) nowait
|
||||
for ( int position = firstIndependent ; position < last; ++position ) {
|
||||
NodeID x = remainingNodes[position].id;
|
||||
_UpdateNeighbours( nodePriority, nodeData, data, x );
|
||||
}
|
||||
}
|
||||
//remove contracted nodes from the pool
|
||||
numberOfContractedNodes += last - firstIndependent;
|
||||
remainingNodes.resize( firstIndependent );
|
||||
std::vector< _RemainingNodeData>( remainingNodes ).swap( remainingNodes );
|
||||
// unsigned maxdegree = 0;
|
||||
// unsigned avgdegree = 0;
|
||||
// unsigned mindegree = UINT_MAX;
|
||||
// unsigned quaddegree = 0;
|
||||
//
|
||||
// for(unsigned i = 0; i < remainingNodes.size(); ++i) {
|
||||
// unsigned degree = _graph->EndEdges(remainingNodes[i].first) - _graph->BeginEdges(remainingNodes[i].first);
|
||||
// if(degree > maxdegree)
|
||||
// maxdegree = degree;
|
||||
// if(degree < mindegree)
|
||||
// mindegree = degree;
|
||||
//
|
||||
// avgdegree += degree;
|
||||
// quaddegree += (degree*degree);
|
||||
// }
|
||||
//
|
||||
// avgdegree /= std::max((unsigned)1,(unsigned)remainingNodes.size() );
|
||||
// quaddegree /= std::max((unsigned)1,(unsigned)remainingNodes.size() );
|
||||
//
|
||||
// INFO("rest: " << remainingNodes.size() << ", max: " << maxdegree << ", min: " << mindegree << ", avg: " << avgdegree << ", quad: " << quaddegree);
|
||||
|
||||
p.printStatus(numberOfContractedNodes);
|
||||
}
|
||||
BOOST_FOREACH(_ThreadData * data, threadData)
|
||||
delete data;
|
||||
threadData.clear();
|
||||
}
|
||||
|
||||
template< class Edge >
|
||||
inline void GetEdges( DeallocatingVector< Edge >& edges ) {
|
||||
Percent p (_graph->GetNumberOfNodes());
|
||||
INFO("Getting edges of minimized graph");
|
||||
NodeID numberOfNodes = _graph->GetNumberOfNodes();
|
||||
if(oldNodeIDFromNewNodeIDMap.size()) {
|
||||
for ( NodeID node = 0; node < numberOfNodes; ++node ) {
|
||||
p.printStatus(node);
|
||||
for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge < endEdges; ++edge ) {
|
||||
const NodeID target = _graph->GetTarget( edge );
|
||||
const _DynamicGraph::EdgeData& data = _graph->GetEdgeData( edge );
|
||||
Edge newEdge;
|
||||
newEdge.source = oldNodeIDFromNewNodeIDMap[node];
|
||||
newEdge.target = oldNodeIDFromNewNodeIDMap[target];
|
||||
assert(UINT_MAX != newEdge.source);
|
||||
assert(UINT_MAX != newEdge.target);
|
||||
|
||||
newEdge.data.distance = data.distance;
|
||||
newEdge.data.shortcut = data.shortcut;
|
||||
if(!data.originalViaNodeID)
|
||||
newEdge.data.id = oldNodeIDFromNewNodeIDMap[data.id];
|
||||
else
|
||||
newEdge.data.id = data.id;
|
||||
|
||||
assert(newEdge.data.id != UINT_MAX);
|
||||
newEdge.data.forward = data.forward;
|
||||
newEdge.data.backward = data.backward;
|
||||
edges.push_back( newEdge );
|
||||
}
|
||||
}
|
||||
}
|
||||
INFO("Renumbered edges of minimized graph, freeing space");
|
||||
_graph.reset();
|
||||
std::vector<NodeID>().swap(oldNodeIDFromNewNodeIDMap);
|
||||
INFO("Loading temporary edges");
|
||||
|
||||
// std::ifstream temporaryEdgeStorage(temporaryEdgeStorageFilename.c_str(), std::ios::binary);
|
||||
TemporaryStorage & tempStorage = TemporaryStorage::GetInstance();
|
||||
//Also get the edges from temporary storage
|
||||
unsigned numberOfTemporaryEdges = 0;
|
||||
tempStorage.readFromSlot(temporaryStorageSlotID, (char*)&numberOfTemporaryEdges, sizeof(unsigned));
|
||||
//loads edges of graph before renumbering, no need for further numbering action.
|
||||
NodeID start;
|
||||
NodeID target;
|
||||
//edges.reserve(edges.size()+numberOfTemporaryEdges);
|
||||
_DynamicGraph::EdgeData data;
|
||||
for(unsigned i = 0; i < numberOfTemporaryEdges; ++i) {
|
||||
tempStorage.readFromSlot(temporaryStorageSlotID, (char*)&start, sizeof(NodeID));
|
||||
tempStorage.readFromSlot(temporaryStorageSlotID, (char*)&target, sizeof(NodeID));
|
||||
tempStorage.readFromSlot(temporaryStorageSlotID, (char*)&data, sizeof(_DynamicGraph::EdgeData));
|
||||
Edge newEdge;
|
||||
newEdge.source = start;
|
||||
newEdge.target = target;
|
||||
newEdge.data.distance = data.distance;
|
||||
newEdge.data.shortcut = data.shortcut;
|
||||
newEdge.data.id = data.id;
|
||||
newEdge.data.forward = data.forward;
|
||||
newEdge.data.backward = data.backward;
|
||||
edges.push_back( newEdge );
|
||||
}
|
||||
tempStorage.deallocateSlot(temporaryStorageSlotID);
|
||||
INFO("Hierarchy has " << edges.size() << " edges");
|
||||
}
|
||||
|
||||
private:
|
||||
inline void _Dijkstra( const int maxDistance, const unsigned numTargets, const int maxNodes, _ThreadData* const data, const NodeID middleNode ){
|
||||
|
||||
_Heap& heap = data->heap;
|
||||
|
||||
int nodes = 0;
|
||||
unsigned targetsFound = 0;
|
||||
while ( heap.Size() > 0 ) {
|
||||
const NodeID node = heap.DeleteMin();
|
||||
const int distance = heap.GetKey( node );
|
||||
const short currentHop = heap.GetData( node ).hop+1;
|
||||
|
||||
if ( ++nodes > maxNodes )
|
||||
return;
|
||||
//Destination settled?
|
||||
if ( distance > maxDistance )
|
||||
return;
|
||||
|
||||
if ( heap.GetData( node ).target ) {
|
||||
++targetsFound;
|
||||
if ( targetsFound >= numTargets )
|
||||
return;
|
||||
}
|
||||
|
||||
//iterate over all edges of node
|
||||
for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge != endEdges; ++edge ) {
|
||||
const _ContractorEdgeData& data = _graph->GetEdgeData( edge );
|
||||
if ( !data.forward )
|
||||
continue;
|
||||
const NodeID to = _graph->GetTarget( edge );
|
||||
if(middleNode == to)
|
||||
continue;
|
||||
const int toDistance = distance + data.distance;
|
||||
|
||||
//New Node discovered -> Add to Heap + Node Info Storage
|
||||
if ( !heap.WasInserted( to ) )
|
||||
heap.Insert( to, toDistance, _HeapData(currentHop, false) );
|
||||
|
||||
//Found a shorter Path -> Update distance
|
||||
else if ( toDistance < heap.GetKey( to ) ) {
|
||||
heap.DecreaseKey( to, toDistance );
|
||||
heap.GetData( to ).hop = currentHop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline float _Evaluate( _ThreadData* const data, _PriorityData* const nodeData, const NodeID node){
|
||||
_ContractionInformation stats;
|
||||
|
||||
//perform simulated contraction
|
||||
_Contract< true> ( data, node, &stats );
|
||||
|
||||
// Result will contain the priority
|
||||
float result;
|
||||
if ( 0 == (stats.edgesDeleted*stats.originalEdgesDeleted) )
|
||||
result = 1 * nodeData->depth;
|
||||
else
|
||||
result = 2 * ((( float ) stats.edgesAdded ) / stats.edgesDeleted ) + 4 * ((( float ) stats.originalEdgesAdded ) / stats.originalEdgesDeleted ) + 1 * nodeData->depth;
|
||||
assert( result >= 0 );
|
||||
return result;
|
||||
}
|
||||
|
||||
template< bool Simulate >
|
||||
inline bool _Contract( _ThreadData* data, NodeID node, _ContractionInformation* stats = NULL ) {
|
||||
_Heap& heap = data->heap;
|
||||
int insertedEdgesSize = data->insertedEdges.size();
|
||||
std::vector< _ContractorEdge >& insertedEdges = data->insertedEdges;
|
||||
|
||||
for ( _DynamicGraph::EdgeIterator inEdge = _graph->BeginEdges( node ), endInEdges = _graph->EndEdges( node ); inEdge != endInEdges; ++inEdge ) {
|
||||
const _ContractorEdgeData& inData = _graph->GetEdgeData( inEdge );
|
||||
const NodeID source = _graph->GetTarget( inEdge );
|
||||
if ( Simulate ) {
|
||||
assert( stats != NULL );
|
||||
++stats->edgesDeleted;
|
||||
stats->originalEdgesDeleted += inData.originalEdges;
|
||||
}
|
||||
if ( !inData.backward )
|
||||
continue;
|
||||
|
||||
heap.Clear();
|
||||
heap.Insert( source, 0, _HeapData() );
|
||||
int maxDistance = 0;
|
||||
unsigned numTargets = 0;
|
||||
|
||||
for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) {
|
||||
const _ContractorEdgeData& outData = _graph->GetEdgeData( outEdge );
|
||||
if ( !outData.forward )
|
||||
continue;
|
||||
const NodeID target = _graph->GetTarget( outEdge );
|
||||
const int pathDistance = inData.distance + outData.distance;
|
||||
maxDistance = std::max( maxDistance, pathDistance );
|
||||
if ( !heap.WasInserted( target ) ) {
|
||||
heap.Insert( target, INT_MAX, _HeapData( 0, true ) );
|
||||
++numTargets;
|
||||
}
|
||||
}
|
||||
|
||||
if( Simulate )
|
||||
_Dijkstra( maxDistance, numTargets, 1000, data, node );
|
||||
else
|
||||
_Dijkstra( maxDistance, numTargets, 2000, data, node );
|
||||
|
||||
for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) {
|
||||
const _ContractorEdgeData& outData = _graph->GetEdgeData( outEdge );
|
||||
if ( !outData.forward )
|
||||
continue;
|
||||
const NodeID target = _graph->GetTarget( outEdge );
|
||||
const int pathDistance = inData.distance + outData.distance;
|
||||
const int distance = heap.GetKey( target );
|
||||
if ( pathDistance < distance ) {
|
||||
if ( Simulate ) {
|
||||
assert( stats != NULL );
|
||||
stats->edgesAdded+=2;
|
||||
stats->originalEdgesAdded += 2* ( outData.originalEdges + inData.originalEdges );
|
||||
} else {
|
||||
_ContractorEdge newEdge;
|
||||
newEdge.source = source;
|
||||
newEdge.target = target;
|
||||
newEdge.data = _ContractorEdgeData( pathDistance, outData.originalEdges + inData.originalEdges, node/*, 0, inData.turnInstruction*/, true, true, false);;
|
||||
insertedEdges.push_back( newEdge );
|
||||
std::swap( newEdge.source, newEdge.target );
|
||||
newEdge.data.forward = false;
|
||||
newEdge.data.backward = true;
|
||||
insertedEdges.push_back( newEdge );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !Simulate ) {
|
||||
for ( int i = insertedEdgesSize, iend = insertedEdges.size(); i < iend; ++i ) {
|
||||
bool found = false;
|
||||
for ( int other = i + 1 ; other < iend ; ++other ) {
|
||||
if ( insertedEdges[other].source != insertedEdges[i].source )
|
||||
continue;
|
||||
if ( insertedEdges[other].target != insertedEdges[i].target )
|
||||
continue;
|
||||
if ( insertedEdges[other].data.distance != insertedEdges[i].data.distance )
|
||||
continue;
|
||||
if ( insertedEdges[other].data.shortcut != insertedEdges[i].data.shortcut )
|
||||
continue;
|
||||
insertedEdges[other].data.forward |= insertedEdges[i].data.forward;
|
||||
insertedEdges[other].data.backward |= insertedEdges[i].data.backward;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if ( !found )
|
||||
insertedEdges[insertedEdgesSize++] = insertedEdges[i];
|
||||
}
|
||||
insertedEdges.resize( insertedEdgesSize );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void _DeleteIncomingEdges( _ThreadData* data, const NodeID node ) {
|
||||
std::vector< NodeID >& neighbours = data->neighbours;
|
||||
neighbours.clear();
|
||||
|
||||
//find all neighbours
|
||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ) ; e < _graph->EndEdges( node ) ; ++e ) {
|
||||
const NodeID u = _graph->GetTarget( e );
|
||||
if ( u != node )
|
||||
neighbours.push_back( u );
|
||||
}
|
||||
//eliminate duplicate entries ( forward + backward edges )
|
||||
std::sort( neighbours.begin(), neighbours.end() );
|
||||
neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
|
||||
|
||||
for ( int i = 0, e = ( int ) neighbours.size(); i < e; ++i ) {
|
||||
_graph->DeleteEdgesTo( neighbours[i], node );
|
||||
}
|
||||
}
|
||||
|
||||
inline bool _UpdateNeighbours( std::vector< float > & priorities, std::vector< _PriorityData > & nodeData, _ThreadData* const data, const NodeID node) {
|
||||
std::vector< NodeID >& neighbours = data->neighbours;
|
||||
neighbours.clear();
|
||||
|
||||
//find all neighbours
|
||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ) ; e < endEdges ; ++e ) {
|
||||
const NodeID u = _graph->GetTarget( e );
|
||||
if ( u == node )
|
||||
continue;
|
||||
neighbours.push_back( u );
|
||||
nodeData[u].depth = (std::max)(nodeData[node].depth + 1, nodeData[u].depth );
|
||||
}
|
||||
//eliminate duplicate entries ( forward + backward edges )
|
||||
std::sort( neighbours.begin(), neighbours.end() );
|
||||
neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
|
||||
|
||||
BOOST_FOREACH(const NodeID u, neighbours) {
|
||||
priorities[u] = _Evaluate( data, &( nodeData )[u], u );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool _IsIndependent( const std::vector< float >& priorities/*, const std::vector< _PriorityData >& nodeData*/, _ThreadData* const data, NodeID node ) const {
|
||||
const double priority = priorities[node];
|
||||
|
||||
std::vector< NodeID >& neighbours = data->neighbours;
|
||||
neighbours.clear();
|
||||
|
||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ) ; e < _graph->EndEdges( node ) ; ++e ) {
|
||||
const NodeID target = _graph->GetTarget( e );
|
||||
if(node==target)
|
||||
continue;
|
||||
const double targetPriority = priorities[target];
|
||||
assert( targetPriority >= 0 );
|
||||
//found a neighbour with lower priority?
|
||||
if ( priority > targetPriority )
|
||||
return false;
|
||||
//tie breaking
|
||||
if ( fabs(priority - targetPriority) < FLT_EPSILON && bias(node, target) ) {
|
||||
return false;
|
||||
}
|
||||
neighbours.push_back( target );
|
||||
}
|
||||
|
||||
std::sort( neighbours.begin(), neighbours.end() );
|
||||
neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
|
||||
|
||||
//examine all neighbours that are at most 2 hops away
|
||||
BOOST_FOREACH(const NodeID u, neighbours) {
|
||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( u ) ; e < _graph->EndEdges( u ) ; ++e ) {
|
||||
const NodeID target = _graph->GetTarget( e );
|
||||
if(node==target)
|
||||
continue;
|
||||
|
||||
const double targetPriority = priorities[target];
|
||||
assert( targetPriority >= 0 );
|
||||
//found a neighbour with lower priority?
|
||||
if ( priority > targetPriority)
|
||||
return false;
|
||||
//tie breaking
|
||||
if ( fabs(priority - targetPriority) < FLT_EPSILON && bias(node, target) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This bias function takes up 22 assembly instructions in total on X86
|
||||
*/
|
||||
inline bool bias(const NodeID a, const NodeID b) const {
|
||||
unsigned short hasha = fastHash(a);
|
||||
unsigned short hashb = fastHash(b);
|
||||
|
||||
//The compiler optimizes that to conditional register flags but without branching statements!
|
||||
if(hasha != hashb)
|
||||
return hasha < hashb;
|
||||
return a < b;
|
||||
}
|
||||
|
||||
boost::shared_ptr<_DynamicGraph> _graph;
|
||||
std::vector<_DynamicGraph::InputEdge> contractedEdges;
|
||||
unsigned temporaryStorageSlotID;
|
||||
std::vector<NodeID> oldNodeIDFromNewNodeIDMap;
|
||||
XORFastHash fastHash;
|
||||
};
|
||||
|
||||
#endif // CONTRACTOR_H_INCLUDED
|
||||
@@ -1,391 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#include "EdgeBasedGraphFactory.h"
|
||||
|
||||
template<>
|
||||
EdgeBasedGraphFactory::EdgeBasedGraphFactory(int nodes, std::vector<NodeBasedEdge> & inputEdges, std::vector<NodeID> & bn, std::vector<NodeID> & tl, std::vector<_Restriction> & irs, std::vector<NodeInfo> & nI, SpeedProfileProperties sp) : inputNodeInfoList(nI), numberOfTurnRestrictions(irs.size()), speedProfile(sp) {
|
||||
BOOST_FOREACH(_Restriction & restriction, irs) {
|
||||
std::pair<NodeID, NodeID> restrictionSource = std::make_pair(restriction.fromNode, restriction.viaNode);
|
||||
unsigned index;
|
||||
RestrictionMap::iterator restrIter = _restrictionMap.find(restrictionSource);
|
||||
if(restrIter == _restrictionMap.end()) {
|
||||
index = _restrictionBucketVector.size();
|
||||
_restrictionBucketVector.resize(index+1);
|
||||
_restrictionMap[restrictionSource] = index;
|
||||
} else {
|
||||
index = restrIter->second;
|
||||
//Map already contains an is_only_*-restriction
|
||||
if(_restrictionBucketVector.at(index).begin()->second)
|
||||
continue;
|
||||
else if(restriction.flags.isOnly){
|
||||
//We are going to insert an is_only_*-restriction. There can be only one.
|
||||
_restrictionBucketVector.at(index).clear();
|
||||
}
|
||||
}
|
||||
|
||||
_restrictionBucketVector.at(index).push_back(std::make_pair(restriction.toNode, restriction.flags.isOnly));
|
||||
}
|
||||
|
||||
BOOST_FOREACH(NodeID id, bn) {
|
||||
_barrierNodes[id] = true;
|
||||
}
|
||||
BOOST_FOREACH(NodeID id, tl) {
|
||||
_trafficLights[id] = true;
|
||||
}
|
||||
|
||||
DeallocatingVector< _NodeBasedEdge > edges;
|
||||
// edges.reserve( 2 * inputEdges.size() );
|
||||
for ( std::vector< NodeBasedEdge >::const_iterator i = inputEdges.begin(); i != inputEdges.end(); ++i ) {
|
||||
|
||||
_NodeBasedEdge edge;
|
||||
if(!i->isForward()) {
|
||||
edge.source = i->target();
|
||||
edge.target = i->source();
|
||||
edge.data.backward = i->isForward();
|
||||
edge.data.forward = i->isBackward();
|
||||
} else {
|
||||
edge.source = i->source();
|
||||
edge.target = i->target();
|
||||
edge.data.forward = i->isForward();
|
||||
edge.data.backward = i->isBackward();
|
||||
}
|
||||
if(edge.source == edge.target)
|
||||
continue;
|
||||
|
||||
edge.data.distance = (std::max)((int)i->weight(), 1 );
|
||||
assert( edge.data.distance > 0 );
|
||||
edge.data.shortcut = false;
|
||||
edge.data.roundabout = i->isRoundabout();
|
||||
edge.data.ignoreInGrid = i->ignoreInGrid();
|
||||
edge.data.nameID = i->name();
|
||||
edge.data.type = i->type();
|
||||
edge.data.isAccessRestricted = i->isAccessRestricted();
|
||||
edge.data.edgeBasedNodeID = edges.size();
|
||||
edges.push_back( edge );
|
||||
if( edge.data.backward ) {
|
||||
std::swap( edge.source, edge.target );
|
||||
edge.data.forward = i->isBackward();
|
||||
edge.data.backward = i->isForward();
|
||||
edge.data.edgeBasedNodeID = edges.size();
|
||||
edges.push_back( edge );
|
||||
}
|
||||
}
|
||||
std::vector<NodeBasedEdge>().swap(inputEdges);
|
||||
std::sort( edges.begin(), edges.end() );
|
||||
_nodeBasedGraph = boost::make_shared<_NodeBasedDynamicGraph>( nodes, edges );
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::GetEdgeBasedEdges(DeallocatingVector< EdgeBasedEdge >& outputEdgeList ) {
|
||||
GUARANTEE(0 == outputEdgeList.size(), "Vector passed to EdgeBasedGraphFactory::GetEdgeBasedEdges(..) is not empty");
|
||||
edgeBasedEdges.swap(outputEdgeList);
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::GetEdgeBasedNodes( DeallocatingVector< EdgeBasedNode> & nodes) {
|
||||
#ifndef NDEBUG
|
||||
BOOST_FOREACH(EdgeBasedNode & node, edgeBasedNodes){
|
||||
assert(node.lat1 != INT_MAX); assert(node.lon1 != INT_MAX);
|
||||
assert(node.lat2 != INT_MAX); assert(node.lon2 != INT_MAX);
|
||||
}
|
||||
#endif
|
||||
nodes.swap(edgeBasedNodes);
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::GetOriginalEdgeData( std::vector< OriginalEdgeData> & oed) {
|
||||
oed.swap(originalEdgeData);
|
||||
}
|
||||
|
||||
NodeID EdgeBasedGraphFactory::CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const {
|
||||
std::pair < NodeID, NodeID > restrictionSource = std::make_pair(u, v);
|
||||
RestrictionMap::const_iterator restrIter = _restrictionMap.find(restrictionSource);
|
||||
if (restrIter != _restrictionMap.end()) {
|
||||
unsigned index = restrIter->second;
|
||||
BOOST_FOREACH(RestrictionSource restrictionTarget, _restrictionBucketVector.at(index)) {
|
||||
if(restrictionTarget.second) {
|
||||
return restrictionTarget.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
bool EdgeBasedGraphFactory::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 > restrictionSource = std::make_pair(u, v);
|
||||
RestrictionMap::const_iterator restrIter = _restrictionMap.find(restrictionSource);
|
||||
if (restrIter != _restrictionMap.end()) {
|
||||
unsigned index = restrIter->second;
|
||||
BOOST_FOREACH(RestrictionTarget restrictionTarget, _restrictionBucketVector.at(index)) {
|
||||
if(w == restrictionTarget.first)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::InsertEdgeBasedNode(
|
||||
_NodeBasedDynamicGraph::EdgeIterator e1,
|
||||
_NodeBasedDynamicGraph::NodeIterator u,
|
||||
_NodeBasedDynamicGraph::NodeIterator v,
|
||||
bool belongsToTinyComponent) {
|
||||
_NodeBasedDynamicGraph::EdgeData & data = _nodeBasedGraph->GetEdgeData(e1);
|
||||
EdgeBasedNode currentNode;
|
||||
currentNode.nameID = data.nameID;
|
||||
currentNode.lat1 = inputNodeInfoList[u].lat;
|
||||
currentNode.lon1 = inputNodeInfoList[u].lon;
|
||||
currentNode.lat2 = inputNodeInfoList[v].lat;
|
||||
currentNode.lon2 = inputNodeInfoList[v].lon;
|
||||
currentNode.belongsToTinyComponent = belongsToTinyComponent;
|
||||
currentNode.id = data.edgeBasedNodeID;
|
||||
currentNode.ignoreInGrid = data.ignoreInGrid;
|
||||
currentNode.weight = data.distance;
|
||||
edgeBasedNodes.push_back(currentNode);
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::Run(const char * originalEdgeDataFilename) {
|
||||
Percent p(_nodeBasedGraph->GetNumberOfNodes());
|
||||
int numberOfSkippedTurns(0);
|
||||
int nodeBasedEdgeCounter(0);
|
||||
unsigned numberOfOriginalEdges(0);
|
||||
std::ofstream originalEdgeDataOutFile(originalEdgeDataFilename, std::ios::binary);
|
||||
originalEdgeDataOutFile.write((char*)&numberOfOriginalEdges, sizeof(unsigned));
|
||||
|
||||
|
||||
INFO("Identifying small components");
|
||||
//Run a BFS on the undirected graph and identify small components
|
||||
std::queue<std::pair<NodeID, NodeID> > bfsQueue;
|
||||
std::vector<unsigned> componentsIndex(_nodeBasedGraph->GetNumberOfNodes(), UINT_MAX);
|
||||
std::vector<NodeID> vectorOfComponentSizes;
|
||||
unsigned currentComponent = 0, sizeOfCurrentComponent = 0;
|
||||
//put unexplorered node with parent pointer into queue
|
||||
for(NodeID node = 0, endNodes = _nodeBasedGraph->GetNumberOfNodes(); node < endNodes; ++node) {
|
||||
if(UINT_MAX == componentsIndex[node]) {
|
||||
bfsQueue.push(std::make_pair(node, node));
|
||||
//mark node as read
|
||||
componentsIndex[node] = currentComponent;
|
||||
p.printIncrement();
|
||||
while(!bfsQueue.empty()) {
|
||||
//fetch element from BFS queue
|
||||
std::pair<NodeID, NodeID> currentQueueItem = bfsQueue.front();
|
||||
bfsQueue.pop();
|
||||
// INFO("sizeof queue: " << bfsQueue.size() << ", sizeOfCurrentComponents: " << sizeOfCurrentComponent << ", settled nodes: " << settledNodes++ << ", max: " << endNodes);
|
||||
const NodeID v = currentQueueItem.first; //current node
|
||||
const NodeID u = currentQueueItem.second; //parent
|
||||
//increment size counter of current component
|
||||
++sizeOfCurrentComponent;
|
||||
const bool isBollardNode = (_barrierNodes.find(v) != _barrierNodes.end());
|
||||
if(!isBollardNode) {
|
||||
const NodeID onlyToNode = CheckForEmanatingIsOnlyTurn(u, v);
|
||||
|
||||
//relaxieren edge outgoing edge like below where edge-expanded graph
|
||||
for(_NodeBasedDynamicGraph::EdgeIterator e2 = _nodeBasedGraph->BeginEdges(v); e2 < _nodeBasedGraph->EndEdges(v); ++e2) {
|
||||
_NodeBasedDynamicGraph::NodeIterator w = _nodeBasedGraph->GetTarget(e2);
|
||||
|
||||
if(onlyToNode != UINT_MAX && w != onlyToNode) { //We are 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 it is the end of dead-end street.
|
||||
if (!CheckIfTurnIsRestricted(u, v, w) ) { //only add an edge if turn is not prohibited
|
||||
//insert next (node, parent) only if w has not yet been explored
|
||||
if(UINT_MAX == componentsIndex[w]) {
|
||||
//mark node as read
|
||||
componentsIndex[w] = currentComponent;
|
||||
bfsQueue.push(std::make_pair(w,v));
|
||||
p.printIncrement();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//push size into vector
|
||||
vectorOfComponentSizes.push_back(sizeOfCurrentComponent);
|
||||
//reset counters;
|
||||
sizeOfCurrentComponent = 0;
|
||||
++currentComponent;
|
||||
}
|
||||
}
|
||||
INFO("identified: " << vectorOfComponentSizes.size() << " many components");
|
||||
|
||||
p.reinit(_nodeBasedGraph->GetNumberOfNodes());
|
||||
//loop over all edges and generate new set of nodes.
|
||||
for(_NodeBasedDynamicGraph::NodeIterator u = 0; u < _nodeBasedGraph->GetNumberOfNodes(); ++u ) {
|
||||
for(_NodeBasedDynamicGraph::EdgeIterator e1 = _nodeBasedGraph->BeginEdges(u); e1 < _nodeBasedGraph->EndEdges(u); ++e1) {
|
||||
_NodeBasedDynamicGraph::NodeIterator v = _nodeBasedGraph->GetTarget(e1);
|
||||
|
||||
if(_nodeBasedGraph->GetEdgeData(e1).type != SHRT_MAX) {
|
||||
assert(e1 != UINT_MAX);
|
||||
assert(u != UINT_MAX);
|
||||
assert(v != UINT_MAX);
|
||||
//edges that end on bollard nodes may actually be in two distinct components
|
||||
InsertEdgeBasedNode(e1, u, v, (std::min(vectorOfComponentSizes[componentsIndex[u]], vectorOfComponentSizes[componentsIndex[v]]) < 1000) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<NodeID>().swap(vectorOfComponentSizes);
|
||||
std::vector<NodeID>().swap(componentsIndex);
|
||||
|
||||
//Loop over all turns and generate new set of edges.
|
||||
//Three nested loop look super-linear, but we are dealing with a linear number of turns only.
|
||||
for(_NodeBasedDynamicGraph::NodeIterator u = 0; u < _nodeBasedGraph->GetNumberOfNodes(); ++u ) {
|
||||
for(_NodeBasedDynamicGraph::EdgeIterator e1 = _nodeBasedGraph->BeginEdges(u); e1 < _nodeBasedGraph->EndEdges(u); ++e1) {
|
||||
++nodeBasedEdgeCounter;
|
||||
_NodeBasedDynamicGraph::NodeIterator v = _nodeBasedGraph->GetTarget(e1);
|
||||
//EdgeWeight heightPenalty = ComputeHeightPenalty(u, v);
|
||||
NodeID onlyToNode = CheckForEmanatingIsOnlyTurn(u, v);
|
||||
for(_NodeBasedDynamicGraph::EdgeIterator e2 = _nodeBasedGraph->BeginEdges(v); e2 < _nodeBasedGraph->EndEdges(v); ++e2) {
|
||||
const _NodeBasedDynamicGraph::NodeIterator w = _nodeBasedGraph->GetTarget(e2);
|
||||
|
||||
if(onlyToNode != UINT_MAX && w != onlyToNode) { //We are at an only_-restriction but not at the right turn.
|
||||
++numberOfSkippedTurns;
|
||||
continue;
|
||||
}
|
||||
bool isBollardNode = (_barrierNodes.find(v) != _barrierNodes.end());
|
||||
if(u == w && 1 != _nodeBasedGraph->GetOutDegree(v) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if( !isBollardNode ) { //only add an edge if turn is not a U-turn except it is the end of dead-end street.
|
||||
if (!CheckIfTurnIsRestricted(u, v, w) || (onlyToNode != UINT_MAX && w == onlyToNode)) { //only add an edge if turn is not prohibited
|
||||
const _NodeBasedDynamicGraph::EdgeData edgeData1 = _nodeBasedGraph->GetEdgeData(e1);
|
||||
const _NodeBasedDynamicGraph::EdgeData edgeData2 = _nodeBasedGraph->GetEdgeData(e2);
|
||||
assert(edgeData1.edgeBasedNodeID < _nodeBasedGraph->GetNumberOfEdges());
|
||||
assert(edgeData2.edgeBasedNodeID < _nodeBasedGraph->GetNumberOfEdges());
|
||||
|
||||
if(!edgeData1.forward || !edgeData2.forward) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned distance = edgeData1.distance;
|
||||
if(_trafficLights.find(v) != _trafficLights.end()) {
|
||||
distance += speedProfile.trafficSignalPenalty;
|
||||
}
|
||||
TurnInstruction turnInstruction = AnalyzeTurn(u, v, w);
|
||||
if(turnInstruction == TurnInstructions.UTurn)
|
||||
distance += speedProfile.uTurnPenalty;
|
||||
// if(!edgeData1.isAccessRestricted && edgeData2.isAccessRestricted) {
|
||||
// distance += TurnInstructions.AccessRestrictionPenalty;
|
||||
// turnInstruction |= TurnInstructions.AccessRestrictionFlag;
|
||||
// }
|
||||
|
||||
|
||||
//distance += heightPenalty;
|
||||
//distance += ComputeTurnPenalty(u, v, w);
|
||||
assert(edgeData1.edgeBasedNodeID != edgeData2.edgeBasedNodeID);
|
||||
if(originalEdgeData.size() == originalEdgeData.capacity()-3) {
|
||||
originalEdgeData.reserve(originalEdgeData.size()*1.2);
|
||||
}
|
||||
OriginalEdgeData oed(v,edgeData2.nameID, turnInstruction);
|
||||
EdgeBasedEdge newEdge(edgeData1.edgeBasedNodeID, edgeData2.edgeBasedNodeID, edgeBasedEdges.size(), distance, true, false );
|
||||
originalEdgeData.push_back(oed);
|
||||
if(originalEdgeData.size() > 100000) {
|
||||
originalEdgeDataOutFile.write((char*)&(originalEdgeData[0]), originalEdgeData.size()*sizeof(OriginalEdgeData));
|
||||
originalEdgeData.clear();
|
||||
}
|
||||
++numberOfOriginalEdges;
|
||||
++nodeBasedEdgeCounter;
|
||||
edgeBasedEdges.push_back(newEdge);
|
||||
} else {
|
||||
++numberOfSkippedTurns;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
p.printIncrement();
|
||||
}
|
||||
numberOfOriginalEdges += originalEdgeData.size();
|
||||
originalEdgeDataOutFile.write((char*)&(originalEdgeData[0]), originalEdgeData.size()*sizeof(OriginalEdgeData));
|
||||
originalEdgeDataOutFile.seekp(std::ios::beg);
|
||||
originalEdgeDataOutFile.write((char*)&numberOfOriginalEdges, sizeof(unsigned));
|
||||
originalEdgeDataOutFile.close();
|
||||
|
||||
// INFO("Sorting edge-based Nodes");
|
||||
// std::sort(edgeBasedNodes.begin(), edgeBasedNodes.end());
|
||||
// INFO("Removing duplicate nodes (if any)");
|
||||
// edgeBasedNodes.erase( std::unique(edgeBasedNodes.begin(), edgeBasedNodes.end()), edgeBasedNodes.end() );
|
||||
// INFO("Applying vector self-swap trick to free up memory");
|
||||
// INFO("size: " << edgeBasedNodes.size() << ", cap: " << edgeBasedNodes.capacity());
|
||||
// std::vector<EdgeBasedNode>(edgeBasedNodes).swap(edgeBasedNodes);
|
||||
// INFO("size: " << edgeBasedNodes.size() << ", cap: " << edgeBasedNodes.capacity());
|
||||
INFO("Node-based graph contains " << nodeBasedEdgeCounter << " edges");
|
||||
// INFO("Edge-based graph contains " << edgeBasedEdges.size() << " edges, blowup is " << 2*((double)edgeBasedEdges.size()/(double)nodeBasedEdgeCounter));
|
||||
INFO("Edge-based graph skipped " << numberOfSkippedTurns << " turns, defined by " << numberOfTurnRestrictions << " restrictions.");
|
||||
INFO("Generated " << edgeBasedNodes.size() << " edge based nodes");
|
||||
}
|
||||
|
||||
TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w) const {
|
||||
if(u == w) {
|
||||
return TurnInstructions.UTurn;
|
||||
}
|
||||
|
||||
_NodeBasedDynamicGraph::EdgeIterator edge1 = _nodeBasedGraph->FindEdge(u, v);
|
||||
_NodeBasedDynamicGraph::EdgeIterator edge2 = _nodeBasedGraph->FindEdge(v, w);
|
||||
|
||||
_NodeBasedDynamicGraph::EdgeData & data1 = _nodeBasedGraph->GetEdgeData(edge1);
|
||||
_NodeBasedDynamicGraph::EdgeData & data2 = _nodeBasedGraph->GetEdgeData(edge2);
|
||||
|
||||
//roundabouts need to be handled explicitely
|
||||
if(data1.roundabout && data2.roundabout) {
|
||||
//Is a turn possible? If yes, we stay on the roundabout!
|
||||
if( 1 == (_nodeBasedGraph->EndEdges(v) - _nodeBasedGraph->BeginEdges(v)) ) {
|
||||
//No turn possible.
|
||||
return TurnInstructions.NoTurn;
|
||||
} else {
|
||||
return TurnInstructions.StayOnRoundAbout;
|
||||
}
|
||||
}
|
||||
//Does turn start or end on roundabout?
|
||||
if(data1.roundabout || data2.roundabout) {
|
||||
//We are entering the roundabout
|
||||
if( (!data1.roundabout) && data2.roundabout)
|
||||
return TurnInstructions.EnterRoundAbout;
|
||||
//We are leaving the roundabout
|
||||
else if(data1.roundabout && (!data2.roundabout) )
|
||||
return TurnInstructions.LeaveRoundAbout;
|
||||
}
|
||||
|
||||
//If street names stay the same and if we are certain that it is not a roundabout, we skip it.
|
||||
if( (data1.nameID == data2.nameID) && (0 != data1.nameID))
|
||||
return TurnInstructions.NoTurn;
|
||||
if( (data1.nameID == data2.nameID) && (0 == data1.nameID) && (_nodeBasedGraph->GetOutDegree(v) <= 2) )
|
||||
return TurnInstructions.NoTurn;
|
||||
|
||||
double angle = GetAngleBetweenTwoEdges(inputNodeInfoList[u], inputNodeInfoList[v], inputNodeInfoList[w]);
|
||||
return TurnInstructions.GetTurnDirectionOfInstruction(angle);
|
||||
}
|
||||
|
||||
unsigned EdgeBasedGraphFactory::GetNumberOfNodes() const {
|
||||
return _nodeBasedGraph->GetNumberOfEdges();
|
||||
}
|
||||
|
||||
/* Get angle of line segment (A,C)->(C,B), atan2 magic, formerly cosine theorem*/
|
||||
template<class CoordinateT>
|
||||
double EdgeBasedGraphFactory::GetAngleBetweenTwoEdges(const CoordinateT& A, const CoordinateT& C, const CoordinateT& B) const {
|
||||
const int v1x = A.lon - C.lon;
|
||||
const int v1y = A.lat - C.lat;
|
||||
const int v2x = B.lon - C.lon;
|
||||
const int v2y = B.lat - C.lat;
|
||||
|
||||
double angle = (atan2((double)v2y,v2x) - atan2((double)v1y,v1x) )*180/M_PI;
|
||||
while(angle < 0)
|
||||
angle += 360;
|
||||
return angle;
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This class constructs the edge base representation of a graph from a given node based edge list
|
||||
*/
|
||||
|
||||
#ifndef EDGEBASEDGRAPHFACTORY_H_
|
||||
#define EDGEBASEDGRAPHFACTORY_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#include <stxxl.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
#include "../DataStructures/DynamicGraph.h"
|
||||
#include "../Extractor/ExtractorStructs.h"
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../DataStructures/ImportEdge.h"
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "../DataStructures/Percent.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../Util/BaseConfiguration.h"
|
||||
|
||||
class EdgeBasedGraphFactory {
|
||||
private:
|
||||
struct _NodeBasedEdgeData {
|
||||
int distance;
|
||||
unsigned edgeBasedNodeID;
|
||||
unsigned nameID:31;
|
||||
bool shortcut:1;
|
||||
bool forward:1;
|
||||
bool backward:1;
|
||||
bool roundabout:1;
|
||||
bool ignoreInGrid:1;
|
||||
short type;
|
||||
bool isAccessRestricted;
|
||||
};
|
||||
|
||||
struct _EdgeBasedEdgeData {
|
||||
int distance;
|
||||
unsigned via;
|
||||
unsigned nameID;
|
||||
bool forward;
|
||||
bool backward;
|
||||
TurnInstruction turnInstruction;
|
||||
};
|
||||
|
||||
typedef DynamicGraph< _NodeBasedEdgeData > _NodeBasedDynamicGraph;
|
||||
typedef _NodeBasedDynamicGraph::InputEdge _NodeBasedEdge;
|
||||
std::vector<NodeInfo> inputNodeInfoList;
|
||||
unsigned numberOfTurnRestrictions;
|
||||
public:
|
||||
struct EdgeBasedNode {
|
||||
bool operator<(const EdgeBasedNode & other) const {
|
||||
return other.id < id;
|
||||
}
|
||||
bool operator==(const EdgeBasedNode & other) const {
|
||||
return id == other.id;
|
||||
}
|
||||
NodeID id;
|
||||
int lat1;
|
||||
int lat2;
|
||||
int lon1;
|
||||
int lon2:31;
|
||||
bool belongsToTinyComponent:1;
|
||||
NodeID nameID;
|
||||
unsigned weight:31;
|
||||
bool ignoreInGrid:1;
|
||||
};
|
||||
|
||||
|
||||
struct SpeedProfileProperties{
|
||||
SpeedProfileProperties() : trafficSignalPenalty(0), uTurnPenalty(0) {}
|
||||
int trafficSignalPenalty;
|
||||
int uTurnPenalty;
|
||||
} speedProfile;
|
||||
private:
|
||||
boost::shared_ptr<_NodeBasedDynamicGraph> _nodeBasedGraph;
|
||||
boost::unordered_map<NodeID, bool> _barrierNodes;
|
||||
boost::unordered_map<NodeID, bool> _trafficLights;
|
||||
|
||||
typedef std::pair<NodeID, NodeID> RestrictionSource;
|
||||
typedef std::pair<NodeID, bool> RestrictionTarget;
|
||||
typedef std::vector<RestrictionTarget> EmanatingRestrictionsVector;
|
||||
typedef boost::unordered_map<RestrictionSource, unsigned > RestrictionMap;
|
||||
std::vector<EmanatingRestrictionsVector> _restrictionBucketVector;
|
||||
RestrictionMap _restrictionMap;
|
||||
|
||||
|
||||
DeallocatingVector<EdgeBasedEdge> edgeBasedEdges;
|
||||
DeallocatingVector<EdgeBasedNode> edgeBasedNodes;
|
||||
std::vector<OriginalEdgeData> originalEdgeData;
|
||||
|
||||
NodeID CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const;
|
||||
bool CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const;
|
||||
void InsertEdgeBasedNode(
|
||||
_NodeBasedDynamicGraph::EdgeIterator e1,
|
||||
_NodeBasedDynamicGraph::NodeIterator u,
|
||||
_NodeBasedDynamicGraph::NodeIterator v,
|
||||
bool belongsToTinyComponent);
|
||||
template<class CoordinateT>
|
||||
double GetAngleBetweenTwoEdges(const CoordinateT& A, const CoordinateT& C, const CoordinateT& B) const;
|
||||
// SRTMLookup srtmLookup;
|
||||
|
||||
|
||||
public:
|
||||
template< class InputEdgeT >
|
||||
explicit EdgeBasedGraphFactory(int nodes, std::vector<InputEdgeT> & inputEdges, std::vector<NodeID> & _bollardNodes, std::vector<NodeID> & trafficLights, std::vector<_Restriction> & inputRestrictions, std::vector<NodeInfo> & nI, SpeedProfileProperties speedProfile);
|
||||
|
||||
void Run(const char * originalEdgeDataFilename);
|
||||
void GetEdgeBasedEdges( DeallocatingVector< EdgeBasedEdge >& edges );
|
||||
void GetEdgeBasedNodes( DeallocatingVector< EdgeBasedNode> & nodes);
|
||||
void GetOriginalEdgeData( std::vector< OriginalEdgeData> & originalEdgeData);
|
||||
TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w) const;
|
||||
unsigned GetNumberOfNodes() const;
|
||||
};
|
||||
|
||||
#endif /* EDGEBASEDGRAPHFACTORY_H_ */
|
||||
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "TemporaryStorage.h"
|
||||
|
||||
TemporaryStorage::TemporaryStorage() {
|
||||
try {
|
||||
tempDirectory = boost::filesystem::temp_directory_path();
|
||||
} catch(boost::filesystem::filesystem_error & e) {
|
||||
ERR("could not retrieve location of temporary path: " << e.what());
|
||||
}
|
||||
}
|
||||
|
||||
TemporaryStorage & TemporaryStorage::GetInstance(){
|
||||
static TemporaryStorage runningInstance;
|
||||
return runningInstance;
|
||||
}
|
||||
|
||||
TemporaryStorage::~TemporaryStorage() {
|
||||
removeAll();
|
||||
}
|
||||
|
||||
void TemporaryStorage::removeAll() {
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
try {
|
||||
for(unsigned slotID = 0; slotID < vectorOfStreamDatas.size(); ++slotID)
|
||||
deallocateSlot(slotID);
|
||||
|
||||
} catch(boost::filesystem::filesystem_error & e) {
|
||||
ERR("could not retrieve location of temporary path: " << e.what());
|
||||
}
|
||||
vectorOfStreamDatas.clear();
|
||||
}
|
||||
|
||||
int TemporaryStorage::allocateSlot() {
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
try {
|
||||
vectorOfStreamDatas.push_back(StreamData());
|
||||
//INFO("created new temporary file: " << vectorOfStreamDatas.back().pathToTemporaryFile);
|
||||
} catch(boost::filesystem::filesystem_error & e) {
|
||||
abort(e);
|
||||
}
|
||||
return vectorOfStreamDatas.size() - 1;
|
||||
}
|
||||
|
||||
void TemporaryStorage::deallocateSlot(int slotID) {
|
||||
try {
|
||||
StreamData & data = vectorOfStreamDatas[slotID];
|
||||
boost::mutex::scoped_lock lock(*data.readWriteMutex);
|
||||
if(!boost::filesystem::exists(data.pathToTemporaryFile)) {
|
||||
return;
|
||||
}
|
||||
if(data.streamToTemporaryFile->is_open())
|
||||
data.streamToTemporaryFile->close();
|
||||
|
||||
//INFO("deallocating slot " << slotID << " and its file: " << data.pathToTemporaryFile);
|
||||
boost::filesystem::remove(data.pathToTemporaryFile);
|
||||
} catch(boost::filesystem::filesystem_error & e) {
|
||||
abort(e);
|
||||
}
|
||||
}
|
||||
|
||||
void TemporaryStorage::writeToSlot(int slotID, char * pointer, std::streamsize size) {
|
||||
try {
|
||||
StreamData & data = vectorOfStreamDatas[slotID];
|
||||
boost::mutex::scoped_lock lock(*data.readWriteMutex);
|
||||
if(!data.writeMode)
|
||||
ERR("Writing after first read is not allowed");
|
||||
data.streamToTemporaryFile->write(pointer, size);
|
||||
} catch(boost::filesystem::filesystem_error & e) {
|
||||
abort(e);
|
||||
}
|
||||
}
|
||||
void TemporaryStorage::readFromSlot(int slotID, char * pointer, std::streamsize size) {
|
||||
try {
|
||||
StreamData & data = vectorOfStreamDatas[slotID];
|
||||
boost::mutex::scoped_lock lock(*data.readWriteMutex);
|
||||
if(data.writeMode) {
|
||||
data.writeMode = false;
|
||||
data.streamToTemporaryFile->seekg(0, data.streamToTemporaryFile->beg);
|
||||
}
|
||||
data.streamToTemporaryFile->read(pointer, size);
|
||||
} catch(boost::filesystem::filesystem_error & e) {
|
||||
abort(e);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned TemporaryStorage::getFreeBytesOnTemporaryDevice() {
|
||||
boost::filesystem::space_info tempSpaceInfo;
|
||||
try {
|
||||
tempSpaceInfo = boost::filesystem::space(tempDirectory);
|
||||
} catch(boost::filesystem::filesystem_error & e) {
|
||||
abort(e);
|
||||
}
|
||||
return tempSpaceInfo.available;
|
||||
}
|
||||
|
||||
boost::filesystem::fstream::pos_type TemporaryStorage::tell(int slotID) {
|
||||
boost::filesystem::fstream::pos_type position;
|
||||
try {
|
||||
StreamData & data = vectorOfStreamDatas[slotID];
|
||||
boost::mutex::scoped_lock lock(*data.readWriteMutex);
|
||||
position = data.streamToTemporaryFile->tellp();
|
||||
} catch(boost::filesystem::filesystem_error & e) {
|
||||
abort(e);
|
||||
}
|
||||
// INFO("telling position: " << position);
|
||||
return position;
|
||||
}
|
||||
|
||||
void TemporaryStorage::abort(boost::filesystem::filesystem_error& ) {
|
||||
removeAll();
|
||||
// ERR("I/O Error occured: " << e.what());
|
||||
}
|
||||
|
||||
void TemporaryStorage::seek(int slotID, boost::filesystem::fstream::pos_type position) {
|
||||
try {
|
||||
StreamData & data = vectorOfStreamDatas[slotID];
|
||||
boost::mutex::scoped_lock lock(*data.readWriteMutex);
|
||||
data.streamToTemporaryFile->seekg(position);
|
||||
// INFO("seeking to position: " << position);
|
||||
} catch(boost::filesystem::filesystem_error & e) {
|
||||
abort(e);
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef TEMPORARYSTORAGE_H_
|
||||
#define TEMPORARYSTORAGE_H_
|
||||
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
//This is one big workaround for latest boost renaming woes.
|
||||
|
||||
#ifndef BOOST_FILESYSTEM_VERSION
|
||||
#warning Boost Installation with Filesystem3 (>=1.44) is required, activating workaround
|
||||
#include <cstdio>
|
||||
namespace boost {
|
||||
namespace filesystem {
|
||||
inline path temp_directory_path() {
|
||||
char * buffer;
|
||||
buffer = tmpnam (NULL);
|
||||
|
||||
return path(buffer);
|
||||
}
|
||||
|
||||
inline path unique_path(const path&) {
|
||||
return temp_directory_path();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define BOOST_FILESYSTEM_VERSION 3
|
||||
|
||||
/**
|
||||
* 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 tempDirectory;
|
||||
static std::string TemporaryFilePattern("OSRM-%%%%-%%%%-%%%%");
|
||||
class TemporaryStorage {
|
||||
public:
|
||||
static TemporaryStorage & GetInstance();
|
||||
virtual ~TemporaryStorage();
|
||||
|
||||
int allocateSlot();
|
||||
void deallocateSlot(int slotID);
|
||||
void writeToSlot(int slotID, char * pointer, std::streamsize size);
|
||||
void readFromSlot(int slotID, char * pointer, std::streamsize size);
|
||||
//returns the number of free bytes
|
||||
unsigned getFreeBytesOnTemporaryDevice();
|
||||
boost::filesystem::fstream::pos_type tell(int slotID);
|
||||
void seek(int slotID, boost::filesystem::fstream::pos_type);
|
||||
void removeAll();
|
||||
private:
|
||||
TemporaryStorage();
|
||||
TemporaryStorage(TemporaryStorage const &){};
|
||||
TemporaryStorage& operator=(TemporaryStorage const &) {
|
||||
return *this;
|
||||
}
|
||||
void abort(boost::filesystem::filesystem_error& e);
|
||||
|
||||
;
|
||||
|
||||
struct StreamData {
|
||||
bool writeMode;
|
||||
boost::filesystem::path pathToTemporaryFile;
|
||||
boost::shared_ptr<boost::filesystem::fstream> streamToTemporaryFile;
|
||||
boost::shared_ptr<boost::mutex> readWriteMutex;
|
||||
StreamData() :
|
||||
writeMode(true),
|
||||
pathToTemporaryFile (boost::filesystem::unique_path(tempDirectory.append(TemporaryFilePattern.begin(), TemporaryFilePattern.end()))),
|
||||
streamToTemporaryFile(new boost::filesystem::fstream(pathToTemporaryFile, std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary)),
|
||||
readWriteMutex(new boost::mutex)
|
||||
{
|
||||
if(streamToTemporaryFile->fail())
|
||||
ERR("Aborting, because temporary file at " << pathToTemporaryFile << " could not be created");
|
||||
}
|
||||
};
|
||||
//vector of file streams that is used to store temporary data
|
||||
std::vector<StreamData> vectorOfStreamDatas;
|
||||
boost::mutex mutex;
|
||||
};
|
||||
|
||||
#endif /* TEMPORARYSTORAGE_H_ */
|
||||
@@ -1,264 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef BINARYHEAP_H_INCLUDED
|
||||
#define BINARYHEAP_H_INCLUDED
|
||||
|
||||
//Not compatible with non contiguous node ids
|
||||
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class ArrayStorage {
|
||||
public:
|
||||
|
||||
ArrayStorage( size_t size ) : positions( new Key[size] ) {
|
||||
memset(positions, 0, size*sizeof(Key));
|
||||
}
|
||||
|
||||
~ArrayStorage() {
|
||||
delete[] positions;
|
||||
}
|
||||
|
||||
Key &operator[]( NodeID node ) {
|
||||
return positions[node];
|
||||
}
|
||||
|
||||
void Clear() {}
|
||||
|
||||
private:
|
||||
Key* positions;
|
||||
};
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class MapStorage {
|
||||
public:
|
||||
|
||||
MapStorage( size_t ) {}
|
||||
|
||||
Key &operator[]( NodeID node ) {
|
||||
return nodes[node];
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
nodes.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
std::map< NodeID, Key > nodes;
|
||||
|
||||
};
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class UnorderedMapStorage {
|
||||
public:
|
||||
|
||||
UnorderedMapStorage( size_t ) { }
|
||||
|
||||
Key &operator[]( NodeID node ) {
|
||||
return nodes[node];
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
nodes.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
boost::unordered_map< NodeID, Key > nodes;
|
||||
};
|
||||
|
||||
template<typename NodeID = unsigned>
|
||||
struct _SimpleHeapData {
|
||||
NodeID parent;
|
||||
_SimpleHeapData( NodeID p ) : parent(p) { }
|
||||
};
|
||||
|
||||
template < typename NodeID, typename Key, typename Weight, typename Data, typename IndexStorage = ArrayStorage<NodeID, NodeID> >
|
||||
class BinaryHeap {
|
||||
private:
|
||||
BinaryHeap( const BinaryHeap& right );
|
||||
void operator=( const BinaryHeap& right );
|
||||
public:
|
||||
typedef Weight WeightType;
|
||||
typedef Data DataType;
|
||||
|
||||
BinaryHeap( size_t maxID )
|
||||
: nodeIndex( maxID ) {
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
heap.resize( 1 );
|
||||
insertedNodes.clear();
|
||||
heap[0].weight = std::numeric_limits< Weight >::min();
|
||||
nodeIndex.Clear();
|
||||
}
|
||||
|
||||
Key Size() const {
|
||||
return static_cast<Key>( heap.size() - 1 );
|
||||
}
|
||||
|
||||
void Insert( NodeID node, Weight weight, const Data &data ) {
|
||||
HeapElement element;
|
||||
element.index = static_cast<NodeID>(insertedNodes.size());
|
||||
element.weight = weight;
|
||||
const Key key = static_cast<Key>(heap.size());
|
||||
heap.push_back( element );
|
||||
insertedNodes.push_back( HeapNode( node, key, weight, data ) );
|
||||
nodeIndex[node] = element.index;
|
||||
Upheap( key );
|
||||
CheckHeap();
|
||||
}
|
||||
|
||||
Data& GetData( NodeID node ) {
|
||||
const Key index = nodeIndex[node];
|
||||
return insertedNodes[index].data;
|
||||
}
|
||||
|
||||
Weight& GetKey( NodeID node ) {
|
||||
const Key index = nodeIndex[node];
|
||||
return insertedNodes[index].weight;
|
||||
}
|
||||
|
||||
bool WasRemoved( NodeID node ) {
|
||||
assert( WasInserted( node ) );
|
||||
const Key index = nodeIndex[node];
|
||||
return insertedNodes[index].key == 0;
|
||||
}
|
||||
|
||||
bool WasInserted( NodeID node ) {
|
||||
const Key index = nodeIndex[node];
|
||||
if ( index >= static_cast<Key> (insertedNodes.size()) )
|
||||
return false;
|
||||
return insertedNodes[index].node == node;
|
||||
}
|
||||
|
||||
NodeID Min() const {
|
||||
assert( heap.size() > 1 );
|
||||
return insertedNodes[heap[1].index].node;
|
||||
}
|
||||
|
||||
NodeID DeleteMin() {
|
||||
assert( heap.size() > 1 );
|
||||
const Key removedIndex = heap[1].index;
|
||||
heap[1] = heap[heap.size()-1];
|
||||
heap.pop_back();
|
||||
if ( heap.size() > 1 )
|
||||
Downheap( 1 );
|
||||
insertedNodes[removedIndex].key = 0;
|
||||
CheckHeap();
|
||||
return insertedNodes[removedIndex].node;
|
||||
}
|
||||
|
||||
void DeleteAll() {
|
||||
for ( typename std::vector< HeapElement >::iterator i = heap.begin() + 1, iend = heap.end(); i != iend; ++i )
|
||||
insertedNodes[i->index].key = 0;
|
||||
heap.resize( 1 );
|
||||
heap[0].weight = (std::numeric_limits< Weight >::min)();
|
||||
}
|
||||
|
||||
void DecreaseKey( NodeID node, Weight weight ) {
|
||||
assert( UINT_MAX != node );
|
||||
const Key index = nodeIndex[node];
|
||||
Key key = insertedNodes[index].key;
|
||||
assert ( key >= 0 );
|
||||
|
||||
insertedNodes[index].weight = weight;
|
||||
heap[key].weight = weight;
|
||||
Upheap( key );
|
||||
CheckHeap();
|
||||
}
|
||||
|
||||
private:
|
||||
class HeapNode {
|
||||
public:
|
||||
HeapNode() {
|
||||
}
|
||||
HeapNode( NodeID n, Key k, Weight w, Data d )
|
||||
: node( n ), key( k ), weight( w ), data( d ) {
|
||||
}
|
||||
|
||||
NodeID node;
|
||||
Key key;
|
||||
Weight weight;
|
||||
Data data;
|
||||
};
|
||||
struct HeapElement {
|
||||
Key index;
|
||||
Weight weight;
|
||||
};
|
||||
|
||||
std::vector< HeapNode > insertedNodes;
|
||||
std::vector< HeapElement > heap;
|
||||
IndexStorage nodeIndex;
|
||||
|
||||
void Downheap( Key key ) {
|
||||
const Key droppingIndex = heap[key].index;
|
||||
const Weight weight = heap[key].weight;
|
||||
Key nextKey = key << 1;
|
||||
while ( nextKey < static_cast<Key>( heap.size() ) ) {
|
||||
const Key nextKeyOther = nextKey + 1;
|
||||
if ( ( nextKeyOther < static_cast<Key> ( heap.size() ) )&& ( heap[nextKey].weight > heap[nextKeyOther].weight) )
|
||||
nextKey = nextKeyOther;
|
||||
|
||||
if ( weight <= heap[nextKey].weight )
|
||||
break;
|
||||
|
||||
heap[key] = heap[nextKey];
|
||||
insertedNodes[heap[key].index].key = key;
|
||||
key = nextKey;
|
||||
nextKey <<= 1;
|
||||
}
|
||||
heap[key].index = droppingIndex;
|
||||
heap[key].weight = weight;
|
||||
insertedNodes[droppingIndex].key = key;
|
||||
}
|
||||
|
||||
void Upheap( Key key ) {
|
||||
const Key risingIndex = heap[key].index;
|
||||
const Weight weight = heap[key].weight;
|
||||
Key nextKey = key >> 1;
|
||||
while ( heap[nextKey].weight > weight ) {
|
||||
assert( nextKey != 0 );
|
||||
heap[key] = heap[nextKey];
|
||||
insertedNodes[heap[key].index].key = key;
|
||||
key = nextKey;
|
||||
nextKey >>= 1;
|
||||
}
|
||||
heap[key].index = risingIndex;
|
||||
heap[key].weight = weight;
|
||||
insertedNodes[risingIndex].key = key;
|
||||
}
|
||||
|
||||
void CheckHeap() {
|
||||
#ifndef NDEBUG
|
||||
for ( Key i = 2; i < (Key) heap.size(); ++i ) {
|
||||
assert( heap[i].weight >= heap[i >> 1].weight );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#endif //#ifndef BINARYHEAP_H_INCLUDED
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef CONCURRENTQUEUE_H_INCLUDED
|
||||
#define CONCURRENTQUEUE_H_INCLUDED
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/circular_buffer.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
template<typename Data>
|
||||
class ConcurrentQueue {
|
||||
|
||||
typedef typename boost::circular_buffer<Data>::size_type size_t;
|
||||
|
||||
public:
|
||||
ConcurrentQueue(const size_t max_size) : internal_queue(max_size) { }
|
||||
|
||||
inline void push(Data const& data) {
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
m_not_full.wait(lock, boost::bind(&ConcurrentQueue<Data>::is_not_full, this));
|
||||
internal_queue.push_back(data);
|
||||
lock.unlock();
|
||||
m_not_empty.notify_one();
|
||||
}
|
||||
|
||||
inline bool empty() const {
|
||||
return internal_queue.empty();
|
||||
}
|
||||
|
||||
inline void wait_and_pop(Data& popped_value) {
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
m_not_empty.wait(lock, boost::bind(&ConcurrentQueue<Data>::is_not_empty, this));
|
||||
popped_value=internal_queue.front();
|
||||
internal_queue.pop_front();
|
||||
lock.unlock();
|
||||
m_not_full.notify_one();
|
||||
}
|
||||
|
||||
inline bool try_pop(Data& popped_value) {
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
if(internal_queue.empty()) {
|
||||
return false;
|
||||
}
|
||||
popped_value=internal_queue.front();
|
||||
internal_queue.pop_front();
|
||||
lock.unlock();
|
||||
m_not_full.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::circular_buffer<Data> internal_queue;
|
||||
boost::mutex m_mutex;
|
||||
boost::condition m_not_empty;
|
||||
boost::condition m_not_full;
|
||||
|
||||
inline bool is_not_empty() const { return internal_queue.size() > 0; }
|
||||
inline bool is_not_full() const { return internal_queue.size() < internal_queue.capacity(); }
|
||||
};
|
||||
|
||||
#endif //#ifndef CONCURRENTQUEUE_H_INCLUDED
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef COORDINATE_H_
|
||||
#define COORDINATE_H_
|
||||
|
||||
#include <climits>
|
||||
#include <iostream>
|
||||
|
||||
struct _Coordinate {
|
||||
int lat;
|
||||
int lon;
|
||||
_Coordinate () : lat(INT_MIN), lon(INT_MIN) {}
|
||||
_Coordinate (int t, int n) : lat(t) , lon(n) {}
|
||||
void Reset() {
|
||||
lat = INT_MIN;
|
||||
lon = INT_MIN;
|
||||
}
|
||||
bool isSet() const {
|
||||
return (INT_MIN != lat) && (INT_MIN != lon);
|
||||
}
|
||||
inline bool isValid() const {
|
||||
if(lat > 90*100000 || lat < -90*100000 || lon > 180*100000 || lon <-180*100000) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool operator==(const _Coordinate & other) const {
|
||||
return lat == other.lat && lon == other.lon;
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & out, const _Coordinate & c){
|
||||
out << "(" << c.lat << "," << c.lon << ")";
|
||||
return out;
|
||||
}
|
||||
|
||||
inline double ApproximateDistance( const int lat1, const int lon1, const int lat2, const int lon2 ) {
|
||||
assert(lat1 != INT_MIN);
|
||||
assert(lon1 != INT_MIN);
|
||||
assert(lat2 != INT_MIN);
|
||||
assert(lon2 != INT_MIN);
|
||||
double RAD = 0.017453292519943295769236907684886;
|
||||
double lt1 = lat1/100000.;
|
||||
double ln1 = lon1/100000.;
|
||||
double lt2 = lat2/100000.;
|
||||
double ln2 = lon2/100000.;
|
||||
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's radius from wikipedia varies between 6,356.750 km — 6,378.135 km (˜3,949.901 — 3,963.189 miles)
|
||||
//The IUGG value for the equatorial radius of the Earth is 6378.137 km (3963.19 mile)
|
||||
const double earth=6372797.560856;//I am doing miles, just change this to radius in kilometers to get distances in km
|
||||
double distance=earth*cHarv;
|
||||
return distance;
|
||||
}
|
||||
|
||||
inline double ApproximateDistance(const _Coordinate &c1, const _Coordinate &c2) {
|
||||
return ApproximateDistance( c1.lat, c1.lon, c2.lat, c2.lon );
|
||||
}
|
||||
|
||||
inline double ApproximateDistanceByEuclid(const _Coordinate &c1, const _Coordinate &c2) {
|
||||
assert(c1.lat != INT_MIN);
|
||||
assert(c1.lon != INT_MIN);
|
||||
assert(c2.lat != INT_MIN);
|
||||
assert(c2.lon != INT_MIN);
|
||||
const double RAD = 0.017453292519943295769236907684886;
|
||||
const double lat1 = (c1.lat/100000.)*RAD;
|
||||
const double lon1 = (c1.lon/100000.)*RAD;
|
||||
const double lat2 = (c2.lat/100000.)*RAD;
|
||||
const double lon2 = (c2.lon/100000.)*RAD;
|
||||
|
||||
const double x = (lon2-lon1) * cos((lat1+lat2)/2.);
|
||||
const double y = (lat2-lat1);
|
||||
const double earthRadius = 6372797.560856;
|
||||
const double d = sqrt(x*x + y*y) * earthRadius;
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
#endif /* COORDINATE_H_ */
|
||||
@@ -1,307 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef DEALLOCATINGVECTOR_H_
|
||||
#define DEALLOCATINGVECTOR_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
#if __cplusplus > 199711L
|
||||
#define DEALLOCATION_VECTOR_NULL_PTR nullptr
|
||||
#else
|
||||
#define DEALLOCATION_VECTOR_NULL_PTR NULL
|
||||
#endif
|
||||
|
||||
|
||||
template<typename ElementT, size_t bucketSizeC = 10485760/sizeof(ElementT), bool DeallocateC = false>
|
||||
class DeallocatingVectorIterator : public std::iterator<std::random_access_iterator_tag, ElementT> {
|
||||
protected:
|
||||
|
||||
class DeallocatingVectorIteratorState {
|
||||
private:
|
||||
//make constructors explicit, so we do not mix random access and deallocation iterators.
|
||||
DeallocatingVectorIteratorState();
|
||||
public:
|
||||
explicit DeallocatingVectorIteratorState(const DeallocatingVectorIteratorState &r) : mData(r.mData), mIndex(r.mIndex), mBucketList(r.mBucketList) {}
|
||||
//explicit DeallocatingVectorIteratorState(const ElementT * ptr, const size_t idx, const std::vector<ElementT *> & input_list) : mData(ptr), mIndex(idx), mBucketList(input_list) {}
|
||||
explicit DeallocatingVectorIteratorState(const size_t idx, std::vector<ElementT *> & input_list) : mData(DEALLOCATION_VECTOR_NULL_PTR), mIndex(idx), mBucketList(input_list) {
|
||||
setPointerForIndex();
|
||||
}
|
||||
ElementT * mData;
|
||||
size_t mIndex;
|
||||
std::vector<ElementT *> & mBucketList;
|
||||
|
||||
inline void setPointerForIndex() {
|
||||
if(bucketSizeC*mBucketList.size() <= mIndex) {
|
||||
mData = DEALLOCATION_VECTOR_NULL_PTR;
|
||||
return;
|
||||
}
|
||||
size_t _bucket = mIndex/bucketSizeC;
|
||||
size_t _index = mIndex%bucketSizeC;
|
||||
mData = &(mBucketList[_bucket][_index]);
|
||||
|
||||
if(DeallocateC) {
|
||||
//if we hopped over the border of the previous bucket, then delete that bucket.
|
||||
if(0 == _index && _bucket) {
|
||||
delete[] mBucketList[_bucket-1];
|
||||
mBucketList[_bucket-1] = DEALLOCATION_VECTOR_NULL_PTR;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
inline bool operator!=(const DeallocatingVectorIteratorState &other) {
|
||||
return (mData != other.mData) || (mIndex != other.mIndex) || (mBucketList != other.mBucketList);
|
||||
}
|
||||
|
||||
inline bool operator==(const DeallocatingVectorIteratorState &other) {
|
||||
return (mData == other.mData) && (mIndex == other.mIndex) && (mBucketList == other.mBucketList);
|
||||
}
|
||||
|
||||
inline bool operator<(const DeallocatingVectorIteratorState &other) {
|
||||
return mIndex < other.mIndex;
|
||||
}
|
||||
|
||||
//This is a hack to make assignment operator possible with reference member
|
||||
inline DeallocatingVectorIteratorState& operator= (const DeallocatingVectorIteratorState &a) {
|
||||
if (this != &a) {
|
||||
this->DeallocatingVectorIteratorState::~DeallocatingVectorIteratorState(); // explicit non-virtual destructor
|
||||
new (this) DeallocatingVectorIteratorState(a); // placement new
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
DeallocatingVectorIteratorState mState;
|
||||
|
||||
public:
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::value_type value_type;
|
||||
typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::difference_type difference_type;
|
||||
typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::reference reference;
|
||||
typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::pointer pointer;
|
||||
|
||||
DeallocatingVectorIterator() {}
|
||||
|
||||
template<typename T2>
|
||||
DeallocatingVectorIterator(const DeallocatingVectorIterator<T2> & r) : mState(r.mState) {}
|
||||
|
||||
DeallocatingVectorIterator(size_t idx, std::vector<ElementT *> & input_list) : mState(idx, input_list) {}
|
||||
//DeallocatingVectorIterator(size_t idx, const std::vector<ElementT *> & input_list) : mState(idx, input_list) {}
|
||||
DeallocatingVectorIterator(const DeallocatingVectorIteratorState & r) : mState(r) {}
|
||||
|
||||
template<typename T2>
|
||||
DeallocatingVectorIterator& operator=(const DeallocatingVectorIterator<T2> &r) {
|
||||
if(DeallocateC) assert(false);
|
||||
mState = r.mState; return *this;
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator& operator++() { //prefix
|
||||
// if(DeallocateC) assert(false);
|
||||
++mState.mIndex; mState.setPointerForIndex(); return *this;
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator& operator--() { //prefix
|
||||
if(DeallocateC) assert(false);
|
||||
--mState.mIndex; mState.setPointerForIndex(); return *this;
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator operator++(int) { //postfix
|
||||
DeallocatingVectorIteratorState _myState(mState);
|
||||
mState.mIndex++; mState.setPointerForIndex();
|
||||
return DeallocatingVectorIterator(_myState);
|
||||
}
|
||||
inline DeallocatingVectorIterator operator --(int) { //postfix
|
||||
if(DeallocateC) assert(false);
|
||||
DeallocatingVectorIteratorState _myState(mState);
|
||||
mState.mIndex--; mState.setPointerForIndex();
|
||||
return DeallocatingVectorIterator(_myState);
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator operator+(const difference_type& n) const {
|
||||
DeallocatingVectorIteratorState _myState(mState);
|
||||
_myState.mIndex+=n; _myState.setPointerForIndex();
|
||||
return DeallocatingVectorIterator(_myState);
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator& operator+=(const difference_type& n) const {
|
||||
mState.mIndex+=n; return *this;
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator operator-(const difference_type& n) const {
|
||||
if(DeallocateC) assert(false);
|
||||
DeallocatingVectorIteratorState _myState(mState);
|
||||
_myState.mIndex-=n; _myState.setPointerForIndex();
|
||||
return DeallocatingVectorIterator(_myState);
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator& operator-=(const difference_type &n) const {
|
||||
if(DeallocateC) assert(false);
|
||||
mState.mIndex-=n; return *this;
|
||||
}
|
||||
inline reference operator*() const { return *mState.mData; }
|
||||
inline pointer operator->() const { return mState.mData; }
|
||||
inline reference operator[](const difference_type &n) const {
|
||||
if(DeallocateC) assert(false);
|
||||
DeallocatingVectorIteratorState _myState(mState);
|
||||
_myState.mIndex += n;
|
||||
_myState.setPointerForIndex;
|
||||
return _myState.mData;
|
||||
}
|
||||
|
||||
inline bool operator!=(const DeallocatingVectorIterator & other) {
|
||||
return mState != other.mState;
|
||||
}
|
||||
|
||||
inline bool operator==(const DeallocatingVectorIterator & other) {
|
||||
return mState == other.mState;
|
||||
}
|
||||
|
||||
bool operator<(const DeallocatingVectorIterator & other) {
|
||||
return mState < other.mState;
|
||||
}
|
||||
|
||||
difference_type operator-(const DeallocatingVectorIterator & other) {
|
||||
if(DeallocateC) assert(false);
|
||||
return mState.mIndex-other.mState.mIndex;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ElementT, size_t bucketSizeC = 10485760/sizeof(ElementT) >
|
||||
class DeallocatingVector {
|
||||
private:
|
||||
size_t mCurrentSize;
|
||||
std::vector<ElementT *> mBucketList;
|
||||
|
||||
public:
|
||||
typedef ElementT value_type;
|
||||
typedef DeallocatingVectorIterator<ElementT, bucketSizeC, false> iterator;
|
||||
typedef DeallocatingVectorIterator<ElementT, bucketSizeC, false> const_iterator;
|
||||
|
||||
//this iterator deallocates all buckets that have been visited. Iterators to visited objects become invalid.
|
||||
typedef DeallocatingVectorIterator<ElementT, bucketSizeC, true> deallocation_iterator;
|
||||
|
||||
DeallocatingVector() : mCurrentSize(0) {
|
||||
//initial bucket
|
||||
mBucketList.push_back(new ElementT[bucketSizeC]);
|
||||
}
|
||||
|
||||
~DeallocatingVector() {
|
||||
clear();
|
||||
}
|
||||
|
||||
inline void swap(DeallocatingVector<ElementT, bucketSizeC> & other) {
|
||||
std::swap(mCurrentSize, other.mCurrentSize);
|
||||
mBucketList.swap(other.mBucketList);
|
||||
}
|
||||
|
||||
inline void clear() {
|
||||
//Delete[]'ing ptr's to all Buckets
|
||||
for(unsigned i = 0; i < mBucketList.size(); ++i) {
|
||||
if(DEALLOCATION_VECTOR_NULL_PTR != mBucketList[i]) {
|
||||
delete[] mBucketList[i];
|
||||
mBucketList[i] = DEALLOCATION_VECTOR_NULL_PTR;
|
||||
}
|
||||
}
|
||||
//Removing all ptrs from vector
|
||||
std::vector<ElementT *>().swap(mBucketList);
|
||||
mCurrentSize = 0;
|
||||
}
|
||||
|
||||
inline void push_back(const ElementT & element) {
|
||||
size_t _capacity = capacity();
|
||||
if(mCurrentSize == _capacity) {
|
||||
mBucketList.push_back(new ElementT[bucketSizeC]);
|
||||
}
|
||||
|
||||
size_t _index = size()%bucketSizeC;
|
||||
mBucketList.back()[_index] = element;
|
||||
++mCurrentSize;
|
||||
}
|
||||
|
||||
inline void reserve(const size_t) const {
|
||||
//don't do anything
|
||||
}
|
||||
|
||||
inline void resize(const size_t new_size) {
|
||||
if(new_size > mCurrentSize) {
|
||||
while(capacity() < new_size) {
|
||||
mBucketList.push_back(new ElementT[bucketSizeC]);
|
||||
}
|
||||
mCurrentSize = new_size;
|
||||
}
|
||||
if(new_size < mCurrentSize) {
|
||||
size_t number_of_necessary_buckets = 1+(new_size / bucketSizeC);
|
||||
|
||||
for(unsigned i = number_of_necessary_buckets; i < mBucketList.size(); ++i) {
|
||||
delete[] mBucketList[i];
|
||||
}
|
||||
mBucketList.resize(number_of_necessary_buckets);
|
||||
mCurrentSize = new_size;
|
||||
}
|
||||
}
|
||||
|
||||
inline size_t size() const {
|
||||
return mCurrentSize;
|
||||
}
|
||||
|
||||
inline size_t capacity() const {
|
||||
return mBucketList.size() * bucketSizeC;
|
||||
}
|
||||
|
||||
inline iterator begin() {
|
||||
return iterator(static_cast<size_t>(0), mBucketList);
|
||||
}
|
||||
|
||||
inline iterator end() {
|
||||
return iterator(size(), mBucketList);
|
||||
}
|
||||
|
||||
inline deallocation_iterator dbegin() {
|
||||
return deallocation_iterator(static_cast<size_t>(0), mBucketList);
|
||||
}
|
||||
|
||||
inline deallocation_iterator dend() {
|
||||
return deallocation_iterator(size(), mBucketList);
|
||||
}
|
||||
|
||||
inline const_iterator begin() const {
|
||||
return const_iterator(static_cast<size_t>(0), mBucketList);
|
||||
}
|
||||
|
||||
inline const_iterator end() const {
|
||||
return const_iterator(size(), mBucketList);
|
||||
}
|
||||
|
||||
inline ElementT & operator[](const size_t index) {
|
||||
size_t _bucket = index / bucketSizeC;
|
||||
size_t _index = index % bucketSizeC;
|
||||
return (mBucketList[_bucket][_index]);
|
||||
}
|
||||
|
||||
const inline ElementT & operator[](const size_t index) const {
|
||||
size_t _bucket = index / bucketSizeC;
|
||||
size_t _index = index % bucketSizeC;
|
||||
return (mBucketList[_bucket][_index]);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* DEALLOCATINGVECTOR_H_ */
|
||||
@@ -1,241 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef DYNAMICGRAPH_H_INCLUDED
|
||||
#define DYNAMICGRAPH_H_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
|
||||
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.
|
||||
DynamicGraph( int 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 int nodes, const ContainerT &graph )
|
||||
{
|
||||
m_numNodes = nodes;
|
||||
m_numEdges = ( EdgeIterator ) graph.size();
|
||||
m_nodes.reserve( m_numNodes );
|
||||
m_nodes.resize( m_numNodes );
|
||||
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_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;
|
||||
GUARANTEE(graph[edge].data.distance > 0, "edge: " << edge << "(" << graph[edge].source << "," << graph[edge].target << ")=" << graph[edge].data.distance);
|
||||
++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 );
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
//assert( EndEdges( n ) - EdgeIterator( _nodes[n].firstEdge ) <= 100 );
|
||||
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];
|
||||
--m_numEdges;
|
||||
--node.edges;
|
||||
const unsigned last = node.firstEdge + node.edges;
|
||||
//swap with last edge
|
||||
m_edges[e] = m_edges[last];
|
||||
makeDummy( last );
|
||||
}
|
||||
|
||||
//removes all edges (source,target)
|
||||
int DeleteEdgesTo( const NodeIterator source, const NodeIterator target )
|
||||
{
|
||||
int 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 ( m_edges[i].target == to ) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return EndEdges( from );
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
bool isDummy( EdgeIterator edge ) const
|
||||
{
|
||||
return m_edges[edge].target == (std::numeric_limits< NodeIterator >::max)();
|
||||
}
|
||||
|
||||
void makeDummy( 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;
|
||||
|
||||
DeallocatingVector< Node > m_nodes;
|
||||
DeallocatingVector< Edge > m_edges;
|
||||
|
||||
};
|
||||
|
||||
#endif // DYNAMICGRAPH_H_INCLUDED
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef GRIDEDGE_H_
|
||||
#define GRIDEDGE_H_
|
||||
|
||||
#include "Coordinate.h"
|
||||
|
||||
struct _GridEdge {
|
||||
_GridEdge(NodeID n, NodeID na, int w, _Coordinate sc, _Coordinate tc, bool bttc) : edgeBasedNode(n), nameID(na), weight(w), startCoord(sc), targetCoord(tc), belongsToTinyComponent(bttc) {}
|
||||
_GridEdge() : edgeBasedNode(UINT_MAX), nameID(UINT_MAX), weight(INT_MAX), belongsToTinyComponent(false) {}
|
||||
NodeID edgeBasedNode;
|
||||
NodeID nameID;
|
||||
int weight;
|
||||
_Coordinate startCoord;
|
||||
_Coordinate targetCoord;
|
||||
bool belongsToTinyComponent;
|
||||
|
||||
bool operator< ( const _GridEdge& right) const {
|
||||
return edgeBasedNode < right.edgeBasedNode;
|
||||
}
|
||||
bool operator== ( const _GridEdge& right) const {
|
||||
return edgeBasedNode == right.edgeBasedNode;
|
||||
}
|
||||
};
|
||||
|
||||
struct GridEntry {
|
||||
GridEntry() : fileIndex(UINT_MAX), ramIndex(UINT_MAX){}
|
||||
GridEntry(_GridEdge e, unsigned f, unsigned r) : edge(e), fileIndex(f), ramIndex(r) {}
|
||||
_GridEdge edge;
|
||||
unsigned fileIndex;
|
||||
unsigned ramIndex;
|
||||
bool operator< ( const GridEntry& right ) const {
|
||||
return (edge.edgeBasedNode < right.edge.edgeBasedNode);
|
||||
}
|
||||
bool operator==( const GridEntry& right ) const {
|
||||
return right.edge.edgeBasedNode == edge.edgeBasedNode;
|
||||
}
|
||||
};
|
||||
|
||||
struct CompareGridEdgeDataByFileIndex {
|
||||
bool operator () (const GridEntry & a, const GridEntry & b) const {
|
||||
return a.fileIndex < b.fileIndex;
|
||||
}
|
||||
};
|
||||
|
||||
struct CompareGridEdgeDataByRamIndex {
|
||||
typedef GridEntry value_type;
|
||||
|
||||
bool operator () (const GridEntry & a, const GridEntry & b) const {
|
||||
return a.ramIndex < b.ramIndex;
|
||||
}
|
||||
value_type max_value() {
|
||||
GridEntry e;
|
||||
e.ramIndex = (1024*1024) - 1;
|
||||
return e;
|
||||
}
|
||||
value_type min_value() {
|
||||
GridEntry e;
|
||||
e.ramIndex = 0;
|
||||
return e;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* GRIDEDGE_H_ */
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
|
||||
Created on: 18.11.2010
|
||||
Author: dennis
|
||||
*/
|
||||
|
||||
#ifndef HASHTABLE_H_
|
||||
#define HASHTABLE_H_
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
template<typename keyT, typename valueT>
|
||||
class HashTable {
|
||||
typedef boost::unordered_map<keyT, valueT> MyHashTable;
|
||||
public:
|
||||
typedef typename boost::unordered_map<keyT, valueT>::const_iterator MyIterator;
|
||||
typedef MyIterator iterator;
|
||||
HashTable() { }
|
||||
HashTable(const unsigned size) {
|
||||
table.resize(size);
|
||||
}
|
||||
inline void Add(const keyT& key, const valueT& value){
|
||||
table[key] = value;
|
||||
}
|
||||
inline void Set(const keyT& key, const valueT& value){
|
||||
table[key] = value;
|
||||
}
|
||||
inline valueT Find(const keyT& key) const {
|
||||
if(table.find(key) == table.end())
|
||||
return valueT();
|
||||
return table.find(key)->second;
|
||||
}
|
||||
|
||||
inline bool Holds(const keyT& key) const {
|
||||
if(table.find(key) == table.end())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
void EraseAll() {
|
||||
if(table.size() > 0)
|
||||
table.clear();
|
||||
}
|
||||
|
||||
inline valueT operator[] (keyT key) const {
|
||||
if(table.find(key) == table.end())
|
||||
return valueT();
|
||||
return table.find(key)->second;
|
||||
}
|
||||
inline unsigned Size() const {
|
||||
return table.size();
|
||||
}
|
||||
MyIterator begin() const {
|
||||
return table.begin();
|
||||
}
|
||||
MyIterator end() const {
|
||||
return table.end();
|
||||
}
|
||||
private:
|
||||
MyHashTable table;
|
||||
};
|
||||
|
||||
#endif /* HASHTABLE_H_ */
|
||||
@@ -1,135 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef EDGE_H
|
||||
#define EDGE_H
|
||||
|
||||
#include <cassert>
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
/** Default constructor. target and weight are set to 0.*/
|
||||
NodeBasedEdge() :
|
||||
_source(0), _target(0), _name(0), _weight(0), forward(0), backward(0), _type(0), _roundabout(false), _ignoreInGrid(false), _accessRestricted(false) { assert(false); } //shall not be used.
|
||||
|
||||
explicit NodeBasedEdge(NodeID s, NodeID t, NodeID n, EdgeWeight w, bool f, bool b, short ty, bool ra, bool ig, bool ar) :
|
||||
_source(s), _target(t), _name(n), _weight(w), forward(f), backward(b), _type(ty), _roundabout(ra), _ignoreInGrid(ig), _accessRestricted(ar) { if(ty < 0) {ERR("Type: " << ty);}; }
|
||||
|
||||
NodeID target() const {return _target; }
|
||||
NodeID source() const {return _source; }
|
||||
NodeID name() const { return _name; }
|
||||
EdgeWeight weight() const {return _weight; }
|
||||
|
||||
short type() const { assert(_type >= 0); 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; }
|
||||
|
||||
NodeID _source;
|
||||
NodeID _target;
|
||||
NodeID _name;
|
||||
EdgeWeight _weight;
|
||||
bool forward;
|
||||
bool backward;
|
||||
short _type;
|
||||
bool _roundabout;
|
||||
bool _ignoreInGrid;
|
||||
bool _accessRestricted;
|
||||
};
|
||||
|
||||
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>
|
||||
EdgeBasedEdge(const EdgeT & myEdge ) :
|
||||
_source(myEdge.source),
|
||||
_target(myEdge.target),
|
||||
_edgeID(myEdge.data.via),
|
||||
// _nameID1(myEdge.data.nameID),
|
||||
_weight(myEdge.data.distance),
|
||||
_forward(myEdge.data.forward),
|
||||
_backward(myEdge.data.backward)//,
|
||||
// _turnInstruction(myEdge.data.turnInstruction)
|
||||
{ }
|
||||
|
||||
/** Default constructor. target and weight are set to 0.*/
|
||||
EdgeBasedEdge() :
|
||||
_source(0), _target(0), _edgeID(0), _weight(0), _forward(false), _backward(false) { }
|
||||
|
||||
explicit EdgeBasedEdge(NodeID s, NodeID t, NodeID v, EdgeWeight w, bool f, bool b) :
|
||||
_source(s), _target(t), _edgeID(v), _weight(w), _forward(f), _backward(b){}
|
||||
|
||||
NodeID target() const {return _target; }
|
||||
NodeID source() const {return _source; }
|
||||
EdgeWeight weight() const {return _weight; }
|
||||
NodeID id() const { return _edgeID; }
|
||||
bool isBackward() const { return _backward; }
|
||||
bool isForward() const { return _forward; }
|
||||
|
||||
NodeID _source;
|
||||
NodeID _target;
|
||||
NodeID _edgeID;
|
||||
EdgeWeight _weight:30;
|
||||
bool _forward:1;
|
||||
bool _backward:1;
|
||||
};
|
||||
|
||||
struct MinimalEdgeData {
|
||||
public:
|
||||
EdgeWeight distance;
|
||||
bool forward;
|
||||
bool backward;
|
||||
};
|
||||
|
||||
typedef NodeBasedEdge ImportEdge;
|
||||
|
||||
#endif // EDGE_H
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef IMPORTNODE_H_
|
||||
#define IMPORTNODE_H_
|
||||
|
||||
#include "NodeCoords.h"
|
||||
#include "../DataStructures/HashTable.h"
|
||||
|
||||
|
||||
struct _Node : NodeInfo{
|
||||
_Node(int _lat, int _lon, unsigned int _id, bool _bollard, bool _trafficLight) : NodeInfo(_lat, _lon, _id), bollard(_bollard), trafficLight(_trafficLight) {}
|
||||
_Node() : bollard(false), trafficLight(false) {}
|
||||
|
||||
static _Node min_value() {
|
||||
return _Node(0,0,0, false, false);
|
||||
}
|
||||
static _Node max_value() {
|
||||
return _Node((std::numeric_limits<int>::max)(), (std::numeric_limits<int>::max)(), (std::numeric_limits<unsigned int>::max)(), false, false);
|
||||
}
|
||||
NodeID key() const {
|
||||
return id;
|
||||
}
|
||||
bool bollard;
|
||||
bool trafficLight;
|
||||
};
|
||||
|
||||
struct ImportNode : public _Node {
|
||||
HashTable<std::string, std::string> keyVals;
|
||||
|
||||
inline void Clear() {
|
||||
keyVals.EraseAll();
|
||||
lat = 0; lon = 0; id = 0; bollard = false; trafficLight = false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* IMPORTNODE_H_ */
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef INPUTREADERFACTORY_H
|
||||
#define INPUTREADERFACTORY_H
|
||||
|
||||
#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);
|
||||
if(BZ_OK != context->error) { cerr << "Could not BZ2_bzReadGetUnused" << endl; exit(-1);};
|
||||
unusedTmp = (char*)unusedTmpVoid;
|
||||
for(int i=0;i<context->nUnused;i++) {
|
||||
context->unused[i] = unusedTmp[i];
|
||||
}
|
||||
BZ2_bzReadClose(&context->error, context->bz2);
|
||||
if(BZ_OK != context->error) { cerr << "Could not BZ2_bzReadClose" << endl; exit(-1);};
|
||||
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);
|
||||
if(NULL == context->bz2){ cerr << "Could not open file" << endl; exit(-1);};
|
||||
}
|
||||
} else { cerr << "Could not read bz2 file" << endl; exit(-1); }
|
||||
}
|
||||
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")!=string::npos)
|
||||
{
|
||||
BZ2Context* context = new BZ2Context();
|
||||
context->error = false;
|
||||
context->file = fopen( name, "r" );
|
||||
int error;
|
||||
context->bz2 = BZ2_bzReadOpen( &error, context->file, 0, 0, context->unused, context->nUnused );
|
||||
if ( context->bz2 == NULL || context->file == NULL ) {
|
||||
delete context;
|
||||
return NULL;
|
||||
}
|
||||
return xmlReaderForIO( readFromBz2Stream, closeBz2Stream, (void*) context, NULL, NULL, 0 );
|
||||
} else {
|
||||
return xmlNewTextReaderFilename(name);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // INPUTREADERFACTORY_H
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef LRUCACHE_H
|
||||
#define LRUCACHE_H
|
||||
|
||||
#include <list>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
template<typename KeyT, typename ValueT>
|
||||
class LRUCache {
|
||||
private:
|
||||
struct CacheEntry {
|
||||
CacheEntry(KeyT k, ValueT v) : key(k), value(v) {}
|
||||
KeyT key;
|
||||
ValueT value;
|
||||
};
|
||||
unsigned capacity;
|
||||
std::list<CacheEntry> itemsInCache;
|
||||
boost::unordered_map<KeyT, typename std::list<CacheEntry>::iterator > positionMap;
|
||||
public:
|
||||
LRUCache(unsigned c) : capacity(c) {}
|
||||
|
||||
bool Holds(KeyT key) {
|
||||
if(positionMap.find(key) != positionMap.end()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Insert(const KeyT key, ValueT &value) {
|
||||
itemsInCache.push_front(CacheEntry(key, value));
|
||||
positionMap.insert(std::make_pair(key, itemsInCache.begin()));
|
||||
if(itemsInCache.size() > capacity) {
|
||||
positionMap.erase(itemsInCache.back().key);
|
||||
itemsInCache.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void Insert(const KeyT key, ValueT value) {
|
||||
itemsInCache.push_front(CacheEntry(key, value));
|
||||
positionMap.insert(std::make_pair(key, itemsInCache.begin()));
|
||||
if(itemsInCache.size() > capacity) {
|
||||
positionMap.erase(itemsInCache.back().key);
|
||||
itemsInCache.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
bool Fetch(const KeyT key, ValueT& result) {
|
||||
if(Holds(key)) {
|
||||
CacheEntry e = *(positionMap.find(key)->second);
|
||||
result = e.value;
|
||||
|
||||
//move to front
|
||||
itemsInCache.splice(positionMap.find(key)->second, itemsInCache, itemsInCache.begin());
|
||||
positionMap.find(key)->second = itemsInCache.begin();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
unsigned Size() const {
|
||||
return itemsInCache.size();
|
||||
}
|
||||
};
|
||||
#endif //LRUCACHE_H
|
||||
@@ -1,594 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef NNGRID_H_
|
||||
#define NNGRID_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
#ifndef ROUTED
|
||||
#include <stxxl.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include "DeallocatingVector.h"
|
||||
//#include "ExtractorStructs.h"
|
||||
#include "GridEdge.h"
|
||||
#include "Percent.h"
|
||||
#include "PhantomNodes.h"
|
||||
#include "Util.h"
|
||||
#include "StaticGraph.h"
|
||||
#include "../Algorithms/Bresenham.h"
|
||||
|
||||
namespace NNGrid{
|
||||
|
||||
static boost::thread_specific_ptr<std::ifstream> localStream;
|
||||
|
||||
template<bool WriteAccess = false>
|
||||
class NNGrid {
|
||||
public:
|
||||
NNGrid() /*: cellCache(500), fileCache(500)*/ {
|
||||
ramIndexTable.resize((1024*1024), ULONG_MAX);
|
||||
}
|
||||
|
||||
NNGrid(const char* rif, const char* _i) {
|
||||
if(WriteAccess) {
|
||||
ERR("Not available in Write mode");
|
||||
}
|
||||
iif = std::string(_i);
|
||||
ramIndexTable.resize((1024*1024), ULONG_MAX);
|
||||
ramInFile.open(rif, std::ios::in | std::ios::binary);
|
||||
if(!ramInFile) { ERR(rif << " not found"); }
|
||||
|
||||
}
|
||||
|
||||
~NNGrid() {
|
||||
if(ramInFile.is_open()) ramInFile.close();
|
||||
|
||||
#ifndef ROUTED
|
||||
if (WriteAccess) {
|
||||
entries.clear();
|
||||
}
|
||||
#endif
|
||||
if(localStream.get() && localStream->is_open()) {
|
||||
localStream->close();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenIndexFiles() {
|
||||
assert(ramInFile.is_open());
|
||||
ramInFile.read(static_cast<char*>(static_cast<void*>(&ramIndexTable[0]) ), sizeof(unsigned long)*1024*1024);
|
||||
ramInFile.close();
|
||||
}
|
||||
|
||||
#ifndef ROUTED
|
||||
template<typename EdgeT>
|
||||
inline void ConstructGrid(DeallocatingVector<EdgeT> & edgeList, char * ramIndexOut, char * fileIndexOut) {
|
||||
//TODO: Implement this using STXXL-Streams
|
||||
Percent p(edgeList.size());
|
||||
BOOST_FOREACH(EdgeT & edge, edgeList) {
|
||||
p.printIncrement();
|
||||
if(edge.ignoreInGrid)
|
||||
continue;
|
||||
int slat = 100000*lat2y(edge.lat1/100000.);
|
||||
int slon = edge.lon1;
|
||||
int tlat = 100000*lat2y(edge.lat2/100000.);
|
||||
int tlon = edge.lon2;
|
||||
AddEdge( _GridEdge( edge.id, edge.nameID, edge.weight, _Coordinate(slat, slon), _Coordinate(tlat, tlon), edge.belongsToTinyComponent ) );
|
||||
}
|
||||
double timestamp = get_timestamp();
|
||||
//create index file on disk, old one is over written
|
||||
indexOutFile.open(fileIndexOut, std::ios::out | std::ios::binary | std::ios::trunc);
|
||||
//sort entries
|
||||
stxxl::sort(entries.begin(), entries.end(), CompareGridEdgeDataByRamIndex(), 1024*1024*1024);
|
||||
INFO("finished sorting after " << (get_timestamp() - timestamp) << "s");
|
||||
std::vector<GridEntry> entriesInFileWithRAMSameIndex;
|
||||
unsigned indexInRamTable = entries.begin()->ramIndex;
|
||||
unsigned long lastPositionInIndexFile = 0;
|
||||
cout << "writing data ..." << flush;
|
||||
p.reinit(entries.size());
|
||||
boost::unordered_map< unsigned, unsigned > cellMap(1024);
|
||||
BOOST_FOREACH(GridEntry & gridEntry, entries) {
|
||||
p.printIncrement();
|
||||
if(gridEntry.ramIndex != indexInRamTable) {
|
||||
cellMap.clear();
|
||||
BuildCellIndexToFileIndexMap(indexInRamTable, cellMap);
|
||||
|
||||
unsigned numberOfBytesInCell = FillCell(entriesInFileWithRAMSameIndex, lastPositionInIndexFile, cellMap);
|
||||
ramIndexTable[indexInRamTable] = lastPositionInIndexFile;
|
||||
lastPositionInIndexFile += numberOfBytesInCell;
|
||||
entriesInFileWithRAMSameIndex.clear();
|
||||
indexInRamTable = gridEntry.ramIndex;
|
||||
}
|
||||
entriesInFileWithRAMSameIndex.push_back(gridEntry);
|
||||
}
|
||||
cellMap.clear();
|
||||
BuildCellIndexToFileIndexMap(indexInRamTable, cellMap);
|
||||
/*unsigned numberOfBytesInCell = */FillCell(entriesInFileWithRAMSameIndex, lastPositionInIndexFile, cellMap);
|
||||
ramIndexTable[indexInRamTable] = lastPositionInIndexFile;
|
||||
entriesInFileWithRAMSameIndex.clear();
|
||||
std::vector<GridEntry>().swap(entriesInFileWithRAMSameIndex);
|
||||
assert(entriesInFileWithRAMSameIndex.size() == 0);
|
||||
//close index file
|
||||
indexOutFile.close();
|
||||
|
||||
//Serialize RAM Index
|
||||
ofstream ramFile(ramIndexOut, std::ios::out | std::ios::binary | std::ios::trunc);
|
||||
//write 4 MB of index Table in RAM
|
||||
ramFile.write((char *)&ramIndexTable[0], sizeof(unsigned long)*1024*1024 );
|
||||
//close ram index file
|
||||
ramFile.close();
|
||||
}
|
||||
#endif
|
||||
inline bool CoordinatesAreEquivalent(const _Coordinate & a, const _Coordinate & b, const _Coordinate & c, const _Coordinate & d) const {
|
||||
return (a == b && c == d) || (a == c && b == d) || (a == d && b == c);
|
||||
}
|
||||
|
||||
bool FindPhantomNodeForCoordinate( const _Coordinate & location, PhantomNode & resultNode, const unsigned zoomLevel) {
|
||||
bool ignoreTinyComponents = (zoomLevel <= 14);
|
||||
// INFO("Coordinate: " << location << ", zoomLevel: " << zoomLevel << ", ignoring tinyComponentents: " << (ignoreTinyComponents ? "yes" : "no"));
|
||||
// double time1 = get_timestamp();
|
||||
bool foundNode = false;
|
||||
const _Coordinate startCoord(100000*(lat2y(static_cast<double>(location.lat)/100000.)), location.lon);
|
||||
/** search for point on edge close to source */
|
||||
const unsigned fileIndex = GetFileIndexForLatLon(startCoord.lat, startCoord.lon);
|
||||
std::vector<_GridEdge> candidates;
|
||||
const int lowerBoundForLoop = (fileIndex < 32768 ? 0 : -32768);
|
||||
for(int j = lowerBoundForLoop; (j < (32768+1)) && (fileIndex != UINT_MAX); j+=32768) {
|
||||
for(int i = -1; i < 2; ++i){
|
||||
// unsigned oldSize = candidates.size();
|
||||
GetContentsOfFileBucketEnumerated(fileIndex+i+j, candidates);
|
||||
// INFO("Getting fileIndex=" << fileIndex+i+j << " with " << candidates.size() - oldSize << " candidates");
|
||||
}
|
||||
}
|
||||
// INFO("looked up " << candidates.size());
|
||||
_GridEdge smallestEdge;
|
||||
_Coordinate tmp, edgeStartCoord, edgeEndCoord;
|
||||
double dist = numeric_limits<double>::max();
|
||||
double r, tmpDist;
|
||||
|
||||
BOOST_FOREACH(_GridEdge candidate, candidates) {
|
||||
if(candidate.belongsToTinyComponent && ignoreTinyComponents)
|
||||
continue;
|
||||
r = 0.;
|
||||
tmpDist = ComputeDistance(startCoord, candidate.startCoord, candidate.targetCoord, tmp, &r);
|
||||
// INFO("dist " << startCoord << "->[" << candidate.startCoord << "-" << candidate.targetCoord << "]=" << tmpDist );
|
||||
// INFO("Looking at edge " << candidate.edgeBasedNode << " at distance " << tmpDist);
|
||||
if(tmpDist < dist && !DoubleEpsilonCompare(dist, tmpDist)) {
|
||||
// INFO("a) " << candidate.edgeBasedNode << ", dist: " << tmpDist << ", tinyCC: " << (candidate.belongsToTinyComponent ? "yes" : "no"));
|
||||
dist = tmpDist;
|
||||
resultNode.edgeBasedNode = candidate.edgeBasedNode;
|
||||
resultNode.nodeBasedEdgeNameID = candidate.nameID;
|
||||
resultNode.weight1 = candidate.weight;
|
||||
resultNode.weight2 = INT_MAX;
|
||||
resultNode.location.lat = tmp.lat;
|
||||
resultNode.location.lon = tmp.lon;
|
||||
edgeStartCoord = candidate.startCoord;
|
||||
edgeEndCoord = candidate.targetCoord;
|
||||
foundNode = true;
|
||||
smallestEdge = candidate;
|
||||
//} else if(tmpDist < dist) {
|
||||
//INFO("a) ignored " << candidate.edgeBasedNode << " at distance " << std::fabs(dist - tmpDist));
|
||||
} else if(DoubleEpsilonCompare(dist, tmpDist) && 1 == std::abs(static_cast<int>(candidate.edgeBasedNode)-static_cast<int>(resultNode.edgeBasedNode) ) && CoordinatesAreEquivalent(edgeStartCoord, candidate.startCoord, edgeEndCoord, candidate.targetCoord)) {
|
||||
resultNode.edgeBasedNode = std::min(candidate.edgeBasedNode, resultNode.edgeBasedNode);
|
||||
resultNode.weight2 = candidate.weight;
|
||||
//INFO("b) " << candidate.edgeBasedNode << ", dist: " << tmpDist);
|
||||
}
|
||||
}
|
||||
|
||||
// INFO("startcoord: " << smallestEdge.startCoord << ", tgtcoord" << smallestEdge.targetCoord << "result: " << newEndpoint);
|
||||
// INFO("length of old edge: " << ApproximateDistance(smallestEdge.startCoord, smallestEdge.targetCoord));
|
||||
// INFO("Length of new edge: " << ApproximateDistance(smallestEdge.startCoord, newEndpoint));
|
||||
// assert(!resultNode.isBidirected() || (resultNode.weight1 == resultNode.weight2));
|
||||
// if(resultNode.weight1 != resultNode.weight2) {
|
||||
// INFO("-> Weight1: " << resultNode.weight1 << ", weight2: " << resultNode.weight2);
|
||||
// INFO("-> node: " << resultNode.edgeBasedNode << ", bidir: " << (resultNode.isBidirected() ? "yes" : "no"));
|
||||
// }
|
||||
|
||||
// INFO("startCoord: " << smallestEdge.startCoord << "; targetCoord: " << smallestEdge.targetCoord << "; newEndpoint: " << resultNode.location);
|
||||
double ratio = (foundNode ? std::min(1., ApproximateDistance(smallestEdge.startCoord, resultNode.location)/ApproximateDistance(smallestEdge.startCoord, smallestEdge.targetCoord)) : 0);
|
||||
resultNode.location.lat = round(100000.*(y2lat(static_cast<double>(resultNode.location.lat)/100000.)));
|
||||
// INFO("Length of vector: " << ApproximateDistance(smallestEdge.startCoord, resultNode.location)/ApproximateDistance(smallestEdge.startCoord, smallestEdge.targetCoord));
|
||||
//Hack to fix rounding errors and wandering via nodes.
|
||||
if(std::abs(location.lon - resultNode.location.lon) == 1)
|
||||
resultNode.location.lon = location.lon;
|
||||
if(std::abs(location.lat - resultNode.location.lat) == 1)
|
||||
resultNode.location.lat = location.lat;
|
||||
|
||||
resultNode.weight1 *= ratio;
|
||||
if(INT_MAX != resultNode.weight2) {
|
||||
resultNode.weight2 -= resultNode.weight1;
|
||||
}
|
||||
resultNode.ratio = ratio;
|
||||
// INFO("New weight1: " << resultNode.weight1 << ", new weight2: " << resultNode.weight2 << ", ratio: " << ratio);
|
||||
// INFO("start: " << edgeStartCoord << ", end: " << edgeEndCoord);
|
||||
// INFO("selected node: " << resultNode.edgeBasedNode << ", bidirected: " << (resultNode.isBidirected() ? "yes" : "no") << "\n--");
|
||||
// double time2 = get_timestamp();
|
||||
// INFO("NN-Lookup in " << 1000*(time2-time1) << "ms");
|
||||
return foundNode;
|
||||
}
|
||||
|
||||
bool FindRoutingStarts(const _Coordinate& start, const _Coordinate& target, PhantomNodes & routingStarts, unsigned zoomLevel) {
|
||||
routingStarts.Reset();
|
||||
return (FindPhantomNodeForCoordinate( start, routingStarts.startPhantom, zoomLevel) &&
|
||||
FindPhantomNodeForCoordinate( target, routingStarts.targetPhantom, zoomLevel) );
|
||||
}
|
||||
|
||||
bool FindNearestCoordinateOnEdgeInNodeBasedGraph(const _Coordinate& inputCoordinate, _Coordinate& outputCoordinate, unsigned zoomLevel = 18) {
|
||||
PhantomNode resultNode;
|
||||
bool foundNode = FindPhantomNodeForCoordinate(inputCoordinate, resultNode, zoomLevel);
|
||||
outputCoordinate = resultNode.location;
|
||||
return foundNode;
|
||||
}
|
||||
|
||||
void FindNearestPointOnEdge(const _Coordinate& inputCoordinate, _Coordinate& outputCoordinate) {
|
||||
_Coordinate startCoord(100000*(lat2y(static_cast<double>(inputCoordinate.lat)/100000.)), inputCoordinate.lon);
|
||||
unsigned fileIndex = GetFileIndexForLatLon(startCoord.lat, startCoord.lon);
|
||||
|
||||
std::vector<_GridEdge> candidates;
|
||||
boost::unordered_map< unsigned, unsigned > cellMap;
|
||||
for(int j = -32768; j < (32768+1); j+=32768) {
|
||||
for(int i = -1; i < 2; ++i) {
|
||||
GetContentsOfFileBucket(fileIndex+i+j, candidates, cellMap);
|
||||
}
|
||||
}
|
||||
_Coordinate tmp;
|
||||
double dist = (std::numeric_limits<double>::max)();
|
||||
BOOST_FOREACH(_GridEdge candidate, candidates) {
|
||||
double r = 0.;
|
||||
double tmpDist = ComputeDistance(startCoord, candidate.startCoord, candidate.targetCoord, tmp, &r);
|
||||
if(tmpDist < dist) {
|
||||
dist = tmpDist;
|
||||
outputCoordinate.lat = round(100000*(y2lat(static_cast<double>(tmp.lat)/100000.)));
|
||||
outputCoordinate.lon = tmp.lon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
inline unsigned GetCellIndexFromRAMAndFileIndex(const unsigned ramIndex, const unsigned fileIndex) const {
|
||||
unsigned lineBase = ramIndex/1024;
|
||||
lineBase = lineBase*32*32768;
|
||||
unsigned columnBase = ramIndex%1024;
|
||||
columnBase=columnBase*32;
|
||||
for (int i = 0;i < 32;++i) {
|
||||
for (int j = 0;j < 32;++j) {
|
||||
const unsigned localFileIndex = lineBase + i * 32768 + columnBase + j;
|
||||
if(localFileIndex == fileIndex) {
|
||||
unsigned cellIndex = i * 32 + j;
|
||||
return cellIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
inline void BuildCellIndexToFileIndexMap(const unsigned ramIndex, boost::unordered_map<unsigned, unsigned >& cellMap){
|
||||
unsigned lineBase = ramIndex/1024;
|
||||
lineBase = lineBase*32*32768;
|
||||
unsigned columnBase = ramIndex%1024;
|
||||
columnBase=columnBase*32;
|
||||
std::vector<std::pair<unsigned, unsigned> >insertionVector(1024);
|
||||
for (int i = 0;i < 32;++i) {
|
||||
for (int j = 0;j < 32;++j) {
|
||||
unsigned fileIndex = lineBase + i * 32768 + columnBase + j;
|
||||
unsigned cellIndex = i * 32 + j;
|
||||
insertionVector[i * 32 + j] = std::make_pair(fileIndex, cellIndex);
|
||||
}
|
||||
}
|
||||
cellMap.insert(insertionVector.begin(), insertionVector.end());
|
||||
}
|
||||
|
||||
inline bool DoubleEpsilonCompare(const double d1, const double d2) {
|
||||
return (std::fabs(d1 - d2) < FLT_EPSILON);
|
||||
}
|
||||
|
||||
inline unsigned FillCell(std::vector<GridEntry>& entriesWithSameRAMIndex, const unsigned long fileOffset, boost::unordered_map< unsigned, unsigned > & cellMap ) {
|
||||
std::vector<char> tmpBuffer(32*32*4096,0);
|
||||
unsigned long indexIntoTmpBuffer = 0;
|
||||
unsigned numberOfWrittenBytes = 0;
|
||||
assert(indexOutFile.is_open());
|
||||
|
||||
std::vector<unsigned long> cellIndex(32*32,ULONG_MAX);
|
||||
|
||||
for(unsigned i = 0; i < entriesWithSameRAMIndex.size() -1; ++i) {
|
||||
assert(entriesWithSameRAMIndex[i].ramIndex== entriesWithSameRAMIndex[i+1].ramIndex);
|
||||
}
|
||||
|
||||
//sort & unique
|
||||
std::sort(entriesWithSameRAMIndex.begin(), entriesWithSameRAMIndex.end(), CompareGridEdgeDataByFileIndex());
|
||||
// entriesWithSameRAMIndex.erase(std::unique(entriesWithSameRAMIndex.begin(), entriesWithSameRAMIndex.end()), entriesWithSameRAMIndex.end());
|
||||
|
||||
//traverse each file bucket and write its contents to disk
|
||||
std::vector<GridEntry> entriesWithSameFileIndex;
|
||||
unsigned fileIndex = entriesWithSameRAMIndex.begin()->fileIndex;
|
||||
|
||||
BOOST_FOREACH(GridEntry & gridEntry, entriesWithSameRAMIndex) {
|
||||
assert(cellMap.find(gridEntry.fileIndex) != cellMap.end() ); //asserting that file index belongs to cell index
|
||||
if(gridEntry.fileIndex != fileIndex) {
|
||||
// start in cellIndex vermerken
|
||||
int localFileIndex = entriesWithSameFileIndex.begin()->fileIndex;
|
||||
int localCellIndex = cellMap.find(localFileIndex)->second;
|
||||
assert(cellMap.find(entriesWithSameFileIndex.begin()->fileIndex) != cellMap.end());
|
||||
|
||||
cellIndex[localCellIndex] = indexIntoTmpBuffer + fileOffset;
|
||||
indexIntoTmpBuffer += FlushEntriesWithSameFileIndexToBuffer(entriesWithSameFileIndex, tmpBuffer, indexIntoTmpBuffer);
|
||||
fileIndex = gridEntry.fileIndex;
|
||||
}
|
||||
entriesWithSameFileIndex.push_back(gridEntry);
|
||||
}
|
||||
assert(cellMap.find(entriesWithSameFileIndex.begin()->fileIndex) != cellMap.end());
|
||||
int localFileIndex = entriesWithSameFileIndex.begin()->fileIndex;
|
||||
int localCellIndex = cellMap.find(localFileIndex)->second;
|
||||
|
||||
cellIndex[localCellIndex] = indexIntoTmpBuffer + fileOffset;
|
||||
indexIntoTmpBuffer += FlushEntriesWithSameFileIndexToBuffer(entriesWithSameFileIndex, tmpBuffer, indexIntoTmpBuffer);
|
||||
|
||||
assert(entriesWithSameFileIndex.size() == 0);
|
||||
indexOutFile.write(static_cast<char*>(static_cast<void*>(&cellIndex[0])),32*32*sizeof(unsigned long));
|
||||
numberOfWrittenBytes += 32*32*sizeof(unsigned long);
|
||||
|
||||
//write contents of tmpbuffer to disk
|
||||
indexOutFile.write(&tmpBuffer[0], indexIntoTmpBuffer*sizeof(char));
|
||||
numberOfWrittenBytes += indexIntoTmpBuffer*sizeof(char);
|
||||
|
||||
return numberOfWrittenBytes;
|
||||
}
|
||||
|
||||
inline unsigned FlushEntriesWithSameFileIndexToBuffer( std::vector<GridEntry> &vectorWithSameFileIndex, std::vector<char> & tmpBuffer, const unsigned long index) const {
|
||||
sort( vectorWithSameFileIndex.begin(), vectorWithSameFileIndex.end() );
|
||||
vectorWithSameFileIndex.erase(unique(vectorWithSameFileIndex.begin(), vectorWithSameFileIndex.end()), vectorWithSameFileIndex.end());
|
||||
const unsigned lengthOfBucket = vectorWithSameFileIndex.size();
|
||||
tmpBuffer.resize(tmpBuffer.size()+(sizeof(_GridEdge)*lengthOfBucket) + sizeof(unsigned) );
|
||||
unsigned counter = 0;
|
||||
|
||||
for(unsigned i = 0; i < vectorWithSameFileIndex.size()-1; ++i) {
|
||||
assert( vectorWithSameFileIndex[i].fileIndex == vectorWithSameFileIndex[i+1].fileIndex );
|
||||
assert( vectorWithSameFileIndex[i].ramIndex == vectorWithSameFileIndex[i+1].ramIndex );
|
||||
}
|
||||
|
||||
//write length of bucket
|
||||
memcpy((char*)&(tmpBuffer[index+counter]), (char*)&lengthOfBucket, sizeof(lengthOfBucket));
|
||||
counter += sizeof(lengthOfBucket);
|
||||
|
||||
BOOST_FOREACH(const GridEntry & entry, vectorWithSameFileIndex) {
|
||||
char * data = (char*)&(entry.edge);
|
||||
memcpy(static_cast<char*>(static_cast<void*>(&(tmpBuffer[index+counter]) )), data, sizeof(entry.edge));
|
||||
counter += sizeof(entry.edge);
|
||||
}
|
||||
//Freeing data
|
||||
vectorWithSameFileIndex.clear();
|
||||
return counter;
|
||||
}
|
||||
|
||||
inline void GetContentsOfFileBucketEnumerated(const unsigned fileIndex, std::vector<_GridEdge>& result) const {
|
||||
unsigned ramIndex = GetRAMIndexFromFileIndex(fileIndex);
|
||||
unsigned long startIndexInFile = ramIndexTable[ramIndex];
|
||||
if(startIndexInFile == ULONG_MAX) {
|
||||
return;
|
||||
}
|
||||
unsigned enumeratedIndex = GetCellIndexFromRAMAndFileIndex(ramIndex, fileIndex);
|
||||
|
||||
if(!localStream.get() || !localStream->is_open()) {
|
||||
localStream.reset(new std::ifstream(iif.c_str(), std::ios::in | std::ios::binary));
|
||||
}
|
||||
if(!localStream->good()) {
|
||||
localStream->clear(std::ios::goodbit);
|
||||
DEBUG("Resetting stale filestream");
|
||||
}
|
||||
|
||||
//only read the single necessary cell index
|
||||
localStream->seekg(startIndexInFile+(enumeratedIndex*sizeof(unsigned long)));
|
||||
unsigned long fetchedIndex = 0;
|
||||
localStream->read(static_cast<char*>( static_cast<void*>(&fetchedIndex)), sizeof(unsigned long));
|
||||
|
||||
if(fetchedIndex == ULONG_MAX) {
|
||||
return;
|
||||
}
|
||||
const unsigned long position = fetchedIndex + 32*32*sizeof(unsigned long) ;
|
||||
|
||||
unsigned lengthOfBucket;
|
||||
unsigned currentSizeOfResult = result.size();
|
||||
localStream->seekg(position);
|
||||
localStream->read(static_cast<char*>( static_cast<void*>(&(lengthOfBucket))), sizeof(unsigned));
|
||||
result.resize(currentSizeOfResult+lengthOfBucket);
|
||||
localStream->read(static_cast<char*>( static_cast<void*>(&result[currentSizeOfResult])), lengthOfBucket*sizeof(_GridEdge));
|
||||
}
|
||||
|
||||
inline void GetContentsOfFileBucket(const unsigned fileIndex, std::vector<_GridEdge>& result, boost::unordered_map< unsigned, unsigned> & cellMap) {
|
||||
unsigned ramIndex = GetRAMIndexFromFileIndex(fileIndex);
|
||||
unsigned long startIndexInFile = ramIndexTable[ramIndex];
|
||||
if(startIndexInFile == ULONG_MAX) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long cellIndex[32*32];
|
||||
|
||||
cellMap.clear();
|
||||
BuildCellIndexToFileIndexMap(ramIndex, cellMap);
|
||||
if(!localStream.get() || !localStream->is_open()) {
|
||||
localStream.reset(new std::ifstream(iif.c_str(), std::ios::in | std::ios::binary));
|
||||
}
|
||||
if(!localStream->good()) {
|
||||
localStream->clear(std::ios::goodbit);
|
||||
DEBUG("Resetting stale filestream");
|
||||
}
|
||||
|
||||
localStream->seekg(startIndexInFile);
|
||||
localStream->read(static_cast<char*>(static_cast<void*>( cellIndex)), 32*32*sizeof(unsigned long));
|
||||
assert(cellMap.find(fileIndex) != cellMap.end());
|
||||
if(cellIndex[cellMap[fileIndex]] == ULONG_MAX) {
|
||||
return;
|
||||
}
|
||||
const unsigned long position = cellIndex[cellMap[fileIndex]] + 32*32*sizeof(unsigned long) ;
|
||||
|
||||
unsigned lengthOfBucket;
|
||||
unsigned currentSizeOfResult = result.size();
|
||||
localStream->seekg(position);
|
||||
localStream->read(static_cast<char*>(static_cast<void*>(&(lengthOfBucket))), sizeof(unsigned));
|
||||
result.resize(currentSizeOfResult+lengthOfBucket);
|
||||
localStream->read(static_cast<char*>(static_cast<void*>(&result[currentSizeOfResult])), lengthOfBucket*sizeof(_GridEdge));
|
||||
}
|
||||
|
||||
#ifndef ROUTED
|
||||
inline void AddEdge(const _GridEdge & edge) {
|
||||
std::vector<BresenhamPixel> indexList;
|
||||
GetListOfIndexesForEdgeAndGridSize(edge.startCoord, edge.targetCoord, indexList);
|
||||
for(unsigned i = 0; i < indexList.size(); ++i) {
|
||||
entries.push_back(GridEntry(edge, indexList[i].first, indexList[i].second));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
inline double ComputeDistance(const _Coordinate& inputPoint, const _Coordinate& source, const _Coordinate& target, _Coordinate& nearest, double *r) {
|
||||
// INFO("comparing point " << inputPoint << " to edge [" << source << "-" << target << "]");
|
||||
const double x = static_cast<double>(inputPoint.lat);
|
||||
const double y = static_cast<double>(inputPoint.lon);
|
||||
const double a = static_cast<double>(source.lat);
|
||||
const double b = static_cast<double>(source.lon);
|
||||
const double c = static_cast<double>(target.lat);
|
||||
const double d = static_cast<double>(target.lon);
|
||||
double p,q,mX,nY;
|
||||
// INFO("x=" << x << ", y=" << y << ", a=" << a << ", b=" << b << ", c=" << c << ", d=" << d);
|
||||
if(fabs(a-c) > FLT_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);
|
||||
mX = (p - nY*a)/c;// These values are actually n/m+n and m/m+n , we neednot calculate the values of m an n as we are just interested in the ratio
|
||||
// INFO("p=" << p << ", q=" << q << ", nY=" << nY << ", mX=" << mX);
|
||||
if(std::isnan(mX)) {
|
||||
*r = (target == inputPoint) ? 1. : 0.;
|
||||
} else {
|
||||
*r = mX;
|
||||
}
|
||||
// INFO("r=" << *r);
|
||||
if(*r<=0.){
|
||||
nearest.lat = source.lat;
|
||||
nearest.lon = source.lon;
|
||||
// INFO("a returning distance " << ((b - y)*(b - y) + (a - x)*(a - x)))
|
||||
return ((b - y)*(b - y) + (a - x)*(a - x));
|
||||
}
|
||||
else if(*r >= 1.){
|
||||
nearest.lat = target.lat;
|
||||
nearest.lon = target.lon;
|
||||
// INFO("b returning distance " << ((d - y)*(d - y) + (c - x)*(c - x)))
|
||||
|
||||
return ((d - y)*(d - y) + (c - x)*(c - x));
|
||||
}
|
||||
// point lies in between
|
||||
nearest.lat = p;
|
||||
nearest.lon = q;
|
||||
// INFO("c returning distance " << (p-x)*(p-x) + (q-y)*(q-y))
|
||||
|
||||
return (p-x)*(p-x) + (q-y)*(q-y);
|
||||
}
|
||||
|
||||
inline void GetListOfIndexesForEdgeAndGridSize(const _Coordinate& start, const _Coordinate& target, std::vector<BresenhamPixel> &indexList) const {
|
||||
double lat1 = start.lat/100000.;
|
||||
double lon1 = start.lon/100000.;
|
||||
|
||||
double x1 = ( lon1 + 180.0 ) / 360.0;
|
||||
double y1 = ( lat1 + 180.0 ) / 360.0;
|
||||
|
||||
double lat2 = target.lat/100000.;
|
||||
double lon2 = target.lon/100000.;
|
||||
|
||||
double x2 = ( lon2 + 180.0 ) / 360.0;
|
||||
double y2 = ( lat2 + 180.0 ) / 360.0;
|
||||
|
||||
Bresenham(x1*32768, y1*32768, x2*32768, y2*32768, indexList);
|
||||
BOOST_FOREACH(BresenhamPixel & pixel, indexList) {
|
||||
int fileIndex = (pixel.second-1)*32768 + pixel.first;
|
||||
int ramIndex = GetRAMIndexFromFileIndex(fileIndex);
|
||||
pixel.first = fileIndex;
|
||||
pixel.second = ramIndex;
|
||||
}
|
||||
}
|
||||
|
||||
inline unsigned GetFileIndexForLatLon(const int lt, const int ln) {
|
||||
double lat = lt/100000.;
|
||||
double lon = ln/100000.;
|
||||
|
||||
double x = ( lon + 180.0 ) / 360.0;
|
||||
double y = ( lat + 180.0 ) / 360.0;
|
||||
|
||||
if( x>1.0 || x < 0.)
|
||||
return UINT_MAX;
|
||||
if( y>1.0 || y < 0.)
|
||||
return UINT_MAX;
|
||||
|
||||
unsigned line = (32768 * (32768-1))*y;
|
||||
line = line - (line % 32768);
|
||||
assert(line % 32768 == 0);
|
||||
unsigned column = 32768.*x;
|
||||
unsigned fileIndex = line+column;
|
||||
return fileIndex;
|
||||
}
|
||||
|
||||
inline unsigned GetRAMIndexFromFileIndex(const int fileIndex) const {
|
||||
unsigned fileLine = fileIndex / 32768;
|
||||
fileLine = fileLine / 32;
|
||||
fileLine = fileLine * 1024;
|
||||
unsigned fileColumn = (fileIndex % 32768);
|
||||
fileColumn = fileColumn / 32;
|
||||
unsigned ramIndex = fileLine + fileColumn;
|
||||
assert(ramIndex < 1024*1024);
|
||||
return ramIndex;
|
||||
}
|
||||
|
||||
const static unsigned long END_OF_BUCKET_DELIMITER = UINT_MAX;
|
||||
|
||||
std::ofstream indexOutFile;
|
||||
std::ifstream ramInFile;
|
||||
#ifndef ROUTED
|
||||
stxxl::vector<GridEntry> entries;
|
||||
#endif
|
||||
std::vector<unsigned long> ramIndexTable; //8 MB for first level index in RAM
|
||||
std::string iif;
|
||||
// LRUCache<int,std::vector<unsigned> > cellCache;
|
||||
// LRUCache<int,std::vector<_Edge> > fileCache;
|
||||
};
|
||||
}
|
||||
|
||||
typedef NNGrid::NNGrid<false> ReadOnlyGrid;
|
||||
typedef NNGrid::NNGrid<true > WritableGrid;
|
||||
|
||||
#endif /* NNGRID_H_ */
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef _NODE_COORDS_H
|
||||
#define _NODE_COORDS_H
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <climits>
|
||||
#include <limits>
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
template<typename NodeT>
|
||||
struct NodeCoords {
|
||||
typedef unsigned key_type; //type of NodeID
|
||||
typedef int value_type; //type of lat,lons
|
||||
|
||||
NodeCoords(int _lat, int _lon, NodeT _id) : lat(_lat), lon(_lon), id(_id) {}
|
||||
NodeCoords() : lat(INT_MAX), lon(INT_MAX), id(UINT_MAX) {}
|
||||
int lat;
|
||||
int lon;
|
||||
NodeT id;
|
||||
|
||||
static NodeCoords<NodeT> min_value() {
|
||||
return NodeCoords<NodeT>(-90*100000,-180*100000,std::numeric_limits<NodeT>::min());
|
||||
}
|
||||
static NodeCoords<NodeT> max_value() {
|
||||
return NodeCoords<NodeT>(90*100000, 180*100000, std::numeric_limits<NodeT>::max());
|
||||
}
|
||||
|
||||
value_type operator[](std::size_t n) const {
|
||||
switch(n) {
|
||||
case 1:
|
||||
return lat;
|
||||
break;
|
||||
case 0:
|
||||
return lon;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
return UINT_MAX;
|
||||
break;
|
||||
}
|
||||
assert(false);
|
||||
return UINT_MAX;
|
||||
}
|
||||
};
|
||||
|
||||
typedef NodeCoords<NodeID> NodeInfo;
|
||||
|
||||
#endif //_NODE_COORDS_H
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef NODEINFORMATIONHELPDESK_H_
|
||||
#define NODEINFORMATIONHELPDESK_H_
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "NNGrid.h"
|
||||
#include "PhantomNodes.h"
|
||||
#include "NodeCoords.h"
|
||||
|
||||
class NodeInformationHelpDesk{
|
||||
public:
|
||||
NodeInformationHelpDesk(const char* ramIndexInput, const char* fileIndexInput, const unsigned _numberOfNodes, const unsigned crc) : numberOfNodes(_numberOfNodes), checkSum(crc) {
|
||||
readOnlyGrid = new ReadOnlyGrid(ramIndexInput,fileIndexInput);
|
||||
assert(0 == coordinateVector.size());
|
||||
}
|
||||
|
||||
//Todo: Shared memory mechanism
|
||||
// NodeInformationHelpDesk(const char* ramIndexInput, const char* fileIndexInput, const unsigned crc) : checkSum(crc) {
|
||||
// readOnlyGrid = new ReadOnlyGrid(ramIndexInput,fileIndexInput);
|
||||
// }
|
||||
|
||||
~NodeInformationHelpDesk() {
|
||||
delete readOnlyGrid;
|
||||
}
|
||||
void initNNGrid(std::ifstream& nodesInstream, std::ifstream& edgesInStream) {
|
||||
DEBUG("Loading node data");
|
||||
NodeInfo b;
|
||||
while(!nodesInstream.eof()) {
|
||||
nodesInstream.read((char *)&b, sizeof(NodeInfo));
|
||||
coordinateVector.push_back(_Coordinate(b.lat, b.lon));
|
||||
}
|
||||
std::vector<_Coordinate>(coordinateVector).swap(coordinateVector);
|
||||
nodesInstream.close();
|
||||
|
||||
DEBUG("Loading edge data");
|
||||
unsigned numberOfOrigEdges(0);
|
||||
edgesInStream.read((char*)&numberOfOrigEdges, sizeof(unsigned));
|
||||
origEdgeData.resize(numberOfOrigEdges);
|
||||
edgesInStream.read((char*)&(origEdgeData[0]), numberOfOrigEdges*sizeof(OriginalEdgeData));
|
||||
edgesInStream.close();
|
||||
DEBUG("Loaded " << numberOfOrigEdges << " orig edges");
|
||||
DEBUG("Opening NN indices");
|
||||
readOnlyGrid->OpenIndexFiles();
|
||||
}
|
||||
|
||||
void initNNGrid() {
|
||||
readOnlyGrid->OpenIndexFiles();
|
||||
}
|
||||
|
||||
inline int getLatitudeOfNode(const unsigned id) const {
|
||||
const NodeID node = origEdgeData.at(id).viaNode;
|
||||
return coordinateVector.at(node).lat;
|
||||
}
|
||||
|
||||
inline int getLongitudeOfNode(const unsigned id) const {
|
||||
const NodeID node = origEdgeData.at(id).viaNode;
|
||||
return coordinateVector.at(node).lon;
|
||||
}
|
||||
|
||||
inline unsigned getNameIndexFromEdgeID(const unsigned id) const {
|
||||
return origEdgeData.at(id).nameID;
|
||||
}
|
||||
|
||||
inline TurnInstruction getTurnInstructionFromEdgeID(const unsigned id) const {
|
||||
return origEdgeData.at(id).turnInstruction;
|
||||
}
|
||||
|
||||
inline NodeID getNumberOfNodes() const { return numberOfNodes; }
|
||||
inline NodeID getNumberOfNodes2() const { return coordinateVector.size(); }
|
||||
|
||||
inline bool FindNearestNodeCoordForLatLon(const _Coordinate& coord, _Coordinate& result) const {
|
||||
return readOnlyGrid->FindNearestCoordinateOnEdgeInNodeBasedGraph(coord, result);
|
||||
}
|
||||
|
||||
inline bool FindPhantomNodeForCoordinate( const _Coordinate & location, PhantomNode & resultNode, const unsigned zoomLevel) const {
|
||||
return readOnlyGrid->FindPhantomNodeForCoordinate(location, resultNode, zoomLevel);
|
||||
}
|
||||
|
||||
inline void FindRoutingStarts(const _Coordinate &start, const _Coordinate &target, PhantomNodes & phantomNodes, const unsigned zoomLevel) const {
|
||||
readOnlyGrid->FindRoutingStarts(start, target, phantomNodes, zoomLevel);
|
||||
}
|
||||
|
||||
inline void FindNearestPointOnEdge(const _Coordinate & input, _Coordinate& output){
|
||||
readOnlyGrid->FindNearestPointOnEdge(input, output);
|
||||
}
|
||||
|
||||
inline unsigned GetCheckSum() const {
|
||||
return checkSum;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<_Coordinate> coordinateVector;
|
||||
std::vector<OriginalEdgeData> origEdgeData;
|
||||
|
||||
ReadOnlyGrid * readOnlyGrid;
|
||||
const unsigned numberOfNodes;
|
||||
const unsigned checkSum;
|
||||
};
|
||||
|
||||
#endif /*NODEINFORMATIONHELPDESK_H_*/
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef PERCENT_H
|
||||
#define PERCENT_H
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
class Percent
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param maxValue the value that corresponds to 100%
|
||||
* @param step the progress is shown in steps of 'step' percent
|
||||
*/
|
||||
Percent(unsigned maxValue, unsigned step = 5) {
|
||||
reinit(maxValue, step);
|
||||
}
|
||||
|
||||
/** Reinitializes this object. */
|
||||
void reinit(unsigned maxValue, unsigned step = 5) {
|
||||
_maxValue = maxValue;
|
||||
_current_value = 0;
|
||||
_intervalPercent = _maxValue / 100;
|
||||
_nextThreshold = _intervalPercent;
|
||||
_lastPercent = 0;
|
||||
_step = step;
|
||||
}
|
||||
|
||||
/** If there has been significant progress, display it. */
|
||||
void printStatus(unsigned currentValue) {
|
||||
if (currentValue >= _nextThreshold) {
|
||||
_nextThreshold += _intervalPercent;
|
||||
printPercent( currentValue / (double)_maxValue * 100 );
|
||||
}
|
||||
if (currentValue + 1 == _maxValue)
|
||||
std::cout << " 100%" << std::endl;
|
||||
}
|
||||
|
||||
void printIncrement()
|
||||
{
|
||||
#pragma omp atomic
|
||||
++_current_value;
|
||||
printStatus(_current_value);
|
||||
}
|
||||
|
||||
void printAddition(const unsigned addition) {
|
||||
#pragma omp atomic
|
||||
_current_value += addition;
|
||||
printStatus(_current_value);
|
||||
}
|
||||
private:
|
||||
unsigned _current_value;
|
||||
unsigned _maxValue;
|
||||
unsigned _intervalPercent;
|
||||
unsigned _nextThreshold;
|
||||
unsigned _lastPercent;
|
||||
unsigned _step;
|
||||
|
||||
/** Displays the new progress. */
|
||||
void printPercent(double percent) {
|
||||
while (percent >= _lastPercent+_step) {
|
||||
_lastPercent+=_step;
|
||||
if (_lastPercent % 10 == 0) {
|
||||
std::cout << " " << _lastPercent << "% ";
|
||||
}
|
||||
else {
|
||||
std::cout << ".";
|
||||
}
|
||||
std::cout.flush();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // PERCENT_H
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef PHANTOMNODES_H_
|
||||
#define PHANTOMNODES_H_
|
||||
|
||||
#include "Coordinate.h"
|
||||
|
||||
struct PhantomNode {
|
||||
PhantomNode() : edgeBasedNode(UINT_MAX), nodeBasedEdgeNameID(UINT_MAX), weight1(INT_MAX), weight2(INT_MAX), ratio(0.) {}
|
||||
NodeID edgeBasedNode;
|
||||
unsigned nodeBasedEdgeNameID;
|
||||
int weight1;
|
||||
int weight2;
|
||||
double ratio;
|
||||
_Coordinate location;
|
||||
void Reset() {
|
||||
edgeBasedNode = UINT_MAX;
|
||||
nodeBasedEdgeNameID = UINT_MAX;
|
||||
weight1 = INT_MAX;
|
||||
weight2 = INT_MAX;
|
||||
ratio = 0.;
|
||||
location.Reset();
|
||||
}
|
||||
bool isBidirected() const {
|
||||
return weight2 != INT_MAX;
|
||||
}
|
||||
bool isValid(const unsigned numberOfNodes) const {
|
||||
return location.isValid() && (edgeBasedNode < numberOfNodes) && (weight1 != INT_MAX) && (ratio >= 0.) && (ratio <= 1.) && (nodeBasedEdgeNameID != UINT_MAX);
|
||||
}
|
||||
|
||||
bool operator==(const PhantomNode & other) const {
|
||||
return location == other.location;
|
||||
}
|
||||
};
|
||||
|
||||
struct PhantomNodes {
|
||||
PhantomNode startPhantom;
|
||||
PhantomNode targetPhantom;
|
||||
void Reset() {
|
||||
startPhantom.Reset();
|
||||
targetPhantom.Reset();
|
||||
}
|
||||
|
||||
bool PhantomsAreOnSameNodeBasedEdge() const {
|
||||
return (startPhantom.edgeBasedNode == targetPhantom.edgeBasedNode);
|
||||
}
|
||||
|
||||
bool AtLeastOnePhantomNodeIsUINTMAX() const {
|
||||
return !(startPhantom.edgeBasedNode == UINT_MAX || targetPhantom.edgeBasedNode == UINT_MAX);
|
||||
}
|
||||
|
||||
bool PhantomNodesHaveEqualLocation() const {
|
||||
return startPhantom == targetPhantom;
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream &out, const PhantomNodes & pn){
|
||||
out << "Node1: " << pn.startPhantom.edgeBasedNode << std::endl;
|
||||
out << "Node2: " << pn.targetPhantom.edgeBasedNode << std::endl;
|
||||
out << "startCoord: " << pn.startPhantom.location << std::endl;
|
||||
out << "targetCoord: " << pn.targetPhantom.location << std::endl;
|
||||
return out;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream &out, const PhantomNode & pn){
|
||||
out << "node: " << pn.edgeBasedNode << ", name: " << pn.nodeBasedEdgeNameID << ", w1: " << pn.weight1 << ", w2: " << pn.weight2 << ", ratio: " << pn.ratio << ", loc: " << pn.location;
|
||||
return out;
|
||||
}
|
||||
|
||||
struct NodesOfEdge {
|
||||
NodeID edgeBasedNode;
|
||||
double ratio;
|
||||
_Coordinate projectedPoint;
|
||||
};
|
||||
|
||||
#endif /* PHANTOMNODES_H_ */
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef QUERYEDGE_H_
|
||||
#define QUERYEDGE_H_
|
||||
|
||||
#include "TurnInstructions.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
struct OriginalEdgeData{
|
||||
explicit OriginalEdgeData(NodeID v, unsigned n, TurnInstruction t) : viaNode(v), nameID(n), turnInstruction(t) {}
|
||||
OriginalEdgeData() : viaNode(UINT_MAX), nameID(UINT_MAX), turnInstruction(UCHAR_MAX) {}
|
||||
NodeID viaNode;
|
||||
unsigned nameID;
|
||||
TurnInstruction turnInstruction;
|
||||
};
|
||||
|
||||
struct QueryEdge {
|
||||
NodeID source;
|
||||
NodeID target;
|
||||
struct EdgeData {
|
||||
NodeID id:31;
|
||||
int distance:30;
|
||||
bool shortcut:1;
|
||||
bool forward:1;
|
||||
bool backward:1;
|
||||
} data;
|
||||
bool operator<( const QueryEdge& right ) const {
|
||||
if ( source != right.source )
|
||||
return source < right.source;
|
||||
return target < right.target;
|
||||
}
|
||||
|
||||
//sorts by source and other attributes
|
||||
static bool CompareBySource( const QueryEdge& left, const QueryEdge& right ) {
|
||||
if ( left.source != right.source )
|
||||
return left.source < right.source;
|
||||
int l = ( left.data.forward ? -1 : 0 ) + ( left.data.backward ? -1 : 0 );
|
||||
int r = ( right.data.forward ? -1 : 0 ) + ( right.data.backward ? -1 : 0 );
|
||||
if ( l != r )
|
||||
return l < r;
|
||||
if ( left.target != right.target )
|
||||
return left.target < right.target;
|
||||
return left.data.distance < right.data.distance;
|
||||
}
|
||||
|
||||
bool operator== ( const QueryEdge& right ) const {
|
||||
return ( source == right.source && target == right.target && data.distance == right.data.distance &&
|
||||
data.shortcut == right.data.shortcut && data.forward == right.data.forward && data.backward == right.data.backward
|
||||
&& data.id == right.data.id
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* QUERYEDGE_H_ */
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef RESTRICTION_H_
|
||||
#define RESTRICTION_H_
|
||||
|
||||
#include <climits>
|
||||
|
||||
struct _Restriction {
|
||||
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) {}
|
||||
char isOnly:1;
|
||||
char unused1:1;
|
||||
char unused2:1;
|
||||
char unused3:1;
|
||||
char unused4:1;
|
||||
char unused5:1;
|
||||
char unused6:1;
|
||||
char unused7:1;
|
||||
} flags;
|
||||
|
||||
_Restriction(NodeID vn) : viaNode(vn), fromNode(UINT_MAX), toNode(UINT_MAX) { }
|
||||
_Restriction(bool isOnly = false) : viaNode(UINT_MAX), fromNode(UINT_MAX), toNode(UINT_MAX) {
|
||||
flags.isOnly = isOnly;
|
||||
}
|
||||
};
|
||||
|
||||
inline bool CmpRestrictionByFrom ( _Restriction a, _Restriction b) { return (a.fromNode < b.fromNode); }
|
||||
|
||||
struct _RawRestrictionContainer {
|
||||
_Restriction restriction;
|
||||
EdgeID fromWay;
|
||||
EdgeID toWay;
|
||||
unsigned viaNode;
|
||||
|
||||
_RawRestrictionContainer(EdgeID f, EdgeID t, NodeID vn, unsigned vw) : fromWay(f), toWay(t), viaNode(vw) { restriction.viaNode = vn;}
|
||||
_RawRestrictionContainer(bool isOnly = false) : fromWay(UINT_MAX), toWay(UINT_MAX), viaNode(UINT_MAX) { restriction.flags.isOnly = isOnly;}
|
||||
|
||||
static _RawRestrictionContainer min_value() {
|
||||
return _RawRestrictionContainer(0, 0, 0, 0);
|
||||
}
|
||||
static _RawRestrictionContainer max_value() {
|
||||
return _RawRestrictionContainer(UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX);
|
||||
}
|
||||
};
|
||||
|
||||
struct CmpRestrictionContainerByFrom: public std::binary_function<_RawRestrictionContainer, _RawRestrictionContainer, bool> {
|
||||
typedef _RawRestrictionContainer value_type;
|
||||
bool operator () (const _RawRestrictionContainer & a, const _RawRestrictionContainer & b) const {
|
||||
return a.fromWay < b.fromWay;
|
||||
}
|
||||
value_type max_value() {
|
||||
return _RawRestrictionContainer::max_value();
|
||||
}
|
||||
value_type min_value() {
|
||||
return _RawRestrictionContainer::min_value();
|
||||
}
|
||||
};
|
||||
|
||||
struct CmpRestrictionContainerByTo: public std::binary_function<_RawRestrictionContainer, _RawRestrictionContainer, bool> {
|
||||
typedef _RawRestrictionContainer value_type;
|
||||
bool operator () (const _RawRestrictionContainer & a, const _RawRestrictionContainer & b) const {
|
||||
return a.toWay < b.toWay;
|
||||
}
|
||||
value_type max_value() {
|
||||
return _RawRestrictionContainer::max_value();
|
||||
}
|
||||
value_type min_value() {
|
||||
return _RawRestrictionContainer::min_value();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* RESTRICTION_H_ */
|
||||
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef SEARCHENGINE_H_
|
||||
#define SEARCHENGINE_H_
|
||||
|
||||
#include <climits>
|
||||
#include <deque>
|
||||
#include "SimpleStack.h"
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include "BinaryHeap.h"
|
||||
#include "NodeInformationHelpDesk.h"
|
||||
#include "PhantomNodes.h"
|
||||
#include "../RoutingAlgorithms/AlternativePathRouting.h"
|
||||
#include "../RoutingAlgorithms/BasicRoutingInterface.h"
|
||||
#include "../RoutingAlgorithms/ShortestPathRouting.h"
|
||||
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
struct _HeapData {
|
||||
NodeID parent;
|
||||
_HeapData( NodeID p ) : parent(p) { }
|
||||
};
|
||||
|
||||
typedef boost::thread_specific_ptr<BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> > > SearchEngineHeapPtr;
|
||||
|
||||
template<class EdgeData, class GraphT>
|
||||
struct SearchEngineData {
|
||||
typedef SearchEngineHeapPtr HeapPtr;
|
||||
typedef GraphT Graph;
|
||||
SearchEngineData(GraphT * g, NodeInformationHelpDesk * nh, std::vector<string> & n) :graph(g), nodeHelpDesk(nh), names(n) {}
|
||||
const GraphT * graph;
|
||||
NodeInformationHelpDesk * nodeHelpDesk;
|
||||
std::vector<string> & names;
|
||||
static HeapPtr forwardHeap;
|
||||
static HeapPtr backwardHeap;
|
||||
static HeapPtr forwardHeap2;
|
||||
static HeapPtr backwardHeap2;
|
||||
static HeapPtr forwardHeap3;
|
||||
static HeapPtr backwardHeap3;
|
||||
|
||||
inline void InitializeOrClearFirstThreadLocalStorage() {
|
||||
if(!forwardHeap.get()) {
|
||||
forwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> >(nodeHelpDesk->getNumberOfNodes()));
|
||||
}
|
||||
else
|
||||
forwardHeap->Clear();
|
||||
|
||||
if(!backwardHeap.get()) {
|
||||
backwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> >(nodeHelpDesk->getNumberOfNodes()));
|
||||
}
|
||||
else
|
||||
backwardHeap->Clear();
|
||||
}
|
||||
|
||||
inline void InitializeOrClearSecondThreadLocalStorage() {
|
||||
if(!forwardHeap2.get()) {
|
||||
forwardHeap2.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> >(nodeHelpDesk->getNumberOfNodes()));
|
||||
}
|
||||
else
|
||||
forwardHeap2->Clear();
|
||||
|
||||
if(!backwardHeap2.get()) {
|
||||
backwardHeap2.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> >(nodeHelpDesk->getNumberOfNodes()));
|
||||
}
|
||||
else
|
||||
backwardHeap2->Clear();
|
||||
}
|
||||
|
||||
inline void InitializeOrClearThirdThreadLocalStorage() {
|
||||
if(!forwardHeap3.get()) {
|
||||
forwardHeap3.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> >(nodeHelpDesk->getNumberOfNodes()));
|
||||
}
|
||||
else
|
||||
forwardHeap3->Clear();
|
||||
|
||||
if(!backwardHeap3.get()) {
|
||||
backwardHeap3.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> >(nodeHelpDesk->getNumberOfNodes()));
|
||||
}
|
||||
else
|
||||
backwardHeap3->Clear();
|
||||
}
|
||||
};
|
||||
|
||||
template<class EdgeData, class GraphT>
|
||||
class SearchEngine {
|
||||
private:
|
||||
typedef SearchEngineData<EdgeData, GraphT> SearchEngineDataT;
|
||||
SearchEngineDataT _queryData;
|
||||
|
||||
inline double absDouble(double input) { if(input < 0) return input*(-1); else return input;}
|
||||
public:
|
||||
ShortestPathRouting<SearchEngineDataT> shortestPath;
|
||||
AlternativeRouting<SearchEngineDataT> alternativePaths;
|
||||
|
||||
SearchEngine(GraphT * g, NodeInformationHelpDesk * nh, std::vector<string> & n) :
|
||||
_queryData(g, nh, n),
|
||||
shortestPath(_queryData),
|
||||
alternativePaths(_queryData)
|
||||
{}
|
||||
~SearchEngine() {}
|
||||
|
||||
inline void GetCoordinatesForNodeID(NodeID id, _Coordinate& result) const {
|
||||
result.lat = _queryData.nodeHelpDesk->getLatitudeOfNode(id);
|
||||
result.lon = _queryData.nodeHelpDesk->getLongitudeOfNode(id);
|
||||
}
|
||||
|
||||
inline void FindRoutingStarts(const _Coordinate & start, const _Coordinate & target, PhantomNodes & routingStarts) const {
|
||||
_queryData.nodeHelpDesk->FindRoutingStarts(start, target, routingStarts);
|
||||
}
|
||||
|
||||
inline void FindPhantomNodeForCoordinate(const _Coordinate & location, PhantomNode & result, unsigned zoomLevel) const {
|
||||
_queryData.nodeHelpDesk->FindPhantomNodeForCoordinate(location, result, zoomLevel);
|
||||
}
|
||||
|
||||
inline NodeID GetNameIDForOriginDestinationNodeID(const NodeID s, const NodeID t) const {
|
||||
if(s == t)
|
||||
return 0;
|
||||
|
||||
EdgeID e = _queryData.graph->FindEdge(s, t);
|
||||
if(e == UINT_MAX)
|
||||
e = _queryData.graph->FindEdge( t, s );
|
||||
if(UINT_MAX == e) {
|
||||
return 0;
|
||||
}
|
||||
assert(e != UINT_MAX);
|
||||
const EdgeData ed = _queryData.graph->GetEdgeData(e);
|
||||
return ed.via;
|
||||
}
|
||||
|
||||
inline std::string GetEscapedNameForNameID(const unsigned nameID) const {
|
||||
return ((nameID >= _queryData.names.size() || nameID == 0) ? std::string("") : HTMLEntitize(_queryData.names.at(nameID)));
|
||||
}
|
||||
|
||||
inline std::string GetEscapedNameForEdgeBasedEdgeID(const unsigned edgeID) const {
|
||||
const unsigned nameID = _queryData.graph->GetEdgeData(edgeID).nameID1;
|
||||
return GetEscapedNameForNameID(nameID);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<class EdgeData, class GraphT> SearchEngineHeapPtr SearchEngineData<EdgeData, GraphT>::forwardHeap;
|
||||
template<class EdgeData, class GraphT> SearchEngineHeapPtr SearchEngineData<EdgeData, GraphT>::backwardHeap;
|
||||
|
||||
template<class EdgeData, class GraphT> SearchEngineHeapPtr SearchEngineData<EdgeData, GraphT>::forwardHeap2;
|
||||
template<class EdgeData, class GraphT> SearchEngineHeapPtr SearchEngineData<EdgeData, GraphT>::backwardHeap2;
|
||||
|
||||
template<class EdgeData, class GraphT> SearchEngineHeapPtr SearchEngineData<EdgeData, GraphT>::forwardHeap3;
|
||||
template<class EdgeData, class GraphT> SearchEngineHeapPtr SearchEngineData<EdgeData, GraphT>::backwardHeap3;
|
||||
|
||||
#endif /* SEARCHENGINE_H_ */
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef SEGMENTINFORMATION_H_
|
||||
#define SEGMENTINFORMATION_H_
|
||||
|
||||
#include <climits>
|
||||
|
||||
#include "TurnInstructions.h"
|
||||
|
||||
struct SegmentInformation {
|
||||
_Coordinate location;
|
||||
NodeID nameID;
|
||||
double length;
|
||||
unsigned duration;
|
||||
double bearing;
|
||||
TurnInstruction turnInstruction;
|
||||
bool necessary;
|
||||
SegmentInformation(const _Coordinate & loc, const NodeID nam, const double len, const unsigned dur, const TurnInstruction tInstr, const bool nec) :
|
||||
location(loc), nameID(nam), length(len), duration(dur), bearing(0.), turnInstruction(tInstr), necessary(nec) {}
|
||||
SegmentInformation(const _Coordinate & loc, const NodeID nam, const double len, const unsigned dur, const TurnInstruction tInstr) :
|
||||
location(loc), nameID(nam), length(len), duration(dur), bearing(0.), turnInstruction(tInstr), necessary(tInstr != 0) {}
|
||||
};
|
||||
|
||||
#endif /* SEGMENTINFORMATION_H_ */
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef SIMPLESTACK_H_
|
||||
#define SIMPLESTACK_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
template<typename StackItemT, class ContainerT = std::vector<StackItemT> >
|
||||
class SimpleStack {
|
||||
|
||||
private:
|
||||
int last;
|
||||
ContainerT arr;
|
||||
|
||||
public:
|
||||
SimpleStack() : last(-1) {
|
||||
}
|
||||
|
||||
SimpleStack(std::size_t size_hint) : last(-1) {
|
||||
hint(size_hint);
|
||||
}
|
||||
|
||||
inline void hint(std::size_t size_hint) {
|
||||
arr.reserve(size_hint);
|
||||
}
|
||||
|
||||
inline void push(StackItemT t) {
|
||||
++last;
|
||||
arr.push_back(t);
|
||||
}
|
||||
|
||||
inline void pop() {
|
||||
arr.pop_back();
|
||||
--last;
|
||||
}
|
||||
|
||||
inline StackItemT top() {
|
||||
assert (last >= 0);
|
||||
return arr[last];
|
||||
}
|
||||
|
||||
inline int size() {
|
||||
return last+1;
|
||||
}
|
||||
|
||||
inline bool empty() {
|
||||
return (-1 == last);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif /* SIMPLESTACK_H_ */
|
||||
@@ -1,188 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef STATICGRAPH_H_INCLUDED
|
||||
#define STATICGRAPH_H_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "ImportEdge.h"
|
||||
|
||||
template< typename EdgeDataT>
|
||||
class StaticGraph {
|
||||
public:
|
||||
typedef NodeID NodeIterator;
|
||||
typedef NodeID EdgeIterator;
|
||||
typedef EdgeDataT EdgeData;
|
||||
class InputEdge {
|
||||
public:
|
||||
EdgeDataT data;
|
||||
NodeIterator source;
|
||||
NodeIterator target;
|
||||
bool operator<( const InputEdge& right ) const {
|
||||
if ( source != right.source )
|
||||
return source < right.source;
|
||||
return target < right.target;
|
||||
}
|
||||
};
|
||||
|
||||
struct _StrNode {
|
||||
//index of the first edge
|
||||
EdgeIterator firstEdge;
|
||||
};
|
||||
|
||||
struct _StrEdge {
|
||||
NodeID target;
|
||||
EdgeDataT data;
|
||||
};
|
||||
|
||||
StaticGraph( const int nodes, std::vector< InputEdge > &graph ) {
|
||||
std::sort( graph.begin(), graph.end() );
|
||||
_numNodes = nodes;
|
||||
_numEdges = ( EdgeIterator ) graph.size();
|
||||
_nodes.resize( _numNodes + 1);
|
||||
EdgeIterator edge = 0;
|
||||
EdgeIterator position = 0;
|
||||
for ( NodeIterator node = 0; node <= _numNodes; ++node ) {
|
||||
EdgeIterator lastEdge = edge;
|
||||
while ( edge < _numEdges && graph[edge].source == node )
|
||||
++edge;
|
||||
_nodes[node].firstEdge = position; //=edge
|
||||
position += edge - lastEdge; //remove
|
||||
}
|
||||
_edges.resize( position ); //(edge)
|
||||
edge = 0;
|
||||
for ( NodeIterator node = 0; node < _numNodes; ++node ) {
|
||||
for ( EdgeIterator i = _nodes[node].firstEdge, e = _nodes[node+1].firstEdge; i != e; ++i ) {
|
||||
_edges[i].target = graph[edge].target;
|
||||
_edges[i].data = graph[edge].data;
|
||||
assert(_edges[i].data.distance > 0);
|
||||
edge++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StaticGraph( std::vector<_StrNode> & nodes, std::vector<_StrEdge> & edges) {
|
||||
_numNodes = nodes.size();
|
||||
_numEdges = edges.size();
|
||||
|
||||
_nodes.swap(nodes);
|
||||
_edges.swap(edges);
|
||||
|
||||
//Add dummy node to end of _nodes array;
|
||||
_nodes.push_back(_nodes.back());
|
||||
|
||||
#ifndef NDEBUG
|
||||
Percent p(GetNumberOfNodes());
|
||||
for(unsigned u = 0; u < GetNumberOfNodes(); ++u) {
|
||||
for(unsigned eid = BeginEdges(u); eid < EndEdges(u); ++eid) {
|
||||
unsigned v = GetTarget(eid);
|
||||
EdgeData & data = GetEdgeData(eid);
|
||||
if(data.shortcut) {
|
||||
unsigned eid2 = FindEdgeInEitherDirection(u, data.id);
|
||||
if(eid2 == UINT_MAX) {
|
||||
DEBUG("cannot find first segment of edge (" << u << "," << data.id << "," << v << ")");
|
||||
data.shortcut = false;
|
||||
}
|
||||
eid2 = FindEdgeInEitherDirection(data.id, v);
|
||||
if(eid2 == UINT_MAX) {
|
||||
DEBUG("cannot find second segment of edge (" << u << "," << data.id << "," << v << ")");
|
||||
data.shortcut = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
p.printIncrement();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned GetNumberOfNodes() const {
|
||||
return _numNodes;
|
||||
}
|
||||
|
||||
unsigned GetNumberOfEdges() const {
|
||||
return _numEdges;
|
||||
}
|
||||
|
||||
unsigned GetOutDegree( const NodeIterator &n ) const {
|
||||
return BeginEdges(n)-EndEdges(n) - 1;
|
||||
}
|
||||
|
||||
inline NodeIterator GetTarget( const EdgeIterator &e ) const {
|
||||
return NodeIterator( _edges[e].target );
|
||||
}
|
||||
|
||||
inline EdgeDataT &GetEdgeData( const EdgeIterator &e ) {
|
||||
return _edges[e].data;
|
||||
}
|
||||
|
||||
const EdgeDataT &GetEdgeData( const EdgeIterator &e ) const {
|
||||
return _edges[e].data;
|
||||
}
|
||||
|
||||
EdgeIterator BeginEdges( const NodeIterator &n ) const {
|
||||
return EdgeIterator( _nodes[n].firstEdge );
|
||||
}
|
||||
|
||||
EdgeIterator EndEdges( const NodeIterator &n ) const {
|
||||
return EdgeIterator( _nodes[n+1].firstEdge );
|
||||
}
|
||||
|
||||
//searches for a specific edge
|
||||
EdgeIterator FindEdge( const NodeIterator &from, const NodeIterator &to ) const {
|
||||
EdgeIterator smallestEdge = SPECIAL_EDGEID;
|
||||
EdgeWeight smallestWeight = UINT_MAX;
|
||||
for ( EdgeIterator edge = BeginEdges( from ); edge < EndEdges(from); edge++ ) {
|
||||
const NodeID target = GetTarget(edge);
|
||||
const EdgeWeight weight = GetEdgeData(edge).distance;
|
||||
if(target == to && weight < smallestWeight) {
|
||||
smallestEdge = edge; smallestWeight = weight;
|
||||
}
|
||||
}
|
||||
return smallestEdge;
|
||||
}
|
||||
|
||||
EdgeIterator FindEdgeInEitherDirection( const NodeIterator &from, const NodeIterator &to ) const {
|
||||
EdgeIterator tmp = FindEdge( from, to );
|
||||
return (UINT_MAX != tmp ? tmp : FindEdge( to, from ));
|
||||
}
|
||||
|
||||
EdgeIterator FindEdgeIndicateIfReverse( const NodeIterator &from, const NodeIterator &to, bool & result ) const {
|
||||
EdgeIterator tmp = FindEdge( from, to );
|
||||
if(UINT_MAX == tmp) {
|
||||
tmp = FindEdge( to, from );
|
||||
if(UINT_MAX != tmp)
|
||||
result = true;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
NodeIterator _numNodes;
|
||||
EdgeIterator _numEdges;
|
||||
|
||||
std::vector< _StrNode > _nodes;
|
||||
std::vector< _StrEdge > _edges;
|
||||
};
|
||||
|
||||
#endif // STATICGRAPH_H_INCLUDED
|
||||
@@ -1,223 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
|
||||
KD Tree coded by Christian Vetter, Monav Project
|
||||
|
||||
*/
|
||||
#ifndef STATICKDTREE_H_INCLUDED
|
||||
#define STATICKDTREE_H_INCLUDED
|
||||
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stack>
|
||||
#include <limits>
|
||||
|
||||
namespace KDTree {
|
||||
|
||||
#define KDTREE_BASESIZE (8)
|
||||
|
||||
template< unsigned k, typename T >
|
||||
class BoundingBox {
|
||||
public:
|
||||
BoundingBox() {
|
||||
for ( unsigned dim = 0; dim < k; ++dim ) {
|
||||
min[dim] = std::numeric_limits< T >::min();
|
||||
max[dim] = std::numeric_limits< T >::max();
|
||||
}
|
||||
}
|
||||
|
||||
T min[k];
|
||||
T max[k];
|
||||
};
|
||||
|
||||
struct NoData {};
|
||||
|
||||
template< unsigned k, typename T >
|
||||
class EuclidianMetric {
|
||||
public:
|
||||
double operator() ( const T left[k], const T right[k] ) {
|
||||
double result = 0;
|
||||
for ( unsigned i = 0; i < k; ++i ) {
|
||||
double temp = (double)left[i] - (double)right[i];
|
||||
result += temp * temp;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
double operator() ( const BoundingBox< k, T > &box, const T point[k] ) {
|
||||
T nearest[k];
|
||||
for ( unsigned dim = 0; dim < k; ++dim ) {
|
||||
if ( point[dim] < box.min[dim] )
|
||||
nearest[dim] = box.min[dim];
|
||||
else if ( point[dim] > box.max[dim] )
|
||||
nearest[dim] = box.max[dim];
|
||||
else
|
||||
nearest[dim] = point[dim];
|
||||
}
|
||||
return operator() ( point, nearest );
|
||||
}
|
||||
};
|
||||
|
||||
template < unsigned k, typename T, typename Data = NoData, typename Metric = EuclidianMetric< k, T > >
|
||||
class StaticKDTree {
|
||||
public:
|
||||
|
||||
struct InputPoint {
|
||||
T coordinates[k];
|
||||
Data data;
|
||||
bool operator==( const InputPoint& right )
|
||||
{
|
||||
for ( int i = 0; i < k; i++ ) {
|
||||
if ( coordinates[i] != right.coordinates[i] )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
StaticKDTree( std::vector< InputPoint > * points ){
|
||||
assert( k > 0 );
|
||||
assert ( points->size() > 0 );
|
||||
size = points->size();
|
||||
kdtree = new InputPoint[size];
|
||||
for ( Iterator i = 0; i != size; ++i ) {
|
||||
kdtree[i] = points->at(i);
|
||||
for ( unsigned dim = 0; dim < k; ++dim ) {
|
||||
if ( kdtree[i].coordinates[dim] < boundingBox.min[dim] )
|
||||
boundingBox.min[dim] = kdtree[i].coordinates[dim];
|
||||
if ( kdtree[i].coordinates[dim] > boundingBox.max[dim] )
|
||||
boundingBox.max[dim] = kdtree[i].coordinates[dim];
|
||||
}
|
||||
}
|
||||
std::stack< Tree > s;
|
||||
s.push ( Tree ( 0, size, 0 ) );
|
||||
while ( !s.empty() ) {
|
||||
Tree tree = s.top();
|
||||
s.pop();
|
||||
|
||||
if ( tree.right - tree.left < KDTREE_BASESIZE )
|
||||
continue;
|
||||
|
||||
Iterator middle = tree.left + ( tree.right - tree.left ) / 2;
|
||||
std::nth_element( kdtree + tree.left, kdtree + middle, kdtree + tree.right, Less( tree.dimension ) );
|
||||
s.push( Tree( tree.left, middle, ( tree.dimension + 1 ) % k ) );
|
||||
s.push( Tree( middle + 1, tree.right, ( tree.dimension + 1 ) % k ) );
|
||||
}
|
||||
}
|
||||
|
||||
~StaticKDTree(){
|
||||
delete[] kdtree;
|
||||
}
|
||||
|
||||
bool NearestNeighbor( InputPoint* result, const InputPoint& point ) {
|
||||
Metric distance;
|
||||
bool found = false;
|
||||
double nearestDistance = std::numeric_limits< T >::max();
|
||||
std::stack< NNTree > s;
|
||||
s.push ( NNTree ( 0, size, 0, boundingBox ) );
|
||||
while ( !s.empty() ) {
|
||||
NNTree tree = s.top();
|
||||
s.pop();
|
||||
|
||||
if ( distance( tree.box, point.coordinates ) >= nearestDistance )
|
||||
continue;
|
||||
|
||||
if ( tree.right - tree.left < KDTREE_BASESIZE ) {
|
||||
for ( unsigned i = tree.left; i < tree.right; i++ ) {
|
||||
double newDistance = distance( kdtree[i].coordinates, point.coordinates );
|
||||
if ( newDistance < nearestDistance ) {
|
||||
nearestDistance = newDistance;
|
||||
*result = kdtree[i];
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Iterator middle = tree.left + ( tree.right - tree.left ) / 2;
|
||||
|
||||
double newDistance = distance( kdtree[middle].coordinates, point.coordinates );
|
||||
if ( newDistance < nearestDistance ) {
|
||||
nearestDistance = newDistance;
|
||||
*result = kdtree[middle];
|
||||
found = true;
|
||||
}
|
||||
|
||||
Less comperator( tree.dimension );
|
||||
if ( !comperator( point, kdtree[middle] ) ) {
|
||||
NNTree first( middle + 1, tree.right, ( tree.dimension + 1 ) % k, tree.box );
|
||||
NNTree second( tree.left, middle, ( tree.dimension + 1 ) % k, tree.box );
|
||||
first.box.min[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
|
||||
second.box.max[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
|
||||
s.push( second );
|
||||
s.push( first );
|
||||
}
|
||||
else {
|
||||
NNTree first( middle + 1, tree.right, ( tree.dimension + 1 ) % k, tree.box );
|
||||
NNTree second( tree.left, middle, ( tree.dimension + 1 ) % k, tree.box );
|
||||
first.box.min[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
|
||||
second.box.max[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
|
||||
s.push( first );
|
||||
s.push( second );
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef unsigned Iterator;
|
||||
struct Tree {
|
||||
Iterator left;
|
||||
Iterator right;
|
||||
unsigned dimension;
|
||||
Tree() {}
|
||||
Tree( Iterator l, Iterator r, unsigned d ): left( l ), right( r ), dimension( d ) {}
|
||||
};
|
||||
struct NNTree {
|
||||
Iterator left;
|
||||
Iterator right;
|
||||
unsigned dimension;
|
||||
BoundingBox< k, T > box;
|
||||
NNTree() {}
|
||||
NNTree( Iterator l, Iterator r, unsigned d, const BoundingBox< k, T >& b ): left( l ), right( r ), dimension( d ), box ( b ) {}
|
||||
};
|
||||
class Less {
|
||||
public:
|
||||
Less( unsigned d ) {
|
||||
dimension = d;
|
||||
assert( dimension < k );
|
||||
}
|
||||
|
||||
bool operator() ( const InputPoint& left, const InputPoint& right ) {
|
||||
assert( dimension < k );
|
||||
return left.coordinates[dimension] < right.coordinates[dimension];
|
||||
}
|
||||
private:
|
||||
unsigned dimension;
|
||||
};
|
||||
|
||||
BoundingBox< k, T > boundingBox;
|
||||
InputPoint* kdtree;
|
||||
Iterator size;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // STATICKDTREE_H_INCLUDED
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef TURNINSTRUCTIONS_H_
|
||||
#define TURNINSTRUCTIONS_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
typedef unsigned char TurnInstruction;
|
||||
|
||||
//This is a hack until c++0x is available enough to use scoped enums
|
||||
struct TurnInstructionsClass {
|
||||
|
||||
const static TurnInstruction NoTurn = 0; //Give no instruction at all
|
||||
const static TurnInstruction GoStraight = 1; //Tell user to go straight!
|
||||
const static TurnInstruction TurnSlightRight = 2;
|
||||
const static TurnInstruction TurnRight = 3;
|
||||
const static TurnInstruction TurnSharpRight = 4;
|
||||
const static TurnInstruction UTurn = 5;
|
||||
const static TurnInstruction TurnSharpLeft = 6;
|
||||
const static TurnInstruction TurnLeft = 7;
|
||||
const static TurnInstruction TurnSlightLeft = 8;
|
||||
const static TurnInstruction ReachViaPoint = 9;
|
||||
const static TurnInstruction HeadOn = 10;
|
||||
const static TurnInstruction EnterRoundAbout = 11;
|
||||
const static TurnInstruction LeaveRoundAbout = 12;
|
||||
const static TurnInstruction StayOnRoundAbout = 13;
|
||||
const static TurnInstruction StartAtEndOfStreet = 14;
|
||||
const static TurnInstruction ReachedYourDestination = 15;
|
||||
|
||||
const static TurnInstruction AccessRestrictionFlag = 128;
|
||||
const static TurnInstruction InverseAccessRestrictionFlag = 0x7f; // ~128 does not work without a warning.
|
||||
|
||||
const static int AccessRestrictionPenalty = 1 << 15; //unrelated to the bit set in the restriction flag
|
||||
|
||||
// std::string TurnStrings[16];
|
||||
// std::string Ordinals[12];
|
||||
|
||||
//This is a hack until c++0x is available enough to use initializer lists.
|
||||
// TurnInstructionsClass(){
|
||||
// TurnStrings [0] = "";
|
||||
// TurnStrings [1] = "Continue";
|
||||
// TurnStrings [2] = "Turn slight right";
|
||||
// TurnStrings [3] = "Turn right";
|
||||
// TurnStrings [4] = "Turn sharp right";
|
||||
// TurnStrings [5] = "U-Turn";
|
||||
// TurnStrings [6] = "Turn sharp left";
|
||||
// TurnStrings [7] = "Turn left";
|
||||
// TurnStrings [8] = "Turn slight left";
|
||||
// TurnStrings [9] = "Reach via point";
|
||||
// TurnStrings[10] = "Head";
|
||||
// TurnStrings[11] = "Enter roundabout";
|
||||
// TurnStrings[12] = "Leave roundabout";
|
||||
// TurnStrings[13] = "Stay on roundabout";
|
||||
// TurnStrings[14] = "Start";
|
||||
// TurnStrings[15] = "You have reached your destination";
|
||||
//
|
||||
// Ordinals[0] = "zeroth";
|
||||
// Ordinals[1] = "first";
|
||||
// Ordinals[2] = "second";
|
||||
// Ordinals[3] = "third";
|
||||
// Ordinals[4] = "fourth";
|
||||
// Ordinals[5] = "fifth";
|
||||
// Ordinals[6] = "sixth";
|
||||
// Ordinals[7] = "seventh";
|
||||
// Ordinals[8] = "eighth";
|
||||
// Ordinals[9] = "nineth";
|
||||
// Ordinals[10] = "tenth";
|
||||
// Ordinals[11] = "one of the too many";
|
||||
// };
|
||||
|
||||
static inline TurnInstruction GetTurnDirectionOfInstruction( const double angle ) {
|
||||
if(angle >= 23 && angle < 67) {
|
||||
return TurnSharpRight;
|
||||
}
|
||||
if (angle >= 67 && angle < 113) {
|
||||
return TurnRight;
|
||||
}
|
||||
if (angle >= 113 && angle < 158) {
|
||||
return TurnSlightRight;
|
||||
}
|
||||
if (angle >= 158 && angle < 202) {
|
||||
return GoStraight;
|
||||
}
|
||||
if (angle >= 202 && angle < 248) {
|
||||
return TurnSlightLeft;
|
||||
}
|
||||
if (angle >= 248 && angle < 292) {
|
||||
return TurnLeft;
|
||||
}
|
||||
if (angle >= 292 && angle < 336) {
|
||||
return TurnSharpLeft;
|
||||
}
|
||||
return UTurn;
|
||||
}
|
||||
|
||||
static inline bool TurnIsNecessary ( const short turnInstruction ) {
|
||||
if(NoTurn == turnInstruction || StayOnRoundAbout == turnInstruction)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static TurnInstructionsClass TurnInstructions;
|
||||
|
||||
#endif /* TURNINSTRUCTIONS_H_ */
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef TIMEUTIL_H_
|
||||
#define TIMEUTIL_H_
|
||||
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <sys/timeb.h>
|
||||
#include <sys/types.h>
|
||||
#include <winsock.h>
|
||||
void gettimeofday(struct timeval* t,void* timezone)
|
||||
{ struct _timeb timebuffer;
|
||||
_ftime( &timebuffer );
|
||||
t->tv_sec=timebuffer.time;
|
||||
t->tv_usec=1000*timebuffer.millitm;
|
||||
}
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <boost/functional/hash.hpp>
|
||||
#else
|
||||
#include <tr1/functional_hash.h>
|
||||
#endif
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
/** Returns a timestamp (now) in seconds (incl. a fractional part). */
|
||||
static inline double get_timestamp() {
|
||||
struct timeval tp;
|
||||
gettimeofday(&tp, NULL);
|
||||
return double(tp.tv_sec) + tp.tv_usec / 1000000.;
|
||||
}
|
||||
|
||||
static inline double y2lat(double a) { return 180/M_PI * (2 * atan(exp(a*M_PI/180)) - M_PI/2); }
|
||||
static inline double lat2y(double a) { return 180/M_PI * log(tan(M_PI/4+a*(M_PI/180)/2)); }
|
||||
|
||||
static inline unsigned boost_thread_id_hash(boost::thread::id const& id) {
|
||||
std::stringstream ostr;
|
||||
ostr << id;
|
||||
std::tr1::hash<std::string> h;
|
||||
return h(ostr.str());
|
||||
}
|
||||
|
||||
#endif /* TIMEUTIL_H_ */
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef FASTXORHASH_H_
|
||||
#define FASTXORHASH_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
/*
|
||||
This is an implementation of Tabulation hashing, which has suprising properties like universality.
|
||||
The space requirement is 2*2^16 = 256 kb of memory, which fits into L2 cache.
|
||||
Evaluation boils down to 10 or less assembly instruction on any recent X86 CPU:
|
||||
|
||||
1: movq table2(%rip), %rdx
|
||||
2: movl %edi, %eax
|
||||
3: movzwl %di, %edi
|
||||
4: shrl $16, %eax
|
||||
5: movzwl %ax, %eax
|
||||
6: movzbl (%rdx,%rax), %eax
|
||||
7: movq table1(%rip), %rdx
|
||||
8: xorb (%rdx,%rdi), %al
|
||||
9: movzbl %al, %eax
|
||||
10: ret
|
||||
|
||||
*/
|
||||
class XORFastHash { //65k entries
|
||||
std::vector<unsigned short> table1;
|
||||
std::vector<unsigned short> table2;
|
||||
public:
|
||||
XORFastHash() {
|
||||
table1.resize(2 << 16);
|
||||
table2.resize(2 << 16);
|
||||
for(unsigned i = 0; i < (2 << 16); ++i) {
|
||||
table1[i] = i; table2[i];
|
||||
}
|
||||
std::random_shuffle(table1.begin(), table1.end());
|
||||
std::random_shuffle(table2.begin(), table2.end());
|
||||
}
|
||||
|
||||
inline unsigned short operator()(const unsigned originalValue) const {
|
||||
unsigned short lsb = ((originalValue) & 0xffff);
|
||||
unsigned short msb = (((originalValue) >> 16) & 0xffff);
|
||||
return table1[lsb] ^ table2[msb];
|
||||
}
|
||||
};
|
||||
|
||||
class XORMiniHash { //256 entries
|
||||
std::vector<unsigned char> table1;
|
||||
std::vector<unsigned char> table2;
|
||||
std::vector<unsigned char> table3;
|
||||
std::vector<unsigned char> table4;
|
||||
|
||||
public:
|
||||
XORMiniHash() {
|
||||
table1.resize(1 << 8);
|
||||
table2.resize(1 << 8);
|
||||
table3.resize(1 << 8);
|
||||
table4.resize(1 << 8);
|
||||
for(unsigned i = 0; i < (1 << 8); ++i) {
|
||||
table1[i] = i; table2[i];
|
||||
table3[i] = i; table4[i];
|
||||
}
|
||||
std::random_shuffle(table1.begin(), table1.end());
|
||||
std::random_shuffle(table2.begin(), table2.end());
|
||||
std::random_shuffle(table3.begin(), table3.end());
|
||||
std::random_shuffle(table4.begin(), table4.end());
|
||||
}
|
||||
unsigned char operator()(const unsigned originalValue) const {
|
||||
unsigned char byte1 = ((originalValue) & 0xff);
|
||||
unsigned char byte2 = ((originalValue >> 8) & 0xff);
|
||||
unsigned char byte3 = ((originalValue >> 16) & 0xff);
|
||||
unsigned char byte4 = ((originalValue >> 24) & 0xff);
|
||||
return table1[byte1] ^ table2[byte2] ^ table3[byte3] ^ table4[byte4];
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* FASTXORHASH_H_ */
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef XORFASTHASHSTORAGE_H_
|
||||
#define XORFASTHASHSTORAGE_H_
|
||||
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
#include <bitset>
|
||||
|
||||
#include "XORFastHash.h"
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class XORFastHashStorage {
|
||||
public:
|
||||
struct HashCell{
|
||||
Key key;
|
||||
NodeID id;
|
||||
unsigned time;
|
||||
HashCell() : key(UINT_MAX), id(UINT_MAX), time(UINT_MAX) {}
|
||||
|
||||
HashCell(const HashCell & other) : key(other.key), id(other.id), time(other.time) { }
|
||||
|
||||
inline operator Key() const {
|
||||
return key;
|
||||
}
|
||||
|
||||
inline void operator=(const Key & keyToInsert) {
|
||||
key = keyToInsert;
|
||||
}
|
||||
};
|
||||
|
||||
XORFastHashStorage( size_t ) : positions(2<<16), currentTimestamp(0) { }
|
||||
|
||||
inline HashCell& operator[]( const NodeID node ) {
|
||||
unsigned short position = fastHash(node);
|
||||
while((positions[position].time == currentTimestamp) && (positions[position].id != node)){
|
||||
++position %= (2<<16);
|
||||
}
|
||||
|
||||
positions[position].id = node;
|
||||
positions[position].time = currentTimestamp;
|
||||
return positions[position];
|
||||
}
|
||||
|
||||
inline void Clear() {
|
||||
++currentTimestamp;
|
||||
if(UINT_MAX == currentTimestamp) {
|
||||
positions.clear();
|
||||
positions.resize((2<<16));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
XORFastHashStorage() : positions(2<<16), currentTimestamp(0) {}
|
||||
std::vector<HashCell> positions;
|
||||
XORFastHash fastHash;
|
||||
unsigned currentTimestamp;
|
||||
};
|
||||
|
||||
|
||||
#endif /* XORFASTHASHSTORAGE_H_ */
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef BASE_DESCRIPTOR_H_
|
||||
#define BASE_DESCRIPTOR_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../DataStructures/PhantomNodes.h"
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include "../Plugins/RawRouteData.h"
|
||||
|
||||
struct _DescriptorConfig {
|
||||
_DescriptorConfig() : instructions(true), geometry(true), encodeGeometry(true), z(18) {}
|
||||
bool instructions;
|
||||
bool geometry;
|
||||
bool encodeGeometry;
|
||||
unsigned short z;
|
||||
};
|
||||
|
||||
template<class SearchEngineT>
|
||||
class BaseDescriptor {
|
||||
public:
|
||||
BaseDescriptor() { }
|
||||
//Maybe someone can explain the pure virtual destructor thing to me (dennis)
|
||||
virtual ~BaseDescriptor() { }
|
||||
virtual void Run(http::Reply & reply, const RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine) = 0;
|
||||
virtual void SetConfig(const _DescriptorConfig & config) = 0;
|
||||
};
|
||||
|
||||
#endif /* BASE_DESCRIPTOR_H_ */
|
||||
@@ -1,210 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#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 _Coordinate& A, const _Coordinate& B) const {
|
||||
double deltaLong = DegreeToRadian(B.lon/100000. - A.lon/100000.);
|
||||
|
||||
double lat1 = DegreeToRadian(A.lat/100000.);
|
||||
double lat2 = DegreeToRadian(B.lat/100000.);
|
||||
|
||||
double y = sin(deltaLong) * cos(lat2);
|
||||
double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(deltaLong);
|
||||
double result = RadianToDegree(atan2(y, x));
|
||||
while(result <= 0.)
|
||||
result += 360.;
|
||||
while(result >= 360.)
|
||||
result -= 360.;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void DescriptionFactory::SetStartSegment(const PhantomNode & _startPhantom) {
|
||||
startPhantom = _startPhantom;
|
||||
AppendSegment(_startPhantom.location, _PathData(0, _startPhantom.nodeBasedEdgeNameID, 10, _startPhantom.weight1));
|
||||
}
|
||||
|
||||
void DescriptionFactory::SetEndSegment(const PhantomNode & _targetPhantom) {
|
||||
targetPhantom = _targetPhantom;
|
||||
pathDescription.push_back(SegmentInformation(_targetPhantom.location, _targetPhantom.nodeBasedEdgeNameID, 0, _targetPhantom.weight1, 0, true) );
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendSegment(const _Coordinate & coordinate, const _PathData & data ) {
|
||||
if(1 == pathDescription.size() && pathDescription.back().location == coordinate) {
|
||||
pathDescription.back().nameID = data.nameID;
|
||||
} else {
|
||||
pathDescription.push_back(SegmentInformation(coordinate, data.nameID, 0, data.durationOfSegment, data.turnInstruction) );
|
||||
}
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendEncodedPolylineString(std::string & output, bool isEncoded) {
|
||||
if(isEncoded)
|
||||
pc.printEncodedString(pathDescription, output);
|
||||
else
|
||||
pc.printUnencodedString(pathDescription, output);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendEncodedPolylineString(std::string &output) {
|
||||
pc.printEncodedString(pathDescription, output);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendUnencodedPolylineString(std::string &output) {
|
||||
pc.printUnencodedString(pathDescription, output);
|
||||
}
|
||||
|
||||
void DescriptionFactory::Run(const SearchEngineT &sEngine, const unsigned zoomLevel) {
|
||||
|
||||
if(0 == pathDescription.size())
|
||||
return;
|
||||
|
||||
// unsigned entireLength = 0;
|
||||
/** starts at index 1 */
|
||||
pathDescription[0].length = 0;
|
||||
for(unsigned i = 1; i < pathDescription.size(); ++i) {
|
||||
pathDescription[i].length = ApproximateDistanceByEuclid(pathDescription[i-1].location, pathDescription[i].location);
|
||||
}
|
||||
|
||||
double lengthOfSegment = 0;
|
||||
unsigned durationOfSegment = 0;
|
||||
unsigned indexOfSegmentBegin = 0;
|
||||
|
||||
std::string string0 = sEngine.GetEscapedNameForNameID(pathDescription[0].nameID);
|
||||
std::string string1;
|
||||
|
||||
|
||||
/*Simplify turn instructions
|
||||
Input :
|
||||
10. Turn left on B 36 for 20 km
|
||||
11. Continue on B 35; B 36 for 2 km
|
||||
12. Continue on B 36 for 13 km
|
||||
|
||||
becomes:
|
||||
10. Turn left on B 36 for 35 km
|
||||
*/
|
||||
//TODO: rework to check only end and start of string.
|
||||
// stl string is way to expensive
|
||||
|
||||
// unsigned lastTurn = 0;
|
||||
// for(unsigned i = 1; i < pathDescription.size(); ++i) {
|
||||
// string1 = sEngine.GetEscapedNameForNameID(pathDescription[i].nameID);
|
||||
// if(TurnInstructionsClass::GoStraight == pathDescription[i].turnInstruction) {
|
||||
// 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)
|
||||
// ){
|
||||
// INFO("->next correct: " << string0 << " contains " << string1);
|
||||
// for(; lastTurn != i; ++lastTurn)
|
||||
// pathDescription[lastTurn].nameID = pathDescription[i].nameID;
|
||||
// pathDescription[i].turnInstruction = TurnInstructionsClass::NoTurn;
|
||||
// } else if(std::string::npos != string1.find(string0+";")
|
||||
// || std::string::npos != string1.find(";"+string0)
|
||||
// || std::string::npos != string1.find(string0+" ;")
|
||||
// || std::string::npos != string1.find("; "+string0)
|
||||
// ){
|
||||
// INFO("->prev correct: " << string1 << " contains " << string0);
|
||||
// pathDescription[i].nameID = pathDescription[i-1].nameID;
|
||||
// pathDescription[i].turnInstruction = TurnInstructionsClass::NoTurn;
|
||||
// }
|
||||
// }
|
||||
// if (TurnInstructionsClass::NoTurn != pathDescription[i].turnInstruction) {
|
||||
// lastTurn = i;
|
||||
// }
|
||||
// string0 = string1;
|
||||
// }
|
||||
|
||||
|
||||
for(unsigned i = 1; i < pathDescription.size(); ++i) {
|
||||
entireLength += pathDescription[i].length;
|
||||
lengthOfSegment += pathDescription[i].length;
|
||||
durationOfSegment += pathDescription[i].duration;
|
||||
pathDescription[indexOfSegmentBegin].length = lengthOfSegment;
|
||||
pathDescription[indexOfSegmentBegin].duration = durationOfSegment;
|
||||
|
||||
|
||||
if(TurnInstructionsClass::NoTurn != pathDescription[i].turnInstruction) {
|
||||
//INFO("Turn after " << lengthOfSegment << "m into way with name id " << segment.nameID);
|
||||
assert(pathDescription[i].necessary);
|
||||
lengthOfSegment = 0;
|
||||
durationOfSegment = 0;
|
||||
indexOfSegmentBegin = i;
|
||||
}
|
||||
}
|
||||
// INFO("#segs: " << pathDescription.size());
|
||||
|
||||
//Post-processing to remove empty or nearly empty path segments
|
||||
if(FLT_EPSILON > pathDescription.back().length) {
|
||||
// INFO("#segs: " << pathDescription.size() << ", last ratio: " << targetPhantom.ratio << ", length: " << pathDescription.back().length);
|
||||
if(pathDescription.size() > 2){
|
||||
pathDescription.pop_back();
|
||||
pathDescription.back().necessary = true;
|
||||
pathDescription.back().turnInstruction = TurnInstructions.NoTurn;
|
||||
targetPhantom.nodeBasedEdgeNameID = (pathDescription.end()-2)->nameID;
|
||||
// INFO("Deleting last turn instruction");
|
||||
}
|
||||
} else {
|
||||
pathDescription[indexOfSegmentBegin].duration *= (1.-targetPhantom.ratio);
|
||||
}
|
||||
if(FLT_EPSILON > pathDescription[0].length) {
|
||||
//TODO: this is never called actually?
|
||||
if(pathDescription.size() > 2) {
|
||||
pathDescription.erase(pathDescription.begin());
|
||||
pathDescription[0].turnInstruction = TurnInstructions.HeadOn;
|
||||
pathDescription[0].necessary = true;
|
||||
startPhantom.nodeBasedEdgeNameID = pathDescription[0].nameID;
|
||||
// INFO("Deleting first turn instruction, ratio: " << startPhantom.ratio << ", length: " << pathDescription[0].length);
|
||||
}
|
||||
} else {
|
||||
pathDescription[0].duration *= startPhantom.ratio;
|
||||
}
|
||||
|
||||
//Generalize poly line
|
||||
dp.Run(pathDescription, zoomLevel);
|
||||
|
||||
//fix what needs to be fixed else
|
||||
for(unsigned i = 0; i < pathDescription.size()-1 && pathDescription.size() >= 2; ++i){
|
||||
if(pathDescription[i].necessary) {
|
||||
double angle = GetBearing(pathDescription[i].location, pathDescription[i+1].location);
|
||||
pathDescription[i].bearing = angle;
|
||||
}
|
||||
}
|
||||
|
||||
// BuildRouteSummary(entireLength, duration);
|
||||
return;
|
||||
}
|
||||
|
||||
void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time) {
|
||||
summary.startName = startPhantom.nodeBasedEdgeNameID;
|
||||
summary.destName = targetPhantom.nodeBasedEdgeNameID;
|
||||
summary.BuildDurationAndLengthStrings(distance, time);
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef DESCRIPTIONFACTORY_H_
|
||||
#define DESCRIPTIONFACTORY_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../Algorithms/DouglasPeucker.h"
|
||||
#include "../Algorithms/PolylineCompressor.h"
|
||||
#include "../DataStructures/Coordinate.h"
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "../DataStructures/SearchEngine.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
|
||||
/* This class is fed with all way segments in consecutive order
|
||||
* and produces the description plus the encoded polyline */
|
||||
|
||||
class DescriptionFactory {
|
||||
DouglasPeucker<SegmentInformation> dp;
|
||||
PolylineCompressor pc;
|
||||
PhantomNode startPhantom, targetPhantom;
|
||||
|
||||
typedef SearchEngine<QueryEdge::EdgeData, StaticGraph<QueryEdge::EdgeData> > SearchEngineT;
|
||||
|
||||
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
|
||||
std::ostringstream s;
|
||||
s << round(distance);
|
||||
lengthString = s.str();
|
||||
int travelTime = time/10 + 1;
|
||||
s.str("");
|
||||
s << travelTime;
|
||||
durationString = s.str();
|
||||
}
|
||||
} summary;
|
||||
|
||||
double entireLength;
|
||||
|
||||
//I know, declaring this public is considered bad. I'm lazy
|
||||
std::vector <SegmentInformation> pathDescription;
|
||||
DescriptionFactory();
|
||||
virtual ~DescriptionFactory();
|
||||
double GetBearing(const _Coordinate& C, const _Coordinate& B) const;
|
||||
void AppendEncodedPolylineString(std::string &output);
|
||||
void AppendUnencodedPolylineString(std::string &output);
|
||||
void AppendSegment(const _Coordinate & coordinate, const _PathData & data);
|
||||
void BuildRouteSummary(const double distance, const unsigned time);
|
||||
void SetStartSegment(const PhantomNode & startPhantom);
|
||||
void SetEndSegment(const PhantomNode & startPhantom);
|
||||
void AppendEncodedPolylineString(std::string & output, bool isEncoded);
|
||||
void Run(const SearchEngineT &sEngine, const unsigned zoomLevel);
|
||||
};
|
||||
|
||||
#endif /* DESCRIPTIONFACTORY_H_ */
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef GPX_DESCRIPTOR_H_
|
||||
#define GPX_DESCRIPTOR_H_
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include "BaseDescriptor.h"
|
||||
|
||||
template<class SearchEngineT>
|
||||
class GPXDescriptor : public BaseDescriptor<SearchEngineT>{
|
||||
private:
|
||||
_DescriptorConfig config;
|
||||
_Coordinate current;
|
||||
|
||||
std::string tmp;
|
||||
public:
|
||||
void SetConfig(const _DescriptorConfig& c) { config = c; }
|
||||
void Run(http::Reply & reply, const RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine) {
|
||||
reply.content += ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
reply.content += "<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 += "<rte>";
|
||||
if(rawRoute.lengthOfShortestPath != INT_MAX && rawRoute.computedShortestPath.size()) {
|
||||
convertInternalLatLonToString(phantomNodes.startPhantom.location.lat, tmp);
|
||||
reply.content += "<rtept lat=\"" + tmp + "\" ";
|
||||
convertInternalLatLonToString(phantomNodes.startPhantom.location.lon, tmp);
|
||||
reply.content += "lon=\"" + tmp + "\"></rtept>";
|
||||
|
||||
BOOST_FOREACH(_PathData pathData, rawRoute.computedShortestPath) {
|
||||
sEngine.GetCoordinatesForNodeID(pathData.node, current);
|
||||
|
||||
convertInternalLatLonToString(current.lat, tmp);
|
||||
reply.content += "<rtept lat=\"" + tmp + "\" ";
|
||||
convertInternalLatLonToString(current.lon, tmp);
|
||||
reply.content += "lon=\"" + tmp + "\"></rtept>";
|
||||
}
|
||||
convertInternalLatLonToString(phantomNodes.targetPhantom.location.lat, tmp);
|
||||
reply.content += "<rtept lat=\"" + tmp + "\" ";
|
||||
convertInternalLatLonToString(phantomNodes.targetPhantom.location.lon, tmp);
|
||||
reply.content += "lon=\"" + tmp + "\"></rtept>";
|
||||
}
|
||||
reply.content += "</rte></gpx>";
|
||||
}
|
||||
};
|
||||
#endif /* GPX_DESCRIPTOR_H_ */
|
||||
@@ -1,391 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef JSON_DESCRIPTOR_H_
|
||||
#define JSON_DESCRIPTOR_H_
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#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"
|
||||
|
||||
template<class SearchEngineT>
|
||||
class JSONDescriptor : public BaseDescriptor<SearchEngineT>{
|
||||
private:
|
||||
_DescriptorConfig config;
|
||||
DescriptionFactory descriptionFactory;
|
||||
DescriptionFactory alternateDescriptionFactory;
|
||||
_Coordinate current;
|
||||
unsigned numberOfEnteredRestrictedAreas;
|
||||
struct {
|
||||
int startIndex;
|
||||
int nameID;
|
||||
int leaveAtExit;
|
||||
} roundAbout;
|
||||
|
||||
struct Segment {
|
||||
Segment() : nameID(-1), length(-1), position(-1) {}
|
||||
Segment(int n, int l, int p) : nameID(n), length(l), position(p) {}
|
||||
int nameID;
|
||||
int length;
|
||||
int position;
|
||||
};
|
||||
std::vector<Segment> shortestSegments, alternativeSegments;
|
||||
|
||||
struct RouteNames {
|
||||
std::string shortestPathName1;
|
||||
std::string shortestPathName2;
|
||||
std::string alternativePathName1;
|
||||
std::string alternativePathName2;
|
||||
};
|
||||
|
||||
public:
|
||||
JSONDescriptor() : numberOfEnteredRestrictedAreas(0) {}
|
||||
void SetConfig(const _DescriptorConfig & c) { config = c; }
|
||||
|
||||
void Run(http::Reply & reply, const RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine) {
|
||||
|
||||
WriteHeaderToOutput(reply.content);
|
||||
|
||||
if(rawRoute.lengthOfShortestPath != INT_MAX) {
|
||||
descriptionFactory.SetStartSegment(phantomNodes.startPhantom);
|
||||
reply.content += "0,"
|
||||
"\"status_message\": \"Found route between points\",";
|
||||
|
||||
//Get all the coordinates for the computed route
|
||||
BOOST_FOREACH(const _PathData & pathData, rawRoute.computedShortestPath) {
|
||||
sEngine.GetCoordinatesForNodeID(pathData.node, current);
|
||||
descriptionFactory.AppendSegment(current, pathData );
|
||||
}
|
||||
descriptionFactory.SetEndSegment(phantomNodes.targetPhantom);
|
||||
} else {
|
||||
//We do not need to do much, if there is no route ;-)
|
||||
reply.content += "207,"
|
||||
"\"status_message\": \"Cannot find route between points\",";
|
||||
}
|
||||
|
||||
descriptionFactory.Run(sEngine, config.z);
|
||||
reply.content += "\"route_geometry\": ";
|
||||
if(config.geometry) {
|
||||
descriptionFactory.AppendEncodedPolylineString(reply.content, config.encodeGeometry);
|
||||
} else {
|
||||
reply.content += "[]";
|
||||
}
|
||||
|
||||
reply.content += ","
|
||||
"\"route_instructions\": [";
|
||||
numberOfEnteredRestrictedAreas = 0;
|
||||
if(config.instructions) {
|
||||
BuildTextualDescription(descriptionFactory, reply, rawRoute.lengthOfShortestPath, sEngine, shortestSegments);
|
||||
} else {
|
||||
BOOST_FOREACH(const SegmentInformation & segment, descriptionFactory.pathDescription) {
|
||||
TurnInstruction currentInstruction = segment.turnInstruction & TurnInstructions.InverseAccessRestrictionFlag;
|
||||
numberOfEnteredRestrictedAreas += (currentInstruction != segment.turnInstruction);
|
||||
}
|
||||
}
|
||||
reply.content += "],";
|
||||
descriptionFactory.BuildRouteSummary(descriptionFactory.entireLength, rawRoute.lengthOfShortestPath - ( numberOfEnteredRestrictedAreas*TurnInstructions.AccessRestrictionPenalty));
|
||||
|
||||
reply.content += "\"route_summary\":";
|
||||
reply.content += "{";
|
||||
reply.content += "\"total_distance\":";
|
||||
reply.content += descriptionFactory.summary.lengthString;
|
||||
reply.content += ","
|
||||
"\"total_time\":";
|
||||
reply.content += descriptionFactory.summary.durationString;
|
||||
reply.content += ","
|
||||
"\"start_point\":\"";
|
||||
reply.content += sEngine.GetEscapedNameForNameID(descriptionFactory.summary.startName);
|
||||
reply.content += "\","
|
||||
"\"end_point\":\"";
|
||||
reply.content += sEngine.GetEscapedNameForNameID(descriptionFactory.summary.destName);
|
||||
reply.content += "\"";
|
||||
reply.content += "}";
|
||||
reply.content +=",";
|
||||
|
||||
//only one alternative route is computed at this time, so this is hardcoded
|
||||
|
||||
if(rawRoute.lengthOfAlternativePath != INT_MAX) {
|
||||
alternateDescriptionFactory.SetStartSegment(phantomNodes.startPhantom);
|
||||
//Get all the coordinates for the computed route
|
||||
BOOST_FOREACH(const _PathData & pathData, rawRoute.computedAlternativePath) {
|
||||
sEngine.GetCoordinatesForNodeID(pathData.node, current);
|
||||
alternateDescriptionFactory.AppendSegment(current, pathData );
|
||||
}
|
||||
alternateDescriptionFactory.SetEndSegment(phantomNodes.targetPhantom);
|
||||
}
|
||||
alternateDescriptionFactory.Run(sEngine, config.z);
|
||||
|
||||
//give an array of alternative routes
|
||||
reply.content += "\"alternative_geometries\": [";
|
||||
if(config.geometry && INT_MAX != rawRoute.lengthOfAlternativePath) {
|
||||
//Generate the linestrings for each alternative
|
||||
alternateDescriptionFactory.AppendEncodedPolylineString(reply.content, config.encodeGeometry);
|
||||
}
|
||||
reply.content += "],";
|
||||
reply.content += "\"alternative_instructions\":[";
|
||||
numberOfEnteredRestrictedAreas = 0;
|
||||
if(INT_MAX != rawRoute.lengthOfAlternativePath) {
|
||||
reply.content += "[";
|
||||
//Generate instructions for each alternative
|
||||
if(config.instructions) {
|
||||
BuildTextualDescription(alternateDescriptionFactory, reply, rawRoute.lengthOfAlternativePath, sEngine, alternativeSegments);
|
||||
} else {
|
||||
BOOST_FOREACH(const SegmentInformation & segment, alternateDescriptionFactory.pathDescription) {
|
||||
TurnInstruction currentInstruction = segment.turnInstruction & TurnInstructions.InverseAccessRestrictionFlag;
|
||||
numberOfEnteredRestrictedAreas += (currentInstruction != segment.turnInstruction);
|
||||
}
|
||||
}
|
||||
reply.content += "]";
|
||||
}
|
||||
reply.content += "],";
|
||||
reply.content += "\"alternative_summaries\":[";
|
||||
if(INT_MAX != rawRoute.lengthOfAlternativePath) {
|
||||
//Generate route summary (length, duration) for each alternative
|
||||
alternateDescriptionFactory.BuildRouteSummary(alternateDescriptionFactory.entireLength, rawRoute.lengthOfAlternativePath - ( numberOfEnteredRestrictedAreas*TurnInstructions.AccessRestrictionPenalty));
|
||||
reply.content += "{";
|
||||
reply.content += "\"total_distance\":";
|
||||
reply.content += alternateDescriptionFactory.summary.lengthString;
|
||||
reply.content += ","
|
||||
"\"total_time\":";
|
||||
reply.content += alternateDescriptionFactory.summary.durationString;
|
||||
reply.content += ","
|
||||
"\"start_point\":\"";
|
||||
reply.content += sEngine.GetEscapedNameForNameID(descriptionFactory.summary.startName);
|
||||
reply.content += "\","
|
||||
"\"end_point\":\"";
|
||||
reply.content += sEngine.GetEscapedNameForNameID(descriptionFactory.summary.destName);
|
||||
reply.content += "\"";
|
||||
reply.content += "}";
|
||||
}
|
||||
reply.content += "],";
|
||||
|
||||
//Get Names for both routes
|
||||
RouteNames routeNames;
|
||||
GetRouteNames(shortestSegments, alternativeSegments, sEngine, routeNames);
|
||||
|
||||
reply.content += "\"route_name\":[\"";
|
||||
reply.content += routeNames.shortestPathName1;
|
||||
reply.content += "\",\"";
|
||||
reply.content += routeNames.shortestPathName2;
|
||||
reply.content += "\"],"
|
||||
"\"alternative_names\":[";
|
||||
reply.content += "[\"";
|
||||
reply.content += routeNames.alternativePathName1;
|
||||
reply.content += "\",\"";
|
||||
reply.content += routeNames.alternativePathName2;
|
||||
reply.content += "\"]";
|
||||
reply.content += "],";
|
||||
//list all viapoints so that the client may display it
|
||||
reply.content += "\"via_points\":[";
|
||||
std::string tmp;
|
||||
if(config.geometry && INT_MAX != rawRoute.lengthOfShortestPath) {
|
||||
for(unsigned i = 0; i < rawRoute.segmentEndCoordinates.size(); ++i) {
|
||||
reply.content += "[";
|
||||
if(rawRoute.segmentEndCoordinates[i].startPhantom.location.isSet())
|
||||
convertInternalReversedCoordinateToString(rawRoute.segmentEndCoordinates[i].startPhantom.location, tmp);
|
||||
else
|
||||
convertInternalReversedCoordinateToString(rawRoute.rawViaNodeCoordinates[i], tmp);
|
||||
|
||||
reply.content += tmp;
|
||||
reply.content += "],";
|
||||
}
|
||||
reply.content += "[";
|
||||
if(rawRoute.segmentEndCoordinates.back().startPhantom.location.isSet())
|
||||
convertInternalReversedCoordinateToString(rawRoute.segmentEndCoordinates.back().targetPhantom.location, tmp);
|
||||
else
|
||||
convertInternalReversedCoordinateToString(rawRoute.rawViaNodeCoordinates.back(), tmp);
|
||||
reply.content += tmp;
|
||||
reply.content += "]";
|
||||
}
|
||||
reply.content += "],";
|
||||
reply.content += "\"hint_data\": {";
|
||||
reply.content += "\"checksum\":";
|
||||
intToString(rawRoute.checkSum, tmp);
|
||||
reply.content += tmp;
|
||||
reply.content += ", \"locations\": [";
|
||||
|
||||
std::string hint;
|
||||
for(unsigned i = 0; i < rawRoute.segmentEndCoordinates.size(); ++i) {
|
||||
reply.content += "\"";
|
||||
EncodeObjectToBase64(rawRoute.segmentEndCoordinates[i].startPhantom, hint);
|
||||
reply.content += hint;
|
||||
reply.content += "\", ";
|
||||
}
|
||||
EncodeObjectToBase64(rawRoute.segmentEndCoordinates.back().targetPhantom, hint);
|
||||
reply.content += "\"";
|
||||
reply.content += hint;
|
||||
reply.content += "\"]";
|
||||
reply.content += "},";
|
||||
reply.content += "\"transactionId\": \"OSRM Routing Engine JSON Descriptor (v0.3)\"";
|
||||
reply.content += "}";
|
||||
}
|
||||
|
||||
void GetRouteNames(std::vector<Segment> & shortestSegments, std::vector<Segment> & alternativeSegments, SearchEngineT &sEngine, RouteNames & routeNames) {
|
||||
/*** extract names for both alternatives ***/
|
||||
|
||||
Segment shortestSegment1, shortestSegment2;
|
||||
Segment alternativeSegment1, alternativeSegment2;
|
||||
|
||||
if(0 < shortestSegments.size()) {
|
||||
sort(shortestSegments.begin(), shortestSegments.end(), boost::bind(&Segment::length, _1) > boost::bind(&Segment::length, _2) );
|
||||
shortestSegment1 = shortestSegments[0];
|
||||
if(0 < alternativeSegments.size()) {
|
||||
sort(alternativeSegments.begin(), alternativeSegments.end(), boost::bind(&Segment::length, _1) > boost::bind(&Segment::length, _2) );
|
||||
alternativeSegment1 = alternativeSegments[0];
|
||||
}
|
||||
std::vector<Segment> shortestDifference(shortestSegments.size());
|
||||
std::vector<Segment> alternativeDifference(alternativeSegments.size());
|
||||
std::set_difference(shortestSegments.begin(), shortestSegments.end(), alternativeSegments.begin(), alternativeSegments.end(), shortestDifference.begin(), boost::bind(&Segment::nameID, _1) < boost::bind(&Segment::nameID, _2) );
|
||||
if(0 < shortestDifference.size() ) {
|
||||
unsigned i = 0;
|
||||
while( i < shortestDifference.size() && shortestDifference[i].nameID == shortestSegments[0].nameID) {
|
||||
++i;
|
||||
}
|
||||
if(i < shortestDifference.size()) {
|
||||
shortestSegment2 = shortestDifference[i];
|
||||
}
|
||||
}
|
||||
|
||||
std::set_difference(alternativeSegments.begin(), alternativeSegments.end(), shortestSegments.begin(), shortestSegments.end(), alternativeDifference.begin(), boost::bind(&Segment::nameID, _1) < boost::bind(&Segment::nameID, _2) );
|
||||
if(0 < alternativeDifference.size() ) {
|
||||
unsigned i = 0;
|
||||
while( i < alternativeDifference.size() && alternativeDifference[i].nameID == alternativeSegments[0].nameID) {
|
||||
++i;
|
||||
}
|
||||
if(i < alternativeDifference.size()) {
|
||||
alternativeSegment2 = alternativeDifference[i];
|
||||
}
|
||||
}
|
||||
if(shortestSegment1.position > shortestSegment2.position)
|
||||
std::swap(shortestSegment1, shortestSegment2);
|
||||
|
||||
if(alternativeSegment1.position > alternativeSegment2.position)
|
||||
std::swap(alternativeSegment1, alternativeSegment2);
|
||||
|
||||
routeNames.shortestPathName1 = sEngine.GetEscapedNameForNameID(shortestSegment1.nameID);
|
||||
routeNames.shortestPathName2 = sEngine.GetEscapedNameForNameID(shortestSegment2.nameID);
|
||||
|
||||
routeNames.alternativePathName1 = sEngine.GetEscapedNameForNameID(alternativeSegment1.nameID);
|
||||
routeNames.alternativePathName2 += sEngine.GetEscapedNameForNameID(alternativeSegment2.nameID);
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteHeaderToOutput(std::string & output) {
|
||||
output += "{"
|
||||
"\"version\": 0.3,"
|
||||
"\"status\":";
|
||||
}
|
||||
|
||||
inline void BuildTextualDescription(DescriptionFactory & descriptionFactory, http::Reply & reply, const int lengthOfRoute, const SearchEngineT &sEngine, std::vector<Segment> & segmentVector) {
|
||||
//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]
|
||||
//See also: http://developers.cloudmade.com/wiki/navengine/JSON_format
|
||||
unsigned prefixSumOfNecessarySegments = 0;
|
||||
roundAbout.leaveAtExit = 0;
|
||||
roundAbout.nameID = 0;
|
||||
std::string tmpDist, tmpLength, tmpDuration, tmpBearing, tmpInstruction;
|
||||
//Fetch data from Factory and generate a string from it.
|
||||
BOOST_FOREACH(const SegmentInformation & segment, descriptionFactory.pathDescription) {
|
||||
TurnInstruction currentInstruction = segment.turnInstruction & TurnInstructions.InverseAccessRestrictionFlag;
|
||||
numberOfEnteredRestrictedAreas += (currentInstruction != segment.turnInstruction);
|
||||
if(TurnInstructions.TurnIsNecessary( currentInstruction) ) {
|
||||
if(TurnInstructions.EnterRoundAbout == currentInstruction) {
|
||||
roundAbout.nameID = segment.nameID;
|
||||
roundAbout.startIndex = prefixSumOfNecessarySegments;
|
||||
} else {
|
||||
if(0 != prefixSumOfNecessarySegments){
|
||||
reply.content += ",";
|
||||
}
|
||||
reply.content += "[\"";
|
||||
if(TurnInstructions.LeaveRoundAbout == currentInstruction) {
|
||||
intToString(TurnInstructions.EnterRoundAbout, tmpInstruction);
|
||||
reply.content += tmpInstruction;
|
||||
reply.content += "-";
|
||||
intToString(roundAbout.leaveAtExit+1, tmpInstruction);
|
||||
reply.content += tmpInstruction;
|
||||
roundAbout.leaveAtExit = 0;
|
||||
} else {
|
||||
intToString(currentInstruction, tmpInstruction);
|
||||
reply.content += tmpInstruction;
|
||||
}
|
||||
|
||||
|
||||
reply.content += "\",\"";
|
||||
reply.content += sEngine.GetEscapedNameForNameID(segment.nameID);
|
||||
reply.content += "\",";
|
||||
intToString(segment.length, tmpDist);
|
||||
reply.content += tmpDist;
|
||||
reply.content += ",";
|
||||
intToString(prefixSumOfNecessarySegments, tmpLength);
|
||||
reply.content += tmpLength;
|
||||
reply.content += ",";
|
||||
intToString(segment.duration/10, tmpDuration);
|
||||
reply.content += tmpDuration;
|
||||
reply.content += ",\"";
|
||||
intToString(segment.length, tmpLength);
|
||||
reply.content += tmpLength;
|
||||
reply.content += "m\",\"";
|
||||
reply.content += Azimuth::Get(segment.bearing);
|
||||
reply.content += "\",";
|
||||
intToString(round(segment.bearing), tmpBearing);
|
||||
reply.content += tmpBearing;
|
||||
reply.content += "]";
|
||||
|
||||
segmentVector.push_back( Segment(segment.nameID, segment.length, segmentVector.size() ));
|
||||
}
|
||||
} else if(TurnInstructions.StayOnRoundAbout == currentInstruction) {
|
||||
++roundAbout.leaveAtExit;
|
||||
}
|
||||
if(segment.necessary)
|
||||
++prefixSumOfNecessarySegments;
|
||||
}
|
||||
if(INT_MAX != lengthOfRoute) {
|
||||
reply.content += ",[\"";
|
||||
intToString(TurnInstructions.ReachedYourDestination, tmpInstruction);
|
||||
reply.content += tmpInstruction;
|
||||
reply.content += "\",\"";
|
||||
reply.content += "\",";
|
||||
reply.content += "0";
|
||||
reply.content += ",";
|
||||
intToString(prefixSumOfNecessarySegments-1, tmpLength);
|
||||
reply.content += tmpLength;
|
||||
reply.content += ",";
|
||||
reply.content += "0";
|
||||
reply.content += ",\"";
|
||||
reply.content += "\",\"";
|
||||
reply.content += Azimuth::Get(0.0);
|
||||
reply.content += "\",";
|
||||
reply.content += "0.0";
|
||||
reply.content += "]";
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
#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
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef BASEPARSER_H_
|
||||
#define BASEPARSER_H_
|
||||
|
||||
extern "C" {
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
}
|
||||
|
||||
#include "ScriptingEnvironment.h"
|
||||
|
||||
template<class ExternalMemoryT, typename NodeT, typename RestrictionT, typename WayT>
|
||||
class BaseParser {
|
||||
public:
|
||||
virtual ~BaseParser() {}
|
||||
virtual bool Init() = 0;
|
||||
virtual void RegisterCallbacks(ExternalMemoryT * externalMemory) = 0;
|
||||
virtual void RegisterScriptingEnvironment(ScriptingEnvironment & _se) = 0;
|
||||
virtual bool Parse() = 0;
|
||||
|
||||
void report_errors(lua_State *L, int status) {
|
||||
if ( status!=0 ) {
|
||||
std::cerr << "-- " << lua_tostring(L, -1) << std::endl;
|
||||
lua_pop(L, 1); // remove error message
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif /* BASEPARSER_H_ */
|
||||
@@ -1,305 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#include "ExtractionContainers.h"
|
||||
|
||||
void ExtractionContainers::PrepareData(const std::string & outputFileName, const std::string restrictionsFileName, const unsigned amountOfRAM) {
|
||||
try {
|
||||
unsigned usedNodeCounter = 0;
|
||||
unsigned usedEdgeCounter = 0;
|
||||
double time = get_timestamp();
|
||||
boost::uint64_t memory_to_use = static_cast<boost::uint64_t>(amountOfRAM) * 1024 * 1024 * 1024;
|
||||
|
||||
cout << "[extractor] Sorting used nodes ... " << flush;
|
||||
stxxl::sort(usedNodeIDs.begin(), usedNodeIDs.end(), Cmp(), memory_to_use);
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
|
||||
time = get_timestamp();
|
||||
cout << "[extractor] Erasing duplicate nodes ... " << flush;
|
||||
stxxl::vector<NodeID>::iterator NewEnd = unique ( usedNodeIDs.begin(),usedNodeIDs.end() ) ;
|
||||
usedNodeIDs.resize ( NewEnd - usedNodeIDs.begin() );
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
|
||||
cout << "[extractor] Sorting all nodes ... " << flush;
|
||||
stxxl::sort(allNodes.begin(), allNodes.end(), CmpNodeByID(), memory_to_use);
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
|
||||
cout << "[extractor] Sorting used ways ... " << flush;
|
||||
stxxl::sort(wayStartEndVector.begin(), wayStartEndVector.end(), CmpWayByID(), memory_to_use);
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
|
||||
cout << "[extractor] Sorting restrctns. by from... " << flush;
|
||||
stxxl::sort(restrictionsVector.begin(), restrictionsVector.end(), CmpRestrictionContainerByFrom(), memory_to_use);
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
|
||||
cout << "[extractor] Fixing restriction starts ... " << flush;
|
||||
STXXLRestrictionsVector::iterator restrictionsIT = restrictionsVector.begin();
|
||||
STXXLWayIDStartEndVector::iterator wayStartAndEndEdgeIT = wayStartEndVector.begin();
|
||||
|
||||
while(wayStartAndEndEdgeIT != wayStartEndVector.end() && restrictionsIT != restrictionsVector.end()) {
|
||||
if(wayStartAndEndEdgeIT->wayID < restrictionsIT->fromWay){
|
||||
++wayStartAndEndEdgeIT;
|
||||
continue;
|
||||
}
|
||||
if(wayStartAndEndEdgeIT->wayID > restrictionsIT->fromWay) {
|
||||
++restrictionsIT;
|
||||
continue;
|
||||
}
|
||||
assert(wayStartAndEndEdgeIT->wayID == restrictionsIT->fromWay);
|
||||
NodeID viaNode = restrictionsIT->restriction.viaNode;
|
||||
|
||||
if(wayStartAndEndEdgeIT->firstStart == viaNode) {
|
||||
restrictionsIT->restriction.fromNode = wayStartAndEndEdgeIT->firstTarget;
|
||||
} else if(wayStartAndEndEdgeIT->firstTarget == viaNode) {
|
||||
restrictionsIT->restriction.fromNode = wayStartAndEndEdgeIT->firstStart;
|
||||
} else if(wayStartAndEndEdgeIT->lastStart == viaNode) {
|
||||
restrictionsIT->restriction.fromNode = wayStartAndEndEdgeIT->lastTarget;
|
||||
} else if(wayStartAndEndEdgeIT->lastTarget == viaNode) {
|
||||
restrictionsIT->restriction.fromNode = wayStartAndEndEdgeIT->lastStart;
|
||||
}
|
||||
++restrictionsIT;
|
||||
}
|
||||
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
|
||||
cout << "[extractor] Sorting restrctns. by to ... " << flush;
|
||||
stxxl::sort(restrictionsVector.begin(), restrictionsVector.end(), CmpRestrictionContainerByTo(), memory_to_use);
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
|
||||
time = get_timestamp();
|
||||
unsigned usableRestrictionsCounter(0);
|
||||
cout << "[extractor] Fixing restriction ends ... " << flush;
|
||||
restrictionsIT = restrictionsVector.begin();
|
||||
wayStartAndEndEdgeIT = wayStartEndVector.begin();
|
||||
while(wayStartAndEndEdgeIT != wayStartEndVector.end() && restrictionsIT != restrictionsVector.end()) {
|
||||
if(wayStartAndEndEdgeIT->wayID < restrictionsIT->toWay){
|
||||
++wayStartAndEndEdgeIT;
|
||||
continue;
|
||||
}
|
||||
if(wayStartAndEndEdgeIT->wayID > restrictionsIT->toWay) {
|
||||
++restrictionsIT;
|
||||
continue;
|
||||
}
|
||||
NodeID viaNode = restrictionsIT->restriction.viaNode;
|
||||
if(wayStartAndEndEdgeIT->lastStart == viaNode) {
|
||||
restrictionsIT->restriction.toNode = wayStartAndEndEdgeIT->lastTarget;
|
||||
} else if(wayStartAndEndEdgeIT->lastTarget == viaNode) {
|
||||
restrictionsIT->restriction.toNode = wayStartAndEndEdgeIT->lastStart;
|
||||
} else if(wayStartAndEndEdgeIT->firstStart == viaNode) {
|
||||
restrictionsIT->restriction.toNode = wayStartAndEndEdgeIT->firstTarget;
|
||||
} else if(wayStartAndEndEdgeIT->firstTarget == viaNode) {
|
||||
restrictionsIT->restriction.toNode = wayStartAndEndEdgeIT->firstStart;
|
||||
}
|
||||
|
||||
if(UINT_MAX != restrictionsIT->restriction.fromNode && UINT_MAX != restrictionsIT->restriction.toNode) {
|
||||
++usableRestrictionsCounter;
|
||||
}
|
||||
++restrictionsIT;
|
||||
}
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
INFO("usable restrictions: " << usableRestrictionsCounter );
|
||||
//serialize restrictions
|
||||
ofstream restrictionsOutstream;
|
||||
restrictionsOutstream.open(restrictionsFileName.c_str(), ios::binary);
|
||||
restrictionsOutstream.write((char*)&usableRestrictionsCounter, sizeof(unsigned));
|
||||
for(restrictionsIT = restrictionsVector.begin(); restrictionsIT != restrictionsVector.end(); ++restrictionsIT) {
|
||||
if(UINT_MAX != restrictionsIT->restriction.fromNode && UINT_MAX != restrictionsIT->restriction.toNode) {
|
||||
restrictionsOutstream.write((char *)&(restrictionsIT->restriction), sizeof(_Restriction));
|
||||
}
|
||||
}
|
||||
restrictionsOutstream.close();
|
||||
|
||||
ofstream fout;
|
||||
fout.open(outputFileName.c_str(), ios::binary);
|
||||
fout.write((char*)&usedNodeCounter, sizeof(unsigned));
|
||||
time = get_timestamp();
|
||||
cout << "[extractor] Confirming/Writing used nodes ... " << flush;
|
||||
|
||||
STXXLNodeVector::iterator nodesIT = allNodes.begin();
|
||||
STXXLNodeIDVector::iterator usedNodeIDsIT = usedNodeIDs.begin();
|
||||
while(usedNodeIDsIT != usedNodeIDs.end() && nodesIT != allNodes.end()) {
|
||||
if(*usedNodeIDsIT < nodesIT->id){
|
||||
++usedNodeIDsIT;
|
||||
continue;
|
||||
}
|
||||
if(*usedNodeIDsIT > nodesIT->id) {
|
||||
++nodesIT;
|
||||
continue;
|
||||
}
|
||||
if(*usedNodeIDsIT == nodesIT->id) {
|
||||
fout.write((char*)&(*nodesIT), sizeof(_Node));
|
||||
++usedNodeCounter;
|
||||
++usedNodeIDsIT;
|
||||
++nodesIT;
|
||||
}
|
||||
}
|
||||
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
|
||||
cout << "[extractor] setting number of nodes ... " << flush;
|
||||
ios::pos_type positionInFile = fout.tellp();
|
||||
fout.seekp(ios::beg);
|
||||
fout.write((char*)&usedNodeCounter, sizeof(unsigned));
|
||||
fout.seekp(positionInFile);
|
||||
|
||||
cout << "ok" << endl;
|
||||
time = get_timestamp();
|
||||
|
||||
// Sort edges by start.
|
||||
cout << "[extractor] Sorting edges by start ... " << flush;
|
||||
stxxl::sort(allEdges.begin(), allEdges.end(), CmpEdgeByStartID(), memory_to_use);
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
|
||||
cout << "[extractor] Setting start coords ... " << flush;
|
||||
fout.write((char*)&usedEdgeCounter, sizeof(unsigned));
|
||||
// Traverse list of edges and nodes in parallel and set start coord
|
||||
nodesIT = allNodes.begin();
|
||||
STXXLEdgeVector::iterator edgeIT = allEdges.begin();
|
||||
while(edgeIT != allEdges.end() && nodesIT != allNodes.end()) {
|
||||
if(edgeIT->start < nodesIT->id){
|
||||
++edgeIT;
|
||||
continue;
|
||||
}
|
||||
if(edgeIT->start > nodesIT->id) {
|
||||
nodesIT++;
|
||||
continue;
|
||||
}
|
||||
if(edgeIT->start == nodesIT->id) {
|
||||
edgeIT->startCoord.lat = nodesIT->lat;
|
||||
edgeIT->startCoord.lon = nodesIT->lon;
|
||||
++edgeIT;
|
||||
}
|
||||
}
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
|
||||
// Sort Edges by target
|
||||
cout << "[extractor] Sorting edges by target ... " << flush;
|
||||
stxxl::sort(allEdges.begin(), allEdges.end(), CmpEdgeByTargetID(), memory_to_use);
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
|
||||
cout << "[extractor] Setting target coords ... " << flush;
|
||||
// Traverse list of edges and nodes in parallel and set target coord
|
||||
nodesIT = allNodes.begin();
|
||||
edgeIT = allEdges.begin();
|
||||
|
||||
while(edgeIT != allEdges.end() && nodesIT != allNodes.end()) {
|
||||
if(edgeIT->target < nodesIT->id){
|
||||
++edgeIT;
|
||||
continue;
|
||||
}
|
||||
if(edgeIT->target > nodesIT->id) {
|
||||
++nodesIT;
|
||||
continue;
|
||||
}
|
||||
if(edgeIT->target == nodesIT->id) {
|
||||
if(edgeIT->startCoord.lat != INT_MIN && edgeIT->startCoord.lon != INT_MIN) {
|
||||
edgeIT->targetCoord.lat = nodesIT->lat;
|
||||
edgeIT->targetCoord.lon = nodesIT->lon;
|
||||
|
||||
double distance = ApproximateDistance(edgeIT->startCoord.lat, edgeIT->startCoord.lon, nodesIT->lat, nodesIT->lon);
|
||||
assert(edgeIT->speed != -1);
|
||||
double weight = ( distance * 10. ) / (edgeIT->speed / 3.6);
|
||||
int intWeight = std::max(1, (int)std::floor((edgeIT->isDurationSet ? edgeIT->speed : weight)+.5) );
|
||||
int intDist = std::max(1, (int)distance);
|
||||
short zero = 0;
|
||||
short one = 1;
|
||||
|
||||
fout.write((char*)&edgeIT->start, sizeof(unsigned));
|
||||
fout.write((char*)&edgeIT->target, sizeof(unsigned));
|
||||
fout.write((char*)&intDist, sizeof(int));
|
||||
switch(edgeIT->direction) {
|
||||
case _Way::notSure:
|
||||
fout.write((char*)&zero, sizeof(short));
|
||||
break;
|
||||
case _Way::oneway:
|
||||
fout.write((char*)&one, sizeof(short));
|
||||
break;
|
||||
case _Way::bidirectional:
|
||||
fout.write((char*)&zero, sizeof(short));
|
||||
|
||||
break;
|
||||
case _Way::opposite:
|
||||
fout.write((char*)&one, sizeof(short));
|
||||
break;
|
||||
default:
|
||||
cerr << "[error] edge with no direction: " << edgeIT->direction << endl;
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
fout.write((char*)&intWeight, sizeof(int));
|
||||
assert(edgeIT->type >= 0);
|
||||
fout.write((char*)&edgeIT->type, sizeof(short));
|
||||
fout.write((char*)&edgeIT->nameID, sizeof(unsigned));
|
||||
fout.write((char*)&edgeIT->isRoundabout, sizeof(bool));
|
||||
fout.write((char*)&edgeIT->ignoreInGrid, sizeof(bool));
|
||||
fout.write((char*)&edgeIT->isAccessRestricted, sizeof(bool));
|
||||
}
|
||||
++usedEdgeCounter;
|
||||
++edgeIT;
|
||||
}
|
||||
}
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
cout << "[extractor] setting number of edges ... " << flush;
|
||||
|
||||
fout.seekp(positionInFile);
|
||||
fout.write((char*)&usedEdgeCounter, sizeof(unsigned));
|
||||
fout.close();
|
||||
cout << "ok" << endl;
|
||||
time = get_timestamp();
|
||||
cout << "[extractor] writing street name index ... " << flush;
|
||||
std::string nameOutFileName = (outputFileName + ".names");
|
||||
ofstream nameOutFile(nameOutFileName.c_str(), ios::binary);
|
||||
unsigned sizeOfNameIndex = nameVector.size();
|
||||
nameOutFile.write((char *)&(sizeOfNameIndex), sizeof(unsigned));
|
||||
|
||||
BOOST_FOREACH(string str, nameVector) {
|
||||
unsigned lengthOfRawString = strlen(str.c_str());
|
||||
nameOutFile.write((char *)&(lengthOfRawString), sizeof(unsigned));
|
||||
nameOutFile.write(str.c_str(), lengthOfRawString);
|
||||
}
|
||||
|
||||
nameOutFile.close();
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
|
||||
// time = get_timestamp();
|
||||
// cout << "[extractor] writing address list ... " << flush;
|
||||
//
|
||||
// adressFileName.append(".address");
|
||||
// ofstream addressOutFile(adressFileName.c_str());
|
||||
// for(STXXLAddressVector::iterator it = adressVector.begin(); it != adressVector.end(); it++) {
|
||||
// addressOutFile << it->node.id << "|" << it->node.lat << "|" << it->node.lon << "|" << it->city << "|" << it->street << "|" << it->housenumber << "|" << it->state << "|" << it->country << "\n";
|
||||
// }
|
||||
// addressOutFile.close();
|
||||
// cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
|
||||
INFO("Processed " << usedNodeCounter << " nodes and " << usedEdgeCounter << " edges");
|
||||
|
||||
|
||||
} catch ( const exception& e ) {
|
||||
cerr << "Caught Execption:" << e.what() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTIONCONTAINERS_H_
|
||||
#define EXTRACTIONCONTAINERS_H_
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <stxxl.h>
|
||||
|
||||
#include "ExtractorStructs.h"
|
||||
#include "../DataStructures/Util.h"
|
||||
|
||||
class ExtractionContainers {
|
||||
public:
|
||||
typedef stxxl::vector<NodeID> STXXLNodeIDVector;
|
||||
typedef stxxl::vector<_Node> STXXLNodeVector;
|
||||
typedef stxxl::vector<_Edge> STXXLEdgeVector;
|
||||
typedef stxxl::vector<std::string> STXXLStringVector;
|
||||
typedef stxxl::vector<_RawRestrictionContainer> STXXLRestrictionsVector;
|
||||
typedef stxxl::vector<_WayIDStartAndEndEdge> STXXLWayIDStartEndVector;
|
||||
|
||||
ExtractionContainers() {
|
||||
//Check if another instance of stxxl is already running or if there is a general problem
|
||||
try {
|
||||
stxxl::vector<unsigned> testForRunningInstance;
|
||||
} catch(std::exception & e) {
|
||||
ERR("Could not instantiate STXXL layer." << std::endl << e.what());
|
||||
}
|
||||
|
||||
nameVector.push_back("");
|
||||
}
|
||||
virtual ~ExtractionContainers() {
|
||||
usedNodeIDs.clear();
|
||||
allNodes.clear();
|
||||
allEdges.clear();
|
||||
nameVector.clear();
|
||||
restrictionsVector.clear();
|
||||
wayStartEndVector.clear();
|
||||
}
|
||||
|
||||
void PrepareData( const std::string & outputFileName, const std::string restrictionsFileName, const unsigned amountOfRAM);
|
||||
|
||||
STXXLNodeIDVector usedNodeIDs;
|
||||
STXXLNodeVector allNodes;
|
||||
STXXLEdgeVector allEdges;
|
||||
STXXLStringVector nameVector;
|
||||
STXXLRestrictionsVector restrictionsVector;
|
||||
STXXLWayIDStartEndVector wayStartEndVector;
|
||||
|
||||
};
|
||||
|
||||
#endif /* EXTRACTIONCONTAINERS_H_ */
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef EXTRACTIONHELPERFUNCTIONS_H_
|
||||
#define EXTRACTIONHELPERFUNCTIONS_H_
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string_regex.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <climits>
|
||||
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
//TODO: Move into LUA
|
||||
|
||||
inline bool durationIsValid(const std::string &s) {
|
||||
boost::regex e ("((\\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) {
|
||||
int hours = 0;
|
||||
int minutes = 0;
|
||||
boost::regex e ("((\\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) {
|
||||
hours = (result.size()== 2) ? stringToInt(result[0]) : 0;
|
||||
minutes = (result.size()== 2) ? stringToInt(result[1]) : stringToInt(result[0]);
|
||||
return 600*(hours*60+minutes);
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
inline int parseMaxspeed(std::string input) { //call-by-value on purpose.
|
||||
boost::algorithm::to_lower(input);
|
||||
int n = stringToInt(input);
|
||||
if (input.find("mph") != std::string::npos || input.find("mp/h") != std::string::npos) {
|
||||
n = (n*1609)/1000;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
#endif /* EXTRACTIONHELPERFUNCTIONS_H_ */
|
||||
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
|
||||
#include "ExtractorCallbacks.h"
|
||||
#include "ExtractionHelperFunctions.h"
|
||||
|
||||
ExtractorCallbacks::ExtractorCallbacks() {externalMemory = NULL; stringMap = NULL; }
|
||||
ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers * ext, StringMap * strMap) {
|
||||
externalMemory = ext;
|
||||
stringMap = strMap;
|
||||
}
|
||||
|
||||
ExtractorCallbacks::~ExtractorCallbacks() {
|
||||
}
|
||||
|
||||
/** warning: caller needs to take care of synchronization! */
|
||||
bool ExtractorCallbacks::nodeFunction(_Node &n) {
|
||||
if(n.lat <= 85*100000 && n.lat >= -85*100000)
|
||||
externalMemory->allNodes.push_back(n);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExtractorCallbacks::restrictionFunction(_RawRestrictionContainer &r) {
|
||||
externalMemory->restrictionsVector.push_back(r);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** warning: caller needs to take care of synchronization! */
|
||||
bool ExtractorCallbacks::wayFunction(_Way &w) {
|
||||
/*** Store name of way and split it into edge segments ***/
|
||||
|
||||
if ( w.speed > 0 ) { //Only true if the way is specified by the speed profile
|
||||
|
||||
//Get the unique identifier for the street name
|
||||
const StringMap::const_iterator strit = stringMap->find(w.name);
|
||||
if(strit == stringMap->end()) {
|
||||
w.nameID = externalMemory->nameVector.size();
|
||||
externalMemory->nameVector.push_back(w.name);
|
||||
stringMap->insert(StringMap::value_type(w.name, w.nameID));
|
||||
} else {
|
||||
w.nameID = strit->second;
|
||||
}
|
||||
|
||||
if(fabs(-1. - w.speed) < FLT_EPSILON){
|
||||
WARN("found way with bogus speed, id: " << w.id);
|
||||
return true;
|
||||
}
|
||||
if(w.id == UINT_MAX) {
|
||||
WARN("found way with unknown type: " << w.id);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( w.direction == _Way::opposite ){
|
||||
std::reverse( w.path.begin(), w.path.end() );
|
||||
}
|
||||
|
||||
for(vector< NodeID >::size_type n = 0; n < w.path.size()-1; ++n) {
|
||||
externalMemory->allEdges.push_back(_Edge(w.path[n], w.path[n+1], w.type, w.direction, w.speed, w.nameID, w.roundabout, w.ignoreInGrid, w.isDurationSet, w.isAccessRestricted));
|
||||
externalMemory->usedNodeIDs.push_back(w.path[n]);
|
||||
}
|
||||
externalMemory->usedNodeIDs.push_back(w.path.back());
|
||||
|
||||
//The following information is needed to identify start and end segments of restrictions
|
||||
externalMemory->wayStartEndVector.push_back(_WayIDStartAndEndEdge(w.id, w.path[0], w.path[1], w.path[w.path.size()-2], w.path[w.path.size()-1]));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTORCALLBACKS_H_
|
||||
#define EXTRACTORCALLBACKS_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cfloat>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/regex.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include "ExtractionContainers.h"
|
||||
#include "ExtractorStructs.h"
|
||||
|
||||
class ExtractorCallbacks{
|
||||
private:
|
||||
StringMap * stringMap;
|
||||
ExtractionContainers * externalMemory;
|
||||
|
||||
ExtractorCallbacks();
|
||||
public:
|
||||
explicit ExtractorCallbacks(ExtractionContainers * ext, StringMap * strMap);
|
||||
|
||||
~ExtractorCallbacks();
|
||||
|
||||
/** warning: caller needs to take care of synchronization! */
|
||||
bool nodeFunction(_Node &n);
|
||||
|
||||
bool restrictionFunction(_RawRestrictionContainer &r);
|
||||
|
||||
/** warning: caller needs to take care of synchronization! */
|
||||
bool wayFunction(_Way &w);
|
||||
|
||||
};
|
||||
|
||||
#endif /* EXTRACTORCALLBACKS_H_ */
|
||||
@@ -1,219 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTORSTRUCTS_H_
|
||||
#define EXTRACTORSTRUCTS_H_
|
||||
|
||||
#include <climits>
|
||||
#include <string>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/regex.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include "../DataStructures/Coordinate.h"
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
#include "../DataStructures/NodeCoords.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../DataStructures/Util.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
typedef boost::unordered_map<std::string, NodeID > StringMap;
|
||||
typedef boost::unordered_map<std::string, std::pair<int, short> > StringToIntPairMap;
|
||||
|
||||
struct _Way {
|
||||
_Way() {
|
||||
Clear();
|
||||
}
|
||||
|
||||
inline void Clear(){
|
||||
id = UINT_MAX;
|
||||
nameID = UINT_MAX;
|
||||
path.clear();
|
||||
keyVals.EraseAll();
|
||||
direction = _Way::notSure;
|
||||
speed = -1;
|
||||
type = -1;
|
||||
access = true;
|
||||
roundabout = false;
|
||||
isDurationSet = false;
|
||||
isAccessRestricted = false;
|
||||
ignoreInGrid = false;
|
||||
}
|
||||
|
||||
enum {
|
||||
notSure = 0, oneway, bidirectional, opposite
|
||||
} direction;
|
||||
unsigned id;
|
||||
unsigned nameID;
|
||||
std::string name;
|
||||
double speed;
|
||||
short type;
|
||||
bool access;
|
||||
bool roundabout;
|
||||
bool isDurationSet;
|
||||
bool isAccessRestricted;
|
||||
bool ignoreInGrid;
|
||||
std::vector< NodeID > path;
|
||||
HashTable<std::string, std::string> keyVals;
|
||||
};
|
||||
|
||||
struct _Relation {
|
||||
_Relation() : type(unknown){}
|
||||
enum {
|
||||
unknown = 0, ferry, turnRestriction
|
||||
} type;
|
||||
HashTable<std::string, std::string> keyVals;
|
||||
};
|
||||
|
||||
struct _Edge {
|
||||
_Edge() : start(0), target(0), type(0), direction(0), speed(0), nameID(0), isRoundabout(false), ignoreInGrid(false), isDurationSet(false), isAccessRestricted(false) {};
|
||||
_Edge(NodeID s, NodeID t) : start(s), target(t), type(0), direction(0), speed(0), nameID(0), isRoundabout(false), ignoreInGrid(false), isDurationSet(false), isAccessRestricted(false) { }
|
||||
_Edge(NodeID s, NodeID t, short tp, short d, double sp): start(s), target(t), type(tp), direction(d), speed(sp), nameID(0), isRoundabout(false), ignoreInGrid(false), isDurationSet(false), isAccessRestricted(false) { }
|
||||
_Edge(NodeID s, NodeID t, short tp, short d, double sp, unsigned nid, bool isra, bool iing, bool ids, bool iar): start(s), target(t), type(tp), direction(d), speed(sp), nameID(nid), isRoundabout(isra), ignoreInGrid(iing), isDurationSet(ids), isAccessRestricted(iar) {
|
||||
assert(0 <= type);
|
||||
}
|
||||
NodeID start;
|
||||
NodeID target;
|
||||
short type;
|
||||
short direction;
|
||||
double speed;
|
||||
unsigned nameID;
|
||||
bool isRoundabout;
|
||||
bool ignoreInGrid;
|
||||
bool isDurationSet;
|
||||
bool isAccessRestricted;
|
||||
|
||||
_Coordinate startCoord;
|
||||
_Coordinate targetCoord;
|
||||
|
||||
static _Edge min_value() {
|
||||
return _Edge(0,0);
|
||||
}
|
||||
static _Edge max_value() {
|
||||
return _Edge((numeric_limits<unsigned>::max)(), (numeric_limits<unsigned>::max)());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct _WayIDStartAndEndEdge {
|
||||
unsigned wayID;
|
||||
NodeID firstStart;
|
||||
NodeID firstTarget;
|
||||
NodeID lastStart;
|
||||
NodeID lastTarget;
|
||||
_WayIDStartAndEndEdge() : wayID(UINT_MAX), firstStart(UINT_MAX), firstTarget(UINT_MAX), lastStart(UINT_MAX), lastTarget(UINT_MAX) {}
|
||||
_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((numeric_limits<unsigned>::min)(), (numeric_limits<unsigned>::min)(), (numeric_limits<unsigned>::min)(), (numeric_limits<unsigned>::min)(), (numeric_limits<unsigned>::min)());
|
||||
}
|
||||
static _WayIDStartAndEndEdge max_value() {
|
||||
return _WayIDStartAndEndEdge((numeric_limits<unsigned>::max)(), (numeric_limits<unsigned>::max)(), (numeric_limits<unsigned>::max)(), (numeric_limits<unsigned>::max)(), (numeric_limits<unsigned>::max)());
|
||||
}
|
||||
};
|
||||
|
||||
struct CmpWayByID : public std::binary_function<_WayIDStartAndEndEdge, _WayIDStartAndEndEdge, bool> {
|
||||
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 : public std::binary_function<NodeID, NodeID, bool> {
|
||||
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 : public std::binary_function<_Node, _Node, bool> {
|
||||
typedef _Node value_type;
|
||||
bool operator () (const _Node & a, const _Node & b) const {
|
||||
return a.id < b.id;
|
||||
}
|
||||
value_type max_value() {
|
||||
return _Node::max_value();
|
||||
}
|
||||
value_type min_value() {
|
||||
return _Node::min_value();
|
||||
}
|
||||
};
|
||||
|
||||
struct CmpEdgeByStartID : public std::binary_function<_Edge, _Edge, bool>
|
||||
{
|
||||
typedef _Edge value_type;
|
||||
bool operator () (const _Edge & a, const _Edge & b) const {
|
||||
return a.start < b.start;
|
||||
}
|
||||
value_type max_value() {
|
||||
return _Edge::max_value();
|
||||
}
|
||||
value_type min_value() {
|
||||
return _Edge::min_value();
|
||||
}
|
||||
};
|
||||
|
||||
struct CmpEdgeByTargetID : public std::binary_function<_Edge, _Edge, bool>
|
||||
{
|
||||
typedef _Edge value_type;
|
||||
bool operator () (const _Edge & a, const _Edge & b) const
|
||||
{
|
||||
return a.target < b.target;
|
||||
}
|
||||
value_type max_value()
|
||||
{
|
||||
return _Edge::max_value();
|
||||
}
|
||||
value_type min_value()
|
||||
{
|
||||
return _Edge::min_value();
|
||||
}
|
||||
};
|
||||
|
||||
inline string GetRandomString() {
|
||||
char s[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 string(s);
|
||||
}
|
||||
|
||||
#endif /* EXTRACTORSTRUCTS_H_ */
|
||||
@@ -1,600 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef PBFPARSER_H_
|
||||
#define PBFPARSER_H_
|
||||
|
||||
#include <zlib.h>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <osmpbf/fileformat.pb.h>
|
||||
#include <osmpbf/osmformat.pb.h>
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include "BaseParser.h"
|
||||
#include "ExtractorCallbacks.h"
|
||||
#include "ExtractorStructs.h"
|
||||
#include "ScriptingEnvironment.h"
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../DataStructures/ConcurrentQueue.h"
|
||||
#include "../Util/OpenMPWrapper.h"
|
||||
|
||||
class PBFParser : public BaseParser<ExtractorCallbacks, _Node, _RawRestrictionContainer, _Way> {
|
||||
|
||||
// typedef BaseParser<ExtractorCallbacks, _Node, _RawRestrictionContainer, _Way> super;
|
||||
|
||||
enum EntityType {
|
||||
TypeNode = 1,
|
||||
TypeWay = 2,
|
||||
TypeRelation = 4,
|
||||
TypeDenseNode = 8
|
||||
} ;
|
||||
|
||||
enum Endianness {
|
||||
LittleEndian = 1,
|
||||
BigEndian = 2
|
||||
};
|
||||
|
||||
struct _ThreadData {
|
||||
int currentGroupID;
|
||||
int currentEntityID;
|
||||
short entityTypeIndicator;
|
||||
|
||||
OSMPBF::BlobHeader PBFBlobHeader;
|
||||
OSMPBF::Blob PBFBlob;
|
||||
|
||||
OSMPBF::HeaderBlock PBFHeaderBlock;
|
||||
OSMPBF::PrimitiveBlock PBFprimitiveBlock;
|
||||
|
||||
std::vector<char> charBuffer;
|
||||
};
|
||||
|
||||
public:
|
||||
PBFParser(const char * fileName) : externalMemory(NULL){
|
||||
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.
|
||||
threadDataQueue = boost::make_shared<ConcurrentQueue<_ThreadData*> >( 2500 ); /* Max 2500 items in queue, hardcoded. */
|
||||
input.open(fileName, std::ios::in | std::ios::binary);
|
||||
|
||||
if (!input) {
|
||||
std::cerr << fileName << ": File not found." << std::endl;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
blockCount = 0;
|
||||
groupCount = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void RegisterCallbacks(ExtractorCallbacks * em) {
|
||||
externalMemory = em;
|
||||
}
|
||||
|
||||
//call by value, but who cares. It is done once.
|
||||
void RegisterScriptingEnvironment(ScriptingEnvironment & _se) {
|
||||
scriptingEnvironment = _se;
|
||||
}
|
||||
|
||||
~PBFParser() {
|
||||
if(input.is_open())
|
||||
input.close();
|
||||
|
||||
// Clean up any leftover ThreadData objects in the queue
|
||||
_ThreadData* td;
|
||||
while (threadDataQueue->try_pop(td)) {
|
||||
delete td;
|
||||
}
|
||||
google::protobuf::ShutdownProtobufLibrary();
|
||||
|
||||
#ifndef NDEBUG
|
||||
DEBUG("parsed " << blockCount << " blocks from pbf with " << groupCount << " groups");
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool Init() {
|
||||
_ThreadData initData;
|
||||
/** read Header */
|
||||
if(!readPBFBlobHeader(input, &initData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(readBlob(input, &initData)) {
|
||||
if(!initData.PBFHeaderBlock.ParseFromArray(&(initData.charBuffer[0]), initData.charBuffer.size() ) ) {
|
||||
std::cerr << "[error] Header not parseable!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i = 0, featureSize = initData.PBFHeaderBlock.required_features_size(); i < featureSize; ++i) {
|
||||
const std::string& feature = initData.PBFHeaderBlock.required_features( i );
|
||||
bool supported = false;
|
||||
if ( "OsmSchema-V0.6" == feature )
|
||||
supported = true;
|
||||
else if ( "DenseNodes" == feature )
|
||||
supported = true;
|
||||
|
||||
if ( !supported ) {
|
||||
std::cerr << "[error] required feature not supported: " << feature.data() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::cerr << "[error] blob not loaded!" << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void ReadData() {
|
||||
bool keepRunning = true;
|
||||
do {
|
||||
_ThreadData *threadData = new _ThreadData();
|
||||
keepRunning = readNextBlock(input, threadData);
|
||||
|
||||
if (keepRunning)
|
||||
threadDataQueue->push(threadData);
|
||||
else {
|
||||
threadDataQueue->push(NULL); // No more data to read, parse stops when NULL encountered
|
||||
delete threadData;
|
||||
}
|
||||
} while(keepRunning);
|
||||
}
|
||||
|
||||
inline void ParseData() {
|
||||
while (1) {
|
||||
_ThreadData *threadData;
|
||||
threadDataQueue->wait_and_pop(threadData);
|
||||
if (threadData == NULL) {
|
||||
INFO("Parse Data Thread Finished");
|
||||
threadDataQueue->push(NULL); // Signal end of data for other threads
|
||||
break;
|
||||
}
|
||||
|
||||
loadBlock(threadData);
|
||||
|
||||
for(int i = 0, groupSize = threadData->PBFprimitiveBlock.primitivegroup_size(); i < groupSize; ++i) {
|
||||
threadData->currentGroupID = i;
|
||||
loadGroup(threadData);
|
||||
|
||||
if(threadData->entityTypeIndicator == TypeNode)
|
||||
parseNode(threadData);
|
||||
if(threadData->entityTypeIndicator == TypeWay)
|
||||
parseWay(threadData);
|
||||
if(threadData->entityTypeIndicator == TypeRelation)
|
||||
parseRelation(threadData);
|
||||
if(threadData->entityTypeIndicator == TypeDenseNode)
|
||||
parseDenseNode(threadData);
|
||||
}
|
||||
|
||||
delete threadData;
|
||||
threadData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool Parse() {
|
||||
// Start the read and parse threads
|
||||
boost::thread readThread(boost::bind(&PBFParser::ReadData, this));
|
||||
|
||||
//Open several parse threads that are synchronized before call to
|
||||
boost::thread parseThread(boost::bind(&PBFParser::ParseData, this));
|
||||
|
||||
// Wait for the threads to finish
|
||||
readThread.join();
|
||||
parseThread.join();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
inline void parseDenseNode(_ThreadData * threadData) {
|
||||
const OSMPBF::DenseNodes& dense = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).dense();
|
||||
int denseTagIndex = 0;
|
||||
int m_lastDenseID = 0;
|
||||
int m_lastDenseLatitude = 0;
|
||||
int m_lastDenseLongitude = 0;
|
||||
|
||||
ImportNode n;
|
||||
std::vector<ImportNode> nodesToParse;
|
||||
for(int i = 0, idSize = dense.id_size(); i < idSize; ++i) {
|
||||
n.Clear();
|
||||
m_lastDenseID += dense.id( i );
|
||||
m_lastDenseLatitude += dense.lat( i );
|
||||
m_lastDenseLongitude += dense.lon( i );
|
||||
n.id = m_lastDenseID;
|
||||
n.lat = 100000*( ( double ) m_lastDenseLatitude * threadData->PBFprimitiveBlock.granularity() +threadData-> PBFprimitiveBlock.lat_offset() ) / NANO;
|
||||
n.lon = 100000*( ( double ) m_lastDenseLongitude * threadData->PBFprimitiveBlock.granularity() + threadData->PBFprimitiveBlock.lon_offset() ) / NANO;
|
||||
while (denseTagIndex < dense.keys_vals_size()) {
|
||||
const int tagValue = dense.keys_vals( denseTagIndex );
|
||||
if(tagValue == 0) {
|
||||
++denseTagIndex;
|
||||
break;
|
||||
}
|
||||
const int keyValue = dense.keys_vals ( denseTagIndex+1 );
|
||||
const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(tagValue).data();
|
||||
const std::string & value = threadData->PBFprimitiveBlock.stringtable().s(keyValue).data();
|
||||
n.keyVals.Add(key, value);
|
||||
denseTagIndex += 2;
|
||||
}
|
||||
nodesToParse.push_back(n);
|
||||
}
|
||||
|
||||
unsigned endi_nodes = nodesToParse.size();
|
||||
#pragma omp parallel for schedule ( guided )
|
||||
for(unsigned i = 0; i < endi_nodes; ++i) {
|
||||
ImportNode &n = nodesToParse[i];
|
||||
/** Pass the unpacked node to the LUA call back **/
|
||||
try {
|
||||
luabind::call_function<int>(
|
||||
scriptingEnvironment.getLuaStateForThreadID(omp_get_thread_num()),
|
||||
"node_function",
|
||||
boost::ref(n)
|
||||
);
|
||||
} catch (const luabind::error &er) {
|
||||
lua_State* Ler=er.state();
|
||||
report_errors(Ler, -1);
|
||||
ERR(er.what());
|
||||
}
|
||||
// catch (...) {
|
||||
// ERR("Unknown error occurred during PBF dense node parsing!");
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
BOOST_FOREACH(ImportNode &n, nodesToParse) {
|
||||
if(!externalMemory->nodeFunction(n))
|
||||
std::cerr << "[PBFParser] dense node not parsed" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
inline void parseNode(_ThreadData * ) {
|
||||
ERR("Parsing of simple nodes not supported. PBF should use dense nodes");
|
||||
}
|
||||
|
||||
inline void parseRelation(_ThreadData * threadData) {
|
||||
//TODO: leave early, if relatio is not a restriction
|
||||
//TODO: reuse rawRestriction container
|
||||
const OSMPBF::PrimitiveGroup& group = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID );
|
||||
for(int i = 0; i < group.relations_size(); ++i ) {
|
||||
const OSMPBF::Relation& inputRelation = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).relations(i);
|
||||
bool isRestriction = false;
|
||||
bool isOnlyRestriction = false;
|
||||
for(int k = 0, endOfKeys = inputRelation.keys_size(); k < endOfKeys; ++k) {
|
||||
const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputRelation.keys(k));
|
||||
const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputRelation.vals(k));
|
||||
if ("type" == key) {
|
||||
if( "restriction" == val)
|
||||
isRestriction = true;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if ("restriction" == key) {
|
||||
if(val.find("only_") == 0)
|
||||
isOnlyRestriction = true;
|
||||
}
|
||||
|
||||
}
|
||||
if(isRestriction) {
|
||||
long long lastRef = 0;
|
||||
_RawRestrictionContainer currentRestrictionContainer(isOnlyRestriction);
|
||||
for(int rolesIndex = 0; rolesIndex < inputRelation.roles_sid_size(); ++rolesIndex) {
|
||||
std::string role(threadData->PBFprimitiveBlock.stringtable().s( inputRelation.roles_sid( rolesIndex ) ).data());
|
||||
lastRef += inputRelation.memids(rolesIndex);
|
||||
|
||||
if(false == ("from" == role || "to" == role || "via" == role)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(inputRelation.types(rolesIndex)) {
|
||||
case 0: //node
|
||||
if("from" == role || "to" == role) //Only via should be a node
|
||||
continue;
|
||||
assert("via" == role);
|
||||
if(UINT_MAX != currentRestrictionContainer.viaNode)
|
||||
currentRestrictionContainer.viaNode = UINT_MAX;
|
||||
assert(UINT_MAX == currentRestrictionContainer.viaNode);
|
||||
currentRestrictionContainer.restriction.viaNode = lastRef;
|
||||
break;
|
||||
case 1: //way
|
||||
assert("from" == role || "to" == role || "via" == role);
|
||||
if("from" == role) {
|
||||
currentRestrictionContainer.fromWay = lastRef;
|
||||
}
|
||||
if ("to" == role) {
|
||||
currentRestrictionContainer.toWay = lastRef;
|
||||
}
|
||||
if ("via" == role) {
|
||||
assert(currentRestrictionContainer.restriction.toNode == UINT_MAX);
|
||||
currentRestrictionContainer.viaNode = lastRef;
|
||||
}
|
||||
break;
|
||||
case 2: //relation, not used. relations relating to relations are evil.
|
||||
continue;
|
||||
assert(false);
|
||||
break;
|
||||
|
||||
default: //should not happen
|
||||
//cout << "unknown";
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if(UINT_MAX != currentRestriction.viaNode) {
|
||||
// cout << "restr from " << currentRestriction.from << " via ";
|
||||
// cout << "node " << currentRestriction.viaNode;
|
||||
// cout << " to " << currentRestriction.to << endl;
|
||||
// }
|
||||
if(!externalMemory->restrictionFunction(currentRestrictionContainer))
|
||||
std::cerr << "[PBFParser] relation not parsed" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void parseWay(_ThreadData * threadData) {
|
||||
_Way w;
|
||||
std::vector<_Way> waysToParse(threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways_size());
|
||||
for(int i = 0, ways_size = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways_size(); i < ways_size; ++i) {
|
||||
w.Clear();
|
||||
const OSMPBF::Way& inputWay = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways( i );
|
||||
w.id = inputWay.id();
|
||||
unsigned pathNode(0);
|
||||
for(int i = 0; i < inputWay.refs_size(); ++i) {
|
||||
pathNode += inputWay.refs(i);
|
||||
w.path.push_back(pathNode);
|
||||
}
|
||||
assert(inputWay.keys_size() == inputWay.vals_size());
|
||||
for(int i = 0; i < inputWay.keys_size(); ++i) {
|
||||
const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputWay.keys(i));
|
||||
const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputWay.vals(i));
|
||||
w.keyVals.Add(key, val);
|
||||
}
|
||||
|
||||
waysToParse.push_back(w);
|
||||
}
|
||||
|
||||
unsigned endi_ways = waysToParse.size();
|
||||
#pragma omp parallel for schedule ( guided )
|
||||
for(unsigned i = 0; i < endi_ways; ++i) {
|
||||
_Way & w = waysToParse[i];
|
||||
/** Pass the unpacked way to the LUA call back **/
|
||||
try {
|
||||
luabind::call_function<int>(
|
||||
scriptingEnvironment.getLuaStateForThreadID(omp_get_thread_num()),
|
||||
"way_function",
|
||||
boost::ref(w),
|
||||
w.path.size()
|
||||
);
|
||||
|
||||
} catch (const luabind::error &er) {
|
||||
lua_State* Ler=er.state();
|
||||
report_errors(Ler, -1);
|
||||
ERR(er.what());
|
||||
}
|
||||
// catch (...) {
|
||||
// ERR("Unknown error!");
|
||||
// }
|
||||
}
|
||||
|
||||
BOOST_FOREACH(_Way & w, waysToParse) {
|
||||
if(!externalMemory->wayFunction(w)) {
|
||||
std::cerr << "[PBFParser] way not parsed" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void loadGroup(_ThreadData * threadData) {
|
||||
#ifndef NDEBUG
|
||||
++groupCount;
|
||||
#endif
|
||||
|
||||
const OSMPBF::PrimitiveGroup& group = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID );
|
||||
threadData->entityTypeIndicator = 0;
|
||||
if ( group.nodes_size() != 0 ) {
|
||||
threadData->entityTypeIndicator = TypeNode;
|
||||
}
|
||||
if ( group.ways_size() != 0 ) {
|
||||
threadData->entityTypeIndicator = TypeWay;
|
||||
}
|
||||
if ( group.relations_size() != 0 ) {
|
||||
threadData->entityTypeIndicator = TypeRelation;
|
||||
}
|
||||
if ( group.has_dense() ) {
|
||||
threadData->entityTypeIndicator = TypeDenseNode;
|
||||
assert( group.dense().id_size() != 0 );
|
||||
}
|
||||
assert( threadData->entityTypeIndicator != 0 );
|
||||
}
|
||||
|
||||
inline void loadBlock(_ThreadData * threadData) {
|
||||
#ifndef NDEBUG
|
||||
++blockCount;
|
||||
#endif
|
||||
threadData->currentGroupID = 0;
|
||||
threadData->currentEntityID = 0;
|
||||
}
|
||||
|
||||
/* Reverses Network Byte Order into something usable, compiles down to a bswap-mov combination */
|
||||
inline unsigned swapEndian(unsigned x) const {
|
||||
if(getMachineEndianness() == LittleEndian)
|
||||
return ( (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24) );
|
||||
return x;
|
||||
}
|
||||
|
||||
inline bool readPBFBlobHeader(std::fstream& stream, _ThreadData * threadData) {
|
||||
int size(0);
|
||||
stream.read((char *)&size, sizeof(int));
|
||||
size = swapEndian(size);
|
||||
if(stream.eof()) {
|
||||
return false;
|
||||
}
|
||||
if ( size > MAX_BLOB_HEADER_SIZE || size < 0 ) {
|
||||
return false;
|
||||
}
|
||||
char *data = new char[size];
|
||||
stream.read(data, size*sizeof(data[0]));
|
||||
|
||||
bool dataSuccessfullyParsed = (threadData->PBFBlobHeader).ParseFromArray( data, size);
|
||||
delete[] data;
|
||||
return dataSuccessfullyParsed;
|
||||
}
|
||||
|
||||
inline bool unpackZLIB(std::fstream &, _ThreadData * threadData) {
|
||||
unsigned rawSize = threadData->PBFBlob.raw_size();
|
||||
char* unpackedDataArray = new char[rawSize];
|
||||
z_stream compressedDataStream;
|
||||
compressedDataStream.next_in = ( unsigned char* ) threadData->PBFBlob.zlib_data().data();
|
||||
compressedDataStream.avail_in = threadData->PBFBlob.zlib_data().size();
|
||||
compressedDataStream.next_out = ( unsigned char* ) unpackedDataArray;
|
||||
compressedDataStream.avail_out = rawSize;
|
||||
compressedDataStream.zalloc = Z_NULL;
|
||||
compressedDataStream.zfree = Z_NULL;
|
||||
compressedDataStream.opaque = Z_NULL;
|
||||
int ret = inflateInit( &compressedDataStream );
|
||||
if ( ret != Z_OK ) {
|
||||
std::cerr << "[error] failed to init zlib stream" << std::endl;
|
||||
delete[] unpackedDataArray;
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = inflate( &compressedDataStream, Z_FINISH );
|
||||
if ( ret != Z_STREAM_END ) {
|
||||
std::cerr << "[error] failed to inflate zlib stream" << std::endl;
|
||||
std::cerr << "[error] Error type: " << ret << std::endl;
|
||||
delete[] unpackedDataArray;
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = inflateEnd( &compressedDataStream );
|
||||
if ( ret != Z_OK ) {
|
||||
std::cerr << "[error] failed to deinit zlib stream" << std::endl;
|
||||
delete[] unpackedDataArray;
|
||||
return false;
|
||||
}
|
||||
|
||||
threadData->charBuffer.clear(); threadData->charBuffer.resize(rawSize);
|
||||
std::copy(unpackedDataArray, unpackedDataArray + rawSize, threadData->charBuffer.begin());
|
||||
delete[] unpackedDataArray;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool unpackLZMA(std::fstream &, _ThreadData * ) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool readBlob(std::fstream& stream, _ThreadData * threadData) {
|
||||
if(stream.eof())
|
||||
return false;
|
||||
|
||||
const int size = threadData->PBFBlobHeader.datasize();
|
||||
if ( size < 0 || size > MAX_BLOB_SIZE ) {
|
||||
std::cerr << "[error] invalid Blob size:" << size << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
char* data = new char[size];
|
||||
stream.read(data, sizeof(data[0])*size);
|
||||
|
||||
if ( !threadData->PBFBlob.ParseFromArray( data, size ) ) {
|
||||
std::cerr << "[error] failed to parse blob" << std::endl;
|
||||
delete[] data;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( threadData->PBFBlob.has_raw() ) {
|
||||
const std::string& data = threadData->PBFBlob.raw();
|
||||
threadData->charBuffer.clear();
|
||||
threadData->charBuffer.resize( data.size() );
|
||||
std::copy(data.begin(), data.end(), threadData->charBuffer.begin());
|
||||
} else if ( threadData->PBFBlob.has_zlib_data() ) {
|
||||
if ( !unpackZLIB(stream, threadData) ) {
|
||||
std::cerr << "[error] zlib data encountered that could not be unpacked" << std::endl;
|
||||
delete[] data;
|
||||
return false;
|
||||
}
|
||||
} else if ( threadData->PBFBlob.has_lzma_data() ) {
|
||||
if ( !unpackLZMA(stream, threadData) )
|
||||
std::cerr << "[error] lzma data encountered that could not be unpacked" << std::endl;
|
||||
delete[] data;
|
||||
return false;
|
||||
} else {
|
||||
std::cerr << "[error] Blob contains no data" << std::endl;
|
||||
delete[] data;
|
||||
return false;
|
||||
}
|
||||
delete[] data;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool readNextBlock(std::fstream& stream, _ThreadData * threadData) {
|
||||
if(stream.eof()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !readPBFBlobHeader(stream, threadData) ){
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( threadData->PBFBlobHeader.type() != "OSMData" ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !readBlob(stream, threadData) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !threadData->PBFprimitiveBlock.ParseFromArray( &(threadData->charBuffer[0]), threadData-> charBuffer.size() ) ) {
|
||||
ERR("failed to parse PrimitiveBlock");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//Is optimized to a single 'mov eax,1' on GCC, clang and icc using -O3
|
||||
inline Endianness getMachineEndianness() const {
|
||||
int i(1);
|
||||
char *p = (char *) &i;
|
||||
if (1 == p[0])
|
||||
return LittleEndian;
|
||||
return BigEndian;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
#ifndef NDEBUG
|
||||
/* counting the number of read blocks and groups */
|
||||
unsigned groupCount;
|
||||
unsigned blockCount;
|
||||
#endif
|
||||
|
||||
ExtractorCallbacks * externalMemory;
|
||||
/* the input stream to parse */
|
||||
std::fstream input;
|
||||
|
||||
/* ThreadData Queue */
|
||||
boost::shared_ptr<ConcurrentQueue < _ThreadData* > > threadDataQueue;
|
||||
|
||||
ScriptingEnvironment scriptingEnvironment;
|
||||
};
|
||||
|
||||
#endif /* PBFPARSER_H_ */
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
}
|
||||
|
||||
#include "ScriptingEnvironment.h"
|
||||
#include "../typedefs.h"
|
||||
#include "../Util/OpenMPWrapper.h"
|
||||
|
||||
ScriptingEnvironment::ScriptingEnvironment() {}
|
||||
ScriptingEnvironment::ScriptingEnvironment(const char * fileName) {
|
||||
INFO("Using script " << fileName);
|
||||
|
||||
// Create a new lua state
|
||||
for(int i = 0; i < omp_get_max_threads(); ++i)
|
||||
luaStateVector.push_back(luaL_newstate());
|
||||
|
||||
// Connect LuaBind to this lua state for all threads
|
||||
#pragma omp parallel
|
||||
{
|
||||
lua_State * myLuaState = getLuaStateForThreadID(omp_get_thread_num());
|
||||
luabind::open(myLuaState);
|
||||
//open utility libraries string library;
|
||||
luaL_openlibs(myLuaState);
|
||||
|
||||
// Add our function to the state's global scope
|
||||
luabind::module(myLuaState) [
|
||||
luabind::def("print", LUA_print<std::string>),
|
||||
luabind::def("parseMaxspeed", parseMaxspeed),
|
||||
luabind::def("durationIsValid", durationIsValid),
|
||||
luabind::def("parseDuration", parseDuration)
|
||||
];
|
||||
//#pragma omp critical
|
||||
// {
|
||||
// if(0 != luaL_dostring(
|
||||
// myLuaState,
|
||||
// "print('Initializing LUA engine')\n"
|
||||
// )) {
|
||||
// ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block");
|
||||
// }
|
||||
// }
|
||||
luabind::module(myLuaState) [
|
||||
luabind::class_<HashTable<std::string, std::string> >("keyVals")
|
||||
.def("Add", &HashTable<std::string, std::string>::Add)
|
||||
.def("Find", &HashTable<std::string, std::string>::Find)
|
||||
.def("Holds", &HashTable<std::string, std::string>::Holds)
|
||||
];
|
||||
|
||||
luabind::module(myLuaState) [
|
||||
luabind::class_<ImportNode>("Node")
|
||||
.def(luabind::constructor<>())
|
||||
.def_readwrite("lat", &ImportNode::lat)
|
||||
.def_readwrite("lon", &ImportNode::lon)
|
||||
.def_readwrite("id", &ImportNode::id)
|
||||
.def_readwrite("bollard", &ImportNode::bollard)
|
||||
.def_readwrite("traffic_light", &ImportNode::trafficLight)
|
||||
.def_readwrite("tags", &ImportNode::keyVals)
|
||||
];
|
||||
|
||||
luabind::module(myLuaState) [
|
||||
luabind::class_<_Way>("Way")
|
||||
.def(luabind::constructor<>())
|
||||
.def_readwrite("name", &_Way::name)
|
||||
.def_readwrite("speed", &_Way::speed)
|
||||
.def_readwrite("type", &_Way::type)
|
||||
.def_readwrite("access", &_Way::access)
|
||||
.def_readwrite("roundabout", &_Way::roundabout)
|
||||
.def_readwrite("is_duration_set", &_Way::isDurationSet)
|
||||
.def_readwrite("is_access_restricted", &_Way::isAccessRestricted)
|
||||
.def_readwrite("ignore_in_grid", &_Way::ignoreInGrid)
|
||||
.def_readwrite("tags", &_Way::keyVals)
|
||||
.def_readwrite("direction", &_Way::direction)
|
||||
.enum_("constants")
|
||||
[
|
||||
luabind::value("notSure", 0),
|
||||
luabind::value("oneway", 1),
|
||||
luabind::value("bidirectional", 2),
|
||||
luabind::value("opposite", 3)
|
||||
]
|
||||
];
|
||||
|
||||
// Now call our function in a lua script
|
||||
//#pragma omp critical
|
||||
// {
|
||||
// INFO("Parsing speedprofile from " << fileName );
|
||||
// }
|
||||
if(0 != luaL_dofile(myLuaState, fileName) ) {
|
||||
ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScriptingEnvironment::~ScriptingEnvironment() {
|
||||
for(unsigned i = 0; i < luaStateVector.size(); ++i) {
|
||||
// luaStateVector[i];
|
||||
}
|
||||
}
|
||||
|
||||
lua_State * ScriptingEnvironment::getLuaStateForThreadID(const int id) {
|
||||
return luaStateVector[id];
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef SCRIPTINGENVIRONMENT_H_
|
||||
#define SCRIPTINGENVIRONMENT_H_
|
||||
|
||||
extern "C" {
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
}
|
||||
#include <luabind/luabind.hpp>
|
||||
|
||||
#include "ExtractionHelperFunctions.h"
|
||||
#include "ExtractorStructs.h"
|
||||
#include "LuaUtil.h"
|
||||
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
|
||||
class ScriptingEnvironment {
|
||||
public:
|
||||
ScriptingEnvironment();
|
||||
ScriptingEnvironment(const char * fileName);
|
||||
virtual ~ScriptingEnvironment();
|
||||
|
||||
lua_State * getLuaStateForThreadID(const int);
|
||||
|
||||
std::vector<lua_State *> luaStateVector;
|
||||
};
|
||||
|
||||
#endif /* SCRIPTINGENVIRONMENT_H_ */
|
||||
@@ -1,308 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef XMLPARSER_H_
|
||||
#define XMLPARSER_H_
|
||||
|
||||
#include <boost/ref.hpp>
|
||||
#include <libxml/xmlreader.h>
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "BaseParser.h"
|
||||
#include "ExtractorStructs.h"
|
||||
#include "ExtractorCallbacks.h"
|
||||
#include "ScriptingEnvironment.h"
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../DataStructures/InputReaderFactory.h"
|
||||
|
||||
class XMLParser : public BaseParser<ExtractorCallbacks, _Node, _RawRestrictionContainer, _Way> {
|
||||
public:
|
||||
XMLParser(const char * filename) : externalMemory(NULL), myLuaState(NULL){
|
||||
WARN("Parsing plain .osm/.osm.bz2 is deprecated. Switch to .pbf");
|
||||
inputReader = inputReaderFactory(filename);
|
||||
}
|
||||
virtual ~XMLParser() {}
|
||||
|
||||
void RegisterCallbacks(ExtractorCallbacks * em) {
|
||||
externalMemory = em;
|
||||
}
|
||||
|
||||
void RegisterScriptingEnvironment(ScriptingEnvironment & _se) {
|
||||
myLuaState = _se.getLuaStateForThreadID(0);
|
||||
}
|
||||
|
||||
bool Init() {
|
||||
return (xmlTextReaderRead( inputReader ) == 1);
|
||||
}
|
||||
bool 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( );
|
||||
/** Pass the unpacked node to the LUA call back **/
|
||||
try {
|
||||
luabind::call_function<int>(
|
||||
myLuaState,
|
||||
"node_function",
|
||||
boost::ref(n)
|
||||
);
|
||||
if(!externalMemory->nodeFunction(n))
|
||||
std::cerr << "[XMLParser] dense node not parsed" << std::endl;
|
||||
} catch (const luabind::error &er) {
|
||||
cerr << er.what() << endl;
|
||||
lua_State* Ler=er.state();
|
||||
report_errors(Ler, -1);
|
||||
} catch (std::exception & e) {
|
||||
ERR(e.what());
|
||||
} catch (...) {
|
||||
ERR("Unknown error occurred during XML node parsing!");
|
||||
}
|
||||
}
|
||||
|
||||
if ( xmlStrEqual( currentName, ( const xmlChar* ) "way" ) == 1 ) {
|
||||
string name;
|
||||
_Way way = _ReadXMLWay( );
|
||||
|
||||
/** Pass the unpacked way to the LUA call back **/
|
||||
try {
|
||||
luabind::call_function<int>(
|
||||
myLuaState,
|
||||
"way_function",
|
||||
boost::ref(way),
|
||||
way.path.size()
|
||||
);
|
||||
if(!externalMemory->wayFunction(way)) {
|
||||
std::cerr << "[PBFParser] way not parsed" << std::endl;
|
||||
}
|
||||
} catch (const luabind::error &er) {
|
||||
cerr << er.what() << endl;
|
||||
lua_State* Ler=er.state();
|
||||
report_errors(Ler, -1);
|
||||
} catch (std::exception & e) {
|
||||
ERR(e.what());
|
||||
} catch (...) {
|
||||
ERR("Unknown error occurred during XML way parsing!");
|
||||
}
|
||||
}
|
||||
if ( xmlStrEqual( currentName, ( const xmlChar* ) "relation" ) == 1 ) {
|
||||
_RawRestrictionContainer r = _ReadXMLRestriction();
|
||||
if(r.fromWay != UINT_MAX) {
|
||||
if(!externalMemory->restrictionFunction(r)) {
|
||||
std::cerr << "[XMLParser] restriction not parsed" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlFree( currentName );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
_RawRestrictionContainer _ReadXMLRestriction ( ) {
|
||||
_RawRestrictionContainer restriction;
|
||||
|
||||
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" )){
|
||||
if(0 == std::string((const char *) value).find("only_"))
|
||||
restriction.restriction.flags.isOnly = true;
|
||||
}
|
||||
|
||||
}
|
||||
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 = atoi((const char*) ref);
|
||||
}
|
||||
if(xmlStrEqual(role, (const xmlChar *) "from") && xmlStrEqual(type, (const xmlChar *) "way")) {
|
||||
restriction.fromWay = atoi((const char*) ref);
|
||||
}
|
||||
if(xmlStrEqual(role, (const xmlChar *) "via") && xmlStrEqual(type, (const xmlChar *) "node")) {
|
||||
restriction.restriction.viaNode = atoi((const char*) ref);
|
||||
}
|
||||
|
||||
if(NULL != type)
|
||||
xmlFree( type );
|
||||
if(NULL != role)
|
||||
xmlFree( role );
|
||||
if(NULL != ref)
|
||||
xmlFree( ref );
|
||||
}
|
||||
}
|
||||
xmlFree( childName );
|
||||
}
|
||||
}
|
||||
return restriction;
|
||||
}
|
||||
|
||||
_Way _ReadXMLWay( ) {
|
||||
_Way 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 = atoi((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" );
|
||||
// cout << "->k=" << k << ", v=" << value << endl;
|
||||
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( atoi(( const char* ) ref ) );
|
||||
xmlFree( ref );
|
||||
}
|
||||
}
|
||||
xmlFree( childName );
|
||||
}
|
||||
}
|
||||
return way;
|
||||
}
|
||||
|
||||
ImportNode _ReadXMLNode( ) {
|
||||
ImportNode node;
|
||||
|
||||
xmlChar* attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "lat" );
|
||||
if ( attribute != NULL ) {
|
||||
node.lat = static_cast<NodeID>(100000.*atof(( const char* ) attribute ) );
|
||||
xmlFree( attribute );
|
||||
}
|
||||
attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "lon" );
|
||||
if ( attribute != NULL ) {
|
||||
node.lon = static_cast<NodeID>(100000.*atof(( const char* ) attribute ));
|
||||
xmlFree( attribute );
|
||||
}
|
||||
attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "id" );
|
||||
if ( attribute != NULL ) {
|
||||
node.id = atoi(( 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.Add(std::string( reinterpret_cast<char*>(k) ), std::string( reinterpret_cast<char*>(value)));
|
||||
}
|
||||
if ( k != NULL )
|
||||
xmlFree( k );
|
||||
if ( value != NULL )
|
||||
xmlFree( value );
|
||||
}
|
||||
|
||||
xmlFree( childName );
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
/* Input Reader */
|
||||
xmlTextReaderPtr inputReader;
|
||||
|
||||
//holds the callback functions and storage for our temporary data
|
||||
ExtractorCallbacks * externalMemory;
|
||||
|
||||
lua_State *myLuaState;
|
||||
};
|
||||
|
||||
#endif /* XMLPARSER_H_ */
|
||||
+15
-15
@@ -1,23 +1,23 @@
|
||||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
builder (3.0.0)
|
||||
cucumber (1.1.4)
|
||||
builder (3.2.2)
|
||||
cucumber (1.3.8)
|
||||
builder (>= 2.1.2)
|
||||
diff-lcs (>= 1.1.2)
|
||||
gherkin (~> 2.7.1)
|
||||
json (>= 1.4.6)
|
||||
term-ansicolor (>= 1.0.6)
|
||||
diff-lcs (1.1.3)
|
||||
gherkin (2.7.6)
|
||||
json (>= 1.4.6)
|
||||
json (1.6.5)
|
||||
diff-lcs (>= 1.1.3)
|
||||
gherkin (~> 2.12.1)
|
||||
multi_json (>= 1.7.5, < 2.0)
|
||||
multi_test (>= 0.0.2)
|
||||
diff-lcs (1.2.4)
|
||||
gherkin (2.12.1)
|
||||
multi_json (~> 1.3)
|
||||
multi_json (1.8.0)
|
||||
multi_test (0.0.2)
|
||||
osmlib-base (0.1.4)
|
||||
rake (0.9.2.2)
|
||||
rspec-expectations (2.11.3)
|
||||
diff-lcs (~> 1.1.3)
|
||||
sys-proctable (0.9.1)
|
||||
term-ansicolor (1.0.7)
|
||||
rake (10.1.0)
|
||||
rspec-expectations (2.14.3)
|
||||
diff-lcs (>= 1.1.3, < 2.0)
|
||||
sys-proctable (0.9.3)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef FIXED_POINT_COORDINATE_H_
|
||||
#define FIXED_POINT_COORDINATE_H_
|
||||
|
||||
#include <iosfwd> //for std::ostream
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr float COORDINATE_PRECISION = 1000000.f;
|
||||
}
|
||||
struct FixedPointCoordinate
|
||||
{
|
||||
int lat;
|
||||
int lon;
|
||||
|
||||
FixedPointCoordinate();
|
||||
FixedPointCoordinate(int lat, int lon);
|
||||
|
||||
template<class T>
|
||||
FixedPointCoordinate(const T &coordinate) : lat(coordinate.lat), lon(coordinate.lon)
|
||||
{
|
||||
static_assert(std::is_same<decltype(lat), decltype(coordinate.lat)>::value, "coordinate types incompatible");
|
||||
static_assert(std::is_same<decltype(lon), decltype(coordinate.lon)>::value, "coordinate types incompatible");
|
||||
}
|
||||
|
||||
void Reset();
|
||||
bool isSet() const;
|
||||
bool is_valid() const;
|
||||
bool operator==(const FixedPointCoordinate &other) const;
|
||||
|
||||
static double
|
||||
ApproximateDistance(const int lat1, const int lon1, const int lat2, const int lon2);
|
||||
|
||||
static double ApproximateDistance(const FixedPointCoordinate &first_coordinate,
|
||||
const FixedPointCoordinate &second_coordinate);
|
||||
|
||||
static float ApproximateEuclideanDistance(const FixedPointCoordinate &first_coordinate,
|
||||
const FixedPointCoordinate &second_coordinate);
|
||||
|
||||
static float
|
||||
ApproximateEuclideanDistance(const int lat1, const int lon1, const int lat2, const int lon2);
|
||||
|
||||
static float ApproximateSquaredEuclideanDistance(const FixedPointCoordinate &first_coordinate,
|
||||
const FixedPointCoordinate &second_coordinate);
|
||||
|
||||
static void convertInternalLatLonToString(const int value, std::string &output);
|
||||
|
||||
static void convertInternalCoordinateToString(const FixedPointCoordinate &coordinate,
|
||||
std::string &output);
|
||||
|
||||
static void convertInternalReversedCoordinateToString(const FixedPointCoordinate &coordinate,
|
||||
std::string &output);
|
||||
|
||||
static float ComputePerpendicularDistance(const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location);
|
||||
|
||||
static float ComputePerpendicularDistance(const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location,
|
||||
FixedPointCoordinate &nearest_location,
|
||||
float &ratio);
|
||||
|
||||
static int
|
||||
OrderedPerpendicularDistanceApproximation(const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location);
|
||||
|
||||
static float GetBearing(const FixedPointCoordinate &A, const FixedPointCoordinate &B);
|
||||
|
||||
float GetBearing(const FixedPointCoordinate &other) const;
|
||||
|
||||
void Output(std::ostream &out) const;
|
||||
|
||||
static float DegreeToRadian(const float degree);
|
||||
static float RadianToDegree(const float radian);
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &out_stream, FixedPointCoordinate const &coordinate)
|
||||
{
|
||||
coordinate.Output(out_stream);
|
||||
return out_stream;
|
||||
}
|
||||
|
||||
#endif /* FIXED_POINT_COORDINATE_H_ */
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HTTP_HEADER_H
|
||||
#define HTTP_HEADER_H
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
namespace http
|
||||
{
|
||||
struct Header
|
||||
{
|
||||
Header& operator=(const Header& other) = default;
|
||||
Header(const std::string & name, const std::string & value) : name(name), value(value) {}
|
||||
Header(Header && other) : name(std::move(other.name)), value(std::move(other.value)) {}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
name.clear();
|
||||
value.clear();
|
||||
}
|
||||
|
||||
std::string name;
|
||||
std::string value;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // HTTP_HEADER_H
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef REPLY_H
|
||||
#define REPLY_H
|
||||
|
||||
#include "Header.h"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace http
|
||||
{
|
||||
|
||||
const char okHTML[] = "";
|
||||
const char badRequestHTML[] = "{\"status\": 400,\"status_message\":\"Bad Request\"}";
|
||||
const char internalServerErrorHTML[] =
|
||||
"{\"status\": 500,\"status_message\":\"Internal Server Error\"}";
|
||||
const char seperators[] = {':', ' '};
|
||||
const char crlf[] = {'\r', '\n'};
|
||||
const std::string okString = "HTTP/1.0 200 OK\r\n";
|
||||
const std::string badRequestString = "HTTP/1.0 400 Bad Request\r\n";
|
||||
const std::string internalServerErrorString = "HTTP/1.0 500 Internal Server Error\r\n";
|
||||
|
||||
class Reply
|
||||
{
|
||||
public:
|
||||
enum status_type
|
||||
{ ok = 200,
|
||||
badRequest = 400,
|
||||
internalServerError = 500 } status;
|
||||
|
||||
std::vector<Header> headers;
|
||||
std::vector<boost::asio::const_buffer> ToBuffers();
|
||||
std::vector<boost::asio::const_buffer> HeaderstoBuffers();
|
||||
std::vector<char> content;
|
||||
static Reply StockReply(status_type status);
|
||||
void SetSize(const unsigned size);
|
||||
void SetUncompressedSize();
|
||||
|
||||
Reply();
|
||||
|
||||
private:
|
||||
std::string ToString(Reply::status_type status);
|
||||
boost::asio::const_buffer ToBuffer(Reply::status_type status);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // REPLY_H
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ROUTE_PARAMETERS_H
|
||||
#define ROUTE_PARAMETERS_H
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/fusion/container/vector/vector_fwd.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct RouteParameters
|
||||
{
|
||||
RouteParameters();
|
||||
|
||||
void setZoomLevel(const short level);
|
||||
|
||||
void setNumberOfResults(const short number);
|
||||
|
||||
void setAlternateRouteFlag(const bool flag);
|
||||
|
||||
void setUTurn(const bool flag);
|
||||
|
||||
void setAllUTurns(const bool flag);
|
||||
|
||||
void setDeprecatedAPIFlag(const std::string &);
|
||||
|
||||
void setChecksum(const unsigned check_sum);
|
||||
|
||||
void setInstructionFlag(const bool flag);
|
||||
|
||||
void setService(const std::string &service);
|
||||
|
||||
void setOutputFormat(const std::string &format);
|
||||
|
||||
void setJSONpParameter(const std::string ¶meter);
|
||||
|
||||
void addHint(const std::string &hint);
|
||||
|
||||
void setLanguage(const std::string &language);
|
||||
|
||||
void setGeometryFlag(const bool flag);
|
||||
|
||||
void setCompressionFlag(const bool flag);
|
||||
|
||||
void addCoordinate(const boost::fusion::vector<double, double> &coordinates);
|
||||
|
||||
short zoom_level;
|
||||
bool print_instructions;
|
||||
bool alternate_route;
|
||||
bool geometry;
|
||||
bool compression;
|
||||
bool deprecatedAPI;
|
||||
bool uturn_default;
|
||||
unsigned check_sum;
|
||||
short num_results;
|
||||
std::string service;
|
||||
std::string output_format;
|
||||
std::string jsonp_parameter;
|
||||
std::string language;
|
||||
std::vector<std::string> hints;
|
||||
std::vector<bool> uturns;
|
||||
std::vector<FixedPointCoordinate> coordinates;
|
||||
};
|
||||
|
||||
#endif // ROUTE_PARAMETERS_H
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SERVER_PATH_H
|
||||
#define SERVER_PATH_H
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
typedef std::unordered_map<std::string, boost::filesystem::path> ServerPaths;
|
||||
|
||||
#endif // SERVER_PATH_H
|
||||
+22
-661
@@ -1,661 +1,22 @@
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
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.
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OSRM_H
|
||||
#define OSRM_H
|
||||
|
||||
#include <osrm/ServerPaths.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class OSRM_impl;
|
||||
struct RouteParameters;
|
||||
|
||||
namespace http
|
||||
{
|
||||
class Reply;
|
||||
}
|
||||
|
||||
class OSRM
|
||||
{
|
||||
private:
|
||||
std::unique_ptr<OSRM_impl> OSRM_pimpl_;
|
||||
|
||||
public:
|
||||
explicit OSRM(ServerPaths paths, const bool use_shared_memory = false);
|
||||
~OSRM();
|
||||
void RunQuery(RouteParameters &route_parameters, http::Reply &reply);
|
||||
};
|
||||
|
||||
#endif // OSRM_H
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
namespace boost { namespace interprocess { class named_mutex; } }
|
||||
|
||||
#include "OSRM_impl.h"
|
||||
#include "OSRM.h"
|
||||
|
||||
#include <osrm/Reply.h>
|
||||
#include <osrm/RouteParameters.h>
|
||||
#include <osrm/ServerPaths.h>
|
||||
|
||||
#include "../plugins/distance_table.hpp"
|
||||
#include "../plugins/hello_world.hpp"
|
||||
#include "../plugins/locate.hpp"
|
||||
#include "../plugins/nearest.hpp"
|
||||
#include "../plugins/timestamp.hpp"
|
||||
#include "../plugins/viaroute.hpp"
|
||||
#include "../Server/DataStructures/BaseDataFacade.h"
|
||||
#include "../Server/DataStructures/InternalDataFacade.h"
|
||||
#include "../Server/DataStructures/SharedBarriers.h"
|
||||
#include "../Server/DataStructures/SharedDataFacade.h"
|
||||
#include "../Util/make_unique.hpp"
|
||||
#include "../Util/ProgramOptions.h"
|
||||
#include "../Util/simple_logger.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/interprocess/sync/named_condition.hpp>
|
||||
#include <boost/interprocess/sync/scoped_lock.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
OSRM_impl::OSRM_impl(ServerPaths server_paths, const bool use_shared_memory)
|
||||
{
|
||||
if (use_shared_memory)
|
||||
{
|
||||
barrier = osrm::make_unique<SharedBarriers>();
|
||||
query_data_facade = new SharedDataFacade<QueryEdge::EdgeData>();
|
||||
}
|
||||
else
|
||||
{
|
||||
// populate base path
|
||||
populate_base_path(server_paths);
|
||||
query_data_facade = new InternalDataFacade<QueryEdge::EdgeData>(server_paths);
|
||||
}
|
||||
|
||||
// The following plugins handle all requests.
|
||||
RegisterPlugin(new DistanceTablePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
|
||||
RegisterPlugin(new HelloWorldPlugin());
|
||||
RegisterPlugin(new LocatePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
|
||||
RegisterPlugin(new NearestPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
|
||||
RegisterPlugin(new TimestampPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
|
||||
RegisterPlugin(new ViaRoutePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
|
||||
}
|
||||
|
||||
OSRM_impl::~OSRM_impl()
|
||||
{
|
||||
delete query_data_facade;
|
||||
for (PluginMap::value_type &plugin_pointer : plugin_map)
|
||||
{
|
||||
delete plugin_pointer.second;
|
||||
}
|
||||
}
|
||||
|
||||
void OSRM_impl::RegisterPlugin(BasePlugin *plugin)
|
||||
{
|
||||
SimpleLogger().Write() << "loaded plugin: " << plugin->GetDescriptor();
|
||||
if (plugin_map.find(plugin->GetDescriptor()) != plugin_map.end())
|
||||
{
|
||||
delete plugin_map.find(plugin->GetDescriptor())->second;
|
||||
}
|
||||
plugin_map.emplace(plugin->GetDescriptor(), plugin);
|
||||
}
|
||||
|
||||
void OSRM_impl::RunQuery(RouteParameters &route_parameters, http::Reply &reply)
|
||||
{
|
||||
const PluginMap::const_iterator &iter = plugin_map.find(route_parameters.service);
|
||||
|
||||
if (plugin_map.end() != iter)
|
||||
{
|
||||
reply.status = http::Reply::ok;
|
||||
if (barrier)
|
||||
{
|
||||
// lock update pending
|
||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> pending_lock(
|
||||
barrier->pending_update_mutex);
|
||||
|
||||
// lock query
|
||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
|
||||
barrier->query_mutex);
|
||||
|
||||
// unlock update pending
|
||||
pending_lock.unlock();
|
||||
|
||||
// increment query count
|
||||
++(barrier->number_of_queries);
|
||||
|
||||
(static_cast<SharedDataFacade<QueryEdge::EdgeData> *>(query_data_facade))
|
||||
->CheckAndReloadFacade();
|
||||
}
|
||||
|
||||
iter->second->HandleRequest(route_parameters, reply);
|
||||
if (barrier)
|
||||
{
|
||||
// lock query
|
||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
|
||||
barrier->query_mutex);
|
||||
|
||||
// decrement query count
|
||||
--(barrier->number_of_queries);
|
||||
BOOST_ASSERT_MSG(0 <= barrier->number_of_queries, "invalid number of queries");
|
||||
|
||||
// notify all processes that were waiting for this condition
|
||||
if (0 == barrier->number_of_queries)
|
||||
{
|
||||
barrier->no_running_queries_condition.notify_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
}
|
||||
}
|
||||
|
||||
// proxy code for compilation firewall
|
||||
|
||||
OSRM::OSRM(ServerPaths paths, const bool use_shared_memory)
|
||||
: OSRM_pimpl_(osrm::make_unique<OSRM_impl>(paths, use_shared_memory))
|
||||
{
|
||||
}
|
||||
|
||||
OSRM::~OSRM() { OSRM_pimpl_.reset(); }
|
||||
|
||||
void OSRM::RunQuery(RouteParameters &route_parameters, http::Reply &reply)
|
||||
{
|
||||
OSRM_pimpl_->RunQuery(route_parameters, reply);
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OSRM_IMPL_H
|
||||
#define OSRM_IMPL_H
|
||||
|
||||
class BasePlugin;
|
||||
namespace http { class Reply; }
|
||||
struct RouteParameters;
|
||||
|
||||
#include <osrm/ServerPaths.h>
|
||||
|
||||
#include "../data_structures/query_edge.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
struct SharedBarriers;
|
||||
template <class EdgeDataT> class BaseDataFacade;
|
||||
|
||||
class OSRM_impl
|
||||
{
|
||||
private:
|
||||
using PluginMap = std::unordered_map<std::string, BasePlugin *>;
|
||||
|
||||
public:
|
||||
OSRM_impl(ServerPaths paths, const bool use_shared_memory);
|
||||
OSRM_impl(const OSRM_impl &) = delete;
|
||||
virtual ~OSRM_impl();
|
||||
void RunQuery(RouteParameters &route_parameters, http::Reply &reply);
|
||||
|
||||
private:
|
||||
void RegisterPlugin(BasePlugin *plugin);
|
||||
PluginMap plugin_map;
|
||||
// will only be initialized if shared memory is used
|
||||
std::unique_ptr<SharedBarriers> barrier;
|
||||
// base class pointer to the objects
|
||||
BaseDataFacade<QueryEdge::EdgeData> *query_data_facade;
|
||||
};
|
||||
|
||||
#endif // OSRM_IMPL_H
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef BASEPLUGIN_H_
|
||||
#define BASEPLUGIN_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "RouteParameters.h"
|
||||
#include "../Server/BasicDatastructures.h"
|
||||
|
||||
class BasePlugin {
|
||||
public:
|
||||
BasePlugin() { }
|
||||
//Maybe someone can explain the pure virtual destructor thing to me (dennis)
|
||||
virtual ~BasePlugin() { }
|
||||
virtual std::string GetDescriptor() const = 0;
|
||||
virtual std::string GetVersionString() const = 0 ;
|
||||
virtual void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) = 0;
|
||||
};
|
||||
|
||||
#endif /* BASEPLUGIN_H_ */
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* LocatePlugin.h
|
||||
*
|
||||
* Created on: 01.01.2011
|
||||
* Author: dennis
|
||||
*/
|
||||
|
||||
#ifndef HELLOWORLDPLUGIN_H_
|
||||
#define HELLOWORLDPLUGIN_H_
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "RouteParameters.h"
|
||||
|
||||
class HelloWorldPlugin : public BasePlugin {
|
||||
public:
|
||||
HelloWorldPlugin() {}
|
||||
virtual ~HelloWorldPlugin() { /*std::cout << GetDescriptor() << " destructor" << std::endl;*/ }
|
||||
std::string GetDescriptor() const { return std::string("hello"); }
|
||||
std::string GetVersionString() const { return std::string("0.1a"); }
|
||||
|
||||
void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) {
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.append("<html><head><title>Hello World Demonstration Document</title></head><body><h1>Hello, World!</h1>");
|
||||
std::stringstream content;
|
||||
content << "<pre>";
|
||||
content << "zoom level: " << routeParameters.zoomLevel << "\n";
|
||||
content << "checksum: " << routeParameters.checkSum << "\n";
|
||||
content << "instructions: " << (routeParameters.printInstructions ? "yes" : "no") << "\n";
|
||||
content << "geometry: " << (routeParameters.geometry ? "yes" : "no") << "\n";
|
||||
content << "compression: " << (routeParameters.compression ? "yes" : "no") << "\n";
|
||||
content << "output format: " << routeParameters.outputFormat << "\n";
|
||||
content << "json parameter: " << routeParameters.jsonpParameter << "\n";
|
||||
content << "language: " << routeParameters.language << "<br>";
|
||||
content << "Number of locations: " << routeParameters.coordinates.size() << "\n";
|
||||
for(unsigned i = 0; i < routeParameters.coordinates.size(); ++i) {
|
||||
content << " [" << i << "] " << routeParameters.coordinates[i].lat/100000. << "," << routeParameters.coordinates[i].lon/100000. << "\n";
|
||||
}
|
||||
content << "Number of hints: " << routeParameters.hints.size() << "\n";
|
||||
for(unsigned i = 0; i < routeParameters.hints.size(); ++i) {
|
||||
content << " [" << i << "] " << routeParameters.hints[i] << "\n";
|
||||
}
|
||||
content << "</pre>";
|
||||
reply.content.append(content.str());
|
||||
reply.content.append("</body></html>");
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* HELLOWORLDPLUGIN_H_ */
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef LOCATEPLUGIN_H_
|
||||
#define LOCATEPLUGIN_H_
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "../Server/DataStructures/QueryObjectsStorage.h"
|
||||
#include "BasePlugin.h"
|
||||
#include "RouteParameters.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../DataStructures/NodeInformationHelpDesk.h"
|
||||
|
||||
/*
|
||||
* This Plugin locates the nearest node in the road network for a given coordinate.
|
||||
*/
|
||||
class LocatePlugin : public BasePlugin {
|
||||
public:
|
||||
LocatePlugin(QueryObjectsStorage * objects) {
|
||||
nodeHelpDesk = objects->nodeHelpDesk;
|
||||
}
|
||||
std::string GetDescriptor() const { return std::string("locate"); }
|
||||
std::string GetVersionString() const { return std::string("0.3 (DL)"); }
|
||||
void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) {
|
||||
//check number of parameters
|
||||
if(!routeParameters.coordinates.size()) {
|
||||
reply = http::Reply::stockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
if(false == checkCoord(routeParameters.coordinates[0])) {
|
||||
reply = http::Reply::stockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
//query to helpdesk
|
||||
_Coordinate result;
|
||||
std::string JSONParameter, tmp;
|
||||
//json
|
||||
|
||||
// JSONParameter = routeParameters.options.Find("jsonp");
|
||||
if("" != routeParameters.jsonpParameter) {
|
||||
reply.content += JSONParameter;
|
||||
reply.content += "(";
|
||||
}
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content += ("{");
|
||||
reply.content += ("\"version\":0.3,");
|
||||
if(!nodeHelpDesk->FindNearestNodeCoordForLatLon(routeParameters.coordinates[0], result)) {
|
||||
reply.content += ("\"status\":207,");
|
||||
reply.content += ("\"mapped_coordinate\":[]");
|
||||
} else {
|
||||
//Write coordinate to stream
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content += ("\"status\":0,");
|
||||
reply.content += ("\"mapped_coordinate\":");
|
||||
convertInternalLatLonToString(result.lat, tmp);
|
||||
reply.content += "[";
|
||||
reply.content += tmp;
|
||||
convertInternalLatLonToString(result.lon, tmp);
|
||||
reply.content += ",";
|
||||
reply.content += tmp;
|
||||
reply.content += "]";
|
||||
}
|
||||
reply.content += ",\"transactionId\": \"OSRM Routing Engine JSON Locate (v0.3)\"";
|
||||
reply.content += ("}");
|
||||
reply.headers.resize(3);
|
||||
if("" != JSONParameter) {
|
||||
reply.content += ")";
|
||||
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";
|
||||
intToString(reply.content.size(), tmp);
|
||||
reply.headers[0].value = tmp;
|
||||
return;
|
||||
}
|
||||
private:
|
||||
inline bool checkCoord(const _Coordinate & c) {
|
||||
if(c.lat > 90*100000 || c.lat < -90*100000 || c.lon > 180*100000 || c.lon <-180*100000) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
NodeInformationHelpDesk * nodeHelpDesk;
|
||||
};
|
||||
|
||||
#endif /* LOCATEPLUGIN_H_ */
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef NearestPlugin_H_
|
||||
#define NearestPlugin_H_
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "RouteParameters.h"
|
||||
|
||||
#include "../Server/DataStructures/QueryObjectsStorage.h"
|
||||
|
||||
#include "../DataStructures/NodeInformationHelpDesk.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
/*
|
||||
* This Plugin locates the nearest point on a street in the road network for a given coordinate.
|
||||
*/
|
||||
class NearestPlugin : public BasePlugin {
|
||||
public:
|
||||
NearestPlugin(QueryObjectsStorage * objects) : names(objects->names) {
|
||||
nodeHelpDesk = objects->nodeHelpDesk;
|
||||
|
||||
descriptorTable.Set("", 0); //default descriptor
|
||||
descriptorTable.Set("json", 1);
|
||||
}
|
||||
std::string GetDescriptor() const { return std::string("nearest"); }
|
||||
std::string GetVersionString() const { return std::string("0.3 (DL)"); }
|
||||
void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) {
|
||||
//check number of parameters
|
||||
if(!routeParameters.coordinates.size()) {
|
||||
reply = http::Reply::stockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
if(false == checkCoord(routeParameters.coordinates[0])) {
|
||||
reply = http::Reply::stockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
//query to helpdesk
|
||||
PhantomNode result;
|
||||
nodeHelpDesk->FindPhantomNodeForCoordinate(routeParameters.coordinates[0], result, routeParameters.zoomLevel);
|
||||
|
||||
std::string tmp;
|
||||
std::string JSONParameter;
|
||||
//json
|
||||
|
||||
if("" != routeParameters.jsonpParameter) {
|
||||
reply.content += routeParameters.jsonpParameter;
|
||||
reply.content += "(";
|
||||
}
|
||||
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content += ("{");
|
||||
reply.content += ("\"version\":0.3,");
|
||||
reply.content += ("\"status\":");
|
||||
if(UINT_MAX != result.edgeBasedNode)
|
||||
reply.content += "0,";
|
||||
else
|
||||
reply.content += "207,";
|
||||
reply.content += ("\"mapped_coordinate\":");
|
||||
reply.content += "[";
|
||||
if(UINT_MAX != result.edgeBasedNode) {
|
||||
convertInternalLatLonToString(result.location.lat, tmp);
|
||||
reply.content += tmp;
|
||||
convertInternalLatLonToString(result.location.lon, tmp);
|
||||
reply.content += ",";
|
||||
reply.content += tmp;
|
||||
}
|
||||
reply.content += "],";
|
||||
reply.content += "\"name\":\"";
|
||||
if(UINT_MAX != result.edgeBasedNode)
|
||||
reply.content += names[result.nodeBasedEdgeNameID];
|
||||
reply.content += "\"";
|
||||
reply.content += ",\"transactionId\":\"OSRM Routing Engine JSON Nearest (v0.3)\"";
|
||||
reply.content += ("}");
|
||||
reply.headers.resize(3);
|
||||
if("" != JSONParameter) {
|
||||
reply.content += ")";
|
||||
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";
|
||||
intToString(reply.content.size(), tmp);
|
||||
reply.headers[0].value = tmp;
|
||||
}
|
||||
private:
|
||||
inline bool checkCoord(const _Coordinate & c) {
|
||||
if(c.lat > 90*100000 || c.lat < -90*100000 || c.lon > 180*100000 || c.lon <-180*100000) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
NodeInformationHelpDesk * nodeHelpDesk;
|
||||
HashTable<std::string, unsigned> descriptorTable;
|
||||
std::vector<std::string> & names;
|
||||
};
|
||||
|
||||
#endif /* NearestPlugin_H_ */
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef PLUGINMAPFACTORY_H_
|
||||
#define PLUGINMAPFACTORY_H_
|
||||
|
||||
//#include "../DataStructures/HashTable.h"
|
||||
//#include "../Plugins/BasePlugin.h"
|
||||
//
|
||||
//struct PluginMapFactory {
|
||||
// static HashTable<std::string, BasePlugin *> * CreatePluginMap() {
|
||||
// HashTable<std::string, BasePlugin *> * map = new HashTable<std::string, BasePlugin *>();
|
||||
//
|
||||
// }
|
||||
//};
|
||||
|
||||
#endif /* PLUGINMAPFACTORY_H_ */
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef RAWROUTEDATA_H_
|
||||
#define RAWROUTEDATA_H_
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
struct _PathData {
|
||||
_PathData(NodeID no, unsigned na, unsigned tu, unsigned dur) : node(no), nameID(na), durationOfSegment(dur), turnInstruction(tu) { }
|
||||
NodeID node;
|
||||
unsigned nameID;
|
||||
unsigned durationOfSegment;
|
||||
short turnInstruction;
|
||||
};
|
||||
|
||||
struct RawRouteData {
|
||||
std::vector< _PathData > computedShortestPath;
|
||||
std::vector< _PathData > computedAlternativePath;
|
||||
std::vector< PhantomNodes > segmentEndCoordinates;
|
||||
std::vector< _Coordinate > rawViaNodeCoordinates;
|
||||
unsigned checkSum;
|
||||
int lengthOfShortestPath;
|
||||
int lengthOfAlternativePath;
|
||||
RawRouteData() : checkSum(UINT_MAX), lengthOfShortestPath(INT_MAX), lengthOfAlternativePath(INT_MAX) {}
|
||||
};
|
||||
|
||||
#endif /* RAWROUTEDATA_H_ */
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef ROUTE_PARAMETERS_H
|
||||
#define ROUTE_PARAMETERS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/fusion/sequence/intrinsic.hpp>
|
||||
|
||||
#include "../DataStructures/Coordinate.h"
|
||||
|
||||
struct RouteParameters {
|
||||
RouteParameters() : zoomLevel(18), printInstructions(false), alternateRoute(true), geometry(true), compression(true), deprecatedAPI(false), checkSum(-1) {}
|
||||
short zoomLevel;
|
||||
bool printInstructions;
|
||||
bool alternateRoute;
|
||||
bool geometry;
|
||||
bool compression;
|
||||
bool deprecatedAPI;
|
||||
unsigned checkSum;
|
||||
std::string service;
|
||||
std::string outputFormat;
|
||||
std::string jsonpParameter;
|
||||
std::string language;
|
||||
std::vector<std::string> hints;
|
||||
std::vector<_Coordinate> coordinates;
|
||||
typedef HashTable<std::string, std::string>::MyIterator OptionsIterator;
|
||||
|
||||
void setZoomLevel(const short i) {
|
||||
if (18 > i && 0 < i)
|
||||
zoomLevel = i;
|
||||
}
|
||||
|
||||
void setAlternateRouteFlag(const bool b) {
|
||||
alternateRoute = b;
|
||||
}
|
||||
|
||||
void setDeprecatedAPIFlag(const std::string &) {
|
||||
deprecatedAPI = true;
|
||||
}
|
||||
|
||||
void setChecksum(const unsigned c) {
|
||||
checkSum = c;
|
||||
}
|
||||
|
||||
void setInstructionFlag(const bool b) {
|
||||
printInstructions = b;
|
||||
}
|
||||
|
||||
void setService( const std::string & s) {
|
||||
service = s;
|
||||
}
|
||||
|
||||
void setOutputFormat(const std::string & s) {
|
||||
outputFormat = s;
|
||||
}
|
||||
|
||||
void setJSONpParameter(const std::string & s) {
|
||||
jsonpParameter = s;
|
||||
}
|
||||
|
||||
void addHint(const std::string & s) {
|
||||
hints.resize(coordinates.size());
|
||||
hints.back() = s;
|
||||
}
|
||||
|
||||
void setLanguage(const std::string & s) {
|
||||
language = s;
|
||||
}
|
||||
|
||||
void setGeometryFlag(const bool b) {
|
||||
geometry = b;
|
||||
}
|
||||
|
||||
void setCompressionFlag(const bool b) {
|
||||
compression = b;
|
||||
}
|
||||
|
||||
void addCoordinate(boost::fusion::vector < double, double > arg_) {
|
||||
int lat = 100000.*boost::fusion::at_c < 0 > (arg_);
|
||||
int lon = 100000.*boost::fusion::at_c < 1 > (arg_);
|
||||
_Coordinate myCoordinate(lat, lon);
|
||||
coordinates.push_back(_Coordinate(lat, lon));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif /*ROUTE_PARAMETERS_H*/
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef TIMESTAMPPLUGIN_H_
|
||||
#define TIMESTAMPPLUGIN_H_
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "RouteParameters.h"
|
||||
|
||||
class TimestampPlugin : public BasePlugin {
|
||||
public:
|
||||
TimestampPlugin(QueryObjectsStorage * o) : objects(o) {
|
||||
}
|
||||
std::string GetDescriptor() const { return std::string("timestamp"); }
|
||||
std::string GetVersionString() const { return std::string("0.3 (DL)"); }
|
||||
void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) {
|
||||
std::string tmp;
|
||||
|
||||
//json
|
||||
if("" != routeParameters.jsonpParameter) {
|
||||
reply.content += routeParameters.jsonpParameter;
|
||||
reply.content += "(";
|
||||
}
|
||||
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content += ("{");
|
||||
reply.content += ("\"version\":0.3,");
|
||||
reply.content += ("\"status\":");
|
||||
reply.content += "0,";
|
||||
reply.content += ("\"timestamp\":\"");
|
||||
reply.content += objects->timestamp;
|
||||
reply.content += "\"";
|
||||
reply.content += ",\"transactionId\":\"OSRM Routing Engine JSON timestamp (v0.3)\"";
|
||||
reply.content += ("}");
|
||||
reply.headers.resize(3);
|
||||
if("" != routeParameters.jsonpParameter) {
|
||||
reply.content += ")";
|
||||
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\"";
|
||||
}
|
||||
reply.headers[0].name = "Content-Length";
|
||||
intToString(reply.content.size(), tmp);
|
||||
reply.headers[0].value = tmp;
|
||||
}
|
||||
private:
|
||||
QueryObjectsStorage * objects;
|
||||
};
|
||||
|
||||
#endif /* TIMESTAMPPLUGIN_H_ */
|
||||
@@ -1,224 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef VIAROUTEPLUGIN_H_
|
||||
#define VIAROUTEPLUGIN_H_
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "RouteParameters.h"
|
||||
|
||||
#include "../Algorithms/ObjectToBase64.h"
|
||||
|
||||
#include "../Descriptors/BaseDescriptor.h"
|
||||
#include "../Descriptors/GPXDescriptor.h"
|
||||
#include "../Descriptors/JSONDescriptor.h"
|
||||
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "../DataStructures/StaticGraph.h"
|
||||
#include "../DataStructures/SearchEngine.h"
|
||||
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include "../Server/DataStructures/QueryObjectsStorage.h"
|
||||
|
||||
class ViaRoutePlugin : public BasePlugin {
|
||||
private:
|
||||
NodeInformationHelpDesk * nodeHelpDesk;
|
||||
std::vector<std::string> & names;
|
||||
StaticGraph<QueryEdge::EdgeData> * graph;
|
||||
HashTable<std::string, unsigned> descriptorTable;
|
||||
std::string pluginDescriptorString;
|
||||
SearchEngine<QueryEdge::EdgeData, StaticGraph<QueryEdge::EdgeData> > * searchEngine;
|
||||
public:
|
||||
|
||||
ViaRoutePlugin(QueryObjectsStorage * objects, std::string psd = "viaroute") : names(objects->names), pluginDescriptorString(psd) {
|
||||
nodeHelpDesk = objects->nodeHelpDesk;
|
||||
graph = objects->graph;
|
||||
|
||||
searchEngine = new SearchEngine<QueryEdge::EdgeData, StaticGraph<QueryEdge::EdgeData> >(graph, nodeHelpDesk, names);
|
||||
|
||||
descriptorTable.Set("", 0); //default descriptor
|
||||
descriptorTable.Set("json", 0);
|
||||
descriptorTable.Set("gpx", 1);
|
||||
}
|
||||
|
||||
virtual ~ViaRoutePlugin() {
|
||||
delete searchEngine;
|
||||
}
|
||||
|
||||
std::string GetDescriptor() const { return pluginDescriptorString; }
|
||||
std::string GetVersionString() const { return std::string("0.3 (DL)"); }
|
||||
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 rawRoute;
|
||||
rawRoute.checkSum = nodeHelpDesk->GetCheckSum();
|
||||
bool checksumOK = (routeParameters.checkSum == rawRoute.checkSum);
|
||||
std::vector<std::string> textCoord;
|
||||
for(unsigned i = 0; i < routeParameters.coordinates.size(); ++i) {
|
||||
if(false == checkCoord(routeParameters.coordinates[i])) {
|
||||
reply = http::Reply::stockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
rawRoute.rawViaNodeCoordinates.push_back(routeParameters.coordinates[i]);
|
||||
}
|
||||
std::vector<PhantomNode> phantomNodeVector(rawRoute.rawViaNodeCoordinates.size());
|
||||
for(unsigned i = 0; i < rawRoute.rawViaNodeCoordinates.size(); ++i) {
|
||||
if(checksumOK && i < routeParameters.hints.size() && "" != routeParameters.hints[i]) {
|
||||
// INFO("Decoding hint: " << routeParameters.hints[i] << " for location index " << i);
|
||||
DecodeObjectFromBase64(phantomNodeVector[i], routeParameters.hints[i]);
|
||||
if(phantomNodeVector[i].isValid(nodeHelpDesk->getNumberOfNodes())) {
|
||||
// INFO("Decoded hint " << i << " successfully");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// INFO("Brute force lookup of coordinate " << i);
|
||||
searchEngine->FindPhantomNodeForCoordinate( rawRoute.rawViaNodeCoordinates[i], phantomNodeVector[i], routeParameters.zoomLevel);
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < phantomNodeVector.size()-1; ++i) {
|
||||
PhantomNodes segmentPhantomNodes;
|
||||
segmentPhantomNodes.startPhantom = phantomNodeVector[i];
|
||||
segmentPhantomNodes.targetPhantom = phantomNodeVector[i+1];
|
||||
rawRoute.segmentEndCoordinates.push_back(segmentPhantomNodes);
|
||||
}
|
||||
if( ( routeParameters.alternateRoute ) && (1 == rawRoute.segmentEndCoordinates.size()) ) {
|
||||
// INFO("Checking for alternative paths");
|
||||
searchEngine->alternativePaths(rawRoute.segmentEndCoordinates[0], rawRoute);
|
||||
|
||||
} else {
|
||||
searchEngine->shortestPath(rawRoute.segmentEndCoordinates, rawRoute);
|
||||
}
|
||||
|
||||
|
||||
if(INT_MAX == rawRoute.lengthOfShortestPath ) {
|
||||
DEBUG( "Error occurred, single path not found" );
|
||||
}
|
||||
reply.status = http::Reply::ok;
|
||||
|
||||
//TODO: Move to member as smart pointer
|
||||
BaseDescriptor<SearchEngine<QueryEdge::EdgeData, StaticGraph<QueryEdge::EdgeData> > > * desc;
|
||||
if("" != routeParameters.jsonpParameter) {
|
||||
reply.content += routeParameters.jsonpParameter;
|
||||
reply.content += "(";
|
||||
}
|
||||
|
||||
_DescriptorConfig descriptorConfig;
|
||||
unsigned descriptorType = descriptorTable[routeParameters.outputFormat];
|
||||
descriptorConfig.z = routeParameters.zoomLevel;
|
||||
descriptorConfig.instructions = routeParameters.printInstructions;
|
||||
descriptorConfig.geometry = routeParameters.geometry;
|
||||
descriptorConfig.encodeGeometry = routeParameters.compression;
|
||||
|
||||
switch(descriptorType){
|
||||
case 0:
|
||||
desc = new JSONDescriptor<SearchEngine<QueryEdge::EdgeData, StaticGraph<QueryEdge::EdgeData> > >();
|
||||
|
||||
break;
|
||||
case 1:
|
||||
desc = new GPXDescriptor<SearchEngine<QueryEdge::EdgeData, StaticGraph<QueryEdge::EdgeData> > >();
|
||||
|
||||
break;
|
||||
default:
|
||||
desc = new JSONDescriptor<SearchEngine<QueryEdge::EdgeData, StaticGraph<QueryEdge::EdgeData> > >();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
PhantomNodes phantomNodes;
|
||||
phantomNodes.startPhantom = rawRoute.segmentEndCoordinates[0].startPhantom;
|
||||
// INFO("Start location: " << phantomNodes.startPhantom.location)
|
||||
phantomNodes.targetPhantom = rawRoute.segmentEndCoordinates[rawRoute.segmentEndCoordinates.size()-1].targetPhantom;
|
||||
// INFO("TargetLocation: " << phantomNodes.targetPhantom.location);
|
||||
// INFO("Number of segments: " << rawRoute.segmentEndCoordinates.size());
|
||||
desc->SetConfig(descriptorConfig);
|
||||
|
||||
desc->Run(reply, rawRoute, phantomNodes, *searchEngine);
|
||||
if("" != routeParameters.jsonpParameter) {
|
||||
reply.content += ")\n";
|
||||
}
|
||||
reply.headers.resize(3);
|
||||
reply.headers[0].name = "Content-Length";
|
||||
std::string tmp;
|
||||
intToString(reply.content.size(), tmp);
|
||||
reply.headers[0].value = tmp;
|
||||
switch(descriptorType){
|
||||
case 0:
|
||||
if("" != routeParameters.jsonpParameter){
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.js\"";
|
||||
} else {
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.json\"";
|
||||
}
|
||||
|
||||
break;
|
||||
case 1:
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/gpx+xml; charset=UTF-8";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.gpx\"";
|
||||
|
||||
break;
|
||||
default:
|
||||
if("" != routeParameters.jsonpParameter){
|
||||
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;
|
||||
}
|
||||
|
||||
delete desc;
|
||||
return;
|
||||
}
|
||||
private:
|
||||
inline bool checkCoord(const _Coordinate & c) {
|
||||
if(c.lat > 90*100000 || c.lat < -90*100000 || c.lon > 180*100000 || c.lon <-180*100000) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif /* VIAROUTEPLUGIN_H_ */
|
||||
@@ -1,7 +0,0 @@
|
||||
For instructions on how to compile and run OSRM, please consult the Wiki at
|
||||
|
||||
https://github.com/DennisOSRM/Project-OSRM/wiki
|
||||
|
||||
or use our free and daily updated online service at
|
||||
|
||||
http://map.project-osrm.org
|
||||
@@ -0,0 +1,41 @@
|
||||
# Readme
|
||||
|
||||
For instructions on how to compile and run OSRM, please consult the Wiki at
|
||||
|
||||
https://github.com/Project-OSRM/osrm-backend/wiki
|
||||
|
||||
or use our free and daily updated online service at
|
||||
|
||||
http://map.project-osrm.org
|
||||
|
||||
## References in publications
|
||||
|
||||
When using the code in a (scientific) publication, please cite
|
||||
|
||||
```
|
||||
@inproceedings{luxen-vetter-2011,
|
||||
author = {Luxen, Dennis and Vetter, Christian},
|
||||
title = {Real-time routing with OpenStreetMap data},
|
||||
booktitle = {Proceedings of the 19th ACM SIGSPATIAL International Conference on Advances in Geographic Information Systems},
|
||||
series = {GIS '11},
|
||||
year = {2011},
|
||||
isbn = {978-1-4503-1031-4},
|
||||
location = {Chicago, Illinois},
|
||||
pages = {513--516},
|
||||
numpages = {4},
|
||||
url = {http://doi.acm.org/10.1145/2093973.2094062},
|
||||
doi = {10.1145/2093973.2094062},
|
||||
acmid = {2094062},
|
||||
publisher = {ACM},
|
||||
address = {New York, NY, USA},
|
||||
}
|
||||
```
|
||||
|
||||
## Current build status
|
||||
|
||||
| build config | branch | status |
|
||||
|:-------------|:--------|:------------|
|
||||
| Linux | master | [](https://travis-ci.org/DennisOSRM/Project-OSRM) |
|
||||
| Linux | develop | [](https://travis-ci.org/DennisOSRM/Project-OSRM) |
|
||||
| Windows | master/develop | [](https://ci.appveyor.com/project/DennisOSRM/osrm-backend) |
|
||||
| LUAbind fork | master | [](https://travis-ci.org/DennisOSRM/luabind) |
|
||||
@@ -4,9 +4,11 @@ require 'digest/sha1'
|
||||
require 'cucumber/rake/task'
|
||||
require 'sys/proctable'
|
||||
|
||||
BUILD_FOLDER = 'build'
|
||||
DATA_FOLDER = 'sandbox'
|
||||
PROFILE = 'bicycle'
|
||||
OSRM_PORT = 5000
|
||||
PROFILES_FOLDER = '../profiles'
|
||||
|
||||
Cucumber::Rake::Task.new do |t|
|
||||
t.cucumber_opts = %w{--format pretty}
|
||||
@@ -16,7 +18,7 @@ areas = {
|
||||
:kbh => { :country => 'denmark', :bbox => 'top=55.6972 left=12.5222 right=12.624 bottom=55.6376' },
|
||||
:frd => { :country => 'denmark', :bbox => 'top=55.7007 left=12.4765 bottom=55.6576 right=12.5698' },
|
||||
:regh => { :country => 'denmark', :bbox => 'top=56.164 left=11.792 bottom=55.403 right=12.731' },
|
||||
:dk => { :country => 'denmark', :bbox => nil },
|
||||
:denmark => { :country => 'denmark', :bbox => nil },
|
||||
:skaane => { :country => 'sweden', :bbox => 'top=56.55 left=12.4 bottom=55.3 right=14.6' }
|
||||
}
|
||||
|
||||
@@ -57,49 +59,31 @@ def wait_for_shutdown name
|
||||
raise "*** Could not terminate #{name}."
|
||||
end
|
||||
|
||||
def write_server_ini osm_file
|
||||
s=<<-EOF
|
||||
Threads = 1
|
||||
IP = 0.0.0.0
|
||||
Port = #{OSRM_PORT}
|
||||
|
||||
hsgrData=#{osm_file}.osrm.hsgr
|
||||
nodesData=#{osm_file}.osrm.nodes
|
||||
edgesData=#{osm_file}.osrm.edges
|
||||
ramIndex=#{osm_file}.osrm.ramIndex
|
||||
fileIndex=#{osm_file}.osrm.fileIndex
|
||||
namesData=#{osm_file}.osrm.names
|
||||
timestamp=#{osm_file}.osrm.timestamp
|
||||
EOF
|
||||
File.open( 'server.ini', 'w') {|f| f.write( s ) }
|
||||
end
|
||||
|
||||
|
||||
desc "Rebuild and run tests."
|
||||
task :default => [:build, :cucumber]
|
||||
task :default => [:build]
|
||||
|
||||
desc "Build using SConsstruct."
|
||||
desc "Build using CMake."
|
||||
task :build do
|
||||
system "scons"
|
||||
if Dir.exists? BUILD_FOLDER
|
||||
Dir.chdir BUILD_FOLDER do
|
||||
system "make"
|
||||
end
|
||||
else
|
||||
system "mkdir build; cd build; cmake ..; make"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Setup config files."
|
||||
task :setup do
|
||||
Dir.mkdir "#{DATA_FOLDER}" unless File.exist? "#{DATA_FOLDER}"
|
||||
['server.ini','extractor.ini','contractor.ini'].each do |file|
|
||||
unless File.exist? "#{DATA_FOLDER}/#{file}"
|
||||
puts "Copying #{file} template to #{DATA_FOLDER}/#{file}"
|
||||
FileUtils.cp file, "#{DATA_FOLDER}/#{file}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc "Download OSM data."
|
||||
task :download => :setup do
|
||||
task :download do
|
||||
Dir.mkdir "#{DATA_FOLDER}" unless File.exist? "#{DATA_FOLDER}"
|
||||
puts "Downloading..."
|
||||
puts "curl http://download.geofabrik.de/openstreetmap/europe/#{osm_data_country}.osm.pbf -o #{DATA_FOLDER}/#{osm_data_country}.osm.pbf"
|
||||
raise "Error while downloading data." unless system "curl http://download.geofabrik.de/openstreetmap/europe/#{osm_data_country}.osm.pbf -o #{DATA_FOLDER}/#{osm_data_country}.osm.pbf"
|
||||
puts "curl http://download.geofabrik.de/europe/#{osm_data_country}-latest.osm.pbf -o #{DATA_FOLDER}/#{osm_data_country}.osm.pbf"
|
||||
raise "Error while downloading data." unless system "curl http://download.geofabrik.de/europe/#{osm_data_country}-latest.osm.pbf -o #{DATA_FOLDER}/#{osm_data_country}.osm.pbf"
|
||||
if osm_data_area_bbox
|
||||
puts "Cropping and converting to protobuffer..."
|
||||
raise "Error while cropping data." unless system "osmosis --read-pbf file=#{DATA_FOLDER}/#{osm_data_country}.osm.pbf --bounding-box #{osm_data_area_bbox} --write-pbf file=#{DATA_FOLDER}/#{osm_data_area_name}.osm.pbf omitmetadata=true"
|
||||
@@ -114,12 +98,20 @@ task :crop do
|
||||
end
|
||||
|
||||
desc "Reprocess OSM data."
|
||||
task :process => :setup do
|
||||
task :process => [:extract,:prepare] do
|
||||
end
|
||||
|
||||
desc "Extract OSM data."
|
||||
task :extract do
|
||||
Dir.chdir DATA_FOLDER do
|
||||
raise "Error while extracting data." unless system "../osrm-extract #{osm_data_area_name}.osm.pbf ../profiles/#{PROFILE}.lua"
|
||||
puts
|
||||
raise "Error while preparing data." unless system "../osrm-prepare #{osm_data_area_name}.osrm #{osm_data_area_name}.osrm.restrictions ../profiles/#{PROFILE}.lua"
|
||||
puts
|
||||
raise "Error while extracting data." unless system "../#{BUILD_FOLDER}/osrm-extract #{osm_data_area_name}.osm.pbf --profile ../profiles/#{PROFILE}.lua"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Prepare OSM data."
|
||||
task :prepare do
|
||||
Dir.chdir DATA_FOLDER do
|
||||
raise "Error while preparing data." unless system "../#{BUILD_FOLDER}/osrm-prepare #{osm_data_area_name}.osrm --profile ../profiles/#{PROFILE}.lua"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -136,19 +128,17 @@ task :test do
|
||||
end
|
||||
|
||||
desc "Run the routing server in the terminal. Press Ctrl-C to stop."
|
||||
task :run => :setup do
|
||||
task :run do
|
||||
Dir.chdir DATA_FOLDER do
|
||||
write_server_ini osm_data_area_name
|
||||
system "../osrm-routed"
|
||||
system "../#{BUILD_FOLDER}/osrm-routed #{osm_data_area_name}.osrm --port #{OSRM_PORT}"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Launch the routing server in the background. Use rake:down to stop it."
|
||||
task :up => :setup do
|
||||
task :up do
|
||||
Dir.chdir DATA_FOLDER do
|
||||
abort("Already up.") if up?
|
||||
write_server_ini osm_data_area_name
|
||||
pipe = IO.popen('../osrm-routed 1>>osrm-routed.log 2>>osrm-routed.log')
|
||||
pipe = IO.popen("../#{BUILD_FOLDER}/osrm-routed #{osm_data_area_name}.osrm --port #{OSRM_PORT} 1>>osrm-routed.log 2>>osrm-routed.log")
|
||||
timeout = 5
|
||||
(timeout*10).times do
|
||||
begin
|
||||
@@ -191,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,477 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef ALTERNATIVEROUTES_H_
|
||||
#define ALTERNATIVEROUTES_H_
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "BasicRoutingInterface.h"
|
||||
|
||||
const double VIAPATH_ALPHA = 0.25;
|
||||
const double VIAPATH_EPSILON = 0.25;
|
||||
const double VIAPATH_GAMMA = 0.80;
|
||||
|
||||
template<class QueryDataT>
|
||||
class AlternativeRouting : private BasicRoutingInterface<QueryDataT>{
|
||||
typedef BasicRoutingInterface<QueryDataT> super;
|
||||
typedef std::pair<NodeID, int> PreselectedNode;
|
||||
typedef typename QueryDataT::HeapPtr HeapPtr;
|
||||
typedef std::pair<NodeID, NodeID> UnpackEdge;
|
||||
|
||||
struct RankedCandidateNode {
|
||||
RankedCandidateNode(NodeID n, int l, int s) : node(n), length(l), sharing(s) {}
|
||||
NodeID node;
|
||||
int length;
|
||||
int sharing;
|
||||
bool operator<(const RankedCandidateNode& other) const {
|
||||
return (2*length + sharing) < (2*other.length + other.sharing);
|
||||
}
|
||||
};
|
||||
public:
|
||||
|
||||
AlternativeRouting(QueryDataT & qd) : super(qd) { }
|
||||
|
||||
~AlternativeRouting() {}
|
||||
|
||||
void operator()(const PhantomNodes & phantomNodePair, RawRouteData & rawRouteData) {
|
||||
if(!phantomNodePair.AtLeastOnePhantomNodeIsUINTMAX() || phantomNodePair.PhantomNodesHaveEqualLocation()) {
|
||||
rawRouteData.lengthOfShortestPath = rawRouteData.lengthOfAlternativePath = INT_MAX;
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<NodeID> alternativePath;
|
||||
std::vector<NodeID> viaNodeCandidates;
|
||||
std::vector <NodeID> packedShortestPath;
|
||||
std::vector<PreselectedNode> nodesThatPassPreselection;
|
||||
|
||||
HeapPtr & forwardHeap = super::_queryData.forwardHeap;
|
||||
HeapPtr & backwardHeap = super::_queryData.backwardHeap;
|
||||
HeapPtr & forwardHeap2 = super::_queryData.forwardHeap2;
|
||||
HeapPtr & backwardHeap2 = super::_queryData.backwardHeap2;
|
||||
|
||||
//Initialize Queues
|
||||
super::_queryData.InitializeOrClearFirstThreadLocalStorage();
|
||||
int _upperBound = INT_MAX;
|
||||
NodeID middle = UINT_MAX;
|
||||
forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode);
|
||||
if(phantomNodePair.startPhantom.isBidirected() ) {
|
||||
forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1);
|
||||
}
|
||||
backwardHeap->Insert(phantomNodePair.targetPhantom.edgeBasedNode, phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.edgeBasedNode);
|
||||
if(phantomNodePair.targetPhantom.isBidirected() ) {
|
||||
backwardHeap->Insert(phantomNodePair.targetPhantom.edgeBasedNode+1, phantomNodePair.targetPhantom.weight2, phantomNodePair.targetPhantom.edgeBasedNode+1);
|
||||
}
|
||||
|
||||
const int offset = (phantomNodePair.startPhantom.isBidirected() ? std::max(phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.weight2) : phantomNodePair.startPhantom.weight1)
|
||||
+ (phantomNodePair.targetPhantom.isBidirected() ? std::max(phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.weight2) : phantomNodePair.targetPhantom.weight1);
|
||||
|
||||
//exploration dijkstra from nodes s and t until deletemin/(1+epsilon) > _lengthOfShortestPath
|
||||
while(forwardHeap->Size() + backwardHeap->Size() > 0){
|
||||
if(forwardHeap->Size() > 0){
|
||||
AlternativeRoutingStep(forwardHeap, backwardHeap, &middle, &_upperBound, 2*offset, true, viaNodeCandidates);
|
||||
}
|
||||
if(backwardHeap->Size() > 0){
|
||||
AlternativeRoutingStep(backwardHeap, forwardHeap, &middle, &_upperBound, 2*offset, false, viaNodeCandidates);
|
||||
}
|
||||
}
|
||||
std::sort(viaNodeCandidates.begin(), viaNodeCandidates.end());
|
||||
int size = std::unique(viaNodeCandidates.begin(), viaNodeCandidates.end())- viaNodeCandidates.begin();
|
||||
viaNodeCandidates.resize(size);
|
||||
|
||||
//save (packed) shortest path of shortest path and keep it for later use.
|
||||
//we need it during the checks and dont want to recompute it always
|
||||
super::RetrievePackedPathFromHeap(forwardHeap, backwardHeap, middle, packedShortestPath);
|
||||
|
||||
//ch-pruning of via nodes in both search spaces
|
||||
BOOST_FOREACH(const NodeID node, viaNodeCandidates) {
|
||||
if(node == middle) //subpath optimality tells us that this case is just the shortest path
|
||||
continue;
|
||||
|
||||
int sharing = approximateAmountOfSharing(node, forwardHeap, backwardHeap, packedShortestPath);
|
||||
int length1 = forwardHeap->GetKey(node);
|
||||
int length2 = backwardHeap->GetKey(node);
|
||||
bool lengthPassed = (length1+length2 < _upperBound*(1+VIAPATH_EPSILON));
|
||||
bool sharingPassed = (sharing <= _upperBound*VIAPATH_GAMMA);
|
||||
bool stretchPassed = length1+length2 - sharing < (1.+VIAPATH_EPSILON)*(_upperBound-sharing);
|
||||
|
||||
if(lengthPassed && sharingPassed && stretchPassed)
|
||||
nodesThatPassPreselection.push_back(std::make_pair(node, length1+length2));
|
||||
}
|
||||
|
||||
std::vector<RankedCandidateNode > rankedCandidates;
|
||||
|
||||
//prioritizing via nodes for deep inspection
|
||||
BOOST_FOREACH(const PreselectedNode node, nodesThatPassPreselection) {
|
||||
int lengthOfViaPath = 0, sharingOfViaPath = 0;
|
||||
|
||||
computeLengthAndSharingOfViaPath(node, &lengthOfViaPath, &sharingOfViaPath, offset, packedShortestPath);
|
||||
if(sharingOfViaPath <= VIAPATH_GAMMA*_upperBound)
|
||||
rankedCandidates.push_back(RankedCandidateNode(node.first, lengthOfViaPath, sharingOfViaPath));
|
||||
}
|
||||
|
||||
std::sort(rankedCandidates.begin(), rankedCandidates.end());
|
||||
|
||||
NodeID selectedViaNode = UINT_MAX;
|
||||
int lengthOfViaPath = INT_MAX;
|
||||
NodeID s_v_middle = UINT_MAX, v_t_middle = UINT_MAX;
|
||||
BOOST_FOREACH(const RankedCandidateNode candidate, rankedCandidates){
|
||||
if(viaNodeCandidatePasses_T_Test(forwardHeap, backwardHeap, forwardHeap2, backwardHeap2, candidate, offset, _upperBound, &lengthOfViaPath, &s_v_middle, &v_t_middle)) {
|
||||
// select first admissable
|
||||
selectedViaNode = candidate.node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Unpack shortest path and alternative, if they exist
|
||||
if(INT_MAX != _upperBound) {
|
||||
super::UnpackPath(packedShortestPath, rawRouteData.computedShortestPath);
|
||||
rawRouteData.lengthOfShortestPath = _upperBound;
|
||||
} else {
|
||||
rawRouteData.lengthOfShortestPath = INT_MAX;
|
||||
}
|
||||
|
||||
if(selectedViaNode != UINT_MAX) {
|
||||
retrievePackedViaPath(forwardHeap, backwardHeap, forwardHeap2, backwardHeap2, s_v_middle, v_t_middle, rawRouteData.computedAlternativePath);
|
||||
rawRouteData.lengthOfAlternativePath = lengthOfViaPath;
|
||||
} else {
|
||||
rawRouteData.lengthOfAlternativePath = INT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//unpack <s,..,v,..,t> by exploring search spaces from v
|
||||
inline void retrievePackedViaPath(const HeapPtr & _forwardHeap1, const HeapPtr & _backwardHeap1, const HeapPtr & _forwardHeap2, const HeapPtr & _backwardHeap2,
|
||||
const NodeID s_v_middle, const NodeID v_t_middle, std::vector<_PathData> & unpackedPath) {
|
||||
//unpack [s,v)
|
||||
std::vector<NodeID> packed_s_v_path, packed_v_t_path;
|
||||
super::RetrievePackedPathFromHeap(_forwardHeap1, _backwardHeap2, s_v_middle, packed_s_v_path);
|
||||
packed_s_v_path.resize(packed_s_v_path.size()-1);
|
||||
//unpack [v,t]
|
||||
super::RetrievePackedPathFromHeap(_forwardHeap2, _backwardHeap1, v_t_middle, packed_v_t_path);
|
||||
packed_s_v_path.insert(packed_s_v_path.end(),packed_v_t_path.begin(), packed_v_t_path.end() );
|
||||
super::UnpackPath(packed_s_v_path, unpackedPath);
|
||||
}
|
||||
|
||||
inline void computeLengthAndSharingOfViaPath(const PreselectedNode& node, int *lengthOfViaPath, int *sharingOfViaPath,
|
||||
const int offset, const std::vector<NodeID> & packedShortestPath) {
|
||||
//compute and unpack <s,..,v> and <v,..,t> by exploring search spaces from v and intersecting against queues
|
||||
//only half-searches have to be done at this stage
|
||||
super::_queryData.InitializeOrClearSecondThreadLocalStorage();
|
||||
|
||||
HeapPtr & existingForwardHeap = super::_queryData.forwardHeap;
|
||||
HeapPtr & existingBackwardHeap = super::_queryData.backwardHeap;
|
||||
HeapPtr & newForwardHeap = super::_queryData.forwardHeap2;
|
||||
HeapPtr & newBackwardHeap = super::_queryData.backwardHeap2;
|
||||
|
||||
std::vector < NodeID > packed_s_v_path;
|
||||
std::vector < NodeID > packed_v_t_path;
|
||||
|
||||
std::vector<NodeID> partiallyUnpackedShortestPath;
|
||||
std::vector<NodeID> partiallyUnpackedViaPath;
|
||||
|
||||
NodeID s_v_middle = UINT_MAX;
|
||||
int upperBoundFor_s_v_Path = INT_MAX;//compute path <s,..,v> by reusing forward search from s
|
||||
newBackwardHeap->Insert(node.first, 0, node.first);
|
||||
while (newBackwardHeap->Size() > 0) {
|
||||
super::RoutingStep(newBackwardHeap, existingForwardHeap, &s_v_middle, &upperBoundFor_s_v_Path, 2 * offset, false);
|
||||
}
|
||||
//compute path <v,..,t> by reusing backward search from node t
|
||||
NodeID v_t_middle = UINT_MAX;
|
||||
int upperBoundFor_v_t_Path = INT_MAX;
|
||||
newForwardHeap->Insert(node.first, 0, node.first);
|
||||
while (newForwardHeap->Size() > 0) {
|
||||
super::RoutingStep(newForwardHeap, existingBackwardHeap, &v_t_middle, &upperBoundFor_v_t_Path, 2 * offset, true);
|
||||
}
|
||||
*lengthOfViaPath = upperBoundFor_s_v_Path + upperBoundFor_v_t_Path;
|
||||
|
||||
if(UINT_MAX == s_v_middle || UINT_MAX == v_t_middle)
|
||||
return;
|
||||
|
||||
//retrieve packed paths
|
||||
super::RetrievePackedPathFromHeap(existingForwardHeap, newBackwardHeap, s_v_middle, packed_s_v_path);
|
||||
super::RetrievePackedPathFromHeap(newForwardHeap, existingBackwardHeap, v_t_middle, packed_v_t_path);
|
||||
|
||||
//partial unpacking, compute sharing
|
||||
//First partially unpack s-->v until paths deviate, note length of common path.
|
||||
for (unsigned i = 0, lengthOfPackedPath = std::min( packed_s_v_path.size(), packedShortestPath.size()) - 1; (i < lengthOfPackedPath); ++i) {
|
||||
if (packed_s_v_path[i] == packedShortestPath[i] && packed_s_v_path[i + 1] == packedShortestPath[i + 1]) {
|
||||
typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection(packed_s_v_path[i], packed_s_v_path[i + 1]);
|
||||
*sharingOfViaPath += super::_queryData.graph->GetEdgeData(edgeID).distance;
|
||||
} else {
|
||||
if (packed_s_v_path[i] == packedShortestPath[i]) {
|
||||
super::UnpackEdge(packed_s_v_path[i], packed_s_v_path[i+1], partiallyUnpackedViaPath);
|
||||
super::UnpackEdge(packedShortestPath[i], packedShortestPath[i+1], partiallyUnpackedShortestPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//traverse partially unpacked edge and note common prefix
|
||||
for (int i = 0, lengthOfPackedPath = std::min( partiallyUnpackedViaPath.size(), partiallyUnpackedShortestPath.size()) - 1; (i < lengthOfPackedPath) && (partiallyUnpackedViaPath[i] == partiallyUnpackedShortestPath[i] && partiallyUnpackedViaPath[i+1] == partiallyUnpackedShortestPath[i+1]); ++i) {
|
||||
typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection(partiallyUnpackedViaPath[i], partiallyUnpackedViaPath[i+1]);
|
||||
*sharingOfViaPath += super::_queryData.graph->GetEdgeData(edgeID).distance;
|
||||
}
|
||||
|
||||
//Second, partially unpack v-->t in reverse order until paths deviate and note lengths
|
||||
int viaPathIndex = packed_v_t_path.size() - 1;
|
||||
int shortestPathIndex = packedShortestPath.size() - 1;
|
||||
for (; viaPathIndex > 0 && shortestPathIndex > 0; --viaPathIndex,--shortestPathIndex ) {
|
||||
if (packed_v_t_path[viaPathIndex - 1] == packedShortestPath[shortestPathIndex - 1] && packed_v_t_path[viaPathIndex] == packedShortestPath[shortestPathIndex]) {
|
||||
typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection( packed_v_t_path[viaPathIndex - 1], packed_v_t_path[viaPathIndex]);
|
||||
*sharingOfViaPath += super::_queryData.graph->GetEdgeData(edgeID).distance;
|
||||
} else {
|
||||
if (packed_v_t_path[viaPathIndex] == packedShortestPath[shortestPathIndex]) {
|
||||
super::UnpackEdge(packed_v_t_path[viaPathIndex-1], packed_v_t_path[viaPathIndex], partiallyUnpackedViaPath);
|
||||
super::UnpackEdge(packedShortestPath[shortestPathIndex-1] , packedShortestPath[shortestPathIndex], partiallyUnpackedShortestPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viaPathIndex = partiallyUnpackedViaPath.size() - 1;
|
||||
shortestPathIndex = partiallyUnpackedShortestPath.size() - 1;
|
||||
for (; viaPathIndex > 0 && shortestPathIndex > 0; --viaPathIndex,--shortestPathIndex) {
|
||||
if (partiallyUnpackedViaPath[viaPathIndex - 1] == partiallyUnpackedShortestPath[shortestPathIndex - 1] && partiallyUnpackedViaPath[viaPathIndex] == partiallyUnpackedShortestPath[shortestPathIndex]) {
|
||||
typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection( partiallyUnpackedViaPath[viaPathIndex - 1], partiallyUnpackedViaPath[viaPathIndex]);
|
||||
*sharingOfViaPath += super::_queryData.graph->GetEdgeData(edgeID).distance;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
//finished partial unpacking spree! Amount of sharing is stored to appropriate poiner variable
|
||||
}
|
||||
|
||||
inline int approximateAmountOfSharing(const NodeID middleNodeIDOfAlternativePath, HeapPtr & _forwardHeap, HeapPtr & _backwardHeap, const std::vector<NodeID> & packedShortestPath) {
|
||||
std::vector<NodeID> packedAlternativePath;
|
||||
super::RetrievePackedPathFromHeap(_forwardHeap, _backwardHeap, middleNodeIDOfAlternativePath, packedAlternativePath);
|
||||
|
||||
if(packedShortestPath.size() < 2 || packedAlternativePath.size() < 2)
|
||||
return 0;
|
||||
|
||||
int sharing = 0;
|
||||
int aindex = 0;
|
||||
//compute forward sharing
|
||||
while( (packedAlternativePath[aindex] == packedShortestPath[aindex]) && (packedAlternativePath[aindex+1] == packedShortestPath[aindex+1]) ) {
|
||||
// INFO("retrieving edge (" << packedAlternativePath[aindex] << "," << packedAlternativePath[aindex+1] << ")");
|
||||
typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection(packedAlternativePath[aindex], packedAlternativePath[aindex+1]);
|
||||
sharing += super::_queryData.graph->GetEdgeData(edgeID).distance;
|
||||
++aindex;
|
||||
}
|
||||
|
||||
aindex = packedAlternativePath.size()-1;
|
||||
int bindex = packedShortestPath.size()-1;
|
||||
//compute backward sharing
|
||||
while( aindex > 0 && bindex > 0 && (packedAlternativePath[aindex] == packedShortestPath[bindex]) && (packedAlternativePath[aindex-1] == packedShortestPath[bindex-1]) ) {
|
||||
typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection(packedAlternativePath[aindex], packedAlternativePath[aindex-1]);
|
||||
sharing += super::_queryData.graph->GetEdgeData(edgeID).distance;
|
||||
--aindex; --bindex;
|
||||
}
|
||||
return sharing;
|
||||
}
|
||||
|
||||
inline void AlternativeRoutingStep(HeapPtr & _forwardHeap, HeapPtr & _backwardHeap, NodeID *middle, int *_upperbound, const int edgeBasedOffset, const bool forwardDirection, std::vector<NodeID>& searchSpaceIntersection) const {
|
||||
const NodeID node = _forwardHeap->DeleteMin();
|
||||
|
||||
const int distance = _forwardHeap->GetKey(node);
|
||||
if(_backwardHeap->WasInserted(node) ){
|
||||
searchSpaceIntersection.push_back(node);
|
||||
|
||||
const int newDistance = _backwardHeap->GetKey(node) + distance;
|
||||
if(newDistance < *_upperbound ){
|
||||
if(newDistance>=0 ) {
|
||||
*middle = node;
|
||||
*_upperbound = newDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int scaledDistance = (distance-edgeBasedOffset)/(1.+VIAPATH_EPSILON);
|
||||
if(scaledDistance > *_upperbound){
|
||||
_forwardHeap->DeleteAll();
|
||||
return;
|
||||
}
|
||||
|
||||
for ( typename QueryDataT::Graph::EdgeIterator edge = super::_queryData.graph->BeginEdges( node ); edge < super::_queryData.graph->EndEdges(node); edge++ ) {
|
||||
const typename QueryDataT::Graph::EdgeData & data = super::_queryData.graph->GetEdgeData(edge);
|
||||
bool forwardDirectionFlag = (forwardDirection ? data.forward : data.backward );
|
||||
if(forwardDirectionFlag) {
|
||||
|
||||
const NodeID to = super::_queryData.graph->GetTarget(edge);
|
||||
const int edgeWeight = data.distance;
|
||||
|
||||
assert( edgeWeight > 0 );
|
||||
const int toDistance = distance + edgeWeight;
|
||||
|
||||
//New Node discovered -> Add to Heap + Node Info Storage
|
||||
if ( !_forwardHeap->WasInserted( to ) ) {
|
||||
_forwardHeap->Insert( to, toDistance, node );
|
||||
|
||||
}
|
||||
//Found a shorter Path -> Update distance
|
||||
else if ( toDistance < _forwardHeap->GetKey( to ) ) {
|
||||
_forwardHeap->GetData( to ).parent = node;
|
||||
_forwardHeap->DecreaseKey( to, toDistance );
|
||||
//new parent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//conduct T-Test
|
||||
inline bool viaNodeCandidatePasses_T_Test( HeapPtr& existingForwardHeap, HeapPtr& existingBackwardHeap, HeapPtr& newForwardHeap, HeapPtr& newBackwardHeap, const RankedCandidateNode& candidate, const int offset, const int lengthOfShortestPath, int * lengthOfViaPath, NodeID * s_v_middle, NodeID * v_t_middle) {
|
||||
std::vector < NodeID > packed_s_v_path;
|
||||
std::vector < NodeID > packed_v_t_path;
|
||||
|
||||
super::_queryData.InitializeOrClearSecondThreadLocalStorage();
|
||||
*s_v_middle = UINT_MAX;
|
||||
int upperBoundFor_s_v_Path = INT_MAX;
|
||||
//compute path <s,..,v> by reusing forward search from s
|
||||
newBackwardHeap->Insert(candidate.node, 0, candidate.node);
|
||||
while (newBackwardHeap->Size() > 0) {
|
||||
super::RoutingStep(newBackwardHeap, existingForwardHeap, s_v_middle, &upperBoundFor_s_v_Path, 2*offset, false);
|
||||
}
|
||||
|
||||
if(INT_MAX == upperBoundFor_s_v_Path)
|
||||
return false;
|
||||
|
||||
//compute path <v,..,t> by reusing backward search from t
|
||||
*v_t_middle = UINT_MAX;
|
||||
int upperBoundFor_v_t_Path = INT_MAX;
|
||||
newForwardHeap->Insert(candidate.node, 0, candidate.node);
|
||||
while (newForwardHeap->Size() > 0) {
|
||||
super::RoutingStep(newForwardHeap, existingBackwardHeap, v_t_middle, &upperBoundFor_v_t_Path, 2*offset, true);
|
||||
}
|
||||
|
||||
if(INT_MAX == upperBoundFor_v_t_Path)
|
||||
return false;
|
||||
|
||||
*lengthOfViaPath = upperBoundFor_s_v_Path + upperBoundFor_v_t_Path;
|
||||
|
||||
//retrieve packed paths
|
||||
super::RetrievePackedPathFromHeap(existingForwardHeap, newBackwardHeap, *s_v_middle, packed_s_v_path);
|
||||
super::RetrievePackedPathFromHeap(newForwardHeap, existingBackwardHeap, *v_t_middle, packed_v_t_path);
|
||||
|
||||
NodeID s_P = *s_v_middle, t_P = *v_t_middle;
|
||||
const int T_threshold = VIAPATH_EPSILON * lengthOfShortestPath;
|
||||
int unpackedUntilDistance = 0;
|
||||
|
||||
std::stack<UnpackEdge> unpackStack;
|
||||
//Traverse path s-->v
|
||||
for (unsigned i = packed_s_v_path.size() - 1; (i > 0) && unpackStack.empty(); --i) {
|
||||
typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection( packed_s_v_path[i - 1], packed_s_v_path[i]);
|
||||
int lengthOfCurrentEdge = super::_queryData.graph->GetEdgeData(edgeID).distance;
|
||||
if (lengthOfCurrentEdge + unpackedUntilDistance >= T_threshold) {
|
||||
unpackStack.push(std::make_pair(packed_s_v_path[i - 1], packed_s_v_path[i]));
|
||||
} else {
|
||||
unpackedUntilDistance += lengthOfCurrentEdge;
|
||||
s_P = packed_s_v_path[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
while (!unpackStack.empty()) {
|
||||
const UnpackEdge viaPathEdge = unpackStack.top();
|
||||
unpackStack.pop();
|
||||
typename QueryDataT::Graph::EdgeIterator edgeIDInViaPath = super::_queryData.graph->FindEdgeInEitherDirection(viaPathEdge.first, viaPathEdge.second);
|
||||
if(UINT_MAX == edgeIDInViaPath)
|
||||
return false;
|
||||
typename QueryDataT::Graph::EdgeData currentEdgeData = super::_queryData.graph->GetEdgeData(edgeIDInViaPath);
|
||||
bool IsViaEdgeShortCut = currentEdgeData.shortcut;
|
||||
if (IsViaEdgeShortCut) {
|
||||
const NodeID middleOfViaPath = currentEdgeData.id;
|
||||
typename QueryDataT::Graph::EdgeIterator edgeIDOfSecondSegment = super::_queryData.graph->FindEdgeInEitherDirection(middleOfViaPath, viaPathEdge.second);
|
||||
int lengthOfSecondSegment = super::_queryData.graph->GetEdgeData(edgeIDOfSecondSegment).distance;
|
||||
//attention: !unpacking in reverse!
|
||||
//Check if second segment is the one to go over treshold? if yes add second segment to stack, else push first segment to stack and add distance of second one.
|
||||
if (unpackedUntilDistance + lengthOfSecondSegment >= T_threshold) {
|
||||
unpackStack.push(std::make_pair(middleOfViaPath, viaPathEdge.second));
|
||||
} else {
|
||||
unpackedUntilDistance += lengthOfSecondSegment;
|
||||
unpackStack.push(std::make_pair(viaPathEdge.first, middleOfViaPath));
|
||||
}
|
||||
} else {
|
||||
// edge is not a shortcut, set the start node for T-Test to end of edge.
|
||||
unpackedUntilDistance += currentEdgeData.distance;
|
||||
s_P = viaPathEdge.first;
|
||||
}
|
||||
}
|
||||
|
||||
int lengthOfPathT_Test_Path = unpackedUntilDistance;
|
||||
unpackedUntilDistance = 0;
|
||||
//Traverse path s-->v
|
||||
for (unsigned i = 0, lengthOfPackedPath = packed_v_t_path.size() - 1; (i < lengthOfPackedPath) && unpackStack.empty(); ++i) {
|
||||
typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection( packed_v_t_path[i], packed_v_t_path[i + 1]);
|
||||
int lengthOfCurrentEdge = super::_queryData.graph->GetEdgeData(edgeID).distance;
|
||||
if (lengthOfCurrentEdge + unpackedUntilDistance >= T_threshold) {
|
||||
unpackStack.push( std::make_pair(packed_v_t_path[i], packed_v_t_path[i + 1]));
|
||||
} else {
|
||||
unpackedUntilDistance += lengthOfCurrentEdge;
|
||||
t_P = packed_v_t_path[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
while (!unpackStack.empty()) {
|
||||
const UnpackEdge viaPathEdge = unpackStack.top();
|
||||
unpackStack.pop();
|
||||
typename QueryDataT::Graph::EdgeIterator edgeIDInViaPath = super::_queryData.graph->FindEdgeInEitherDirection(viaPathEdge.first, viaPathEdge.second);
|
||||
if(UINT_MAX == edgeIDInViaPath)
|
||||
return false;
|
||||
typename QueryDataT::Graph::EdgeData currentEdgeData = super::_queryData.graph->GetEdgeData(edgeIDInViaPath);
|
||||
const bool IsViaEdgeShortCut = currentEdgeData.shortcut;
|
||||
if (IsViaEdgeShortCut) {
|
||||
const NodeID middleOfViaPath = currentEdgeData.id;
|
||||
typename QueryDataT::Graph::EdgeIterator edgeIDOfFirstSegment = super::_queryData.graph->FindEdgeInEitherDirection(viaPathEdge.first, middleOfViaPath);
|
||||
int lengthOfFirstSegment = super::_queryData.graph->GetEdgeData( edgeIDOfFirstSegment).distance;
|
||||
//Check if first segment is the one to go over treshold? if yes first segment to stack, else push second segment to stack and add distance of first one.
|
||||
if (unpackedUntilDistance + lengthOfFirstSegment >= T_threshold) {
|
||||
unpackStack.push( std::make_pair(viaPathEdge.first, middleOfViaPath));
|
||||
} else {
|
||||
unpackedUntilDistance += lengthOfFirstSegment;
|
||||
unpackStack.push( std::make_pair(middleOfViaPath, viaPathEdge.second));
|
||||
}
|
||||
} else {
|
||||
// edge is not a shortcut, set the start node for T-Test to end of edge.
|
||||
unpackedUntilDistance += currentEdgeData.distance;
|
||||
t_P = viaPathEdge.second;
|
||||
}
|
||||
}
|
||||
|
||||
lengthOfPathT_Test_Path += unpackedUntilDistance;
|
||||
//Run actual T-Test query and compare if distances equal.
|
||||
HeapPtr& forwardHeap = super::_queryData.forwardHeap3;
|
||||
HeapPtr& backwardHeap = super::_queryData.backwardHeap3;
|
||||
super::_queryData.InitializeOrClearThirdThreadLocalStorage();
|
||||
int _upperBound = INT_MAX;
|
||||
NodeID middle = UINT_MAX;
|
||||
forwardHeap->Insert(s_P, 0, s_P);
|
||||
backwardHeap->Insert(t_P, 0, t_P);
|
||||
//exploration from s and t until deletemin/(1+epsilon) > _lengthOfShortestPath
|
||||
while (forwardHeap->Size() + backwardHeap->Size() > 0) {
|
||||
if (forwardHeap->Size() > 0) {
|
||||
super::RoutingStep(forwardHeap, backwardHeap, &middle, &_upperBound, offset, true);
|
||||
}
|
||||
if (backwardHeap->Size() > 0) {
|
||||
super::RoutingStep(backwardHeap, forwardHeap, &middle, &_upperBound, offset, false);
|
||||
}
|
||||
}
|
||||
return (_upperBound <= lengthOfPathT_Test_Path);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* ALTERNATIVEROUTES_H_ */
|
||||
@@ -1,226 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef BASICROUTINGINTERFACE_H_
|
||||
#define BASICROUTINGINTERFACE_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
|
||||
#include "../Plugins/RawRouteData.h"
|
||||
|
||||
template<class QueryDataT>
|
||||
class BasicRoutingInterface {
|
||||
protected:
|
||||
QueryDataT & _queryData;
|
||||
public:
|
||||
BasicRoutingInterface(QueryDataT & qd) : _queryData(qd) { }
|
||||
virtual ~BasicRoutingInterface(){ };
|
||||
|
||||
inline void RoutingStep(typename QueryDataT::HeapPtr & _forwardHeap, typename QueryDataT::HeapPtr & _backwardHeap, NodeID *middle, int *_upperbound, const int edgeBasedOffset, const bool forwardDirection) const {
|
||||
const NodeID node = _forwardHeap->DeleteMin();
|
||||
const int distance = _forwardHeap->GetKey(node);
|
||||
// INFO((forwardDirection ? "[forw]" : "[back]") << " settled node " << node << " at distance " << distance);
|
||||
if(_backwardHeap->WasInserted(node) ){
|
||||
// INFO((forwardDirection ? "[forw]" : "[back]") << " scanned node " << node << " in both directions, upper bound: " << *_upperbound);
|
||||
const int newDistance = _backwardHeap->GetKey(node) + distance;
|
||||
if(newDistance < *_upperbound ){
|
||||
if(newDistance>=0 ) {
|
||||
// INFO((forwardDirection ? "[forw]" : "[back]") << " -> node " << node << " is new middle at total distance " << newDistance);
|
||||
*middle = node;
|
||||
*_upperbound = newDistance;
|
||||
} else {
|
||||
// INFO((forwardDirection ? "[forw]" : "[back]") << " -> ignored " << node << " as new middle at total distance " << newDistance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(distance-edgeBasedOffset > *_upperbound){
|
||||
_forwardHeap->DeleteAll();
|
||||
return;
|
||||
}
|
||||
|
||||
for ( typename QueryDataT::Graph::EdgeIterator edge = _queryData.graph->BeginEdges( node ); edge < _queryData.graph->EndEdges(node); edge++ ) {
|
||||
const typename QueryDataT::Graph::EdgeData & data = _queryData.graph->GetEdgeData(edge);
|
||||
bool backwardDirectionFlag = (!forwardDirection) ? data.forward : data.backward;
|
||||
if(backwardDirectionFlag) {
|
||||
const NodeID to = _queryData.graph->GetTarget(edge);
|
||||
const int edgeWeight = data.distance;
|
||||
|
||||
assert( edgeWeight > 0 );
|
||||
|
||||
//Stalling
|
||||
if(_forwardHeap->WasInserted( to )) {
|
||||
if(_forwardHeap->GetKey( to ) + edgeWeight < distance) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ( typename QueryDataT::Graph::EdgeIterator edge = _queryData.graph->BeginEdges( node ); edge < _queryData.graph->EndEdges(node); edge++ ) {
|
||||
const typename QueryDataT::Graph::EdgeData & data = _queryData.graph->GetEdgeData(edge);
|
||||
bool forwardDirectionFlag = (forwardDirection ? data.forward : data.backward );
|
||||
if(forwardDirectionFlag) {
|
||||
|
||||
const NodeID to = _queryData.graph->GetTarget(edge);
|
||||
const int edgeWeight = data.distance;
|
||||
|
||||
assert( edgeWeight > 0 );
|
||||
const int toDistance = distance + edgeWeight;
|
||||
|
||||
//New Node discovered -> Add to Heap + Node Info Storage
|
||||
if ( !_forwardHeap->WasInserted( to ) ) {
|
||||
// INFO((forwardDirection ? "[forw]" : "[back]") << " scanning edge (" << node << "," << to << ") with distance " << toDistance << ", edge length: " << data.distance);
|
||||
_forwardHeap->Insert( to, toDistance, node );
|
||||
}
|
||||
//Found a shorter Path -> Update distance
|
||||
else if ( toDistance < _forwardHeap->GetKey( to ) ) {
|
||||
// INFO((forwardDirection ? "[forw]" : "[back]") << " decrease and scanning edge (" << node << "," << to << ") from " << _forwardHeap->GetKey(to) << "to " << toDistance << ", edge length: " << data.distance);
|
||||
_forwardHeap->GetData( to ).parent = node;
|
||||
_forwardHeap->DecreaseKey( to, toDistance );
|
||||
//new parent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void UnpackPath(std::vector<NodeID> & packedPath, std::vector<_PathData> & unpackedPath) const {
|
||||
|
||||
const unsigned sizeOfPackedPath = packedPath.size();
|
||||
std::stack<std::pair<NodeID, NodeID> > recursionStack;
|
||||
|
||||
//We have to push the path in reverse order onto the stack because it's LIFO.
|
||||
for(unsigned i = sizeOfPackedPath-1; i > 0; --i){
|
||||
recursionStack.push(std::make_pair(packedPath[i-1], packedPath[i]));
|
||||
}
|
||||
|
||||
std::pair<NodeID, NodeID> edge;
|
||||
while(!recursionStack.empty()) {
|
||||
edge = recursionStack.top();
|
||||
recursionStack.pop();
|
||||
// INFO("Unpacking edge (" << edge.first << "," << edge.second << ")");
|
||||
|
||||
typename QueryDataT::Graph::EdgeIterator smallestEdge = SPECIAL_EDGEID;
|
||||
int smallestWeight = INT_MAX;
|
||||
for(typename QueryDataT::Graph::EdgeIterator eit = _queryData.graph->BeginEdges(edge.first);eit < _queryData.graph->EndEdges(edge.first);++eit){
|
||||
const int weight = _queryData.graph->GetEdgeData(eit).distance;
|
||||
// INFO("Checking edge (" << edge.first << "/" << _queryData.graph->GetTarget(eit) << ")");
|
||||
if(_queryData.graph->GetTarget(eit) == edge.second && weight < smallestWeight && _queryData.graph->GetEdgeData(eit).forward){
|
||||
// INFO("1smallest " << eit << ", " << weight);
|
||||
smallestEdge = eit;
|
||||
smallestWeight = weight;
|
||||
}
|
||||
}
|
||||
|
||||
if(smallestEdge == SPECIAL_EDGEID){
|
||||
for(typename QueryDataT::Graph::EdgeIterator eit = _queryData.graph->BeginEdges(edge.second);eit < _queryData.graph->EndEdges(edge.second);++eit){
|
||||
const int weight = _queryData.graph->GetEdgeData(eit).distance;
|
||||
// INFO("Checking edge (" << edge.first << "/" << _queryData.graph->GetTarget(eit) << ")");
|
||||
if(_queryData.graph->GetTarget(eit) == edge.first && weight < smallestWeight && _queryData.graph->GetEdgeData(eit).backward){
|
||||
// INFO("2smallest " << eit << ", " << weight);
|
||||
smallestEdge = eit;
|
||||
smallestWeight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(smallestWeight != INT_MAX);
|
||||
|
||||
const typename QueryDataT::Graph::EdgeData& ed = _queryData.graph->GetEdgeData(smallestEdge);
|
||||
if(ed.shortcut) {//unpack
|
||||
const NodeID middle = ed.id;
|
||||
//again, we need to this in reversed order
|
||||
recursionStack.push(std::make_pair(middle, edge.second));
|
||||
recursionStack.push(std::make_pair(edge.first, middle));
|
||||
} else {
|
||||
assert(!ed.shortcut);
|
||||
unpackedPath.push_back(_PathData(ed.id, _queryData.nodeHelpDesk->getNameIndexFromEdgeID(ed.id), _queryData.nodeHelpDesk->getTurnInstructionFromEdgeID(ed.id), ed.distance) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void UnpackEdge(const NodeID s, const NodeID t, std::vector<NodeID> & unpackedPath) const {
|
||||
|
||||
std::stack<std::pair<NodeID, NodeID> > recursionStack;
|
||||
recursionStack.push(std::make_pair(s,t));
|
||||
|
||||
std::pair<NodeID, NodeID> edge;
|
||||
while(!recursionStack.empty()) {
|
||||
edge = recursionStack.top();
|
||||
recursionStack.pop();
|
||||
|
||||
typename QueryDataT::Graph::EdgeIterator smallestEdge = SPECIAL_EDGEID;
|
||||
int smallestWeight = INT_MAX;
|
||||
for(typename QueryDataT::Graph::EdgeIterator eit = _queryData.graph->BeginEdges(edge.first);eit < _queryData.graph->EndEdges(edge.first);++eit){
|
||||
const int weight = _queryData.graph->GetEdgeData(eit).distance;
|
||||
if(_queryData.graph->GetTarget(eit) == edge.second && weight < smallestWeight && _queryData.graph->GetEdgeData(eit).forward){
|
||||
smallestEdge = eit;
|
||||
smallestWeight = weight;
|
||||
}
|
||||
}
|
||||
|
||||
if(smallestEdge == SPECIAL_EDGEID){
|
||||
for(typename QueryDataT::Graph::EdgeIterator eit = _queryData.graph->BeginEdges(edge.second);eit < _queryData.graph->EndEdges(edge.second);++eit){
|
||||
const int weight = _queryData.graph->GetEdgeData(eit).distance;
|
||||
if(_queryData.graph->GetTarget(eit) == edge.first && weight < smallestWeight && _queryData.graph->GetEdgeData(eit).backward){
|
||||
smallestEdge = eit;
|
||||
smallestWeight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(smallestWeight != INT_MAX);
|
||||
|
||||
const typename QueryDataT::Graph::EdgeData& ed = _queryData.graph->GetEdgeData(smallestEdge);
|
||||
if(ed.shortcut) {//unpack
|
||||
const NodeID middle = ed.id;
|
||||
//again, we need to this in reversed order
|
||||
// INFO("unpacking (" << middle << "," << edge.second << ") and (" << edge.first << "," << middle << ")");
|
||||
recursionStack.push(std::make_pair(middle, edge.second));
|
||||
recursionStack.push(std::make_pair(edge.first, middle));
|
||||
} else {
|
||||
assert(!ed.shortcut);
|
||||
unpackedPath.push_back(edge.first );
|
||||
}
|
||||
}
|
||||
unpackedPath.push_back(t);
|
||||
}
|
||||
|
||||
inline void RetrievePackedPathFromHeap(const typename QueryDataT::HeapPtr & _fHeap, const typename QueryDataT::HeapPtr & _bHeap, const NodeID middle, std::vector<NodeID>& packedPath) {
|
||||
NodeID pathNode = middle;
|
||||
while(pathNode != _fHeap->GetData(pathNode).parent) {
|
||||
pathNode = _fHeap->GetData(pathNode).parent;
|
||||
packedPath.push_back(pathNode);
|
||||
}
|
||||
|
||||
std::reverse(packedPath.begin(), packedPath.end());
|
||||
|
||||
packedPath.push_back(middle);
|
||||
pathNode = middle;
|
||||
while (pathNode != _bHeap->GetData(pathNode).parent){
|
||||
pathNode = _bHeap->GetData(pathNode).parent;
|
||||
packedPath.push_back(pathNode);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif /* BASICROUTINGINTERFACE_H_ */
|
||||
@@ -1,261 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef SHORTESTPATHROUTING_H_
|
||||
#define SHORTESTPATHROUTING_H_
|
||||
|
||||
#include "BasicRoutingInterface.h"
|
||||
|
||||
template<class QueryDataT>
|
||||
class ShortestPathRouting : public BasicRoutingInterface<QueryDataT>{
|
||||
typedef BasicRoutingInterface<QueryDataT> super;
|
||||
public:
|
||||
ShortestPathRouting(QueryDataT & qd) : super(qd) {}
|
||||
|
||||
~ShortestPathRouting() {}
|
||||
|
||||
void operator()(std::vector<PhantomNodes> & phantomNodesVector, RawRouteData & rawRouteData) {
|
||||
BOOST_FOREACH(PhantomNodes & phantomNodePair, phantomNodesVector) {
|
||||
if(!phantomNodePair.AtLeastOnePhantomNodeIsUINTMAX()) {
|
||||
rawRouteData.lengthOfShortestPath = rawRouteData.lengthOfAlternativePath = INT_MAX;
|
||||
return;
|
||||
}
|
||||
}
|
||||
int distance1 = 0;
|
||||
int distance2 = 0;
|
||||
|
||||
bool searchFrom1stStartNode(true);
|
||||
bool searchFrom2ndStartNode(true);
|
||||
NodeID middle1 = ( NodeID ) UINT_MAX;
|
||||
NodeID middle2 = ( NodeID ) UINT_MAX;
|
||||
std::vector<NodeID> packedPath1;
|
||||
std::vector<NodeID> packedPath2;
|
||||
|
||||
typename QueryDataT::HeapPtr & forwardHeap = super::_queryData.forwardHeap;
|
||||
typename QueryDataT::HeapPtr & backwardHeap = super::_queryData.backwardHeap;
|
||||
|
||||
typename QueryDataT::HeapPtr & forwardHeap2 = super::_queryData.forwardHeap2;
|
||||
typename QueryDataT::HeapPtr & backwardHeap2 = super::_queryData.backwardHeap2;
|
||||
|
||||
|
||||
//Get distance to next pair of target nodes.
|
||||
BOOST_FOREACH(PhantomNodes & phantomNodePair, phantomNodesVector) {
|
||||
super::_queryData.InitializeOrClearFirstThreadLocalStorage();
|
||||
super::_queryData.InitializeOrClearSecondThreadLocalStorage();
|
||||
|
||||
int _localUpperbound1 = INT_MAX;
|
||||
int _localUpperbound2 = INT_MAX;
|
||||
|
||||
//insert new starting nodes into forward heap, adjusted by previous distances.
|
||||
if(searchFrom1stStartNode) {
|
||||
forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode);
|
||||
forwardHeap2->Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode);
|
||||
// INFO("a 1,2)forw insert " << phantomNodePair.startPhantom.edgeBasedNode << " with weight " << phantomNodePair.startPhantom.weight1);
|
||||
// } else {
|
||||
// INFO("Skipping first start node");
|
||||
}
|
||||
if(phantomNodePair.startPhantom.isBidirected() && searchFrom2ndStartNode) {
|
||||
forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1);
|
||||
forwardHeap2->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1);
|
||||
// INFO("b 1,2)forw insert " << phantomNodePair.startPhantom.edgeBasedNode+1 << " with weight " << -phantomNodePair.startPhantom.weight1);
|
||||
// } else if(!searchFrom2ndStartNode) {
|
||||
// INFO("Skipping second start node");
|
||||
}
|
||||
|
||||
// backwardHeap->Clear();
|
||||
// backwardHeap2->Clear();
|
||||
//insert new backward nodes into backward heap, unadjusted.
|
||||
backwardHeap->Insert(phantomNodePair.targetPhantom.edgeBasedNode, phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.edgeBasedNode);
|
||||
// INFO("1) back insert " << phantomNodePair.targetPhantom.edgeBasedNode << " with weight " << phantomNodePair.targetPhantom.weight1);
|
||||
if(phantomNodePair.targetPhantom.isBidirected() ) {
|
||||
// INFO("2) back insert " << phantomNodePair.targetPhantom.edgeBasedNode+1 << " with weight " << phantomNodePair.targetPhantom.weight2);
|
||||
backwardHeap2->Insert(phantomNodePair.targetPhantom.edgeBasedNode+1, phantomNodePair.targetPhantom.weight2, phantomNodePair.targetPhantom.edgeBasedNode+1);
|
||||
}
|
||||
int offset = (phantomNodePair.startPhantom.isBidirected() ? std::max(phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.weight2) : phantomNodePair.startPhantom.weight1) ;
|
||||
offset += (phantomNodePair.targetPhantom.isBidirected() ? std::max(phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.weight2) : phantomNodePair.targetPhantom.weight1) ;
|
||||
|
||||
//run two-Target Dijkstra routing step.
|
||||
while(forwardHeap->Size() + backwardHeap->Size() > 0){
|
||||
if(forwardHeap->Size() > 0){
|
||||
super::RoutingStep(forwardHeap, backwardHeap, &middle1, &_localUpperbound1, 2*offset, true);
|
||||
}
|
||||
if(backwardHeap->Size() > 0){
|
||||
super::RoutingStep(backwardHeap, forwardHeap, &middle1, &_localUpperbound1, 2*offset, false);
|
||||
}
|
||||
}
|
||||
if(backwardHeap2->Size() > 0) {
|
||||
while(forwardHeap2->Size() + backwardHeap2->Size() > 0){
|
||||
if(forwardHeap2->Size() > 0){
|
||||
super::RoutingStep(forwardHeap2, backwardHeap2, &middle2, &_localUpperbound2, 2*offset, true);
|
||||
}
|
||||
if(backwardHeap2->Size() > 0){
|
||||
super::RoutingStep(backwardHeap2, forwardHeap2, &middle2, &_localUpperbound2, 2*offset, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
// INFO("upperbound1: " << _localUpperbound1 << ", distance1: " << distance1);
|
||||
// INFO("upperbound2: " << _localUpperbound2 << ", distance2: " << distance2);
|
||||
|
||||
//No path found for both target nodes?
|
||||
if(INT_MAX == _localUpperbound1 && INT_MAX == _localUpperbound2) {
|
||||
rawRouteData.lengthOfShortestPath = rawRouteData.lengthOfAlternativePath = INT_MAX;
|
||||
return;
|
||||
}
|
||||
if(UINT_MAX == middle1) {
|
||||
searchFrom1stStartNode = false;
|
||||
// INFO("Next Search will not start from 1st");
|
||||
} else {
|
||||
// INFO("Next Search will start from 1st");
|
||||
searchFrom1stStartNode = true;
|
||||
}
|
||||
if(UINT_MAX == middle2) {
|
||||
searchFrom2ndStartNode = false;
|
||||
// INFO("Next Search will not start from 2nd");
|
||||
} else {
|
||||
searchFrom2ndStartNode = true;
|
||||
// INFO("Next Search will start from 2nd");
|
||||
}
|
||||
|
||||
//Was at most one of the two paths not found?
|
||||
assert(!(INT_MAX == distance1 && INT_MAX == distance2));
|
||||
|
||||
// INFO("middle1: " << middle1);
|
||||
|
||||
//Unpack paths if they exist
|
||||
std::vector<NodeID> temporaryPackedPath1;
|
||||
std::vector<NodeID> temporaryPackedPath2;
|
||||
if(INT_MAX != _localUpperbound1) {
|
||||
super::RetrievePackedPathFromHeap(forwardHeap, backwardHeap, middle1, temporaryPackedPath1);
|
||||
// INFO("temporaryPackedPath1 ends with " << *(temporaryPackedPath1.end()-1) );
|
||||
}
|
||||
// INFO("middle2: " << middle2);
|
||||
|
||||
if(INT_MAX != _localUpperbound2) {
|
||||
super::RetrievePackedPathFromHeap(forwardHeap2, backwardHeap2, middle2, temporaryPackedPath2);
|
||||
// INFO("temporaryPackedPath2 ends with " << *(temporaryPackedPath2.end()-1) );
|
||||
}
|
||||
|
||||
//if one of the paths was not found, replace it with the other one.
|
||||
if(0 == temporaryPackedPath1.size()) {
|
||||
// INFO("Deleting path 1");
|
||||
temporaryPackedPath1.insert(temporaryPackedPath1.end(), temporaryPackedPath2.begin(), temporaryPackedPath2.end());
|
||||
_localUpperbound1 = _localUpperbound2;
|
||||
}
|
||||
if(0 == temporaryPackedPath2.size()) {
|
||||
// INFO("Deleting path 2");
|
||||
temporaryPackedPath2.insert(temporaryPackedPath2.end(), temporaryPackedPath1.begin(), temporaryPackedPath1.end());
|
||||
_localUpperbound2 = _localUpperbound1;
|
||||
}
|
||||
|
||||
assert(0 < temporaryPackedPath1.size() && 0 < temporaryPackedPath2.size());
|
||||
|
||||
//Plug paths together, s.t. end of packed path is begin of temporary packed path
|
||||
if(0 < packedPath1.size() && 0 < packedPath2.size() ) {
|
||||
// INFO("Both paths are non-empty");
|
||||
if( *(temporaryPackedPath1.begin()) == *(temporaryPackedPath2.begin())) {
|
||||
// INFO("both paths start with the same node:" << *(temporaryPackedPath1.begin()));
|
||||
//both new route segments start with the same node, thus one of the packedPath must go.
|
||||
assert( (packedPath1.size() == packedPath2.size() ) || (*(packedPath1.end()-1) != *(packedPath2.end()-1)) );
|
||||
if( *(packedPath1.end()-1) == *(temporaryPackedPath1.begin())) {
|
||||
// INFO("Deleting packedPath2 that ends with " << *(packedPath2.end()-1) << ", other ends with " << *(packedPath1.end()-1));
|
||||
packedPath2.clear();
|
||||
packedPath2.insert(packedPath2.end(), packedPath1.begin(), packedPath1.end());
|
||||
distance2 = distance1;
|
||||
// INFO("packedPath2 now ends with " << *(packedPath2.end()-1));
|
||||
} else {
|
||||
// INFO("Deleting path1 that ends with " << *(packedPath1.end()-1) << ", other ends with " << *(packedPath2.end()-1));
|
||||
packedPath1.clear();
|
||||
packedPath1.insert(packedPath1.end(), packedPath2.begin(), packedPath2.end());
|
||||
distance1 = distance2;
|
||||
// INFO("Path1 now ends with " << *(packedPath1.end()-1));
|
||||
}
|
||||
} else {
|
||||
//packed paths 1 and 2 may need to switch.
|
||||
if(*(packedPath1.end()-1) != *(temporaryPackedPath1.begin())) {
|
||||
// INFO("Switching");
|
||||
packedPath1.swap(packedPath2);
|
||||
std::swap(distance1, distance2);
|
||||
}
|
||||
}
|
||||
}
|
||||
packedPath1.insert(packedPath1.end(), temporaryPackedPath1.begin(), temporaryPackedPath1.end());
|
||||
packedPath2.insert(packedPath2.end(), temporaryPackedPath2.begin(), temporaryPackedPath2.end());
|
||||
|
||||
if( (packedPath1.back() == packedPath2.back()) && phantomNodePair.targetPhantom.isBidirected() ) {
|
||||
// INFO("both paths end in same direction on bidirected edge, make sure start only start with : " << packedPath1.back());
|
||||
|
||||
NodeID lastNodeID = packedPath2.back();
|
||||
searchFrom1stStartNode &= !(lastNodeID == phantomNodePair.targetPhantom.edgeBasedNode+1);
|
||||
searchFrom2ndStartNode &= !(lastNodeID == phantomNodePair.targetPhantom.edgeBasedNode);
|
||||
// INFO("Next search from node " << phantomNodePair.targetPhantom.edgeBasedNode << ": " << (searchFrom1stStartNode ? "yes" : "no") );
|
||||
// INFO("Next search from node " << phantomNodePair.targetPhantom.edgeBasedNode+1 << ": " << (searchFrom2ndStartNode ? "yes" : "no") );
|
||||
}
|
||||
|
||||
distance1 += _localUpperbound1;
|
||||
distance2 += _localUpperbound2;
|
||||
}
|
||||
|
||||
// INFO("length path1: " << distance1);
|
||||
// INFO("length path2: " << distance2);
|
||||
if(distance1 <= distance2){
|
||||
//remove consecutive duplicates
|
||||
// std::cout << "unclean 1: ";
|
||||
// for(unsigned i = 0; i < packedPath1.size(); ++i)
|
||||
// std::cout << packedPath1[i] << " ";
|
||||
// std::cout << std::endl;
|
||||
|
||||
// std::cout << "cleaned 1: ";
|
||||
// for(unsigned i = 0; i < packedPath1.size(); ++i)
|
||||
// std::cout << packedPath1[i] << " ";
|
||||
// std::cout << std::endl;
|
||||
// super::UnpackPath(packedPath1, rawRouteData.computedShortestPath);
|
||||
} else {
|
||||
std::swap(packedPath1, packedPath2);
|
||||
// std::cout << "unclean 2: ";
|
||||
// for(unsigned i = 0; i < packedPath2.size(); ++i)
|
||||
// std::cout << packedPath2[i] << " ";
|
||||
// std::cout << std::endl;
|
||||
// _RemoveConsecutiveDuplicatesFromContainer(packedPath2);
|
||||
// std::cout << "cleaned 2: ";
|
||||
// for(unsigned i = 0; i < packedPath2.size(); ++i)
|
||||
// std::cout << packedPath2[i] << " ";
|
||||
// std::cout << std::endl;
|
||||
// super::UnpackPath(packedPath2, unpackedPath);
|
||||
}
|
||||
_RemoveConsecutiveDuplicatesFromContainer(packedPath1);
|
||||
super::UnpackPath(packedPath1, rawRouteData.computedShortestPath);
|
||||
rawRouteData.lengthOfShortestPath = std::min(distance1, distance2);
|
||||
// INFO("Found via route with distance " << std::min(distance1, distance2));
|
||||
return;
|
||||
}
|
||||
private:
|
||||
template<class ContainerT>
|
||||
void _RemoveConsecutiveDuplicatesFromContainer(ContainerT & packedPath) {
|
||||
//remove consecutive duplicates
|
||||
typename ContainerT::iterator it;
|
||||
// using default comparison:
|
||||
it = std::unique(packedPath.begin(), packedPath.end());
|
||||
packedPath.resize(it - packedPath.begin());
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SHORTESTPATHROUTING_H_ */
|
||||
-299
@@ -1,299 +0,0 @@
|
||||
#Sconstruct
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import string
|
||||
import sys
|
||||
from subprocess import call
|
||||
|
||||
def CheckBoost(context, version):
|
||||
# Boost versions are in format major.minor.subminor
|
||||
v_arr = version.split(".")
|
||||
version_n = 0
|
||||
if len(v_arr) > 0:
|
||||
version_n += int(v_arr[0])*100000
|
||||
if len(v_arr) > 1:
|
||||
version_n += int(v_arr[1])*100
|
||||
if len(v_arr) > 2:
|
||||
version_n += int(v_arr[2])
|
||||
|
||||
context.Message('Checking for Boost version >= %s... ' % (version))
|
||||
ret = context.TryRun("""
|
||||
#include <boost/version.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
return BOOST_VERSION >= %d ? 0 : 1;
|
||||
}
|
||||
""" % version_n, '.cpp')[0]
|
||||
context.Result(ret)
|
||||
return ret
|
||||
|
||||
def CheckProtobuf(context, version):
|
||||
# Protobuf versions are in format major.minor.subminor
|
||||
v_arr = version.split(".")
|
||||
version_n = 0
|
||||
if len(v_arr) > 0:
|
||||
version_n += int(v_arr[0])*1000000
|
||||
if len(v_arr) > 1:
|
||||
version_n += int(v_arr[1])*1000
|
||||
if len(v_arr) > 2:
|
||||
version_n += int(v_arr[2])
|
||||
|
||||
context.Message('Checking for Protobuffer version >= %s... ' % (version))
|
||||
ret = context.TryRun("""
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
int main() {
|
||||
return (GOOGLE_PROTOBUF_VERSION >= %d) ? 0 : 1;
|
||||
}
|
||||
""" % version_n, '.cpp')[0]
|
||||
context.Result(ret)
|
||||
return ret
|
||||
|
||||
# Adding various options to the SConstruct
|
||||
AddOption('--cxx', dest='cxx', type='string', nargs=1, action='store', metavar='STRING', help='C++ Compiler')
|
||||
AddOption('--stxxlroot', dest='stxxlroot', type='string', nargs=1, action='store', metavar='STRING', help='root directory of STXXL')
|
||||
AddOption('--verbosity', dest='verbosity', type='string', nargs=1, action='store', metavar='STRING', help='make Scons talking')
|
||||
AddOption('--buildconfiguration', dest='buildconfiguration', type='string', nargs=1, action='store', metavar='STRING', help='debug or release')
|
||||
AddOption('--all-flags', dest='allflags', type='string', nargs=0, action='store', metavar='STRING', help='turn off -march optimization in release mode')
|
||||
AddOption('--with-tools', dest='withtools', type='string', nargs=0, action='store', metavar='STRING', help='build tools for data analysis')
|
||||
AddOption('--no-march', dest='nomarch', type='string', nargs=0, action='store', metavar='STRING', help='turn off native optimizations')
|
||||
|
||||
env = Environment( ENV = {'PATH' : os.environ['PATH']} ,COMPILER = GetOption('cxx'))
|
||||
env["CC"] = os.getenv("CC") or env["CC"]
|
||||
env["CXX"] = os.getenv("CXX") or env["CXX"]
|
||||
env["ENV"].update(x for x in os.environ.items() if x[0].startswith("CCC_"))
|
||||
try:
|
||||
env['ENV']['TERM'] = os.environ['TERM']
|
||||
except KeyError:
|
||||
env['ENV']['TERM'] = 'none'
|
||||
|
||||
conf = Configure(env, custom_tests = { 'CheckBoost' : CheckBoost, 'CheckProtobuf' : CheckProtobuf })
|
||||
|
||||
if GetOption('cxx') is None:
|
||||
#default Compiler
|
||||
if sys.platform == 'darwin': #Mac OS X
|
||||
env['CXX'] = 'clang++'
|
||||
print 'Using default C++ Compiler: ', env['CXX'].strip()
|
||||
else:
|
||||
env.Replace(CXX = GetOption('cxx'))
|
||||
print 'Using user supplied C++ Compiler: ', env['CXX']
|
||||
|
||||
if GetOption('allflags') is not None:
|
||||
env.Append(CXXFLAGS = ["-Wextra", "-Wall", "-Wnon-virtual-dtor", "-Wundef", "-Wno-long-long", "-Woverloaded-virtual", "-Wfloat-equal", "-Wredundant-decls"])
|
||||
|
||||
if "clang" in env["CXX"]:
|
||||
print "Warning building with clang removes OpenMP parallelization"
|
||||
if GetOption('allflags') is not None:
|
||||
env.Append(CXXFLAGS = ["-W#warnings", "-Wc++0x-compat", "-Waddress-of-temporary", "-Wambiguous-member-template", "-Warray-bounds", "-Watomic-properties", "-Wbind-to-temporary-copy", "-Wbuiltin-macro-redefined", "-Wc++-compat", "-Wc++0x-extensions", "-Wcomments", "-Wconditional-uninitialized", "-Wconstant-logical-operand", "-Wdeclaration-after-statement", "-Wdeprecated", "-Wdeprecated-implementations", "-Wdeprecated-writable-strings", "-Wduplicate-method-arg", "-Wempty-body", "-Wendif-labels", "-Wenum-compare", "-Wformat=2", "-Wfour-char-constants", "-Wgnu", "-Wincomplete-implementation", "-Winvalid-noreturn", "-Winvalid-offsetof", "-Winvalid-token-paste", "-Wlocal-type-template-args", "-Wmethod-signatures", "-Wmicrosoft", "-Wmissing-declarations", "-Wnon-pod-varargs", "-Wnonfragile-abi2", "-Wnull-dereference", "-Wout-of-line-declaration", "-Woverlength-strings", "-Wpacked", "-Wpointer-arith", "-Wpointer-sign", "-Wprotocol", "-Wreadonly-setter-attrs", "-Wselector", "-Wshift-overflow", "-Wshift-sign-overflow", "-Wstrict-selector-match", "-Wsuper-class-method-mismatch", "-Wtautological-compare", "-Wtypedef-redefinition", "-Wundeclared-selector", "-Wunnamed-type-template-args", "-Wunused-exception-parameter", "-Wunused-member-function", "-Wused-but-marked-unused", "-Wvariadic-macros"])
|
||||
else:
|
||||
env.Append(CCFLAGS = ['-minline-all-stringops', '-fopenmp'])
|
||||
env.Append(LINKFLAGS = '-fopenmp')
|
||||
|
||||
if GetOption('buildconfiguration') == 'debug':
|
||||
env.Append(CCFLAGS = ['-Wall', '-g3', '-rdynamic'])
|
||||
else:
|
||||
env.Append(CCFLAGS = ['-O3', '-DNDEBUG'])
|
||||
|
||||
if sys.platform == 'darwin': #Mac OS X
|
||||
#os x default installations
|
||||
env.Append(CPPPATH = ['/usr/include/libxml2'] )
|
||||
env.Append(CPPPATH = ['/usr/X11/include']) #comes with os x
|
||||
# env.Append(LIBPATH = ['/usr/X11/lib']) #needed for libpng
|
||||
|
||||
#assume stxxl and boost are installed via homebrew. call brew binary to get folder locations
|
||||
import subprocess
|
||||
stxxl_prefix = subprocess.check_output(["brew", "--prefix", "libstxxl"]).strip()
|
||||
env.Append(CPPPATH = [stxxl_prefix+"/include"] )
|
||||
env.Append(LIBPATH = [stxxl_prefix+"/lib"] )
|
||||
boost_prefix = subprocess.check_output(["brew", "--prefix", "boost"]).strip()
|
||||
env.Append(CPPPATH = [boost_prefix+"/include"] )
|
||||
env.Append(LIBPATH = [boost_prefix+"/lib"] )
|
||||
if not conf.CheckLibWithHeader('lua', 'lua.h', 'C'):
|
||||
print "lua library not found. Exiting"
|
||||
Exit(-1)
|
||||
|
||||
if not conf.CheckLibWithHeader('luabind', 'luabind/luabind.hpp', 'CXX'):
|
||||
print "luabind library not found. Exiting"
|
||||
Exit(-1)
|
||||
|
||||
elif sys.platform.startswith("freebsd"):
|
||||
env.ParseConfig('pkg-config --cflags --libs protobuf')
|
||||
env.Append(CPPPATH = ['/usr/local/include', '/usr/local/include/libxml2'])
|
||||
env.Append(LIBPATH = ['/usr/local/lib'])
|
||||
if GetOption('stxxlroot') is not None:
|
||||
env.Append(CPPPATH = GetOption('stxxlroot')+'/include')
|
||||
env.Append(LIBPATH = GetOption('stxxlroot')+'/lib')
|
||||
print 'STXXLROOT = ', GetOption('stxxlroot')
|
||||
elif sys.platform == 'win32':
|
||||
#SCons really wants to use Microsoft compiler
|
||||
print "Compiling is not yet supported on Windows"
|
||||
Exit(-1)
|
||||
else:
|
||||
print "Default platform"
|
||||
if GetOption('stxxlroot') is not None:
|
||||
env.Append(CPPPATH = GetOption('stxxlroot')+'/include')
|
||||
env.Append(LIBPATH = GetOption('stxxlroot')+'/lib')
|
||||
print 'STXXLROOT = ', GetOption('stxxlroot')
|
||||
env.Append(CPPPATH = ['/usr/include', '/usr/include/include', '/usr/include/libxml2/'])
|
||||
if not conf.CheckLibWithHeader('pthread', 'pthread.h', 'CXX'):
|
||||
print "pthread not found. Exiting"
|
||||
Exit(-1)
|
||||
|
||||
if not conf.CheckLibWithHeader('luajit-5.1', 'luajit-2.0/lua.h', 'CXX'):
|
||||
print "luajit library not found. Checking for interpreter"
|
||||
env.ParseConfig('pkg-config --cflags --libs lua5.1')
|
||||
env.ParseConfig('pkg-config --cflags --libs luabind')
|
||||
|
||||
#Check if architecture optimizations shall be turned off
|
||||
if GetOption('buildconfiguration') != 'debug' and sys.platform != 'darwin' and GetOption('nomarch') is None:
|
||||
env.Append(CCFLAGS = ['-march=native'])
|
||||
|
||||
if not conf.CheckHeader('omp.h'):
|
||||
print "Compiler does not support OpenMP. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckLibWithHeader('bz2', 'bzlib.h', 'CXX'):
|
||||
print "bz2 library not found. Exiting"
|
||||
Exit(-1)
|
||||
if GetOption('withtools') is not None:
|
||||
if not conf.CheckLibWithHeader('gdal', 'gdal/gdal.h', 'CXX'):
|
||||
print "gdal library not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckLibWithHeader('osmpbf', 'osmpbf/osmpbf.h', 'CXX'):
|
||||
print "osmpbf library not found. Exiting"
|
||||
print "Either install libosmpbf-dev (Ubuntu) or use https://github.com/scrosby/OSM-binary"
|
||||
Exit(-1)
|
||||
if not conf.CheckLibWithHeader('protobuf', 'google/protobuf/descriptor.h', 'CXX'):
|
||||
print "Google Protobuffer library not found. Exiting"
|
||||
Exit(-1)
|
||||
#check for protobuf 2.3.0
|
||||
if not (conf.CheckProtobuf('2.3.0')):
|
||||
print 'libprotobuf version >= 2.3.0 needed'
|
||||
Exit(-1);
|
||||
if not (env.Detect('protoc')):
|
||||
print 'protobuffer compiler not found'
|
||||
Exit(-1);
|
||||
if not conf.CheckLibWithHeader('stxxl', 'stxxl.h', 'CXX'):
|
||||
print "stxxl library not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckLibWithHeader('xml2', 'libxml/xmlreader.h', 'CXX'):
|
||||
print "libxml2 library or header not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckLibWithHeader('z', 'zlib.h', 'CXX'):
|
||||
print "zlib library or header not found. Exiting"
|
||||
Exit(-1)
|
||||
#Check BOOST installation
|
||||
if not (conf.CheckBoost('1.44')):
|
||||
print 'Boost version >= 1.44 needed'
|
||||
Exit(-1);
|
||||
if not conf.CheckLib('boost_system', language="C++"):
|
||||
if not conf.CheckLib('boost_system-mt', language="C++"):
|
||||
print "boost_system library not found. Exiting"
|
||||
Exit(-1)
|
||||
else:
|
||||
print "using boost -mt"
|
||||
env.Append(CCFLAGS = ' -lboost_system-mt')
|
||||
env.Append(LINKFLAGS = ' -lboost_system-mt')
|
||||
if not conf.CheckLibWithHeader('boost_thread', 'boost/thread.hpp', 'CXX'):
|
||||
if not conf.CheckLibWithHeader('boost_thread-mt', 'boost/thread.hpp', 'CXX'):
|
||||
print "boost thread library not found. Exiting"
|
||||
Exit(-1)
|
||||
else:
|
||||
print "using boost -mt"
|
||||
env.Append(CCFLAGS = ' -lboost_thread-mt')
|
||||
env.Append(LINKFLAGS = ' -lboost_thread-mt')
|
||||
if not conf.CheckLibWithHeader('boost_regex', 'boost/regex.hpp', 'CXX'):
|
||||
if not conf.CheckLibWithHeader('boost_regex-mt', 'boost/regex.hpp', 'CXX'):
|
||||
print "boost/regex.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
else:
|
||||
print "using boost_regex -mt"
|
||||
env.Append(CCFLAGS = ' -lboost_regex-mt')
|
||||
env.Append(LINKFLAGS = ' -lboost_regex-mt')
|
||||
if not conf.CheckLib('boost_filesystem', language="C++"):
|
||||
if not conf.CheckLib('boost_filesystem-mt', language="C++"):
|
||||
print "boost_filesystem library not found. Exiting"
|
||||
Exit(-1)
|
||||
else:
|
||||
print "using boost -mt"
|
||||
env.Append(CCFLAGS = ' -lboost_filesystem-mt')
|
||||
env.Append(LINKFLAGS = ' -lboost_filesystem-mt')
|
||||
if not conf.CheckCXXHeader('boost/archive/iterators/base64_from_binary.hpp'):
|
||||
print "boost/archive/iterators/base64_from_binary.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/archive/iterators/binary_from_base64.hpp'):
|
||||
print "boost/archive/iterators/binary_from_base64.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/archive/iterators/transform_width.hpp'):
|
||||
print "boost/archive/iterators/transform_width.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/bind.hpp'):
|
||||
print "boost/bind.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/circular_buffer.hpp'):
|
||||
print "boost/circular_buffer.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/enable_shared_from_this.hpp'):
|
||||
print "boost/bind.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/foreach.hpp'):
|
||||
print "boost/foreach.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/lexical_cast.hpp'):
|
||||
print "boost/foreach.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/logic/tribool.hpp'):
|
||||
print "boost/foreach.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/math/tr1.hpp'):
|
||||
print "boost/foreach.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/noncopyable.hpp'):
|
||||
print "boost/noncopyable.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/property_tree/ptree.hpp'):
|
||||
print "boost/property_tree/ptree.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/property_tree/ini_parser.hpp'):
|
||||
print "boost/property_tree/ini_parser.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/shared_ptr.hpp'):
|
||||
print "boost/shared_ptr.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/thread/mutex.hpp'):
|
||||
print "boost/shared_ptr.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/thread/thread.hpp'):
|
||||
print "boost/thread/thread.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/thread/condition.hpp'):
|
||||
print "boost/thread/condition.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/thread/thread.hpp'):
|
||||
print "boost/thread/thread.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/thread.hpp'):
|
||||
print "boost thread header not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/tuple/tuple.hpp'):
|
||||
print "boost thread header not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/unordered_map.hpp'):
|
||||
print "boost thread header not found. Exiting"
|
||||
Exit(-1)
|
||||
|
||||
#checks for intels thread building blocks library
|
||||
#if not conf.CheckLibWithHeader('tbb', 'tbb/tbb.h', 'CXX'):
|
||||
# print "Intel TBB library not found. Exiting"
|
||||
# Exit(-1)
|
||||
#if not conf.CheckCXXHeader('tbb/task_scheduler_init.h'):
|
||||
# print "tbb/task_scheduler_init.h not found. Exiting"
|
||||
# Exit(-1)
|
||||
|
||||
env.Program(target = 'osrm-extract', source = ["extractor.cpp", Glob('Util/*.cpp'), Glob('Extractor/*.cpp')])
|
||||
env.Program(target = 'osrm-prepare', source = ["createHierarchy.cpp", Glob('Contractor/*.cpp'), Glob('Util/SRTMLookup/*.cpp'), Glob('Algorithms/*.cpp')])
|
||||
env.Program(target = 'osrm-routed', source = ["routed.cpp", 'Descriptors/DescriptionFactory.cpp', Glob('ThirdParty/*.cc'), Glob('Server/DataStructures/*.cpp')], CCFLAGS = env['CCFLAGS'] + ['-DROUTED'])
|
||||
if GetOption('withtools') is not None:
|
||||
env.Program(target = 'Tools/osrm-component', source = ["Tools/componentAnalysis.cpp"])
|
||||
env = conf.Finish()
|
||||
|
||||
+37
-26
@@ -1,24 +1,29 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
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_
|
||||
@@ -30,34 +35,40 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
||||
namespace qi = boost::spirit::qi;
|
||||
|
||||
template <typename Iterator, class HandlerT>
|
||||
struct APIGrammar : qi::grammar<Iterator> {
|
||||
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 | alt_route | old_API) ) ;
|
||||
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) >> -(uturns);
|
||||
query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | u | cmp | language | instruction | geometry | alt_route | old_API | num_results) ) ;
|
||||
|
||||
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") >> '=' >> stringwithDot[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)];
|
||||
checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >> qi::int_[boost::bind(&HandlerT::setChecksum, handler, ::_1)];
|
||||
jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >> stringwithPercent[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)];
|
||||
checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >> qi::uint_[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)];
|
||||
u = (-qi::lit('&')) >> qi::lit("u") >> '=' >> qi::bool_[boost::bind(&HandlerT::setUTurn, handler, ::_1)];
|
||||
uturns = (-qi::lit('&')) >> qi::lit("uturns") >> '=' >> qi::bool_[boost::bind(&HandlerT::setAllUTurns, 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)];
|
||||
num_results = (-qi::lit('&')) >> qi::lit("num_results") >> '=' >> qi::short_[boost::bind(&HandlerT::setNumberOfResults, handler, ::_1)];
|
||||
|
||||
string = +(qi::char_("a-zA-Z"));
|
||||
stringwithDot = +(qi::char_("a-zA-Z0-9_.-"));
|
||||
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, language, instruction, geometry,
|
||||
cmp, alt_route, old_API;
|
||||
stringwithDot, stringwithPercent, language, instruction, geometry,
|
||||
cmp, alt_route, u, uturns, old_API, num_results;
|
||||
|
||||
HandlerT * handler;
|
||||
};
|
||||
|
||||
|
||||
#endif /* APIGRAMMAR_H_ */
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef BASIC_DATASTRUCTURES_H
|
||||
#define BASIC_DATASTRUCTURES_H
|
||||
#include <string>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
namespace http {
|
||||
|
||||
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";
|
||||
|
||||
const char okHTML[] = "";
|
||||
const char badRequestHTML[] = "<html><head><title>Bad Request</title></head><body><h1>400 Bad Request</h1></body></html>";
|
||||
const char internalServerErrorHTML[] = "<html><head><title>Internal Server Error</title></head><body><h1>500 Internal Server Error</h1></body></html>";
|
||||
const char seperators[] = { ':', ' ' };
|
||||
const char crlf[] = { '\r', '\n' };
|
||||
|
||||
struct Header {
|
||||
std::string name;
|
||||
std::string value;
|
||||
void Clear() {
|
||||
name.clear();
|
||||
value.clear();
|
||||
}
|
||||
};
|
||||
|
||||
enum CompressionType {
|
||||
noCompression,
|
||||
gzipRFC1952,
|
||||
deflateRFC1951
|
||||
} Compression;
|
||||
|
||||
struct Request {
|
||||
std::string uri;
|
||||
std::string referrer;
|
||||
std::string agent;
|
||||
boost::asio::ip::address endpoint;
|
||||
};
|
||||
|
||||
struct Reply {
|
||||
Reply() : status(ok) { content.reserve(2 << 20); }
|
||||
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::string content;
|
||||
static Reply stockReply(status_type status);
|
||||
void setSize(unsigned size) {
|
||||
for (std::size_t i = 0; i < headers.size(); ++i) {
|
||||
Header& h = headers[i];
|
||||
if("Content-Length" == h.name) {
|
||||
std::stringstream sizeString;
|
||||
sizeString << size;
|
||||
h.value = sizeString.str();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
boost::asio::const_buffer ToBuffer(Reply::status_type status) {
|
||||
switch (status) {
|
||||
case Reply::ok:
|
||||
return boost::asio::buffer(okString);
|
||||
case Reply::internalServerError:
|
||||
return boost::asio::buffer(internalServerErrorString);
|
||||
default:
|
||||
return boost::asio::buffer(badRequestString);
|
||||
}
|
||||
}
|
||||
|
||||
std::string ToString(Reply::status_type status) {
|
||||
switch (status) {
|
||||
case Reply::ok:
|
||||
return okHTML;
|
||||
case Reply::badRequest:
|
||||
return badRequestHTML;
|
||||
default:
|
||||
return internalServerErrorHTML;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<boost::asio::const_buffer> Reply::toBuffers(){
|
||||
std::vector<boost::asio::const_buffer> buffers;
|
||||
buffers.push_back(ToBuffer(status));
|
||||
for (std::size_t i = 0; i < headers.size(); ++i) {
|
||||
Header& h = headers[i];
|
||||
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));
|
||||
buffers.push_back(boost::asio::buffer(content));
|
||||
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& h = headers[i];
|
||||
// std::cout << h.name << ": " << h.value << std::endl;
|
||||
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));
|
||||
return buffers;
|
||||
}
|
||||
|
||||
Reply Reply::stockReply(Reply::status_type status) {
|
||||
Reply rep;
|
||||
rep.status = status;
|
||||
rep.content = ToString(status);
|
||||
rep.headers.resize(2);
|
||||
rep.headers[0].name = "Content-Length";
|
||||
rep.headers[0].value = boost::lexical_cast<std::string>(rep.content.size());
|
||||
rep.headers[1].name = "Content-Type";
|
||||
rep.headers[1].value = "text/html";
|
||||
return rep;
|
||||
}
|
||||
} // namespace http
|
||||
|
||||
#endif //BASIC_DATASTRUCTURES_H
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
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 &error, std::size_t bytes_transferred)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// no error detected, let's parse the request
|
||||
CompressionType compression_type(noCompression);
|
||||
boost::tribool result;
|
||||
boost::tie(result, boost::tuples::ignore) =
|
||||
RequestParser().Parse(request,
|
||||
incoming_data_buffer.data(),
|
||||
incoming_data_buffer.data() + bytes_transferred,
|
||||
compression_type);
|
||||
|
||||
// the request has been parsed
|
||||
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;
|
||||
|
||||
// compress the result w/ gzip/deflate if requested
|
||||
switch (compression_type)
|
||||
{
|
||||
case deflateRFC1951:
|
||||
// use deflate for compression
|
||||
reply.headers.insert(reply.headers.begin(), {"Content-Encoding", "deflate"});
|
||||
CompressBufferCollection(reply.content, compression_type, compressed_output);
|
||||
reply.SetSize(static_cast<unsigned>(compressed_output.size()));
|
||||
output_buffer = reply.HeaderstoBuffers();
|
||||
output_buffer.push_back(boost::asio::buffer(compressed_output));
|
||||
break;
|
||||
case gzipRFC1952:
|
||||
// use gzip for compression
|
||||
reply.headers.insert(reply.headers.begin(), {"Content-Encoding", "gzip"});
|
||||
CompressBufferCollection(reply.content, compression_type, compressed_output);
|
||||
reply.SetSize(static_cast<unsigned>(compressed_output.size()));
|
||||
output_buffer = reply.HeaderstoBuffers();
|
||||
output_buffer.push_back(boost::asio::buffer(compressed_output));
|
||||
break;
|
||||
case noCompression:
|
||||
// don't use any compression
|
||||
reply.SetUncompressedSize();
|
||||
output_buffer = reply.ToBuffers();
|
||||
break;
|
||||
}
|
||||
// write result to stream
|
||||
boost::asio::async_write(TCP_socket,
|
||||
output_buffer,
|
||||
strand.wrap(boost::bind(&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error)));
|
||||
}
|
||||
else if (!result)
|
||||
{ // request is not parseable
|
||||
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
|
||||
{
|
||||
// we don't have a result yet, so continue reading
|
||||
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 &error)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
// Initiate graceful connection closure.
|
||||
boost::system::error_code ignore_error;
|
||||
TCP_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignore_error);
|
||||
}
|
||||
}
|
||||
|
||||
void Connection::CompressBufferCollection(std::vector<char> uncompressed_data,
|
||||
CompressionType compression_type,
|
||||
std::vector<char> &compressed_data)
|
||||
{
|
||||
boost::iostreams::gzip_params compression_parameters;
|
||||
|
||||
// there's a trade-off between speed and size. speed wins
|
||||
compression_parameters.level = boost::iostreams::zlib::best_speed;
|
||||
// check which compression flavor is used
|
||||
if (deflateRFC1951 == compression_type)
|
||||
{
|
||||
compression_parameters.noheader = true;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(compressed_data.empty());
|
||||
// plug data into boost's compression stream
|
||||
boost::iostreams::filtering_ostream gzip_stream;
|
||||
gzip_stream.push(boost::iostreams::gzip_compressor(compression_parameters));
|
||||
gzip_stream.push(boost::iostreams::back_inserter(compressed_data));
|
||||
gzip_stream.write(&uncompressed_data[0], uncompressed_data.size());
|
||||
boost::iostreams::close(gzip_stream);
|
||||
}
|
||||
}
|
||||
+78
-156
@@ -1,180 +1,102 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CONNECTION_H
|
||||
#define CONNECTION_H
|
||||
|
||||
#include <vector>
|
||||
// #include "RequestParser.h"
|
||||
#include "Http/CompressionType.h"
|
||||
#include "Http/Request.h"
|
||||
|
||||
#include <osrm/Reply.h>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#include "../DataStructures/Util.h"
|
||||
#include "BasicDatastructures.h"
|
||||
#include "RequestHandler.h"
|
||||
#include "RequestParser.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "zlib.h"
|
||||
//workaround for incomplete std::shared_ptr compatibility in old boost versions
|
||||
#if BOOST_VERSION < 105300 || defined BOOST_NO_CXX11_SMART_PTR
|
||||
|
||||
namespace http {
|
||||
namespace boost {
|
||||
template<class T>
|
||||
const T* get_pointer(std::shared_ptr<T> const& p)
|
||||
{
|
||||
return p.get();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T* get_pointer(std::shared_ptr<T>& p)
|
||||
{
|
||||
return p.get();
|
||||
}
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
class RequestHandler;
|
||||
|
||||
namespace http
|
||||
{
|
||||
|
||||
/// Represents a single connection from a client.
|
||||
class Connection : public boost::enable_shared_from_this<Connection>, private boost::noncopyable {
|
||||
public:
|
||||
explicit Connection(boost::asio::io_service& io_service, RequestHandler& handler) : strand(io_service), TCPsocket(io_service), requestHandler(handler) {}
|
||||
class Connection : public std::enable_shared_from_this<Connection>
|
||||
{
|
||||
public:
|
||||
explicit Connection(boost::asio::io_service &io_service, RequestHandler &handler);
|
||||
Connection(const Connection &) = delete;
|
||||
Connection() = delete;
|
||||
|
||||
boost::asio::ip::tcp::socket& socket() {
|
||||
return TCPsocket;
|
||||
}
|
||||
boost::asio::ip::tcp::socket &socket();
|
||||
|
||||
/// Start the first asynchronous operation for the connection.
|
||||
void start() {
|
||||
TCPsocket.async_read_some(boost::asio::buffer(incomingDataBuffer), strand.wrap( boost::bind(&Connection::handleRead, this->shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)));
|
||||
}
|
||||
/// Start the first asynchronous operation for the connection.
|
||||
void start();
|
||||
|
||||
private:
|
||||
void handleRead(const boost::system::error_code& e, std::size_t bytes_transferred) {
|
||||
if (!e) {
|
||||
CompressionType compressionType(noCompression);
|
||||
boost::tribool result;
|
||||
boost::tie(result, boost::tuples::ignore) = requestParser.Parse( request, incomingDataBuffer.data(), incomingDataBuffer.data() + bytes_transferred, &compressionType);
|
||||
private:
|
||||
void handle_read(const boost::system::error_code &e, std::size_t bytes_transferred);
|
||||
|
||||
if (result) {
|
||||
// std::cout << "----" << std::endl;
|
||||
// if(compressionType == gzipRFC1952)
|
||||
// std::cout << "[debug] using gzip" << std::endl;
|
||||
// if(compressionType == deflateRFC1951)
|
||||
// std::cout << "[debug] using deflate" << std::endl;
|
||||
// if(compressionType == noCompression)
|
||||
// std::cout << "[debug] no compression" << std::endl;
|
||||
request.endpoint = TCPsocket.remote_endpoint().address();
|
||||
requestHandler.handle_request(request, reply);
|
||||
/// Handle completion of a write operation.
|
||||
void handle_write(const boost::system::error_code &e);
|
||||
|
||||
Header compressionHeader;
|
||||
std::vector<unsigned char> compressed;
|
||||
std::vector<boost::asio::const_buffer> outputBuffer;
|
||||
switch(compressionType) {
|
||||
case deflateRFC1951:
|
||||
compressionHeader.name = "Content-Encoding";
|
||||
compressionHeader.value = "deflate";
|
||||
reply.headers.insert(reply.headers.begin(), compressionHeader); //push_back(compressionHeader);
|
||||
compressCharArray(reply.content.c_str(), reply.content.length(), compressed, compressionType);
|
||||
reply.setSize(compressed.size());
|
||||
outputBuffer = reply.HeaderstoBuffers();
|
||||
outputBuffer.push_back(boost::asio::buffer(compressed));
|
||||
boost::asio::async_write(TCPsocket, outputBuffer, strand.wrap( boost::bind(&Connection::handleWrite, this->shared_from_this(), boost::asio::placeholders::error)));
|
||||
break;
|
||||
case gzipRFC1952:
|
||||
compressionHeader.name = "Content-Encoding";
|
||||
compressionHeader.value = "gzip";
|
||||
reply.headers.insert(reply.headers.begin(), compressionHeader);
|
||||
compressCharArray(reply.content.c_str(), reply.content.length(), compressed, compressionType);
|
||||
reply.setSize(compressed.size());
|
||||
outputBuffer = reply.HeaderstoBuffers();
|
||||
outputBuffer.push_back(boost::asio::buffer(compressed));
|
||||
boost::asio::async_write(TCPsocket, outputBuffer, strand.wrap( boost::bind(&Connection::handleWrite, this->shared_from_this(), boost::asio::placeholders::error)));break;
|
||||
case noCompression:
|
||||
boost::asio::async_write(TCPsocket, reply.toBuffers(), strand.wrap( boost::bind(&Connection::handleWrite, this->shared_from_this(), boost::asio::placeholders::error)));
|
||||
break;
|
||||
}
|
||||
void CompressBufferCollection(std::vector<char> uncompressed_data,
|
||||
CompressionType compression_type,
|
||||
std::vector<char> &compressed_data);
|
||||
|
||||
} else if (!result) {
|
||||
reply = Reply::stockReply(Reply::badRequest);
|
||||
boost::asio::async_write(TCPsocket, reply.toBuffers(), strand.wrap( boost::bind(&Connection::handleWrite, this->shared_from_this(), boost::asio::placeholders::error)));
|
||||
} else {
|
||||
TCPsocket.async_read_some(boost::asio::buffer(incomingDataBuffer), strand.wrap( boost::bind(&Connection::handleRead, this->shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle completion of a write operation.
|
||||
void handleWrite(const boost::system::error_code& e) {
|
||||
if (!e) {
|
||||
// Initiate graceful connection closure.
|
||||
boost::system::error_code ignoredEC;
|
||||
TCPsocket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignoredEC);
|
||||
}
|
||||
// No new asynchronous operations are started. This means that all shared_ptr
|
||||
// references to the connection object will disappear and the object will be
|
||||
// destroyed automatically after this handler returns. The connection class's
|
||||
// destructor closes the socket.
|
||||
}
|
||||
|
||||
void compressCharArray(const void *in_data, size_t in_data_size, std::vector<unsigned char> &buffer, CompressionType type) {
|
||||
const size_t BUFSIZE = 128 * 1024;
|
||||
unsigned char temp_buffer[BUFSIZE];
|
||||
|
||||
z_stream strm;
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
strm.total_out = 0;
|
||||
strm.next_in = (unsigned char *)(in_data);
|
||||
strm.avail_in = in_data_size;
|
||||
strm.next_out = temp_buffer;
|
||||
strm.avail_out = BUFSIZE;
|
||||
strm.data_type = Z_ASCII;
|
||||
|
||||
switch(type){
|
||||
case deflateRFC1951:
|
||||
deflateInit(&strm, Z_BEST_SPEED);
|
||||
break;
|
||||
case gzipRFC1952:
|
||||
/*
|
||||
* Big thanks to deusty who explains how to have gzip compression turned on by the right call to deflateInit2():
|
||||
* http://deusty.blogspot.com/2007/07/gzip-compressiondecompression.html
|
||||
*/
|
||||
deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 9, Z_DEFAULT_STRATEGY);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
int deflate_res = Z_OK;
|
||||
do {
|
||||
if (strm.avail_out == 0) {
|
||||
buffer.insert(buffer.end(), temp_buffer, temp_buffer + BUFSIZE);
|
||||
strm.next_out = temp_buffer;
|
||||
strm.avail_out = BUFSIZE;
|
||||
}
|
||||
deflate_res = deflate(&strm, Z_FINISH);
|
||||
|
||||
} while (deflate_res == Z_OK);
|
||||
|
||||
assert(deflate_res == Z_STREAM_END);
|
||||
buffer.insert(buffer.end(), temp_buffer, temp_buffer + BUFSIZE - strm.avail_out);
|
||||
deflateEnd(&strm);
|
||||
}
|
||||
|
||||
boost::asio::io_service::strand strand;
|
||||
boost::asio::ip::tcp::socket TCPsocket;
|
||||
RequestHandler& requestHandler;
|
||||
boost::array<char, 8192> incomingDataBuffer;
|
||||
Request request;
|
||||
RequestParser requestParser;
|
||||
Reply reply;
|
||||
boost::asio::io_service::strand strand;
|
||||
boost::asio::ip::tcp::socket TCP_socket;
|
||||
RequestHandler &request_handler;
|
||||
boost::array<char, 8192> incoming_data_buffer;
|
||||
Request request;
|
||||
Reply reply;
|
||||
};
|
||||
|
||||
} // namespace http
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
|
||||
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 BASE_DATA_FACADE_H
|
||||
#define BASE_DATA_FACADE_H
|
||||
|
||||
// Exposes all data access interfaces to the algorithms via base class ptr
|
||||
|
||||
#include "../../data_structures/edge_based_node.hpp"
|
||||
#include "../../data_structures/external_memory_node.hpp"
|
||||
#include "../../data_structures/phantom_node.hpp"
|
||||
#include "../../data_structures/turn_instructions.hpp"
|
||||
#include "../../Util/integer_range.hpp"
|
||||
#include "../../Util/OSRMException.h"
|
||||
#include "../../Util/StringUtil.h"
|
||||
#include "../../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
typedef osrm::range<EdgeID> EdgeRange;
|
||||
|
||||
template <class EdgeDataT> class BaseDataFacade
|
||||
{
|
||||
public:
|
||||
typedef EdgeBasedNode RTreeLeaf;
|
||||
typedef EdgeDataT EdgeData;
|
||||
BaseDataFacade() {}
|
||||
virtual ~BaseDataFacade() {}
|
||||
|
||||
// search graph access
|
||||
virtual unsigned GetNumberOfNodes() const = 0;
|
||||
|
||||
virtual unsigned GetNumberOfEdges() const = 0;
|
||||
|
||||
virtual unsigned GetOutDegree(const NodeID n) const = 0;
|
||||
|
||||
virtual NodeID GetTarget(const EdgeID e) const = 0;
|
||||
|
||||
// virtual EdgeDataT &GetEdgeData(const EdgeID e) = 0;
|
||||
|
||||
virtual const EdgeDataT &GetEdgeData(const EdgeID e) const = 0;
|
||||
|
||||
virtual EdgeID BeginEdges(const NodeID n) const = 0;
|
||||
|
||||
virtual EdgeID EndEdges(const NodeID n) const = 0;
|
||||
|
||||
virtual EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0;
|
||||
|
||||
// searches for a specific edge
|
||||
virtual EdgeID FindEdge(const NodeID from, const NodeID to) const = 0;
|
||||
|
||||
virtual EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const = 0;
|
||||
|
||||
virtual EdgeID
|
||||
FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const = 0;
|
||||
|
||||
// node and edge information access
|
||||
virtual FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const = 0;
|
||||
|
||||
virtual bool EdgeIsCompressed(const unsigned id) const = 0;
|
||||
|
||||
virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const = 0;
|
||||
|
||||
virtual void GetUncompressedGeometry(const unsigned id,
|
||||
std::vector<unsigned> &result_nodes) const = 0;
|
||||
|
||||
virtual TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const = 0;
|
||||
|
||||
virtual TravelMode GetTravelModeForEdgeID(const unsigned id) const = 0;
|
||||
|
||||
virtual bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
FixedPointCoordinate &result,
|
||||
const unsigned zoom_level = 18) = 0;
|
||||
|
||||
virtual bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
PhantomNode &resulting_phantom_node,
|
||||
const unsigned zoom_level) = 0;
|
||||
|
||||
virtual bool
|
||||
IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
std::vector<PhantomNode> &resulting_phantom_node_vector,
|
||||
const unsigned zoom_level,
|
||||
const unsigned number_of_results) = 0;
|
||||
|
||||
virtual bool
|
||||
IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
PhantomNode &resulting_phantom_node,
|
||||
const unsigned zoom_leve) = 0;
|
||||
|
||||
virtual unsigned GetCheckSum() const = 0;
|
||||
|
||||
virtual unsigned GetNameIndexFromEdgeID(const unsigned id) const = 0;
|
||||
|
||||
virtual void GetName(const unsigned name_id, std::string &result) const = 0;
|
||||
|
||||
std::string GetEscapedNameForNameID(const unsigned name_id) const
|
||||
{
|
||||
std::string temporary_string;
|
||||
GetName(name_id, temporary_string);
|
||||
return EscapeJSONString(temporary_string);
|
||||
}
|
||||
|
||||
virtual std::string GetTimestamp() const = 0;
|
||||
};
|
||||
|
||||
#endif // BASE_DATA_FACADE_H
|
||||
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
|
||||
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 "../../data_structures/original_edge_data.hpp"
|
||||
#include "../../data_structures/query_node.hpp"
|
||||
#include "../../data_structures/query_edge.hpp"
|
||||
#include "../../data_structures/shared_memory_vector_wrapper.hpp"
|
||||
#include "../../data_structures/static_graph.hpp"
|
||||
#include "../../data_structures/static_rtree.hpp"
|
||||
#include "../../data_structures/range_table.hpp"
|
||||
#include "../../Util/BoostFileSystemFix.h"
|
||||
#include "../../Util/graph_loader.hpp"
|
||||
#include "../../Util/simple_logger.hpp"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
#include <osrm/ServerPaths.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<TravelMode, false>::vector m_travel_mode_list;
|
||||
ShM<char, false>::vector m_names_char_list;
|
||||
ShM<bool, false>::vector m_edge_is_compressed;
|
||||
ShM<unsigned, false>::vector m_geometry_indices;
|
||||
ShM<unsigned, false>::vector m_geometry_list;
|
||||
|
||||
boost::thread_specific_ptr<
|
||||
StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false>> m_static_rtree;
|
||||
boost::filesystem::path ram_index_path;
|
||||
boost::filesystem::path file_index_path;
|
||||
RangeTable<16, false> m_name_table;
|
||||
|
||||
void LoadTimestamp(const boost::filesystem::path ×tamp_path)
|
||||
{
|
||||
if (boost::filesystem::exists(timestamp_path))
|
||||
{
|
||||
SimpleLogger().Write() << "Loading Timestamp";
|
||||
boost::filesystem::ifstream timestamp_stream(timestamp_path);
|
||||
if (!timestamp_stream)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << timestamp_path << " not found";
|
||||
}
|
||||
getline(timestamp_stream, m_timestamp);
|
||||
timestamp_stream.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);
|
||||
|
||||
QueryNode 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(QueryNode));
|
||||
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_travel_mode_list.resize(number_of_edges);
|
||||
m_edge_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_travel_mode_list[i] = current_edge_data.travel_mode;
|
||||
m_edge_is_compressed[i] = current_edge_data.compressed_geometry;
|
||||
if (m_edge_is_compressed[i])
|
||||
{
|
||||
++compressed;
|
||||
}
|
||||
}
|
||||
|
||||
edges_input_stream.close();
|
||||
}
|
||||
|
||||
void LoadGeometries(const boost::filesystem::path &geometry_file)
|
||||
{
|
||||
std::ifstream geometry_stream(geometry_file.string().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);
|
||||
if (number_of_indices > 0)
|
||||
{
|
||||
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);
|
||||
|
||||
if (number_of_compressed_geometries > 0)
|
||||
{
|
||||
geometry_stream.read((char *)&(m_geometry_list[0]),
|
||||
number_of_compressed_geometries * sizeof(unsigned));
|
||||
}
|
||||
geometry_stream.close();
|
||||
}
|
||||
|
||||
void LoadRTree()
|
||||
{
|
||||
BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
|
||||
|
||||
m_static_rtree.reset(
|
||||
new 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);
|
||||
|
||||
name_stream >> m_name_table;
|
||||
|
||||
unsigned number_of_chars = 0;
|
||||
name_stream.read((char *)&number_of_chars, sizeof(unsigned));
|
||||
BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
|
||||
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));
|
||||
if (0 == m_names_char_list.size())
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "list of street names is empty";
|
||||
}
|
||||
name_stream.close();
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~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);
|
||||
ram_index_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("fileindex");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
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";
|
||||
AssertPathExists(hsgr_path);
|
||||
LoadGraph(hsgr_path);
|
||||
SimpleLogger().Write() << "loading edge information";
|
||||
AssertPathExists(nodes_data_path);
|
||||
AssertPathExists(edges_data_path);
|
||||
LoadNodeAndEdgeInformation(nodes_data_path, edges_data_path);
|
||||
SimpleLogger().Write() << "loading geometries";
|
||||
AssertPathExists(geometries_path);
|
||||
LoadGeometries(geometries_path);
|
||||
SimpleLogger().Write() << "loading r-tree";
|
||||
AssertPathExists(ram_index_path);
|
||||
AssertPathExists(file_index_path);
|
||||
SimpleLogger().Write() << "loading timestamp";
|
||||
LoadTimestamp(timestamp_path);
|
||||
SimpleLogger().Write() << "loading street names";
|
||||
AssertPathExists(names_data_path);
|
||||
LoadStreetNames(names_data_path);
|
||||
}
|
||||
|
||||
// search graph access
|
||||
unsigned GetNumberOfNodes() const final { return m_query_graph->GetNumberOfNodes(); }
|
||||
|
||||
unsigned GetNumberOfEdges() const final { return m_query_graph->GetNumberOfEdges(); }
|
||||
|
||||
unsigned GetOutDegree(const NodeID n) const final { return m_query_graph->GetOutDegree(n); }
|
||||
|
||||
NodeID GetTarget(const EdgeID e) const final { return m_query_graph->GetTarget(e); }
|
||||
|
||||
// EdgeDataT &GetEdgeData(const EdgeID e) final { return m_query_graph->GetEdgeData(e); }
|
||||
|
||||
EdgeDataT &GetEdgeData(const EdgeID e) const final { return m_query_graph->GetEdgeData(e); }
|
||||
|
||||
EdgeID BeginEdges(const NodeID n) const final { return m_query_graph->BeginEdges(n); }
|
||||
|
||||
EdgeID EndEdges(const NodeID n) const final { return m_query_graph->EndEdges(n); }
|
||||
|
||||
EdgeRange GetAdjacentEdgeRange(const NodeID node) const final
|
||||
{
|
||||
return m_query_graph->GetAdjacentEdgeRange(node);
|
||||
};
|
||||
|
||||
// searches for a specific edge
|
||||
EdgeID FindEdge(const NodeID from, const NodeID to) const final
|
||||
{
|
||||
return m_query_graph->FindEdge(from, to);
|
||||
}
|
||||
|
||||
EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const final
|
||||
{
|
||||
return m_query_graph->FindEdgeInEitherDirection(from, to);
|
||||
}
|
||||
|
||||
EdgeID FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const final
|
||||
{
|
||||
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
|
||||
}
|
||||
|
||||
// node and edge information access
|
||||
FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const final
|
||||
{
|
||||
return m_coordinate_list->at(id);
|
||||
};
|
||||
|
||||
bool EdgeIsCompressed(const unsigned id) const { return m_edge_is_compressed.at(id); }
|
||||
|
||||
TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const final
|
||||
{
|
||||
return m_turn_instruction_list.at(id);
|
||||
}
|
||||
|
||||
TravelMode GetTravelModeForEdgeID(const unsigned id) const
|
||||
{
|
||||
return m_travel_mode_list.at(id);
|
||||
}
|
||||
|
||||
bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
FixedPointCoordinate &result,
|
||||
const unsigned zoom_level = 18) final
|
||||
{
|
||||
if (!m_static_rtree.get())
|
||||
{
|
||||
LoadRTree();
|
||||
}
|
||||
|
||||
return m_static_rtree->LocateClosestEndPointForCoordinate(
|
||||
input_coordinate, result, zoom_level);
|
||||
}
|
||||
|
||||
bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
PhantomNode &resulting_phantom_node,
|
||||
const unsigned zoom_level) final
|
||||
{
|
||||
if (!m_static_rtree.get())
|
||||
{
|
||||
LoadRTree();
|
||||
}
|
||||
|
||||
return m_static_rtree->FindPhantomNodeForCoordinate(
|
||||
input_coordinate, resulting_phantom_node, zoom_level);
|
||||
}
|
||||
|
||||
bool
|
||||
IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
PhantomNode &resulting_phantom_node,
|
||||
const unsigned zoom_level) final
|
||||
{
|
||||
std::vector<PhantomNode> resulting_phantom_node_vector;
|
||||
auto result = IncrementalFindPhantomNodeForCoordinate(input_coordinate,
|
||||
resulting_phantom_node_vector,
|
||||
zoom_level,
|
||||
1);
|
||||
if (result)
|
||||
{
|
||||
BOOST_ASSERT(!resulting_phantom_node_vector.empty());
|
||||
resulting_phantom_node = resulting_phantom_node_vector.front();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
std::vector<PhantomNode> &resulting_phantom_node_vector,
|
||||
const unsigned zoom_level,
|
||||
const unsigned number_of_results) final
|
||||
{
|
||||
if (!m_static_rtree.get())
|
||||
{
|
||||
LoadRTree();
|
||||
}
|
||||
|
||||
return m_static_rtree->IncrementalFindPhantomNodeForCoordinate(
|
||||
input_coordinate, resulting_phantom_node_vector, zoom_level, number_of_results);
|
||||
}
|
||||
|
||||
unsigned GetCheckSum() const final { return m_check_sum; }
|
||||
|
||||
unsigned GetNameIndexFromEdgeID(const unsigned id) const final
|
||||
{
|
||||
return m_name_ID_list.at(id);
|
||||
};
|
||||
|
||||
void GetName(const unsigned name_id, std::string &result) const final
|
||||
{
|
||||
if (UINT_MAX == name_id)
|
||||
{
|
||||
result = "";
|
||||
return;
|
||||
}
|
||||
auto range = m_name_table.GetRange(name_id);
|
||||
|
||||
result.clear();
|
||||
if (range.begin() != range.end())
|
||||
{
|
||||
result.resize(range.back() - range.front() + 1);
|
||||
std::copy(m_names_char_list.begin() + range.front(),
|
||||
m_names_char_list.begin() + range.back() + 1,
|
||||
result.begin());
|
||||
}
|
||||
}
|
||||
|
||||
virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const final
|
||||
{
|
||||
return m_via_node_list.at(id);
|
||||
}
|
||||
|
||||
virtual void GetUncompressedGeometry(const unsigned id,
|
||||
std::vector<unsigned> &result_nodes) const final
|
||||
{
|
||||
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 final { return m_timestamp; }
|
||||
};
|
||||
|
||||
#endif // INTERNAL_DATA_FACADE
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
|
||||
#include "QueryObjectsStorage.h"
|
||||
#include "../../Util/GraphLoader.h"
|
||||
|
||||
QueryObjectsStorage::QueryObjectsStorage(std::string hsgrPath, std::string ramIndexPath, std::string fileIndexPath, std::string nodesPath, std::string edgesPath, std::string namesPath, std::string timestampPath) {
|
||||
INFO("loading graph data");
|
||||
std::ifstream hsgrInStream(hsgrPath.c_str(), std::ios::binary);
|
||||
if(!hsgrInStream) { ERR(hsgrPath << " not found"); }
|
||||
//Deserialize road network graph
|
||||
std::vector< QueryGraph::_StrNode> nodeList;
|
||||
std::vector< QueryGraph::_StrEdge> edgeList;
|
||||
const int n = readHSGRFromStream(hsgrInStream, nodeList, edgeList, &checkSum);
|
||||
|
||||
INFO("Data checksum is " << checkSum);
|
||||
graph = new QueryGraph(nodeList, edgeList);
|
||||
assert(0 == nodeList.size());
|
||||
assert(0 == edgeList.size());
|
||||
|
||||
if(timestampPath.length()) {
|
||||
INFO("Loading Timestamp");
|
||||
std::ifstream timestampInStream(timestampPath.c_str());
|
||||
if(!timestampInStream) { ERR(timestampPath << " not found"); }
|
||||
|
||||
getline(timestampInStream, timestamp);
|
||||
timestampInStream.close();
|
||||
}
|
||||
if(!timestamp.length())
|
||||
timestamp = "n/a";
|
||||
if(25 < timestamp.length())
|
||||
timestamp.resize(25);
|
||||
|
||||
INFO("Loading auxiliary information");
|
||||
//Init nearest neighbor data structure
|
||||
std::ifstream nodesInStream(nodesPath.c_str(), std::ios::binary);
|
||||
if(!nodesInStream) { ERR(nodesPath << " not found"); }
|
||||
std::ifstream edgesInStream(edgesPath.c_str(), std::ios::binary);
|
||||
if(!edgesInStream) { ERR(edgesPath << " not found"); }
|
||||
nodeHelpDesk = new NodeInformationHelpDesk(ramIndexPath.c_str(), fileIndexPath.c_str(), n, checkSum);
|
||||
nodeHelpDesk->initNNGrid(nodesInStream, edgesInStream);
|
||||
|
||||
//deserialize street name list
|
||||
INFO("Loading names index");
|
||||
std::ifstream namesInStream(namesPath.c_str(), std::ios::binary);
|
||||
if(!namesInStream) { ERR(namesPath << " not found"); }
|
||||
unsigned size(0);
|
||||
namesInStream.read((char *)&size, sizeof(unsigned));
|
||||
// names = new std::vector<std::string>();
|
||||
|
||||
char buf[1024];
|
||||
for(unsigned i = 0; i < size; ++i) {
|
||||
unsigned sizeOfString = 0;
|
||||
namesInStream.read((char *)&sizeOfString, sizeof(unsigned));
|
||||
buf[sizeOfString] = '\0'; // instead of memset
|
||||
namesInStream.read(buf, sizeOfString);
|
||||
names.push_back(buf);
|
||||
}
|
||||
std::vector<std::string>(names).swap(names);
|
||||
hsgrInStream.close();
|
||||
namesInStream.close();
|
||||
INFO("All query data structures loaded");
|
||||
}
|
||||
|
||||
QueryObjectsStorage::~QueryObjectsStorage() {
|
||||
// delete names;
|
||||
delete graph;
|
||||
delete nodeHelpDesk;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QUERYOBJECTSSTORAGE_H_
|
||||
#define QUERYOBJECTSSTORAGE_H_
|
||||
|
||||
#include<vector>
|
||||
#include<string>
|
||||
|
||||
#include "../../DataStructures/NodeInformationHelpDesk.h"
|
||||
#include "../../DataStructures/QueryEdge.h"
|
||||
#include "../../DataStructures/StaticGraph.h"
|
||||
|
||||
struct QueryObjectsStorage {
|
||||
typedef StaticGraph<QueryEdge::EdgeData> QueryGraph;
|
||||
typedef QueryGraph::InputEdge InputEdge;
|
||||
|
||||
NodeInformationHelpDesk * nodeHelpDesk;
|
||||
std::vector<std::string> names;
|
||||
QueryGraph * graph;
|
||||
std::string timestamp;
|
||||
unsigned checkSum;
|
||||
|
||||
QueryObjectsStorage(std::string hsgrPath, std::string ramIndexPath, std::string fileIndexPath, std::string nodesPath, std::string edgesPath, std::string namesPath, std::string timestampPath);
|
||||
|
||||
~QueryObjectsStorage();
|
||||
};
|
||||
|
||||
#endif /* QUERYOBJECTSSTORAGE_H_ */
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SHARED_BARRIER_H
|
||||
#define SHARED_BARRIER_H
|
||||
|
||||
#include <boost/interprocess/sync/named_mutex.hpp>
|
||||
#include <boost/interprocess/sync/named_condition.hpp>
|
||||
|
||||
struct SharedBarriers
|
||||
{
|
||||
|
||||
SharedBarriers()
|
||||
: pending_update_mutex(boost::interprocess::open_or_create, "pending_update"),
|
||||
update_mutex(boost::interprocess::open_or_create, "update"),
|
||||
query_mutex(boost::interprocess::open_or_create, "query"),
|
||||
no_running_queries_condition(boost::interprocess::open_or_create, "no_running_queries"),
|
||||
update_ongoing(false), number_of_queries(0)
|
||||
{
|
||||
}
|
||||
|
||||
// Mutex to protect access to the boolean variable
|
||||
boost::interprocess::named_mutex pending_update_mutex;
|
||||
boost::interprocess::named_mutex update_mutex;
|
||||
boost::interprocess::named_mutex query_mutex;
|
||||
|
||||
// Condition that no update is running
|
||||
boost::interprocess::named_condition no_running_queries_condition;
|
||||
|
||||
// Is there an ongoing update?
|
||||
bool update_ongoing;
|
||||
// Is there any query?
|
||||
int number_of_queries;
|
||||
};
|
||||
|
||||
#endif // SHARED_BARRIER_H
|
||||
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
|
||||
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 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 "../../data_structures/range_table.hpp"
|
||||
#include "../../data_structures/static_graph.hpp"
|
||||
#include "../../data_structures/static_rtree.hpp"
|
||||
#include "../../Util/BoostFileSystemFix.h"
|
||||
#include "../../Util/make_unique.hpp"
|
||||
#include "../../Util/simple_logger.hpp"
|
||||
|
||||
#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 RangeTable<16, true>::BlockT NameIndexBlock;
|
||||
typedef typename QueryGraph::InputEdge InputEdge;
|
||||
typedef typename super::RTreeLeaf RTreeLeaf;
|
||||
using SharedRTree = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>;
|
||||
using TimeStampedRTreePair = std::pair<unsigned, std::shared_ptr<SharedRTree>>;
|
||||
using RTreeNode = typename SharedRTree::TreeNode;
|
||||
|
||||
SharedDataLayout *data_layout;
|
||||
char *shared_memory;
|
||||
SharedDataTimestamp *data_timestamp_ptr;
|
||||
|
||||
SharedDataType CURRENT_LAYOUT;
|
||||
SharedDataType CURRENT_DATA;
|
||||
unsigned CURRENT_TIMESTAMP;
|
||||
|
||||
unsigned m_check_sum;
|
||||
std::unique_ptr<QueryGraph> m_query_graph;
|
||||
std::unique_ptr<SharedMemory> m_layout_memory;
|
||||
std::unique_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<TravelMode, true>::vector m_travel_mode_list;
|
||||
ShM<char, true>::vector m_names_char_list;
|
||||
ShM<unsigned, true>::vector m_name_begin_indices;
|
||||
ShM<bool, true>::vector m_edge_is_compressed;
|
||||
ShM<unsigned, true>::vector m_geometry_indices;
|
||||
ShM<unsigned, true>::vector m_geometry_list;
|
||||
|
||||
boost::thread_specific_ptr<std::pair<unsigned, std::shared_ptr<SharedRTree>>> m_static_rtree;
|
||||
boost::filesystem::path file_index_path;
|
||||
|
||||
std::shared_ptr<RangeTable<16, true>> m_name_table;
|
||||
|
||||
void LoadChecksum()
|
||||
{
|
||||
m_check_sum =
|
||||
*data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::HSGR_CHECKSUM);
|
||||
SimpleLogger().Write() << "set checksum: " << m_check_sum;
|
||||
}
|
||||
|
||||
void LoadTimestamp()
|
||||
{
|
||||
char *timestamp_ptr =
|
||||
data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::TIMESTAMP);
|
||||
m_timestamp.resize(data_layout->GetBlockSize(SharedDataLayout::TIMESTAMP));
|
||||
std::copy(timestamp_ptr,
|
||||
timestamp_ptr + data_layout->GetBlockSize(SharedDataLayout::TIMESTAMP),
|
||||
m_timestamp.begin());
|
||||
}
|
||||
|
||||
void LoadRTree()
|
||||
{
|
||||
BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
|
||||
|
||||
RTreeNode *tree_ptr =
|
||||
data_layout->GetBlockPtr<RTreeNode>(shared_memory, SharedDataLayout::R_SEARCH_TREE);
|
||||
m_static_rtree.reset(new TimeStampedRTreePair(CURRENT_TIMESTAMP,
|
||||
osrm::make_unique<SharedRTree>(
|
||||
tree_ptr,
|
||||
data_layout->num_entries[SharedDataLayout::R_SEARCH_TREE],
|
||||
file_index_path,
|
||||
m_coordinate_list)));
|
||||
}
|
||||
|
||||
void LoadGraph()
|
||||
{
|
||||
GraphNode *graph_nodes_ptr =
|
||||
data_layout->GetBlockPtr<GraphNode>(shared_memory, SharedDataLayout::GRAPH_NODE_LIST);
|
||||
|
||||
GraphEdge *graph_edges_ptr =
|
||||
data_layout->GetBlockPtr<GraphEdge>(shared_memory, SharedDataLayout::GRAPH_EDGE_LIST);
|
||||
|
||||
typename ShM<GraphNode, true>::vector node_list(
|
||||
graph_nodes_ptr, data_layout->num_entries[SharedDataLayout::GRAPH_NODE_LIST]);
|
||||
typename ShM<GraphEdge, true>::vector edge_list(
|
||||
graph_edges_ptr, data_layout->num_entries[SharedDataLayout::GRAPH_EDGE_LIST]);
|
||||
m_query_graph.reset(new QueryGraph(node_list, edge_list));
|
||||
}
|
||||
|
||||
void LoadNodeAndEdgeInformation()
|
||||
{
|
||||
|
||||
FixedPointCoordinate *coordinate_list_ptr = data_layout->GetBlockPtr<FixedPointCoordinate>(
|
||||
shared_memory, SharedDataLayout::COORDINATE_LIST);
|
||||
m_coordinate_list = osrm::make_unique<ShM<FixedPointCoordinate, true>::vector>(
|
||||
coordinate_list_ptr, data_layout->num_entries[SharedDataLayout::COORDINATE_LIST]);
|
||||
|
||||
TravelMode *travel_mode_list_ptr = data_layout->GetBlockPtr<TravelMode>(
|
||||
shared_memory, SharedDataLayout::TRAVEL_MODE);
|
||||
typename ShM<TravelMode, true>::vector travel_mode_list(
|
||||
travel_mode_list_ptr,
|
||||
data_layout->num_entries[SharedDataLayout::TRAVEL_MODE]);
|
||||
m_travel_mode_list.swap(travel_mode_list);
|
||||
|
||||
TurnInstruction *turn_instruction_list_ptr = data_layout->GetBlockPtr<TurnInstruction>(
|
||||
shared_memory, SharedDataLayout::TURN_INSTRUCTION);
|
||||
typename ShM<TurnInstruction, true>::vector turn_instruction_list(
|
||||
turn_instruction_list_ptr,
|
||||
data_layout->num_entries[SharedDataLayout::TURN_INSTRUCTION]);
|
||||
m_turn_instruction_list.swap(turn_instruction_list);
|
||||
|
||||
unsigned *name_id_list_ptr =
|
||||
data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::NAME_ID_LIST);
|
||||
typename ShM<unsigned, true>::vector name_id_list(
|
||||
name_id_list_ptr, data_layout->num_entries[SharedDataLayout::NAME_ID_LIST]);
|
||||
m_name_ID_list.swap(name_id_list);
|
||||
}
|
||||
|
||||
void LoadViaNodeList()
|
||||
{
|
||||
NodeID *via_node_list_ptr =
|
||||
data_layout->GetBlockPtr<NodeID>(shared_memory, SharedDataLayout::VIA_NODE_LIST);
|
||||
typename ShM<NodeID, true>::vector via_node_list(
|
||||
via_node_list_ptr, data_layout->num_entries[SharedDataLayout::VIA_NODE_LIST]);
|
||||
m_via_node_list.swap(via_node_list);
|
||||
}
|
||||
|
||||
void LoadNames()
|
||||
{
|
||||
unsigned *offsets_ptr =
|
||||
data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::NAME_OFFSETS);
|
||||
NameIndexBlock *blocks_ptr =
|
||||
data_layout->GetBlockPtr<NameIndexBlock>(shared_memory, SharedDataLayout::NAME_BLOCKS);
|
||||
typename ShM<unsigned, true>::vector name_offsets(
|
||||
offsets_ptr, data_layout->num_entries[SharedDataLayout::NAME_OFFSETS]);
|
||||
typename ShM<NameIndexBlock, true>::vector name_blocks(
|
||||
blocks_ptr, data_layout->num_entries[SharedDataLayout::NAME_BLOCKS]);
|
||||
|
||||
char *names_list_ptr =
|
||||
data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::NAME_CHAR_LIST);
|
||||
typename ShM<char, true>::vector names_char_list(
|
||||
names_list_ptr, data_layout->num_entries[SharedDataLayout::NAME_CHAR_LIST]);
|
||||
m_name_table = osrm::make_unique<RangeTable<16, true>>(
|
||||
name_offsets, name_blocks, static_cast<unsigned>(names_char_list.size()));
|
||||
|
||||
m_names_char_list.swap(names_char_list);
|
||||
}
|
||||
|
||||
void LoadGeometries()
|
||||
{
|
||||
unsigned *geometries_compressed_ptr = data_layout->GetBlockPtr<unsigned>(
|
||||
shared_memory, SharedDataLayout::GEOMETRIES_INDICATORS);
|
||||
typename ShM<bool, true>::vector edge_is_compressed(
|
||||
geometries_compressed_ptr,
|
||||
data_layout->num_entries[SharedDataLayout::GEOMETRIES_INDICATORS]);
|
||||
m_edge_is_compressed.swap(edge_is_compressed);
|
||||
|
||||
unsigned *geometries_index_ptr =
|
||||
data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::GEOMETRIES_INDEX);
|
||||
typename ShM<unsigned, true>::vector geometry_begin_indices(
|
||||
geometries_index_ptr, data_layout->num_entries[SharedDataLayout::GEOMETRIES_INDEX]);
|
||||
m_geometry_indices.swap(geometry_begin_indices);
|
||||
|
||||
unsigned *geometries_list_ptr =
|
||||
data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::GEOMETRIES_LIST);
|
||||
typename ShM<unsigned, true>::vector geometry_list(
|
||||
geometries_list_ptr, data_layout->num_entries[SharedDataLayout::GEOMETRIES_LIST]);
|
||||
m_geometry_list.swap(geometry_list);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~SharedDataFacade() {}
|
||||
|
||||
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());
|
||||
|
||||
m_large_memory.reset(SharedMemoryFactory::Get(CURRENT_DATA));
|
||||
shared_memory = (char *)(m_large_memory->Ptr());
|
||||
|
||||
const char *file_index_ptr =
|
||||
data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::FILE_INDEX_PATH);
|
||||
file_index_path = boost::filesystem::path(file_index_ptr);
|
||||
if (!boost::filesystem::exists(file_index_path))
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "Leaf file name " << file_index_path.string();
|
||||
throw OSRMException("Could not load leaf index file."
|
||||
"Is any data loaded into shared memory?");
|
||||
}
|
||||
|
||||
LoadGraph();
|
||||
LoadChecksum();
|
||||
LoadNodeAndEdgeInformation();
|
||||
LoadGeometries();
|
||||
LoadTimestamp();
|
||||
LoadViaNodeList();
|
||||
LoadNames();
|
||||
|
||||
data_layout->PrintInformation();
|
||||
|
||||
SimpleLogger().Write() << "number of geometries: " << m_coordinate_list->size();
|
||||
for (unsigned i = 0; i < m_coordinate_list->size(); ++i)
|
||||
{
|
||||
if (!GetCoordinateOfNode(i).is_valid())
|
||||
{
|
||||
SimpleLogger().Write() << "coordinate " << i << " not valid";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// search graph access
|
||||
unsigned GetNumberOfNodes() const final { return m_query_graph->GetNumberOfNodes(); }
|
||||
|
||||
unsigned GetNumberOfEdges() const final { return m_query_graph->GetNumberOfEdges(); }
|
||||
|
||||
unsigned GetOutDegree(const NodeID n) const final { return m_query_graph->GetOutDegree(n); }
|
||||
|
||||
NodeID GetTarget(const EdgeID e) const final { return m_query_graph->GetTarget(e); }
|
||||
|
||||
EdgeDataT &GetEdgeData(const EdgeID e) const final { return m_query_graph->GetEdgeData(e); }
|
||||
|
||||
EdgeID BeginEdges(const NodeID n) const final { return m_query_graph->BeginEdges(n); }
|
||||
|
||||
EdgeID EndEdges(const NodeID n) const final { return m_query_graph->EndEdges(n); }
|
||||
|
||||
EdgeRange GetAdjacentEdgeRange(const NodeID node) const final
|
||||
{
|
||||
return m_query_graph->GetAdjacentEdgeRange(node);
|
||||
};
|
||||
|
||||
// searches for a specific edge
|
||||
EdgeID FindEdge(const NodeID from, const NodeID to) const final
|
||||
{
|
||||
return m_query_graph->FindEdge(from, to);
|
||||
}
|
||||
|
||||
EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const final
|
||||
{
|
||||
return m_query_graph->FindEdgeInEitherDirection(from, to);
|
||||
}
|
||||
|
||||
EdgeID FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const final
|
||||
{
|
||||
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
|
||||
}
|
||||
|
||||
// node and edge information access
|
||||
FixedPointCoordinate GetCoordinateOfNode(const NodeID id) const final
|
||||
{
|
||||
return m_coordinate_list->at(id);
|
||||
};
|
||||
|
||||
virtual bool EdgeIsCompressed(const unsigned id) const final
|
||||
{
|
||||
return m_edge_is_compressed.at(id);
|
||||
}
|
||||
|
||||
virtual void GetUncompressedGeometry(const unsigned id,
|
||||
std::vector<unsigned> &result_nodes) const final
|
||||
{
|
||||
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 final
|
||||
{
|
||||
return m_via_node_list.at(id);
|
||||
}
|
||||
|
||||
TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const final
|
||||
{
|
||||
return m_turn_instruction_list.at(id);
|
||||
}
|
||||
|
||||
TravelMode GetTravelModeForEdgeID(const unsigned id) const
|
||||
{
|
||||
return m_travel_mode_list.at(id);
|
||||
}
|
||||
|
||||
bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
FixedPointCoordinate &result,
|
||||
const unsigned zoom_level = 18) final
|
||||
{
|
||||
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
|
||||
{
|
||||
LoadRTree();
|
||||
}
|
||||
|
||||
return m_static_rtree->second->LocateClosestEndPointForCoordinate(
|
||||
input_coordinate, result, zoom_level);
|
||||
}
|
||||
|
||||
bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
PhantomNode &resulting_phantom_node,
|
||||
const unsigned zoom_level) final
|
||||
{
|
||||
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
|
||||
{
|
||||
LoadRTree();
|
||||
}
|
||||
|
||||
return m_static_rtree->second->FindPhantomNodeForCoordinate(
|
||||
input_coordinate, resulting_phantom_node, zoom_level);
|
||||
}
|
||||
|
||||
bool
|
||||
IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
PhantomNode &resulting_phantom_node,
|
||||
const unsigned zoom_level) final
|
||||
{
|
||||
std::vector<PhantomNode> resulting_phantom_node_vector;
|
||||
auto result = IncrementalFindPhantomNodeForCoordinate(input_coordinate,
|
||||
resulting_phantom_node_vector,
|
||||
zoom_level,
|
||||
1);
|
||||
if (result)
|
||||
{
|
||||
BOOST_ASSERT(!resulting_phantom_node_vector.empty());
|
||||
resulting_phantom_node = resulting_phantom_node_vector.front();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
std::vector<PhantomNode> &resulting_phantom_node_vector,
|
||||
const unsigned zoom_level,
|
||||
const unsigned number_of_results) final
|
||||
{
|
||||
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
|
||||
{
|
||||
LoadRTree();
|
||||
}
|
||||
|
||||
return m_static_rtree->second->IncrementalFindPhantomNodeForCoordinate(
|
||||
input_coordinate, resulting_phantom_node_vector, zoom_level, number_of_results);
|
||||
}
|
||||
|
||||
unsigned GetCheckSum() const final { return m_check_sum; }
|
||||
|
||||
unsigned GetNameIndexFromEdgeID(const unsigned id) const final
|
||||
{
|
||||
return m_name_ID_list.at(id);
|
||||
};
|
||||
|
||||
void GetName(const unsigned name_id, std::string &result) const final
|
||||
{
|
||||
if (UINT_MAX == name_id)
|
||||
{
|
||||
result = "";
|
||||
return;
|
||||
}
|
||||
auto range = m_name_table->GetRange(name_id);
|
||||
|
||||
result.clear();
|
||||
if (range.begin() != range.end())
|
||||
{
|
||||
result.resize(range.back() - range.front() + 1);
|
||||
std::copy(m_names_char_list.begin() + range.front(),
|
||||
m_names_char_list.begin() + range.back() + 1,
|
||||
result.begin());
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetTimestamp() const final { return m_timestamp; }
|
||||
};
|
||||
|
||||
#endif // SHARED_DATA_FACADE_H
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
|
||||
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 "../../Util/OSRMException.h"
|
||||
#include "../../Util/simple_logger.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <array>
|
||||
|
||||
// Added at the start and end of each block as sanity check
|
||||
static const char CANARY[] = "OSRM";
|
||||
|
||||
struct SharedDataLayout
|
||||
{
|
||||
enum BlockID {
|
||||
NAME_OFFSETS = 0,
|
||||
NAME_BLOCKS,
|
||||
NAME_CHAR_LIST,
|
||||
NAME_ID_LIST,
|
||||
VIA_NODE_LIST,
|
||||
GRAPH_NODE_LIST,
|
||||
GRAPH_EDGE_LIST,
|
||||
COORDINATE_LIST,
|
||||
TURN_INSTRUCTION,
|
||||
TRAVEL_MODE,
|
||||
R_SEARCH_TREE,
|
||||
GEOMETRIES_INDEX,
|
||||
GEOMETRIES_LIST,
|
||||
GEOMETRIES_INDICATORS,
|
||||
HSGR_CHECKSUM,
|
||||
TIMESTAMP,
|
||||
FILE_INDEX_PATH,
|
||||
NUM_BLOCKS
|
||||
};
|
||||
|
||||
std::array<uint64_t, NUM_BLOCKS> num_entries;
|
||||
std::array<uint64_t, NUM_BLOCKS> entry_size;
|
||||
|
||||
SharedDataLayout()
|
||||
: num_entries()
|
||||
, entry_size()
|
||||
{
|
||||
}
|
||||
|
||||
void PrintInformation() const
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "-";
|
||||
SimpleLogger().Write(logDEBUG) << "name_offsets_size: " << num_entries[NAME_OFFSETS];
|
||||
SimpleLogger().Write(logDEBUG) << "name_blocks_size: " << num_entries[NAME_BLOCKS];
|
||||
SimpleLogger().Write(logDEBUG) << "name_char_list_size: " << num_entries[NAME_CHAR_LIST];
|
||||
SimpleLogger().Write(logDEBUG) << "name_id_list_size: " << num_entries[NAME_ID_LIST];
|
||||
SimpleLogger().Write(logDEBUG) << "via_node_list_size: " << num_entries[VIA_NODE_LIST];
|
||||
SimpleLogger().Write(logDEBUG) << "graph_node_list_size: " << num_entries[GRAPH_NODE_LIST];
|
||||
SimpleLogger().Write(logDEBUG) << "graph_edge_list_size: " << num_entries[GRAPH_EDGE_LIST];
|
||||
SimpleLogger().Write(logDEBUG) << "timestamp_length: " << num_entries[TIMESTAMP];
|
||||
SimpleLogger().Write(logDEBUG) << "coordinate_list_size: " << num_entries[COORDINATE_LIST];
|
||||
SimpleLogger().Write(logDEBUG) << "turn_instruction_list_size: " << num_entries[TURN_INSTRUCTION];
|
||||
SimpleLogger().Write(logDEBUG) << "travel_mode_list_size: " << num_entries[TRAVEL_MODE];
|
||||
SimpleLogger().Write(logDEBUG) << "r_search_tree_size: " << num_entries[R_SEARCH_TREE];
|
||||
SimpleLogger().Write(logDEBUG) << "geometries_indicators: " << num_entries[GEOMETRIES_INDICATORS]
|
||||
<< "/" << ((num_entries[GEOMETRIES_INDICATORS] / 8) + 1);
|
||||
SimpleLogger().Write(logDEBUG) << "geometries_index_list_size: " << num_entries[GEOMETRIES_INDEX];
|
||||
SimpleLogger().Write(logDEBUG) << "geometries_list_size: " << num_entries[GEOMETRIES_LIST];
|
||||
SimpleLogger().Write(logDEBUG) << "sizeof(checksum): " << entry_size[HSGR_CHECKSUM];
|
||||
|
||||
SimpleLogger().Write(logDEBUG) << "NAME_OFFSETS " << ": " << GetBlockSize(NAME_OFFSETS );
|
||||
SimpleLogger().Write(logDEBUG) << "NAME_BLOCKS " << ": " << GetBlockSize(NAME_BLOCKS );
|
||||
SimpleLogger().Write(logDEBUG) << "NAME_CHAR_LIST " << ": " << GetBlockSize(NAME_CHAR_LIST );
|
||||
SimpleLogger().Write(logDEBUG) << "NAME_ID_LIST " << ": " << GetBlockSize(NAME_ID_LIST );
|
||||
SimpleLogger().Write(logDEBUG) << "VIA_NODE_LIST " << ": " << GetBlockSize(VIA_NODE_LIST );
|
||||
SimpleLogger().Write(logDEBUG) << "GRAPH_NODE_LIST " << ": " << GetBlockSize(GRAPH_NODE_LIST );
|
||||
SimpleLogger().Write(logDEBUG) << "GRAPH_EDGE_LIST " << ": " << GetBlockSize(GRAPH_EDGE_LIST );
|
||||
SimpleLogger().Write(logDEBUG) << "COORDINATE_LIST " << ": " << GetBlockSize(COORDINATE_LIST );
|
||||
SimpleLogger().Write(logDEBUG) << "TURN_INSTRUCTION " << ": " << GetBlockSize(TURN_INSTRUCTION );
|
||||
SimpleLogger().Write(logDEBUG) << "TRAVEL_MODE " << ": " << GetBlockSize(TRAVEL_MODE );
|
||||
SimpleLogger().Write(logDEBUG) << "R_SEARCH_TREE " << ": " << GetBlockSize(R_SEARCH_TREE );
|
||||
SimpleLogger().Write(logDEBUG) << "GEOMETRIES_INDEX " << ": " << GetBlockSize(GEOMETRIES_INDEX );
|
||||
SimpleLogger().Write(logDEBUG) << "GEOMETRIES_LIST " << ": " << GetBlockSize(GEOMETRIES_LIST );
|
||||
SimpleLogger().Write(logDEBUG) << "GEOMETRIES_INDICATORS" << ": " << GetBlockSize(GEOMETRIES_INDICATORS);
|
||||
SimpleLogger().Write(logDEBUG) << "HSGR_CHECKSUM " << ": " << GetBlockSize(HSGR_CHECKSUM );
|
||||
SimpleLogger().Write(logDEBUG) << "TIMESTAMP " << ": " << GetBlockSize(TIMESTAMP );
|
||||
SimpleLogger().Write(logDEBUG) << "FILE_INDEX_PATH " << ": " << GetBlockSize(FILE_INDEX_PATH );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void SetBlockSize(BlockID bid, uint64_t entries)
|
||||
{
|
||||
num_entries[bid] = entries;
|
||||
entry_size[bid] = sizeof(T);
|
||||
}
|
||||
|
||||
inline uint64_t GetBlockSize(BlockID bid) const
|
||||
{
|
||||
// special encoding
|
||||
if (bid == GEOMETRIES_INDICATORS)
|
||||
{
|
||||
return (num_entries[GEOMETRIES_INDICATORS]/32 + 1) * entry_size[GEOMETRIES_INDICATORS];
|
||||
}
|
||||
|
||||
return num_entries[bid] * entry_size[bid];
|
||||
}
|
||||
|
||||
inline uint64_t GetSizeOfLayout() const
|
||||
{
|
||||
return GetBlockOffset(NUM_BLOCKS) + NUM_BLOCKS*2*sizeof(CANARY);
|
||||
}
|
||||
|
||||
inline uint64_t GetBlockOffset(BlockID bid) const
|
||||
{
|
||||
uint64_t result = sizeof(CANARY);
|
||||
for (auto i = 0; i < bid; i++)
|
||||
{
|
||||
result += GetBlockSize((BlockID) i) + 2*sizeof(CANARY);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T, bool WRITE_CANARY=false>
|
||||
inline T* GetBlockPtr(char* shared_memory, BlockID bid)
|
||||
{
|
||||
T* ptr = (T*)(shared_memory + GetBlockOffset(bid));
|
||||
if (WRITE_CANARY)
|
||||
{
|
||||
char* start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
|
||||
char* end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
|
||||
std::copy(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
|
||||
std::copy(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
char* start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
|
||||
char* end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
|
||||
bool start_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
|
||||
bool end_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
|
||||
if (!start_canary_alive)
|
||||
{
|
||||
throw OSRMException("Start canary of block corrupted.");
|
||||
}
|
||||
if (!end_canary_alive)
|
||||
{
|
||||
throw OSRMException("End canary of block corrupted.");
|
||||
}
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
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_ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user