Compare commits
844 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f9ab8426ce | |||
| b869184c10 | |||
| 68e39b8053 | |||
| 6574436c33 | |||
| 8e023418e4 | |||
| bf94866ec0 | |||
| cba3c46820 | |||
| d4db5cca1c | |||
| e4fc633f68 | |||
| 9857fb7696 | |||
| 199b1cbcf8 | |||
| 1d38ba78e8 | |||
| c9ce018b9f | |||
| 9b4e31c5ea | |||
| 1e7a5e881e | |||
| 102e87bcc0 | |||
| 604043e3d8 | |||
| 10513784c7 | |||
| 5e3c8cdd8e | |||
| 5a5b4eb1f7 | |||
| e839cb4b8c | |||
| 5c3dad0c61 | |||
| f4a1d2df96 | |||
| cb6104e0ac | |||
| 00ed039621 | |||
| b247c20dbf | |||
| 81d26d7702 | |||
| 0f106c627b | |||
| ac06a2ef03 | |||
| 2ea5714d95 | |||
| a51c7416d5 | |||
| 2231765c9e | |||
| 18c948a211 | |||
| ec56478a3c | |||
| 7e9614b9ec | |||
| 7f7055a9e7 | |||
| ae106a3a90 | |||
| 29344f55ae | |||
| da6b750378 | |||
| 96c872ac37 | |||
| 51f67f3fa0 | |||
| d3dce3cc25 | |||
| 411d4331d4 | |||
| 18aff1ae40 | |||
| 3ff7febde0 | |||
| f7fdb8b54e | |||
| cc7f761c3e | |||
| b10b716733 | |||
| a255f222ef | |||
| b0f035bf3c | |||
| e41d52570e | |||
| 824724630f | |||
| 85c5da8512 | |||
| d79ebabe03 | |||
| f9cab44bc1 | |||
| 636f69b29f | |||
| 86a5bbac51 | |||
| b182cd1fa4 | |||
| 6f5fc14f59 | |||
| f1d47328e9 | |||
| 9a865384a1 | |||
| 7379c8c387 | |||
| 07f644f7d3 | |||
| 07302c3df8 | |||
| 33bd546588 | |||
| a790ffc2d1 | |||
| 6003ae7406 | |||
| 3c6121d192 | |||
| 12500e4721 | |||
| 166133a496 | |||
| 06914b13e0 | |||
| 36856fd646 | |||
| 870ed96c24 | |||
| aed5848f5a | |||
| 210f586d49 | |||
| 94657a3258 | |||
| 7e9eaaddc4 | |||
| bd3f069f47 | |||
| a2c9b5b6d1 | |||
| c4be1d1423 | |||
| f9d336ff88 | |||
| 2c08adab24 | |||
| 5faf8d6951 | |||
| b51f98fe0c | |||
| 0e3d2cf68d | |||
| 868d6ec776 | |||
| e45b7b4b14 | |||
| 3353e482ef | |||
| 11d4d3ec30 | |||
| 7fda7f1f9b | |||
| 7752f1ade0 | |||
| aeff6c8caa | |||
| 954710d6cc | |||
| 1c50c55a42 | |||
| 504368b293 | |||
| 03f8845998 | |||
| 7d0bd77643 | |||
| 07b6073dcf | |||
| 1ec49c3914 | |||
| f575da2ca8 | |||
| 591a06b25e | |||
| cbe48decd1 | |||
| 6f8148950e | |||
| ac68ff192e | |||
| 629cccc6e1 | |||
| 763cc86043 | |||
| a82c9d55b3 | |||
| 9fc3ed939a | |||
| 90b07cc6b0 | |||
| ac15c787cc | |||
| b5ed992e94 | |||
| 7493d8aa49 | |||
| 2c61d0a79e | |||
| 55e58375eb | |||
| 24321d860c | |||
| e8c7f7b5da | |||
| 263dcbd188 | |||
| 10cf41d138 | |||
| f4fd9dbd38 | |||
| 10b650caf4 | |||
| 75561b8278 | |||
| d89be86e4f | |||
| 6c218960e0 | |||
| 92d4b40379 | |||
| 4c0203c108 | |||
| 8b2629c273 | |||
| c19c97804a | |||
| 313466941b | |||
| 48c6145bdf | |||
| 9dd45cceab | |||
| b6303626b5 | |||
| d1d800025d | |||
| 57dc1e03b1 | |||
| ad5b96d6f2 | |||
| b5f2a98e89 | |||
| 3a706cade7 | |||
| d9af615db9 | |||
| f40550b18c | |||
| 3ec4a049c5 | |||
| dc86007fa9 | |||
| 64d14da0fa | |||
| c83ab666d7 | |||
| 599b96ed95 | |||
| 38ba10ddad | |||
| 8794db633b | |||
| c0287c0f2f | |||
| 6fe931fe4c | |||
| 680d3e7d92 | |||
| c5b1cea58e | |||
| 11d45f5a10 | |||
| 5c737709e2 | |||
| 7282e543ca | |||
| ea90627e02 | |||
| b95596d6b7 | |||
| 7400e60599 | |||
| 6eab47d768 | |||
| 3f039f59de | |||
| 2a89aeecd8 | |||
| 386d4c7e72 | |||
| df9a8a32eb | |||
| fa9eeb95b6 | |||
| 13069632be | |||
| a502da7c0f | |||
| 0b2df9892d | |||
| c6dc476704 | |||
| c5ebef3499 | |||
| 8e756a2476 | |||
| 5e1dc11000 | |||
| bcddc10b6b | |||
| 8e31b8860c | |||
| 794c3490fe | |||
| 216157e00d | |||
| 8e6b7766a1 | |||
| c1a08af00d | |||
| 59025ca2da | |||
| 17fab42f25 | |||
| 4b00557fda | |||
| 30465f08ac | |||
| 6fb2a41a0a | |||
| b70b74080e | |||
| 230fec9cdb | |||
| 17ca6b1e07 | |||
| 628f40f822 | |||
| 0994a7a20d | |||
| 66ff69355d | |||
| 04f71e65ee | |||
| 2b0e46caf2 | |||
| 549ce9a4d4 | |||
| 50d3c2c9d1 | |||
| 82caa357cd | |||
| 217fc4a0ae | |||
| ed8bc7ae58 | |||
| 87ff3f9b9b | |||
| 1bef65bf2c | |||
| b39507efc8 | |||
| 263409ed91 | |||
| 7610af3378 | |||
| 97f04eae91 | |||
| a14db578e2 | |||
| 62f31f3e2d | |||
| db9292ee86 | |||
| 1ad274ed2e | |||
| 57d6af5486 | |||
| 8b482e433a | |||
| d4352b84ac | |||
| b23a89d5a8 | |||
| 681d05f8f4 | |||
| 81b9e3b4cb | |||
| 2798c5a48d | |||
| 77c9f96f44 | |||
| 098454c875 | |||
| 6f00e8c936 | |||
| 3c32cafc9c | |||
| 585558a9ae | |||
| 6635d239b0 | |||
| f14c76dbca | |||
| 0fb747834b | |||
| 11175748bb | |||
| 49b7fffd66 | |||
| e69777d20a | |||
| dde4a496f6 | |||
| 48cb43cc79 | |||
| 4229b22f86 | |||
| 958e28050e | |||
| eae9e4bab7 | |||
| c6dfc7723b | |||
| 334f02d7f8 | |||
| 4c02542dc5 | |||
| 84ffec81ec | |||
| 3673b1a324 | |||
| 8cd28276ea | |||
| 2185bb3327 | |||
| 2d64dca565 | |||
| fad13506a7 | |||
| ffed740fdf | |||
| c0eb1d6967 | |||
| e2b208280e | |||
| f9279a3646 | |||
| e0ff8894a2 | |||
| c97d00c399 | |||
| c16c2adeda | |||
| c4326ffd0b | |||
| 85369d6310 | |||
| bd6f2db1d1 | |||
| 02c11caf7f | |||
| 0d087fcbce | |||
| 9a3735aa21 | |||
| 63229c9b3a | |||
| 17bc61767b | |||
| 5ec198b761 | |||
| 8e15a32229 | |||
| 3c903ddffd | |||
| 28f8edf459 | |||
| dc029ebefd | |||
| bb09cac7f4 | |||
| 937a3f88a4 | |||
| 352ee956cd | |||
| a735d467bf | |||
| 71d148caa8 | |||
| 01dc1af5f4 | |||
| dccb9f2424 | |||
| df819d20b5 | |||
| 518ea7ed01 | |||
| 8abbe8db4a | |||
| e36a517e86 | |||
| 7e5d5a6d90 | |||
| 51c0b129c9 | |||
| 96ba31cc2b | |||
| 74cc50f52b | |||
| 75cd287ab0 | |||
| 09088e71b5 | |||
| 6228c2c89b | |||
| 44b625520b | |||
| 1c415933da | |||
| ac588911ba | |||
| c14ceff9b3 | |||
| e3062cf3a2 | |||
| b448177278 | |||
| bcc7c41140 | |||
| 71d184c39b | |||
| 5423cff7a8 | |||
| aeb701f52e | |||
| b16db9fe68 | |||
| 2faf9ad1b6 | |||
| a8a0d1b216 | |||
| aef6d1795e | |||
| ae8dfcb55e | |||
| 9e6ac95e4f | |||
| 7965e29d49 | |||
| 6d823c62f4 | |||
| cc72409980 | |||
| beadb241a8 | |||
| 86dbcc8df2 | |||
| 4a89cfee3d | |||
| 837e91f56d | |||
| 8050fec64f | |||
| 3e0b4ee1e5 | |||
| eac900c6b8 | |||
| 117e8380e2 | |||
| 69f1bfb337 | |||
| b78e9ce02c | |||
| 3fd2725122 | |||
| 6f7cb3d9f2 | |||
| db0bb3d749 | |||
| e055211960 | |||
| 1b581b1c17 | |||
| d335e7d5e7 | |||
| f5857da6f4 | |||
| aad484b7f7 | |||
| b3ae4f5c7b | |||
| 428783e183 | |||
| d26d3bb574 | |||
| 7bd4e213c2 | |||
| bdcbb8670c | |||
| 3edf4799d3 | |||
| 62c12e7473 | |||
| e0f51dd5e9 | |||
| 7222231abf | |||
| 91080f0690 | |||
| 4c2c1f519c | |||
| 0eb5d8db4e | |||
| e43d27e86d | |||
| 87df312a9d | |||
| 1412c5db42 | |||
| 4c58674393 | |||
| 1fdfac4aaf | |||
| e1fe363268 | |||
| a127c705f2 | |||
| 827b9e4be2 | |||
| 417fcde9db | |||
| 818c66e774 | |||
| f69076f55c | |||
| ebafd25e77 | |||
| b055334e73 | |||
| f112f944aa | |||
| 62951f3ab9 | |||
| 3e25f85eb6 | |||
| e544233abb | |||
| d6fd898101 | |||
| ad610ac904 | |||
| 70c4b293ce | |||
| 41e7dbf205 | |||
| 2901e6891c | |||
| a911089913 | |||
| ac1925d4b9 | |||
| 5d2c2a3107 | |||
| bab2c80857 | |||
| d3d90e10a5 | |||
| 4336931f46 | |||
| 58dfd29a3a | |||
| 66c23b5843 | |||
| ea1fb0a078 | |||
| 0381e0dd9d | |||
| 595579a6c2 | |||
| 2143df2e4f | |||
| c86060f5bb | |||
| 4f2e9e8442 | |||
| 411803919d | |||
| ebc3d09f0f | |||
| c2ab16f984 | |||
| 3f3da4ee0b | |||
| 922c218394 | |||
| d5cb1fa15f | |||
| 2cf175cf91 | |||
| 0276cf579a | |||
| 5dd1211f46 | |||
| 1b98bd2c68 | |||
| 7261ce3b7f | |||
| 80a9317d8b | |||
| 7467e11147 | |||
| 6f78bd7a85 | |||
| 03276ad386 | |||
| 9c1caba2fa | |||
| 5ef3b12673 | |||
| cf1e2fa930 | |||
| 14e110178a | |||
| 4e2650d6e7 | |||
| f60f676563 | |||
| 7fddfd7a54 | |||
| fd88aba8a1 | |||
| f95c040bed | |||
| 459ebc7508 | |||
| 9b17543021 | |||
| 1326c5a01f | |||
| f01670db80 | |||
| bddac87321 | |||
| 176fa301d3 | |||
| f2ce4f0ff1 | |||
| a1affa6330 | |||
| 2c14d34f59 | |||
| 4a299fd4ff | |||
| cfec837278 | |||
| 1bf5ca2bec | |||
| 61efd41194 | |||
| 5ebc4b392f | |||
| 4236f92de2 | |||
| 7f0d40f459 | |||
| 6918c7fe1f | |||
| fa62f70cdf | |||
| 8ddb3fc6ad | |||
| df68c3ad48 | |||
| b7bcc401e7 | |||
| 82ead0a405 | |||
| 5ff2fc9250 | |||
| bbad30c6e0 | |||
| a962deaffd | |||
| b353df83ee | |||
| 134c02a762 | |||
| 63c6c06436 | |||
| 1b52f67e5d | |||
| e29b19805c | |||
| 7194fe02d1 | |||
| 863b9829ca | |||
| 666371099e | |||
| 0388860ea1 | |||
| eb90be2ec3 | |||
| 0d0a27d1c2 | |||
| 56c81dd890 | |||
| 00502e0476 | |||
| 2eb251bd7f | |||
| cbddbb598f | |||
| bb5b6fef26 | |||
| 4eb379a912 | |||
| 6769f83d5b | |||
| 358f12d910 | |||
| fe35fefc75 | |||
| 5ed9c41d5e | |||
| 9776158cac | |||
| 486eed4875 | |||
| f6225c0baa | |||
| db2047264c | |||
| 68f0cb7684 | |||
| 57b3f42b03 | |||
| a0a0caad38 | |||
| 30e76b4a32 | |||
| b474d7ec77 | |||
| ad3ec9d856 | |||
| 9f63e5da96 | |||
| 2e878d8f2e | |||
| bfaab86330 | |||
| 78b4d715d5 | |||
| 6dfea376ee | |||
| f0188c428f | |||
| 2987b1d425 | |||
| 86128892d7 | |||
| a8bdc59d5a | |||
| ac6ba24861 | |||
| 5b247a3699 | |||
| 580a760aa1 | |||
| f5da6a0e5f | |||
| a394973762 | |||
| 4f73b4725a | |||
| 71b90ab216 | |||
| c4f213f64e | |||
| cacf8f17d3 | |||
| 819c1729f1 | |||
| 765b1cb3a5 | |||
| 908d92fa5c | |||
| 98ef2e18d4 | |||
| f9e1657dcc | |||
| 0a4aa11d09 | |||
| 200028f328 | |||
| 276071b179 | |||
| 26662b7190 | |||
| 8fdfff3014 | |||
| 7e0fb433e4 | |||
| 0b83310100 | |||
| 8c2bd8bd88 | |||
| 44af60563d | |||
| bb98bc92ef | |||
| 3c08b89923 | |||
| 7baef59b79 | |||
| 6fe580bd75 | |||
| 91d875c157 | |||
| 7fa409a72f | |||
| d8927ec5f8 | |||
| 15751ae1a1 | |||
| bda8431d50 | |||
| 492cb727df | |||
| d4536ba242 | |||
| 876a551cd8 | |||
| 41eb07e35b | |||
| 231c593bb3 | |||
| 3b01d785a5 | |||
| 0c0049f8cc | |||
| d7c44e2bbd | |||
| 0504923689 | |||
| 7e47553c88 | |||
| f8761ecea0 | |||
| ff0eae40ea | |||
| 9d6402aad4 | |||
| 1173ac17ee | |||
| fed4a83a8f | |||
| 8343703115 | |||
| 85eb59eb40 | |||
| e11bd5d99f | |||
| f359927b09 | |||
| 70825abb1d | |||
| c4dc85f607 | |||
| 7e8de26657 | |||
| b3570f57ee | |||
| 3c62aa02d4 | |||
| 58e88d43a9 | |||
| 78ade5b7d7 | |||
| 969d5c8558 | |||
| 539199a7e9 | |||
| 60ffe55565 | |||
| dd03c6b168 | |||
| f53c0d7dfa | |||
| 7872354b49 | |||
| 1ee470f5b4 | |||
| 04e6ca9763 | |||
| 80219a31e2 | |||
| 0555dc4bc3 | |||
| 4401b58f45 | |||
| 8d2d3bd73c | |||
| c7dfed8f29 | |||
| 92f9a29de1 | |||
| ff50cfb4da | |||
| 086e10671f | |||
| 68c1c0a6a6 | |||
| 811d77eccb | |||
| f87450efd6 | |||
| e1a8cad552 | |||
| c0141a9744 | |||
| 221de3343a | |||
| 4c0a54f95f | |||
| 1ce21556a1 | |||
| e104017d4c | |||
| 8377e411cb | |||
| b16f3f91d9 | |||
| c669d46efb | |||
| 03deda313a | |||
| 7983063d05 | |||
| e412366bb2 | |||
| 7035d17290 | |||
| b9e0cb6be1 | |||
| 0a78a50eff | |||
| 323bf67037 | |||
| 9ffcec2fcb | |||
| 964c0425bf | |||
| 19208289dc | |||
| a5c5f4c02c | |||
| 53aede83dc | |||
| e4080aba05 | |||
| 2549f7254a | |||
| 87f4341866 | |||
| 3f6cc725d6 | |||
| a558f447cf | |||
| bd2c99d9ec | |||
| 1a224e2adc | |||
| c64aaab193 | |||
| 556e487a15 | |||
| 30d72543b9 | |||
| af0def36c2 | |||
| 6d8f99832f | |||
| 6a9b05e126 | |||
| c45e2cbb82 | |||
| 4d0c02de2d | |||
| e43019a1df | |||
| 4d19793d69 | |||
| 15358a2e72 | |||
| 73f0e6e825 | |||
| 17738c3861 | |||
| 3712868831 | |||
| a0a71d6e05 | |||
| 1116608389 | |||
| a9b9775fe4 | |||
| 75353852fd | |||
| 64ab2da43b | |||
| 6d74ae1b84 | |||
| 26f3c51cf0 | |||
| b192fb9403 | |||
| 24e72bc6cc | |||
| 9dfbd5f671 | |||
| a65339d011 | |||
| 88890a1914 | |||
| 3ea1461839 | |||
| 164e1be018 | |||
| fffb9c8a2c | |||
| f877788cf1 | |||
| 5940e40d22 | |||
| 9c894fb8b0 | |||
| 29b30bb69c | |||
| 9b340a507b | |||
| 0465753bdf | |||
| 08ebe94005 | |||
| 7afd6d32b7 | |||
| f41495dc7a | |||
| b253721df4 | |||
| 8200f889fb | |||
| ec9a7f8165 | |||
| e83891b4fc | |||
| 91c9cb2114 | |||
| 303d571d23 | |||
| f7cc34c807 | |||
| 8b2c0030d0 | |||
| c273351d4a | |||
| 0cd06be13a | |||
| ee64b2f5fd | |||
| f8499e1113 | |||
| 305f4dc5d0 | |||
| 3e73710245 | |||
| 77d5c44664 | |||
| 22e1e6c92f | |||
| e70bcfb343 | |||
| 93bccf36ba | |||
| 1720a2b123 | |||
| b0ecb869f2 | |||
| 58359fe4ac | |||
| 9fdb6eb2c5 | |||
| 9b80d44873 | |||
| 9673980fae | |||
| ec579fb6be | |||
| 3cc3d4fd3b | |||
| 63f4aaf7dd | |||
| 9776373784 | |||
| f8c0c468a9 | |||
| 3e3c5f72e9 | |||
| f332f39ea6 | |||
| 39be1ec116 | |||
| c3bab284ba | |||
| 28581de0ee | |||
| 2bd749b0f7 | |||
| 9586bc26c7 | |||
| e8ef6c8b8a | |||
| 300f7370c8 | |||
| 8d83ce47e9 | |||
| ade2ecdb8e | |||
| 8839a5eb3f | |||
| d61ece7891 | |||
| f736bb9c9a | |||
| f8fb79a838 | |||
| 5ad4992816 | |||
| 02e15bd3d2 | |||
| 25d15fe2af | |||
| fdb4198c0d | |||
| 3f7437fec2 | |||
| ed0733e125 | |||
| cc3255702f | |||
| b53f3b1b5c | |||
| 795d2b264c | |||
| ab961486d9 | |||
| f35a82e36a | |||
| f841a7a25a | |||
| d01f350e94 | |||
| 0e589ecbcd | |||
| 1f381d790f | |||
| e6ce9d3d29 | |||
| a88ad71be6 | |||
| 48daf38f2b | |||
| 7d42330352 | |||
| dfd227cfc9 | |||
| 568dd9bf3c | |||
| 3507a805a9 | |||
| e248517535 | |||
| 0984a669ce | |||
| 15f2b21b62 | |||
| 4aaecfb4f9 | |||
| e6941df981 | |||
| 632f344db5 | |||
| 1f1b472568 | |||
| 20fa2f8738 | |||
| d3bf394b16 | |||
| 887092bacd | |||
| 61aa095722 | |||
| 7aa2700d8f | |||
| e842c7b28b | |||
| 091cd57f68 | |||
| 045b1e0cb8 | |||
| e7bc232eb1 | |||
| 4eaaf91794 | |||
| 9542ab0482 | |||
| f427550bb7 | |||
| ef9c3c8431 | |||
| 9eef17506d | |||
| 801490b9fc | |||
| 169988b3c4 | |||
| 695fecddeb | |||
| 429eb316d0 | |||
| a99a26aeab | |||
| ae93423116 | |||
| b897b5d0e2 | |||
| 1744e69214 | |||
| e034733ac6 | |||
| ac41c3b06c | |||
| 3c8cea2af6 | |||
| 99e8f36901 | |||
| eeea5b0e81 | |||
| b210b22975 | |||
| 84b35f47a1 | |||
| 0727ff09fa | |||
| fe416526f2 | |||
| 3c10844067 | |||
| 94bd6e22ff | |||
| d11524781e | |||
| 8d16c047cc | |||
| f94ebf5296 | |||
| 8cddaf39c4 | |||
| 7ce75733d0 | |||
| e8af613aaa | |||
| 96f2358d28 | |||
| bb8645dd18 | |||
| 12c547126e | |||
| 78d6a25d98 | |||
| 2c4621011d | |||
| 7a6c36d43c | |||
| d9f0d92262 | |||
| cc91ee1c52 | |||
| 0dc77b056a | |||
| c793672d63 | |||
| 5136853ce0 | |||
| 9da873330a | |||
| bd67e7a4ed | |||
| 9eb73f9306 | |||
| 5e275b3935 | |||
| c98f19c5a6 | |||
| 66b4f65d84 | |||
| b85898c5da | |||
| f1332c7c6a | |||
| 8a47c87a8a | |||
| 88b2d8a8ef | |||
| 2fd3ebc8fb | |||
| 204f522ea4 | |||
| 1f986598f1 | |||
| 6996b24c44 | |||
| b44e36e7ba | |||
| 7c41206c6d | |||
| ea6c0353be | |||
| 8a665bc044 | |||
| f68d53ead6 | |||
| 93b1ff1c5d | |||
| d41b0f28b4 | |||
| c686d28675 | |||
| 448095ff98 | |||
| 835bf436e4 | |||
| 6da047005a | |||
| 571824415c | |||
| bef3aad423 | |||
| 7d21a4e0fb | |||
| e9258a238e | |||
| a21376f6ce | |||
| 664f133c4b | |||
| f4cf3596c5 | |||
| d4eebd7c0d | |||
| 70256146fc | |||
| 057e3a936e | |||
| 0aab2510d3 | |||
| ed826e4451 | |||
| 8efb9a38ea | |||
| 8e1d69ac8b | |||
| ee1b3afdcf | |||
| 62aab1cec6 | |||
| 44c07e9504 | |||
| 1c74f84647 | |||
| 1741ce7ec9 | |||
| 53d87eb9be | |||
| 6e7bb505c1 | |||
| e1f137d59a | |||
| 6d7dd2cf39 | |||
| ebf3eea004 | |||
| 913c2e5713 | |||
| d2b5b8d854 | |||
| 5c10d2fae0 | |||
| 738c3eae91 | |||
| 83968bc1cd | |||
| 4cd615ba2e | |||
| ac1908d464 | |||
| 95d8d44259 | |||
| d57be5244c | |||
| 5ef4909bdd | |||
| 83e160d14d | |||
| 9a2e11c0d7 | |||
| 41b381f567 | |||
| ecb979a14b | |||
| 84bba8aa20 | |||
| b133beed5e | |||
| 90502a0c15 | |||
| f5226b2228 | |||
| ad77d6cfec | |||
| a098e38c5a | |||
| a7e7773d85 | |||
| 0df0c85fea | |||
| fdd85a6328 | |||
| 1409d0e06e | |||
| 4765409fe7 | |||
| dad24f1106 | |||
| 9ea39d280c | |||
| a04eb2bba1 | |||
| e849d18c1b | |||
| 57868f38ef | |||
| 85f9b398da | |||
| e081cf1c3d | |||
| 7c85b2f85a | |||
| ec3bcb43a8 | |||
| 3a984668d6 | |||
| b08104367e | |||
| 1fb97f0080 | |||
| 79a989e504 | |||
| d7f8eafe2d | |||
| 6e74ac9bd2 | |||
| 82c2e9978f | |||
| e04ef5a030 | |||
| 0906a0fe1c | |||
| d07994bd73 | |||
| e8699d4337 | |||
| aa0ce0fb88 | |||
| 435efc9886 | |||
| e64e45015a | |||
| 8e9461ea6a | |||
| 1262600895 | |||
| 8589436158 | |||
| 3767ffd79a | |||
| d81c632ef2 | |||
| 18abdd0cd6 | |||
| 0cad039615 | |||
| abfb49818f | |||
| afe9157d65 | |||
| fe12ba23b0 | |||
| 4f54c90a95 | |||
| 045922fb56 | |||
| 4f5678fc95 | |||
| 3986b30b00 | |||
| 7be723782a | |||
| f601664620 | |||
| bd2080fdb5 | |||
| b4585f24bb | |||
| 21c9132902 | |||
| 9abb317e6d | |||
| 5236fb8c0e | |||
| fb661ab6f6 | |||
| 9d22fca5e7 | |||
| eb1d629ea7 | |||
| fd3ce305f4 | |||
| 928e1178b1 | |||
| ff5e34ee70 | |||
| e8d52c0f01 | |||
| 275808d0d5 | |||
| 55488b1fb6 | |||
| e50e6ada6b | |||
| f511af0f0c | |||
| f10bf842c6 | |||
| e3ad54996f | |||
| aac6f45f54 |
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
# OS generated files #
|
# OS generated files #
|
||||||
######################
|
######################
|
||||||
.DS_Store?
|
.DS_Store
|
||||||
ehthumbs.db
|
ehthumbs.db
|
||||||
Icon?
|
Icon?
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
@@ -60,13 +60,24 @@ DataStructures/pbf-proto/*.pb.cc
|
|||||||
# External Libs #
|
# External Libs #
|
||||||
#################
|
#################
|
||||||
lib/
|
lib/
|
||||||
|
win/lib
|
||||||
|
|
||||||
# Visual Studio Temp + build Files #
|
# Visual Studio Temp + build Files #
|
||||||
####################################
|
####################################
|
||||||
vcprojects/*.user
|
win/*.user
|
||||||
vcprojects/*.ncb
|
win/*.ncb
|
||||||
vcprojects/*.suo
|
win/*.suo
|
||||||
vcprojects/Debug/
|
win/Debug/
|
||||||
vcprojects/Release/
|
win/Release/
|
||||||
bin/
|
win/bin/
|
||||||
bin-debug/
|
win/bin-debug/
|
||||||
|
/osrm-extract
|
||||||
|
/osrm-routed
|
||||||
|
/osrm-prepare
|
||||||
|
/nohup.out
|
||||||
|
|
||||||
|
# Sandbox folder #
|
||||||
|
###################
|
||||||
|
sandbox/
|
||||||
|
|
||||||
|
test/profile.lua
|
||||||
@@ -7,4 +7,5 @@ Frederik Ramm
|
|||||||
Bharath Vissapragada
|
Bharath Vissapragada
|
||||||
Pascal Neis
|
Pascal Neis
|
||||||
Sasa Ivetic
|
Sasa Ivetic
|
||||||
Emil Tin
|
Emil Tin
|
||||||
|
Henning Moll
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
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_ */
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
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_ */
|
||||||
@@ -21,9 +21,13 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
#ifndef DOUGLASPEUCKER_H_
|
#ifndef DOUGLASPEUCKER_H_
|
||||||
#define DOUGLASPEUCKER_H_
|
#define DOUGLASPEUCKER_H_
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
#include <cfloat>
|
#include <cfloat>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
|
||||||
|
#include "../DataStructures/Coordinate.h"
|
||||||
|
|
||||||
/*This class object computes the bitvector of indicating generalized input points
|
/*This class object computes the bitvector of indicating generalized input points
|
||||||
* according to the (Ramer-)Douglas-Peucker algorithm.
|
* according to the (Ramer-)Douglas-Peucker algorithm.
|
||||||
*
|
*
|
||||||
@@ -32,7 +36,8 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
* Note: points may also be pre-selected*/
|
* Note: points may also be pre-selected*/
|
||||||
|
|
||||||
//These thresholds are more or less heuristically chosen.
|
//These thresholds are more or less heuristically chosen.
|
||||||
static double DouglasPeuckerThresholds[19] = { 10240000., 512., 2560000., 1280000., 640000., 320000., 160000., 80000., 40000., 20000., 10000., 5000., 2400., 1200., 200, 16, 6, 3., 1. };
|
// 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>
|
template<class PointT>
|
||||||
class DouglasPeucker {
|
class DouglasPeucker {
|
||||||
@@ -41,38 +46,34 @@ private:
|
|||||||
//Stack to simulate the recursion
|
//Stack to simulate the recursion
|
||||||
std::stack<PairOfPoints > recursionStack;
|
std::stack<PairOfPoints > recursionStack;
|
||||||
|
|
||||||
double ComputeDistance(const _Coordinate& inputPoint, const _Coordinate& source, const _Coordinate& target) {
|
/**
|
||||||
double r;
|
* This distance computation does integer arithmetic only and is about twice as fast as
|
||||||
const double x = (double)inputPoint.lat;
|
* the other distance function. It is an approximation only, but works more or less ok.
|
||||||
const double y = (double)inputPoint.lon;
|
*/
|
||||||
const double a = (double)source.lat;
|
template<class CoordT>
|
||||||
const double b = (double)source.lon;
|
inline int fastDistance(const CoordT& point, const CoordT& segA, const CoordT& segB) const {
|
||||||
const double c = (double)target.lat;
|
const int p2x = (segB.lon - segA.lat);
|
||||||
const double d = (double)target.lon;
|
const int p2y = (segB.lon - segA.lat);
|
||||||
double p,q,mX,nY;
|
const int something = p2x*p2x + p2y*p2y;
|
||||||
if(c != a) {
|
int u = (something < FLT_EPSILON ? 0 : ((point.lon - segA.lon) * p2x + (point.lat - segA.lat) * p2y) / something);
|
||||||
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
|
|
||||||
r = mX;
|
|
||||||
if(r<=0){
|
|
||||||
return ((b - y)*(b - y) + (a - x)*(a - x));
|
|
||||||
}
|
|
||||||
else if(r >= 1){
|
|
||||||
return ((d - y)*(d - y) + (c - x)*(c - x));
|
|
||||||
|
|
||||||
}
|
if (u > 1)
|
||||||
// point lies in between
|
u = 1;
|
||||||
return (p-x)*(p-x) + (q-y)*(q-y);
|
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:
|
public:
|
||||||
void Run(std::vector<PointT> & inputVector, const unsigned zoomLevel) {
|
void Run(std::vector<PointT> & inputVector, const unsigned zoomLevel) {
|
||||||
{
|
{
|
||||||
@@ -81,9 +82,10 @@ public:
|
|||||||
std::size_t leftBorderOfRange = 0;
|
std::size_t leftBorderOfRange = 0;
|
||||||
std::size_t rightBorderOfRange = 1;
|
std::size_t rightBorderOfRange = 1;
|
||||||
//Sweep linerarily over array and identify those ranges that need to be checked
|
//Sweep linerarily over array and identify those ranges that need to be checked
|
||||||
|
// recursionStack.hint(inputVector.size());
|
||||||
do {
|
do {
|
||||||
assert(inputVector[leftBorderOfRange].necessary);
|
assert(inputVector[leftBorderOfRange].necessary);
|
||||||
assert(inputVector[inputVector.size()-1].necessary);
|
assert(inputVector.back().necessary);
|
||||||
|
|
||||||
if(inputVector[rightBorderOfRange].necessary) {
|
if(inputVector[rightBorderOfRange].necessary) {
|
||||||
recursionStack.push(std::make_pair(leftBorderOfRange, rightBorderOfRange));
|
recursionStack.push(std::make_pair(leftBorderOfRange, rightBorderOfRange));
|
||||||
@@ -100,11 +102,12 @@ public:
|
|||||||
assert(inputVector[pair.second].necessary);
|
assert(inputVector[pair.second].necessary);
|
||||||
assert(pair.second < inputVector.size());
|
assert(pair.second < inputVector.size());
|
||||||
assert(pair.first < pair.second);
|
assert(pair.first < pair.second);
|
||||||
double maxDistance = -DBL_MAX;
|
int maxDistance = INT_MIN;
|
||||||
|
|
||||||
std::size_t indexOfFarthestElement = pair.second;
|
std::size_t indexOfFarthestElement = pair.second;
|
||||||
//find index idx of element with maxDistance
|
//find index idx of element with maxDistance
|
||||||
for(std::size_t i = pair.first+1; i < pair.second; ++i){
|
for(std::size_t i = pair.first+1; i < pair.second; ++i){
|
||||||
double distance = std::fabs(ComputeDistance(inputVector[i].location, inputVector[pair.first].location, inputVector[pair.second].location));
|
const double distance = std::fabs(fastDistance(inputVector[i].location, inputVector[pair.first].location, inputVector[pair.second].location));
|
||||||
if(distance > DouglasPeuckerThresholds[zoomLevel] && distance > maxDistance) {
|
if(distance > DouglasPeuckerThresholds[zoomLevel] && distance > maxDistance) {
|
||||||
indexOfFarthestElement = i;
|
indexOfFarthestElement = i;
|
||||||
maxDistance = distance;
|
maxDistance = distance;
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
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_ */
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
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_ */
|
||||||
@@ -23,13 +23,13 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "../DataStructures/ExtractorStructs.h"
|
//#include "../DataStructures/ExtractorStructs.h"
|
||||||
#include "../DataStructures/SegmentInformation.h"
|
#include "../DataStructures/SegmentInformation.h"
|
||||||
#include "../Util/StringUtil.h"
|
#include "../Util/StringUtil.h"
|
||||||
|
|
||||||
class PolylineCompressor {
|
class PolylineCompressor {
|
||||||
private:
|
private:
|
||||||
inline void encodeVectorSignedNumber(vector<int> & numbers, string & output) {
|
inline void encodeVectorSignedNumber(std::vector<int> & numbers, std::string & output) const {
|
||||||
for(unsigned i = 0; i < numbers.size(); ++i) {
|
for(unsigned i = 0; i < numbers.size(); ++i) {
|
||||||
numbers[i] <<= 1;
|
numbers[i] <<= 1;
|
||||||
if (numbers[i] < 0) {
|
if (numbers[i] < 0) {
|
||||||
@@ -41,7 +41,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void encodeNumber(int numberToEncode, string & output) {
|
inline void encodeNumber(int numberToEncode, std::string & output) const {
|
||||||
while (numberToEncode >= 0x20) {
|
while (numberToEncode >= 0x20) {
|
||||||
int nextValue = (0x20 | (numberToEncode & 0x1f)) + 63;
|
int nextValue = (0x20 | (numberToEncode & 0x1f)) + 63;
|
||||||
output += (static_cast<char> (nextValue));
|
output += (static_cast<char> (nextValue));
|
||||||
@@ -57,8 +57,8 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline void printEncodedString(const vector<SegmentInformation>& polyline, string &output) {
|
inline void printEncodedString(const std::vector<SegmentInformation>& polyline, std::string &output) const {
|
||||||
vector<int> deltaNumbers;
|
std::vector<int> deltaNumbers;
|
||||||
output += "\"";
|
output += "\"";
|
||||||
if(!polyline.empty()) {
|
if(!polyline.empty()) {
|
||||||
_Coordinate lastCoordinate = polyline[0].location;
|
_Coordinate lastCoordinate = polyline[0].location;
|
||||||
@@ -77,8 +77,8 @@ public:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void printEncodedString(const vector<_Coordinate>& polyline, string &output) {
|
inline void printEncodedString(const std::vector<_Coordinate>& polyline, std::string &output) const {
|
||||||
vector<int> deltaNumbers(2*polyline.size());
|
std::vector<int> deltaNumbers(2*polyline.size());
|
||||||
output += "\"";
|
output += "\"";
|
||||||
if(!polyline.empty()) {
|
if(!polyline.empty()) {
|
||||||
deltaNumbers[0] = polyline[0].lat;
|
deltaNumbers[0] = polyline[0].lat;
|
||||||
@@ -92,9 +92,9 @@ public:
|
|||||||
output += "\"";
|
output += "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void printUnencodedString(vector<_Coordinate> & polyline, string & output) {
|
inline void printUnencodedString(std::vector<_Coordinate> & polyline, std::string & output) const {
|
||||||
output += "[";
|
output += "[";
|
||||||
string tmp;
|
std::string tmp;
|
||||||
for(unsigned i = 0; i < polyline.size(); i++) {
|
for(unsigned i = 0; i < polyline.size(); i++) {
|
||||||
convertInternalLatLonToString(polyline[i].lat, tmp);
|
convertInternalLatLonToString(polyline[i].lat, tmp);
|
||||||
output += "[";
|
output += "[";
|
||||||
@@ -110,9 +110,9 @@ public:
|
|||||||
output += "]";
|
output += "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void printUnencodedString(vector<SegmentInformation> & polyline, string & output) {
|
inline void printUnencodedString(std::vector<SegmentInformation> & polyline, std::string & output) const {
|
||||||
output += "[";
|
output += "[";
|
||||||
string tmp;
|
std::string tmp;
|
||||||
for(unsigned i = 0; i < polyline.size(); i++) {
|
for(unsigned i = 0; i < polyline.size(); i++) {
|
||||||
if(!polyline[i].necessary)
|
if(!polyline[i].necessary)
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -0,0 +1,382 @@
|
|||||||
|
/*
|
||||||
|
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_ */
|
||||||
@@ -21,20 +21,12 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
#ifndef CONTRACTIONCLEANUP_H_INCLUDED
|
#ifndef CONTRACTIONCLEANUP_H_INCLUDED
|
||||||
#define CONTRACTIONCLEANUP_H_INCLUDED
|
#define CONTRACTIONCLEANUP_H_INCLUDED
|
||||||
|
|
||||||
#ifdef _GLIBCXX_PARALLEL
|
|
||||||
#include <parallel/algorithm>
|
|
||||||
#else
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#endif
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#endif
|
#endif
|
||||||
#include "Contractor.h"
|
#include "Contractor.h"
|
||||||
|
|
||||||
#ifdef _OPENMP
|
|
||||||
#include <omp.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class ContractionCleanup {
|
class ContractionCleanup {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -44,11 +36,8 @@ private:
|
|||||||
parent = p;
|
parent = p;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#ifdef _MANYCORES
|
|
||||||
typedef BinaryHeap< NodeID, NodeID, int, _HeapData, DenseStorage<NodeID, NodeID> > _Heap;
|
|
||||||
#else
|
|
||||||
typedef BinaryHeap< NodeID, NodeID, int, _CleanupHeapData > _Heap;
|
typedef BinaryHeap< NodeID, NodeID, int, _CleanupHeapData > _Heap;
|
||||||
#endif
|
|
||||||
struct _ThreadData {
|
struct _ThreadData {
|
||||||
_Heap* _heapForward;
|
_Heap* _heapForward;
|
||||||
_Heap* _heapBackward;
|
_Heap* _heapBackward;
|
||||||
@@ -56,8 +45,7 @@ private:
|
|||||||
_heapBackward = new _Heap(nodes);
|
_heapBackward = new _Heap(nodes);
|
||||||
_heapForward = new _Heap(nodes);
|
_heapForward = new _Heap(nodes);
|
||||||
}
|
}
|
||||||
~_ThreadData()
|
~_ThreadData() {
|
||||||
{
|
|
||||||
delete _heapBackward;
|
delete _heapBackward;
|
||||||
delete _heapForward;
|
delete _heapForward;
|
||||||
}
|
}
|
||||||
@@ -69,15 +57,19 @@ public:
|
|||||||
NodeID source;
|
NodeID source;
|
||||||
NodeID target;
|
NodeID target;
|
||||||
struct EdgeData {
|
struct EdgeData {
|
||||||
NodeID via;
|
NodeID via;
|
||||||
unsigned nameID1;
|
unsigned nameID;
|
||||||
unsigned nameID2;
|
int distance;
|
||||||
int distance;
|
TurnInstruction turnInstruction;
|
||||||
bool shortcut;
|
bool shortcut:1;
|
||||||
bool forward;
|
bool forward:1;
|
||||||
bool backward;
|
bool backward:1;
|
||||||
short turnInstruction;
|
|
||||||
} data;
|
} 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
|
//sorts by source and other attributes
|
||||||
static bool CompareBySource( const Edge& left, const Edge& right ) {
|
static bool CompareBySource( const Edge& left, const Edge& right ) {
|
||||||
@@ -95,7 +87,7 @@ public:
|
|||||||
bool operator== ( const Edge& right ) const {
|
bool operator== ( const Edge& right ) const {
|
||||||
return ( source == right.source && target == right.target && data.distance == right.data.distance &&
|
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.shortcut == right.data.shortcut && data.forward == right.data.forward && data.backward == right.data.backward
|
||||||
&& data.via == right.data.via && data.nameID1 == right.data.nameID1 && data.nameID2 == right.data.nameID2
|
&& data.via == right.data.via && data.nameID == right.data.nameID
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -124,11 +116,7 @@ public:
|
|||||||
edges.push_back( newEdge );
|
edges.push_back( newEdge );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef _GLIBCXX_PARALLEL
|
|
||||||
__gnu_parallel::sort( edges.begin(), edges.end() );
|
|
||||||
#else
|
|
||||||
sort( edges.begin(), edges.end() );
|
sort( edges.begin(), edges.end() );
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -141,15 +129,11 @@ private:
|
|||||||
|
|
||||||
void BuildOutgoingGraph() {
|
void BuildOutgoingGraph() {
|
||||||
//sort edges by source
|
//sort edges by source
|
||||||
#ifdef _GLIBCXX_PARALLEL
|
|
||||||
__gnu_parallel::sort( _graph.begin(), _graph.end(), Edge::CompareBySource );
|
|
||||||
#else
|
|
||||||
sort( _graph.begin(), _graph.end(), Edge::CompareBySource );
|
sort( _graph.begin(), _graph.end(), Edge::CompareBySource );
|
||||||
#endif
|
|
||||||
try {
|
try {
|
||||||
_firstEdge.resize( _numNodes + 1 );
|
_firstEdge.resize( _numNodes + 1 );
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
cerr << "Not enough RAM on machine" << endl;
|
ERR("Not enough RAM on machine");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_firstEdge[0] = 0;
|
_firstEdge[0] = 0;
|
||||||
@@ -169,25 +153,11 @@ private:
|
|||||||
threadData.push_back( new _ThreadData( _numNodes ) );
|
threadData.push_back( new _ThreadData( _numNodes ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
cout << "Scanning for useless shortcuts" << endl;
|
INFO("Scanning for useless shortcuts");
|
||||||
BuildOutgoingGraph();
|
BuildOutgoingGraph();
|
||||||
#pragma omp parallel for
|
/*
|
||||||
|
#pragma omp parallel for
|
||||||
for ( int i = 0; i < ( int ) _graph.size(); i++ ) {
|
for ( int i = 0; i < ( int ) _graph.size(); i++ ) {
|
||||||
for ( unsigned edge = _firstEdge[_graph[i].source]; edge < _firstEdge[_graph[i].source + 1]; ++edge ) {
|
|
||||||
if ( edge == (unsigned)i )
|
|
||||||
continue;
|
|
||||||
if ( _graph[edge].target != _graph[i].target )
|
|
||||||
continue;
|
|
||||||
if ( _graph[edge].data.distance < _graph[i].data.distance )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
_graph[edge].data.forward &= !_graph[i].data.forward;
|
|
||||||
_graph[edge].data.backward &= !_graph[i].data.backward;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !_graph[i].data.forward && !_graph[i].data.backward )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
//only remove shortcuts
|
//only remove shortcuts
|
||||||
if ( !_graph[i].data.shortcut )
|
if ( !_graph[i].data.shortcut )
|
||||||
continue;
|
continue;
|
||||||
@@ -200,22 +170,22 @@ private:
|
|||||||
}
|
}
|
||||||
if ( _graph[i].data.backward ) {
|
if ( _graph[i].data.backward ) {
|
||||||
int result = _ComputeDistance( _graph[i].target, _graph[i].source, threadData[omp_get_thread_num()] );
|
int result = _ComputeDistance( _graph[i].target, _graph[i].source, threadData[omp_get_thread_num()] );
|
||||||
|
|
||||||
if ( result < _graph[i].data.distance ) {
|
if ( result < _graph[i].data.distance ) {
|
||||||
_graph[i].data.backward = false;
|
_graph[i].data.backward = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
cout << "Removing edges" << endl;
|
INFO("Removing edges");
|
||||||
int useful = 0;
|
int useful = 0;
|
||||||
for ( int i = 0; i < ( int ) _graph.size(); i++ ) {
|
for ( int i = 0; i < ( int ) _graph.size(); i++ ) {
|
||||||
if ( !_graph[i].data.forward && !_graph[i].data.backward && _graph[i].data.shortcut )
|
if ( !_graph[i].data.forward && !_graph[i].data.backward && _graph[i].data.shortcut ) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
_graph[useful] = _graph[i];
|
_graph[useful] = _graph[i];
|
||||||
useful++;
|
useful++;
|
||||||
}
|
}
|
||||||
cout << "Removed " << _graph.size() - useful << " useless shortcuts" << endl;
|
INFO("Removed " << _graph.size() - useful << " useless shortcuts");
|
||||||
_graph.resize( useful );
|
_graph.resize( useful );
|
||||||
|
|
||||||
for ( int threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
for ( int threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
||||||
@@ -228,6 +198,11 @@ private:
|
|||||||
const NodeID node = heapForward->DeleteMin();
|
const NodeID node = heapForward->DeleteMin();
|
||||||
const int distance = heapForward->GetKey( node );
|
const int distance = heapForward->GetKey( node );
|
||||||
|
|
||||||
|
if ( distance > *targetDistance ) {
|
||||||
|
heapForward->DeleteAll();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ( heapBackward->WasInserted( node ) ) {
|
if ( heapBackward->WasInserted( node ) ) {
|
||||||
const int newDistance = heapBackward->GetKey( node ) + distance;
|
const int newDistance = heapBackward->GetKey( node ) + distance;
|
||||||
if ( newDistance < *targetDistance ) {
|
if ( newDistance < *targetDistance ) {
|
||||||
@@ -236,11 +211,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( distance > *targetDistance ) {
|
for ( int edge = _firstEdge[node], endEdges = _firstEdge[node + 1]; edge != endEdges; ++edge ) {
|
||||||
heapForward->DeleteAll();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for ( int edge = _firstEdge[node], endEdges = _firstEdge[node + 1]; edge != endEdges; ++edge ) {
|
|
||||||
const NodeID to = _graph[edge].target;
|
const NodeID to = _graph[edge].target;
|
||||||
const int edgeWeight = _graph[edge].data.distance;
|
const int edgeWeight = _graph[edge].data.distance;
|
||||||
assert( edgeWeight > 0 );
|
assert( edgeWeight > 0 );
|
||||||
@@ -261,15 +232,15 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int _ComputeDistance( NodeID source, NodeID target, _ThreadData * data, std::vector< NodeID >* path = NULL ) {
|
int _ComputeDistance( NodeID source, NodeID target, _ThreadData * data ) {
|
||||||
data->_heapForward->Clear();
|
data->_heapForward->Clear();
|
||||||
data->_heapBackward->Clear();
|
data->_heapBackward->Clear();
|
||||||
//insert source into heap
|
//insert source into heap
|
||||||
data->_heapForward->Insert( source, 0, source );
|
data->_heapForward->Insert( source, 0, source );
|
||||||
data->_heapBackward->Insert( target, 0, target );
|
data->_heapBackward->Insert( target, 0, target );
|
||||||
|
|
||||||
int targetDistance = (std::numeric_limits< int >::max)();
|
int targetDistance = std::numeric_limits< int >::max();
|
||||||
NodeID middle = (std::numeric_limits<NodeID>::max)();
|
NodeID middle = std::numeric_limits<NodeID>::max();
|
||||||
|
|
||||||
while ( data->_heapForward->Size() + data->_heapBackward->Size() > 0 ) {
|
while ( data->_heapForward->Size() + data->_heapBackward->Size() > 0 ) {
|
||||||
if ( data->_heapForward->Size() > 0 ) {
|
if ( data->_heapForward->Size() > 0 ) {
|
||||||
|
|||||||
@@ -20,63 +20,67 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
|
|
||||||
#ifndef CONTRACTOR_H_INCLUDED
|
#ifndef CONTRACTOR_H_INCLUDED
|
||||||
#define CONTRACTOR_H_INCLUDED
|
#define CONTRACTOR_H_INCLUDED
|
||||||
#ifdef _GLIBCXX_PARALLEL
|
|
||||||
#include <parallel/algorithm>
|
|
||||||
#else
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#endif
|
#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 <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
#include "TemporaryStorage.h"
|
||||||
|
#include "../DataStructures/BinaryHeap.h"
|
||||||
|
#include "../DataStructures/DeallocatingVector.h"
|
||||||
#include "../DataStructures/DynamicGraph.h"
|
#include "../DataStructures/DynamicGraph.h"
|
||||||
#include "../DataStructures/Percent.h"
|
#include "../DataStructures/Percent.h"
|
||||||
#include "../DataStructures/BinaryHeap.h"
|
#include "../DataStructures/XORFastHash.h"
|
||||||
#include <ctime>
|
#include "../DataStructures/XORFastHashStorage.h"
|
||||||
#include <vector>
|
#include "../Util/OpenMPWrapper.h"
|
||||||
#include <queue>
|
#include "../Util/StringUtil.h"
|
||||||
#include <set>
|
|
||||||
#include <stack>
|
|
||||||
#include <limits>
|
|
||||||
#ifdef _OPEMP
|
|
||||||
#include <omp.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class Contractor {
|
class Contractor {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct _ContractorEdgeData {
|
||||||
struct _EdgeBasedContractorEdgeData {
|
_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 distance;
|
||||||
unsigned originalEdges;
|
unsigned id;
|
||||||
unsigned via;
|
unsigned originalEdges:28;
|
||||||
unsigned nameID;
|
bool shortcut:1;
|
||||||
bool shortcut;
|
bool forward:1;
|
||||||
bool forward;
|
bool backward:1;
|
||||||
bool backward;
|
bool originalViaNodeID:1;
|
||||||
short turnInstruction;
|
|
||||||
} data;
|
} data;
|
||||||
|
|
||||||
struct _HeapData {
|
struct _HeapData {
|
||||||
|
short hop;
|
||||||
bool target;
|
bool target;
|
||||||
_HeapData() : target(false) {}
|
_HeapData() : hop(0), target(false) {}
|
||||||
_HeapData( bool t ) : target(t) {}
|
_HeapData( short h, bool t ) : hop(h), target(t) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef DynamicGraph< _EdgeBasedContractorEdgeData > _DynamicGraph;
|
typedef DynamicGraph< _ContractorEdgeData > _DynamicGraph;
|
||||||
typedef BinaryHeap< NodeID, NodeID, int, _HeapData> _Heap;
|
// typedef BinaryHeap< NodeID, NodeID, int, _HeapData, ArrayStorage<NodeID, NodeID> > _Heap;
|
||||||
typedef _DynamicGraph::InputEdge _ImportEdge;
|
typedef BinaryHeap< NodeID, NodeID, int, _HeapData, XORFastHashStorage<NodeID, NodeID> > _Heap;
|
||||||
|
typedef _DynamicGraph::InputEdge _ContractorEdge;
|
||||||
|
|
||||||
struct _ThreadData {
|
struct _ThreadData {
|
||||||
_Heap heap;
|
_Heap heap;
|
||||||
std::vector< _ImportEdge > insertedEdges;
|
std::vector< _ContractorEdge > insertedEdges;
|
||||||
std::vector< NodeID > neighbours;
|
std::vector< NodeID > neighbours;
|
||||||
_ThreadData( NodeID nodes ): heap( nodes ) {
|
_ThreadData( NodeID nodes ): heap( nodes ) { }
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _PriorityData {
|
struct _PriorityData {
|
||||||
int depth;
|
int depth;
|
||||||
NodeID bias;
|
_PriorityData() : depth(0) { }
|
||||||
_PriorityData() : depth(0), bias(0) { }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _ContractionInformation {
|
struct _ContractionInformation {
|
||||||
@@ -84,80 +88,71 @@ private:
|
|||||||
int edgesAdded;
|
int edgesAdded;
|
||||||
int originalEdgesDeleted;
|
int originalEdgesDeleted;
|
||||||
int originalEdgesAdded;
|
int originalEdgesAdded;
|
||||||
_ContractionInformation() {
|
_ContractionInformation() : edgesDeleted(0), edgesAdded(0), originalEdgesDeleted(0), originalEdgesAdded(0) {}
|
||||||
edgesAdded = edgesDeleted = originalEdgesAdded = originalEdgesDeleted = 0;
|
};
|
||||||
}
|
|
||||||
|
struct _RemainingNodeData {
|
||||||
|
_RemainingNodeData() : id (0), isIndependent(false) {}
|
||||||
|
NodeID id:31;
|
||||||
|
bool isIndependent:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _NodePartitionor {
|
struct _NodePartitionor {
|
||||||
bool operator()( std::pair< NodeID, bool > nodeData ) {
|
inline bool operator()(_RemainingNodeData & nodeData ) const {
|
||||||
return !nodeData.second;
|
return !nodeData.isIndependent;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
template< class InputEdge >
|
template<class ContainerT >
|
||||||
Contractor( int nodes, std::vector< InputEdge >& inputEdges, unsigned eqf = 2, unsigned oqf = 1, unsigned df = 1) : edgeQuotionFactor(eqf), originalQuotientFactor(oqf), depthFactor(df) {
|
Contractor( int nodes, ContainerT& inputEdges) {
|
||||||
|
std::vector< _ContractorEdge > edges;
|
||||||
|
edges.reserve(inputEdges.size()*2);
|
||||||
|
|
||||||
std::vector< _ImportEdge > edges;
|
typename ContainerT::deallocation_iterator diter = inputEdges.dbegin();
|
||||||
edges.reserve( 2 * inputEdges.size() );
|
typename ContainerT::deallocation_iterator dend = inputEdges.dend();
|
||||||
for ( typename std::vector< InputEdge >::const_iterator i = inputEdges.begin(), e = inputEdges.end(); i != e; ++i ) {
|
|
||||||
_ImportEdge edge;
|
|
||||||
edge.source = i->source();
|
|
||||||
edge.target = i->target();
|
|
||||||
|
|
||||||
edge.data.distance = (std::max)((int)i->weight(), 1 );
|
_ContractorEdge newEdge;
|
||||||
assert( edge.data.distance > 0 );
|
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
|
#ifndef NDEBUG
|
||||||
if ( edge.data.distance > 24 * 60 * 60 * 10 ) {
|
if ( newEdge.data.distance > 24 * 60 * 60 * 10 ) {
|
||||||
std::cout << "Edge Weight too large -> May lead to invalid CH" << std::endl;
|
WARN("Edge weight large -> " << newEdge.data.distance);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
edge.data.shortcut = false;
|
edges.push_back( newEdge );
|
||||||
edge.data.nameID = i->getNameIDOfTurnTarget();
|
std::swap( newEdge.source, newEdge.target );
|
||||||
edge.data.via = i->via();
|
newEdge.data.forward = diter->isBackward();
|
||||||
edge.data.turnInstruction = i->turnInstruction();
|
newEdge.data.backward = diter->isForward();
|
||||||
edge.data.forward = i->isForward();
|
edges.push_back( newEdge );
|
||||||
edge.data.backward = i->isBackward();
|
++diter;
|
||||||
edge.data.originalEdges = 1;
|
|
||||||
edges.push_back( edge );
|
|
||||||
std::swap( edge.source, edge.target );
|
|
||||||
edge.data.forward = i->isBackward();
|
|
||||||
edge.data.backward = i->isForward();
|
|
||||||
edges.push_back( edge );
|
|
||||||
}
|
}
|
||||||
//remove data from memory
|
//clear input vector and trim the current set of edges with the well-known swap trick
|
||||||
inputEdges.clear();
|
inputEdges.clear();
|
||||||
std::vector< InputEdge >().swap( inputEdges );
|
|
||||||
|
|
||||||
#ifdef _GLIBCXX_PARALLEL
|
|
||||||
__gnu_parallel::sort( edges.begin(), edges.end() );
|
|
||||||
#else
|
|
||||||
sort( edges.begin(), edges.end() );
|
sort( edges.begin(), edges.end() );
|
||||||
#endif
|
|
||||||
NodeID edge = 0;
|
NodeID edge = 0;
|
||||||
for ( NodeID i = 0; i < edges.size(); ) {
|
for ( NodeID i = 0; i < edges.size(); ) {
|
||||||
const NodeID source = edges[i].source;
|
const NodeID source = edges[i].source;
|
||||||
const NodeID target = edges[i].target;
|
const NodeID target = edges[i].target;
|
||||||
const NodeID via = edges[i].data.via;
|
const NodeID id = edges[i].data.id;
|
||||||
const short turnType = edges[i].data.turnInstruction;
|
|
||||||
//remove eigenloops
|
//remove eigenloops
|
||||||
if ( source == target ) {
|
if ( source == target ) {
|
||||||
i++;
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
_ImportEdge forwardEdge;
|
_ContractorEdge forwardEdge;
|
||||||
_ImportEdge backwardEdge;
|
_ContractorEdge backwardEdge;
|
||||||
forwardEdge.source = backwardEdge.source = source;
|
forwardEdge.source = backwardEdge.source = source;
|
||||||
forwardEdge.target = backwardEdge.target = target;
|
forwardEdge.target = backwardEdge.target = target;
|
||||||
forwardEdge.data.forward = backwardEdge.data.backward = true;
|
forwardEdge.data.forward = backwardEdge.data.backward = true;
|
||||||
forwardEdge.data.backward = backwardEdge.data.forward = false;
|
forwardEdge.data.backward = backwardEdge.data.forward = false;
|
||||||
forwardEdge.data.turnInstruction = backwardEdge.data.turnInstruction = turnType;
|
|
||||||
forwardEdge.data.nameID = backwardEdge.data.nameID = edges[i].data.nameID;
|
|
||||||
forwardEdge.data.shortcut = backwardEdge.data.shortcut = false;
|
forwardEdge.data.shortcut = backwardEdge.data.shortcut = false;
|
||||||
forwardEdge.data.via = backwardEdge.data.via = via;
|
forwardEdge.data.id = backwardEdge.data.id = id;
|
||||||
forwardEdge.data.originalEdges = backwardEdge.data.originalEdges = 1;
|
forwardEdge.data.originalEdges = backwardEdge.data.originalEdges = 1;
|
||||||
forwardEdge.data.distance = backwardEdge.data.distance = std::numeric_limits< int >::max();
|
forwardEdge.data.distance = backwardEdge.data.distance = std::numeric_limits< int >::max();
|
||||||
//remove parallel edges
|
//remove parallel edges
|
||||||
@@ -183,37 +178,60 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::cout << "ok" << std::endl << "merged " << edges.size() - edge << " edges out of " << edges.size() << std::endl;
|
std::cout << "merged " << edges.size() - edge << " edges out of " << edges.size() << std::endl;
|
||||||
edges.resize( edge );
|
edges.resize( edge );
|
||||||
_graph.reset( new _DynamicGraph( nodes, edges ) );
|
_graph = boost::make_shared<_DynamicGraph>( nodes, edges );
|
||||||
std::vector< _ImportEdge >().swap( 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() { }
|
~Contractor() {
|
||||||
|
//Delete temporary file
|
||||||
|
// remove(temporaryEdgeStorageFilename.c_str());
|
||||||
|
TemporaryStorage::GetInstance().deallocateSlot(temporaryStorageSlotID);
|
||||||
|
}
|
||||||
|
|
||||||
void Run() {
|
void Run() {
|
||||||
const NodeID numberOfNodes = _graph->GetNumberOfNodes();
|
const NodeID numberOfNodes = _graph->GetNumberOfNodes();
|
||||||
Percent p (numberOfNodes);
|
Percent p (numberOfNodes);
|
||||||
|
|
||||||
unsigned maxThreads = omp_get_max_threads();
|
const unsigned maxThreads = omp_get_max_threads();
|
||||||
std::vector < _ThreadData* > threadData;
|
std::vector < _ThreadData* > threadData;
|
||||||
for ( unsigned threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
for ( unsigned threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
||||||
threadData.push_back( new _ThreadData( numberOfNodes ) );
|
threadData.push_back( new _ThreadData( numberOfNodes ) );
|
||||||
}
|
}
|
||||||
std::cout << "Contractor is using " << maxThreads << " threads" << std::endl;
|
std::cout << "Contractor is using " << maxThreads << " threads" << std::endl;
|
||||||
|
|
||||||
NodeID levelID = 0;
|
NodeID numberOfContractedNodes = 0;
|
||||||
std::vector< std::pair< NodeID, bool > > remainingNodes( numberOfNodes );
|
std::vector< _RemainingNodeData > remainingNodes( numberOfNodes );
|
||||||
std::vector< double > nodePriority( numberOfNodes );
|
std::vector< float > nodePriority( numberOfNodes );
|
||||||
std::vector< _PriorityData > nodeData( numberOfNodes );
|
std::vector< _PriorityData > nodeData( numberOfNodes );
|
||||||
|
|
||||||
//initialize the variables
|
//initialize the variables
|
||||||
#pragma omp parallel for schedule ( guided )
|
#pragma omp parallel for schedule ( guided )
|
||||||
for ( int x = 0; x < ( int ) numberOfNodes; ++x )
|
for ( int x = 0; x < ( int ) numberOfNodes; ++x )
|
||||||
remainingNodes[x].first = x;
|
remainingNodes[x].id = x;
|
||||||
std::random_shuffle( remainingNodes.begin(), remainingNodes.end() );
|
|
||||||
for ( int x = 0; x < ( int ) numberOfNodes; ++x )
|
|
||||||
nodeData[remainingNodes[x].first].bias = x;
|
|
||||||
|
|
||||||
std::cout << "initializing elimination PQ ..." << std::flush;
|
std::cout << "initializing elimination PQ ..." << std::flush;
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
@@ -226,7 +244,97 @@ public:
|
|||||||
}
|
}
|
||||||
std::cout << "ok" << std::endl << "preprocessing ..." << std::flush;
|
std::cout << "ok" << std::endl << "preprocessing ..." << std::flush;
|
||||||
|
|
||||||
while ( levelID < numberOfNodes ) {
|
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();
|
const int last = ( int ) remainingNodes.size();
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
{
|
{
|
||||||
@@ -234,12 +342,12 @@ public:
|
|||||||
_ThreadData* const data = threadData[omp_get_thread_num()];
|
_ThreadData* const data = threadData[omp_get_thread_num()];
|
||||||
#pragma omp for schedule ( guided )
|
#pragma omp for schedule ( guided )
|
||||||
for ( int i = 0; i < last; ++i ) {
|
for ( int i = 0; i < last; ++i ) {
|
||||||
const NodeID node = remainingNodes[i].first;
|
const NodeID node = remainingNodes[i].id;
|
||||||
remainingNodes[i].second = _IsIndependent( nodePriority, nodeData, data, node );
|
remainingNodes[i].isIndependent = _IsIndependent( nodePriority/*, nodeData*/, data, node );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_NodePartitionor functor;
|
_NodePartitionor functor;
|
||||||
const std::vector < std::pair < NodeID, bool > >::const_iterator first = stable_partition( remainingNodes.begin(), remainingNodes.end(), functor );
|
const std::vector < _RemainingNodeData >::const_iterator first = stable_partition( remainingNodes.begin(), remainingNodes.end(), functor );
|
||||||
const int firstIndependent = first - remainingNodes.begin();
|
const int firstIndependent = first - remainingNodes.begin();
|
||||||
//contract independent nodes
|
//contract independent nodes
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
@@ -247,10 +355,11 @@ public:
|
|||||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||||
#pragma omp for schedule ( guided ) nowait
|
#pragma omp for schedule ( guided ) nowait
|
||||||
for ( int position = firstIndependent ; position < last; ++position ) {
|
for ( int position = firstIndependent ; position < last; ++position ) {
|
||||||
NodeID x = remainingNodes[position].first;
|
NodeID x = remainingNodes[position].id;
|
||||||
_Contract< false > ( data, x );
|
_Contract< false > ( data, x );
|
||||||
nodePriority[x] = -1;
|
//nodePriority[x] = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort( data->insertedEdges.begin(), data->insertedEdges.end() );
|
std::sort( data->insertedEdges.begin(), data->insertedEdges.end() );
|
||||||
}
|
}
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
@@ -258,18 +367,27 @@ public:
|
|||||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||||
#pragma omp for schedule ( guided ) nowait
|
#pragma omp for schedule ( guided ) nowait
|
||||||
for ( int position = firstIndependent ; position < last; ++position ) {
|
for ( int position = firstIndependent ; position < last; ++position ) {
|
||||||
NodeID x = remainingNodes[position].first;
|
NodeID x = remainingNodes[position].id;
|
||||||
_DeleteIncomingEdges( data, x );
|
_DeleteIncomingEdges( data, x );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//insert new edges
|
//insert new edges
|
||||||
for ( unsigned threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
for ( unsigned threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
||||||
_ThreadData& data = *threadData[threadNum];
|
_ThreadData& data = *threadData[threadNum];
|
||||||
for ( int i = 0; i < ( int ) data.insertedEdges.size(); ++i ) {
|
BOOST_FOREACH(const _ContractorEdge& edge, data.insertedEdges) {
|
||||||
const _ImportEdge& edge = data.insertedEdges[i];
|
_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 );
|
_graph->InsertEdge( edge.source, edge.target, edge.data );
|
||||||
}
|
}
|
||||||
std::vector< _ImportEdge >().swap( data.insertedEdges );
|
data.insertedEdges.clear();
|
||||||
}
|
}
|
||||||
//update priorities
|
//update priorities
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
@@ -277,46 +395,108 @@ public:
|
|||||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||||
#pragma omp for schedule ( guided ) nowait
|
#pragma omp for schedule ( guided ) nowait
|
||||||
for ( int position = firstIndependent ; position < last; ++position ) {
|
for ( int position = firstIndependent ; position < last; ++position ) {
|
||||||
NodeID x = remainingNodes[position].first;
|
NodeID x = remainingNodes[position].id;
|
||||||
_UpdateNeighbours( &nodePriority, &nodeData, data, x );
|
_UpdateNeighbours( nodePriority, nodeData, data, x );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//remove contracted nodes from the pool
|
//remove contracted nodes from the pool
|
||||||
levelID += last - firstIndependent;
|
numberOfContractedNodes += last - firstIndependent;
|
||||||
remainingNodes.resize( firstIndependent );
|
remainingNodes.resize( firstIndependent );
|
||||||
std::vector< std::pair< NodeID, bool > >( remainingNodes ).swap( remainingNodes );
|
std::vector< _RemainingNodeData>( remainingNodes ).swap( remainingNodes );
|
||||||
p.printStatus(levelID);
|
// 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);
|
||||||
|
|
||||||
for ( unsigned threadNum = 0; threadNum < maxThreads; threadNum++ ) {
|
p.printStatus(numberOfContractedNodes);
|
||||||
delete threadData[threadNum];
|
|
||||||
}
|
}
|
||||||
|
BOOST_FOREACH(_ThreadData * data, threadData)
|
||||||
|
delete data;
|
||||||
|
threadData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
template< class Edge >
|
template< class Edge >
|
||||||
void GetEdges( std::vector< Edge >& edges ) {
|
inline void GetEdges( DeallocatingVector< Edge >& edges ) {
|
||||||
|
Percent p (_graph->GetNumberOfNodes());
|
||||||
|
INFO("Getting edges of minimized graph");
|
||||||
NodeID numberOfNodes = _graph->GetNumberOfNodes();
|
NodeID numberOfNodes = _graph->GetNumberOfNodes();
|
||||||
for ( NodeID node = 0; node < numberOfNodes; ++node ) {
|
if(oldNodeIDFromNewNodeIDMap.size()) {
|
||||||
for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge < endEdges; edge++ ) {
|
for ( NodeID node = 0; node < numberOfNodes; ++node ) {
|
||||||
const NodeID target = _graph->GetTarget( edge );
|
p.printStatus(node);
|
||||||
const _EdgeBasedContractorEdgeData& data = _graph->GetEdgeData( edge );
|
for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge < endEdges; ++edge ) {
|
||||||
Edge newEdge;
|
const NodeID target = _graph->GetTarget( edge );
|
||||||
newEdge.source = node;
|
const _DynamicGraph::EdgeData& data = _graph->GetEdgeData( edge );
|
||||||
newEdge.target = target;
|
Edge newEdge;
|
||||||
newEdge.data.distance = data.distance;
|
newEdge.source = oldNodeIDFromNewNodeIDMap[node];
|
||||||
newEdge.data.shortcut = data.shortcut;
|
newEdge.target = oldNodeIDFromNewNodeIDMap[target];
|
||||||
newEdge.data.via = data.via;
|
assert(UINT_MAX != newEdge.source);
|
||||||
newEdge.data.nameID1 = data.nameID;
|
assert(UINT_MAX != newEdge.target);
|
||||||
newEdge.data.turnInstruction = data.turnInstruction;
|
|
||||||
newEdge.data.forward = data.forward;
|
newEdge.data.distance = data.distance;
|
||||||
newEdge.data.backward = data.backward;
|
newEdge.data.shortcut = data.shortcut;
|
||||||
edges.push_back( newEdge );
|
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:
|
private:
|
||||||
void _Dijkstra( const int maxDistance, const unsigned numTargets, const int maxNodes, _ThreadData* data ){
|
inline void _Dijkstra( const int maxDistance, const unsigned numTargets, const int maxNodes, _ThreadData* const data, const NodeID middleNode ){
|
||||||
|
|
||||||
_Heap& heap = data->heap;
|
_Heap& heap = data->heap;
|
||||||
|
|
||||||
@@ -325,62 +505,71 @@ private:
|
|||||||
while ( heap.Size() > 0 ) {
|
while ( heap.Size() > 0 ) {
|
||||||
const NodeID node = heap.DeleteMin();
|
const NodeID node = heap.DeleteMin();
|
||||||
const int distance = heap.GetKey( node );
|
const int distance = heap.GetKey( node );
|
||||||
if ( nodes++ > maxNodes )
|
const short currentHop = heap.GetData( node ).hop+1;
|
||||||
|
|
||||||
|
if ( ++nodes > maxNodes )
|
||||||
return;
|
return;
|
||||||
//Destination settled?
|
//Destination settled?
|
||||||
if ( distance > maxDistance )
|
if ( distance > maxDistance )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ( heap.GetData( node ).target ) {
|
if ( heap.GetData( node ).target ) {
|
||||||
targetsFound++;
|
++targetsFound;
|
||||||
if ( targetsFound >= numTargets )
|
if ( targetsFound >= numTargets )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//iterate over all edges of node
|
//iterate over all edges of node
|
||||||
for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge != endEdges; ++edge ) {
|
for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge != endEdges; ++edge ) {
|
||||||
const _EdgeBasedContractorEdgeData& data = _graph->GetEdgeData( edge );
|
const _ContractorEdgeData& data = _graph->GetEdgeData( edge );
|
||||||
if ( !data.forward )
|
if ( !data.forward )
|
||||||
continue;
|
continue;
|
||||||
const NodeID to = _graph->GetTarget( edge );
|
const NodeID to = _graph->GetTarget( edge );
|
||||||
|
if(middleNode == to)
|
||||||
|
continue;
|
||||||
const int toDistance = distance + data.distance;
|
const int toDistance = distance + data.distance;
|
||||||
|
|
||||||
//New Node discovered -> Add to Heap + Node Info Storage
|
//New Node discovered -> Add to Heap + Node Info Storage
|
||||||
if ( !heap.WasInserted( to ) )
|
if ( !heap.WasInserted( to ) )
|
||||||
heap.Insert( to, toDistance, _HeapData() );
|
heap.Insert( to, toDistance, _HeapData(currentHop, false) );
|
||||||
|
|
||||||
//Found a shorter Path -> Update distance
|
//Found a shorter Path -> Update distance
|
||||||
else if ( toDistance < heap.GetKey( to ) ) {
|
else if ( toDistance < heap.GetKey( to ) ) {
|
||||||
heap.DecreaseKey( to, toDistance );
|
heap.DecreaseKey( to, toDistance );
|
||||||
//heap.GetData( to ).hops = hops + 1;
|
heap.GetData( to ).hop = currentHop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double _Evaluate( _ThreadData* const data, _PriorityData* const nodeData, NodeID node ){
|
inline float _Evaluate( _ThreadData* const data, _PriorityData* const nodeData, const NodeID node){
|
||||||
_ContractionInformation stats;
|
_ContractionInformation stats;
|
||||||
|
|
||||||
//perform simulated contraction
|
//perform simulated contraction
|
||||||
_Contract< true > ( data, node, &stats );
|
_Contract< true> ( data, node, &stats );
|
||||||
|
|
||||||
// Result will contain the priority
|
// Result will contain the priority
|
||||||
if ( stats.edgesDeleted == 0 || stats.originalEdgesDeleted == 0 )
|
float result;
|
||||||
return depthFactor * nodeData->depth;
|
if ( 0 == (stats.edgesDeleted*stats.originalEdgesDeleted) )
|
||||||
return edgeQuotionFactor * ((( double ) stats.edgesAdded ) / stats.edgesDeleted ) + originalQuotientFactor * ((( double ) stats.originalEdgesAdded ) / stats.originalEdgesDeleted ) + depthFactor * nodeData->depth;
|
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 > bool _Contract( _ThreadData* data, NodeID node, _ContractionInformation* stats = NULL ) {
|
template< bool Simulate >
|
||||||
|
inline bool _Contract( _ThreadData* data, NodeID node, _ContractionInformation* stats = NULL ) {
|
||||||
_Heap& heap = data->heap;
|
_Heap& heap = data->heap;
|
||||||
int insertedEdgesSize = data->insertedEdges.size();
|
int insertedEdgesSize = data->insertedEdges.size();
|
||||||
std::vector< _ImportEdge >& insertedEdges = data->insertedEdges;
|
std::vector< _ContractorEdge >& insertedEdges = data->insertedEdges;
|
||||||
|
|
||||||
for ( _DynamicGraph::EdgeIterator inEdge = _graph->BeginEdges( node ), endInEdges = _graph->EndEdges( node ); inEdge != endInEdges; ++inEdge ) {
|
for ( _DynamicGraph::EdgeIterator inEdge = _graph->BeginEdges( node ), endInEdges = _graph->EndEdges( node ); inEdge != endInEdges; ++inEdge ) {
|
||||||
const _EdgeBasedContractorEdgeData& inData = _graph->GetEdgeData( inEdge );
|
const _ContractorEdgeData& inData = _graph->GetEdgeData( inEdge );
|
||||||
const NodeID source = _graph->GetTarget( inEdge );
|
const NodeID source = _graph->GetTarget( inEdge );
|
||||||
if ( Simulate ) {
|
if ( Simulate ) {
|
||||||
assert( stats != NULL );
|
assert( stats != NULL );
|
||||||
stats->edgesDeleted++;
|
++stats->edgesDeleted;
|
||||||
stats->originalEdgesDeleted += inData.originalEdges;
|
stats->originalEdgesDeleted += inData.originalEdges;
|
||||||
}
|
}
|
||||||
if ( !inData.backward )
|
if ( !inData.backward )
|
||||||
@@ -388,55 +577,44 @@ private:
|
|||||||
|
|
||||||
heap.Clear();
|
heap.Clear();
|
||||||
heap.Insert( source, 0, _HeapData() );
|
heap.Insert( source, 0, _HeapData() );
|
||||||
if ( node != source )
|
|
||||||
heap.Insert( node, inData.distance, _HeapData() );
|
|
||||||
int maxDistance = 0;
|
int maxDistance = 0;
|
||||||
unsigned numTargets = 0;
|
unsigned numTargets = 0;
|
||||||
|
|
||||||
for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) {
|
for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) {
|
||||||
const _EdgeBasedContractorEdgeData& outData = _graph->GetEdgeData( outEdge );
|
const _ContractorEdgeData& outData = _graph->GetEdgeData( outEdge );
|
||||||
if ( !outData.forward )
|
if ( !outData.forward )
|
||||||
continue;
|
continue;
|
||||||
const NodeID target = _graph->GetTarget( outEdge );
|
const NodeID target = _graph->GetTarget( outEdge );
|
||||||
const int pathDistance = inData.distance + outData.distance;
|
const int pathDistance = inData.distance + outData.distance;
|
||||||
maxDistance = std::max( maxDistance, pathDistance );
|
maxDistance = std::max( maxDistance, pathDistance );
|
||||||
if ( !heap.WasInserted( target ) ) {
|
if ( !heap.WasInserted( target ) ) {
|
||||||
heap.Insert( target, pathDistance, _HeapData( true ) );
|
heap.Insert( target, INT_MAX, _HeapData( 0, true ) );
|
||||||
numTargets++;
|
++numTargets;
|
||||||
} else if ( pathDistance < heap.GetKey( target ) ) {
|
|
||||||
heap.DecreaseKey( target, pathDistance );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( Simulate )
|
if( Simulate )
|
||||||
_Dijkstra( maxDistance, numTargets, 500, data );
|
_Dijkstra( maxDistance, numTargets, 1000, data, node );
|
||||||
else
|
else
|
||||||
_Dijkstra( maxDistance, numTargets, 1000, data );
|
_Dijkstra( maxDistance, numTargets, 2000, data, node );
|
||||||
|
|
||||||
for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) {
|
for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) {
|
||||||
const _EdgeBasedContractorEdgeData& outData = _graph->GetEdgeData( outEdge );
|
const _ContractorEdgeData& outData = _graph->GetEdgeData( outEdge );
|
||||||
if ( !outData.forward )
|
if ( !outData.forward )
|
||||||
continue;
|
continue;
|
||||||
const NodeID target = _graph->GetTarget( outEdge );
|
const NodeID target = _graph->GetTarget( outEdge );
|
||||||
const int pathDistance = inData.distance + outData.distance;
|
const int pathDistance = inData.distance + outData.distance;
|
||||||
const int distance = heap.GetKey( target );
|
const int distance = heap.GetKey( target );
|
||||||
|
if ( pathDistance < distance ) {
|
||||||
if ( pathDistance <= distance ) {
|
|
||||||
if ( Simulate ) {
|
if ( Simulate ) {
|
||||||
assert( stats != NULL );
|
assert( stats != NULL );
|
||||||
stats->edgesAdded+=2;
|
stats->edgesAdded+=2;
|
||||||
stats->originalEdgesAdded += 2* ( outData.originalEdges + inData.originalEdges );
|
stats->originalEdgesAdded += 2* ( outData.originalEdges + inData.originalEdges );
|
||||||
} else {
|
} else {
|
||||||
_ImportEdge newEdge;
|
_ContractorEdge newEdge;
|
||||||
newEdge.source = source;
|
newEdge.source = source;
|
||||||
newEdge.target = target;
|
newEdge.target = target;
|
||||||
newEdge.data.distance = pathDistance;
|
newEdge.data = _ContractorEdgeData( pathDistance, outData.originalEdges + inData.originalEdges, node/*, 0, inData.turnInstruction*/, true, true, false);;
|
||||||
newEdge.data.forward = true;
|
|
||||||
newEdge.data.backward = false;
|
|
||||||
newEdge.data.via = node;
|
|
||||||
newEdge.data.shortcut = true;
|
|
||||||
newEdge.data.turnInstruction = inData.turnInstruction;
|
|
||||||
newEdge.data.originalEdges = outData.originalEdges + inData.originalEdges;
|
|
||||||
insertedEdges.push_back( newEdge );
|
insertedEdges.push_back( newEdge );
|
||||||
std::swap( newEdge.source, newEdge.target );
|
std::swap( newEdge.source, newEdge.target );
|
||||||
newEdge.data.forward = false;
|
newEdge.data.forward = false;
|
||||||
@@ -447,7 +625,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( !Simulate ) {
|
if ( !Simulate ) {
|
||||||
for ( int i = insertedEdgesSize, iend = insertedEdges.size(); i < iend; i++ ) {
|
for ( int i = insertedEdgesSize, iend = insertedEdges.size(); i < iend; ++i ) {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for ( int other = i + 1 ; other < iend ; ++other ) {
|
for ( int other = i + 1 ; other < iend ; ++other ) {
|
||||||
if ( insertedEdges[other].source != insertedEdges[i].source )
|
if ( insertedEdges[other].source != insertedEdges[i].source )
|
||||||
@@ -471,54 +649,48 @@ private:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _DeleteIncomingEdges( _ThreadData* data, NodeID node ) {
|
inline void _DeleteIncomingEdges( _ThreadData* data, const NodeID node ) {
|
||||||
std::vector< NodeID >& neighbours = data->neighbours;
|
std::vector< NodeID >& neighbours = data->neighbours;
|
||||||
neighbours.clear();
|
neighbours.clear();
|
||||||
|
|
||||||
//find all neighbours
|
//find all neighbours
|
||||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ) ; e < _graph->EndEdges( node ) ; ++e ) {
|
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ) ; e < _graph->EndEdges( node ) ; ++e ) {
|
||||||
const NodeID u = _graph->GetTarget( e );
|
const NodeID u = _graph->GetTarget( e );
|
||||||
if ( u == node )
|
if ( u != node )
|
||||||
continue;
|
neighbours.push_back( u );
|
||||||
neighbours.push_back( u );
|
|
||||||
}
|
}
|
||||||
//eliminate duplicate entries ( forward + backward edges )
|
//eliminate duplicate entries ( forward + backward edges )
|
||||||
std::sort( neighbours.begin(), neighbours.end() );
|
std::sort( neighbours.begin(), neighbours.end() );
|
||||||
neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
|
neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
|
||||||
|
|
||||||
for ( int i = 0, e = ( int ) neighbours.size(); i < e; ++i ) {
|
for ( int i = 0, e = ( int ) neighbours.size(); i < e; ++i ) {
|
||||||
const NodeID u = neighbours[i];
|
_graph->DeleteEdgesTo( neighbours[i], node );
|
||||||
_graph->DeleteEdgesTo( u, node );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _UpdateNeighbours( std::vector< double >* priorities, std::vector< _PriorityData >* const nodeData, _ThreadData* const data, NodeID node ) {
|
inline bool _UpdateNeighbours( std::vector< float > & priorities, std::vector< _PriorityData > & nodeData, _ThreadData* const data, const NodeID node) {
|
||||||
std::vector< NodeID >& neighbours = data->neighbours;
|
std::vector< NodeID >& neighbours = data->neighbours;
|
||||||
neighbours.clear();
|
neighbours.clear();
|
||||||
|
|
||||||
//find all neighbours
|
//find all neighbours
|
||||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ) ; e < _graph->EndEdges( node ) ; ++e ) {
|
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ) ; e < endEdges ; ++e ) {
|
||||||
const NodeID u = _graph->GetTarget( e );
|
const NodeID u = _graph->GetTarget( e );
|
||||||
if ( u == node )
|
if ( u == node )
|
||||||
continue;
|
continue;
|
||||||
neighbours.push_back( u );
|
neighbours.push_back( u );
|
||||||
( *nodeData )[u].depth = (std::max)(( *nodeData )[node].depth + 1, ( *nodeData )[u].depth );
|
nodeData[u].depth = (std::max)(nodeData[node].depth + 1, nodeData[u].depth );
|
||||||
}
|
}
|
||||||
//eliminate duplicate entries ( forward + backward edges )
|
//eliminate duplicate entries ( forward + backward edges )
|
||||||
std::sort( neighbours.begin(), neighbours.end() );
|
std::sort( neighbours.begin(), neighbours.end() );
|
||||||
neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
|
neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
|
||||||
|
|
||||||
for ( int i = 0, e = ( int ) neighbours.size(); i < e; ++i ) {
|
BOOST_FOREACH(const NodeID u, neighbours) {
|
||||||
const NodeID u = neighbours[i];
|
priorities[u] = _Evaluate( data, &( nodeData )[u], u );
|
||||||
( *priorities )[u] = _Evaluate( data, &( *nodeData )[u], u );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _IsIndependent( const std::vector< double >& priorities, const std::vector< _PriorityData >& nodeData, _ThreadData* const data, NodeID node ) {
|
inline bool _IsIndependent( const std::vector< float >& priorities/*, const std::vector< _PriorityData >& nodeData*/, _ThreadData* const data, NodeID node ) const {
|
||||||
const double priority = priorities[node];
|
const double priority = priorities[node];
|
||||||
|
|
||||||
std::vector< NodeID >& neighbours = data->neighbours;
|
std::vector< NodeID >& neighbours = data->neighbours;
|
||||||
@@ -526,14 +698,17 @@ private:
|
|||||||
|
|
||||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ) ; e < _graph->EndEdges( node ) ; ++e ) {
|
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ) ; e < _graph->EndEdges( node ) ; ++e ) {
|
||||||
const NodeID target = _graph->GetTarget( e );
|
const NodeID target = _graph->GetTarget( e );
|
||||||
|
if(node==target)
|
||||||
|
continue;
|
||||||
const double targetPriority = priorities[target];
|
const double targetPriority = priorities[target];
|
||||||
assert( targetPriority >= 0 );
|
assert( targetPriority >= 0 );
|
||||||
//found a neighbour with lower priority?
|
//found a neighbour with lower priority?
|
||||||
if ( priority > targetPriority )
|
if ( priority > targetPriority )
|
||||||
return false;
|
return false;
|
||||||
//tie breaking
|
//tie breaking
|
||||||
if ( priority == targetPriority && nodeData[node].bias < nodeData[target].bias )
|
if ( fabs(priority - targetPriority) < FLT_EPSILON && bias(node, target) ) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
neighbours.push_back( target );
|
neighbours.push_back( target );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -541,30 +716,45 @@ private:
|
|||||||
neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
|
neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
|
||||||
|
|
||||||
//examine all neighbours that are at most 2 hops away
|
//examine all neighbours that are at most 2 hops away
|
||||||
for ( std::vector< NodeID >::const_iterator i = neighbours.begin(), lastNode = neighbours.end(); i != lastNode; ++i ) {
|
BOOST_FOREACH(const NodeID u, neighbours) {
|
||||||
const NodeID u = *i;
|
|
||||||
|
|
||||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( u ) ; e < _graph->EndEdges( u ) ; ++e ) {
|
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( u ) ; e < _graph->EndEdges( u ) ; ++e ) {
|
||||||
const NodeID target = _graph->GetTarget( e );
|
const NodeID target = _graph->GetTarget( e );
|
||||||
|
if(node==target)
|
||||||
|
continue;
|
||||||
|
|
||||||
const double targetPriority = priorities[target];
|
const double targetPriority = priorities[target];
|
||||||
assert( targetPriority >= 0 );
|
assert( targetPriority >= 0 );
|
||||||
//found a neighbour with lower priority?
|
//found a neighbour with lower priority?
|
||||||
if ( priority > targetPriority )
|
if ( priority > targetPriority)
|
||||||
return false;
|
return false;
|
||||||
//tie breaking
|
//tie breaking
|
||||||
if ( priority == targetPriority && nodeData[node].bias < nodeData[target].bias )
|
if ( fabs(priority - targetPriority) < FLT_EPSILON && bias(node, target) ) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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;
|
boost::shared_ptr<_DynamicGraph> _graph;
|
||||||
unsigned edgeQuotionFactor;
|
std::vector<_DynamicGraph::InputEdge> contractedEdges;
|
||||||
unsigned originalQuotientFactor;
|
unsigned temporaryStorageSlotID;
|
||||||
unsigned depthFactor;
|
std::vector<NodeID> oldNodeIDFromNewNodeIDMap;
|
||||||
|
XORFastHash fastHash;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONTRACTOR_H_INCLUDED
|
#endif // CONTRACTOR_H_INCLUDED
|
||||||
|
|||||||
@@ -18,32 +18,55 @@
|
|||||||
or see http://www.gnu.org/licenses/agpl.txt.
|
or see http://www.gnu.org/licenses/agpl.txt.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef _GLIBCXX_PARALLEL
|
|
||||||
#include <parallel/algorithm>
|
|
||||||
#else
|
|
||||||
#include <algorithm>
|
|
||||||
#endif
|
|
||||||
#include <boost/foreach.hpp>
|
|
||||||
|
|
||||||
#include "EdgeBasedGraphFactory.h"
|
#include "EdgeBasedGraphFactory.h"
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
EdgeBasedGraphFactory::EdgeBasedGraphFactory(int nodes, std::vector<NodeBasedEdge> & inputEdges, std::vector<_Restriction> & irs, std::vector<NodeInfo> & nI)
|
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) {
|
||||||
: inputRestrictions(irs), inputNodeInfoList(nI) {
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _GLIBCXX_PARALLEL
|
_restrictionBucketVector.at(index).push_back(std::make_pair(restriction.toNode, restriction.flags.isOnly));
|
||||||
__gnu_parallel::sort(inputRestrictions.begin(), inputRestrictions.end(), CmpRestrictionByFrom);
|
}
|
||||||
#else
|
|
||||||
std::sort(inputRestrictions.begin(), inputRestrictions.end(), CmpRestrictionByFrom);
|
BOOST_FOREACH(NodeID id, bn) {
|
||||||
#endif
|
_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 ) {
|
||||||
|
|
||||||
std::vector< _NodeBasedEdge > edges;
|
|
||||||
edges.reserve( 2 * inputEdges.size() );
|
|
||||||
for ( typename std::vector< NodeBasedEdge >::const_iterator i = inputEdges.begin(), e = inputEdges.end(); i != e; ++i ) {
|
|
||||||
_NodeBasedEdge edge;
|
_NodeBasedEdge edge;
|
||||||
edge.source = i->source();
|
if(!i->isForward()) {
|
||||||
edge.target = i->target();
|
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)
|
if(edge.source == edge.target)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -51,139 +74,274 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory(int nodes, std::vector<NodeBasedEdg
|
|||||||
assert( edge.data.distance > 0 );
|
assert( edge.data.distance > 0 );
|
||||||
edge.data.shortcut = false;
|
edge.data.shortcut = false;
|
||||||
edge.data.roundabout = i->isRoundabout();
|
edge.data.roundabout = i->isRoundabout();
|
||||||
|
edge.data.ignoreInGrid = i->ignoreInGrid();
|
||||||
edge.data.nameID = i->name();
|
edge.data.nameID = i->name();
|
||||||
edge.data.type = i->type();
|
edge.data.type = i->type();
|
||||||
edge.data.forward = i->isForward();
|
edge.data.isAccessRestricted = i->isAccessRestricted();
|
||||||
edge.data.backward = i->isBackward();
|
|
||||||
edge.data.edgeBasedNodeID = edges.size();
|
edge.data.edgeBasedNodeID = edges.size();
|
||||||
edges.push_back( edge );
|
edges.push_back( edge );
|
||||||
std::swap( edge.source, edge.target );
|
|
||||||
if( edge.data.backward ) {
|
if( edge.data.backward ) {
|
||||||
|
std::swap( edge.source, edge.target );
|
||||||
edge.data.forward = i->isBackward();
|
edge.data.forward = i->isBackward();
|
||||||
edge.data.backward = i->isForward();
|
edge.data.backward = i->isForward();
|
||||||
edge.data.edgeBasedNodeID = edges.size();
|
edge.data.edgeBasedNodeID = edges.size();
|
||||||
edges.push_back( edge );
|
edges.push_back( edge );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::vector<NodeBasedEdge>().swap(inputEdges);
|
||||||
|
std::sort( edges.begin(), edges.end() );
|
||||||
#ifdef _GLIBCXX_PARALLEL
|
_nodeBasedGraph = boost::make_shared<_NodeBasedDynamicGraph>( nodes, edges );
|
||||||
__gnu_parallel::sort( edges.begin(), edges.end() );
|
|
||||||
#else
|
|
||||||
sort( edges.begin(), edges.end() );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_nodeBasedGraph.reset(new _NodeBasedDynamicGraph( nodes, edges ));
|
|
||||||
INFO("Converted " << inputEdges.size() << " node-based edges into " << _nodeBasedGraph->GetNumberOfEdges() << " edge-based nodes.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
void EdgeBasedGraphFactory::GetEdgeBasedEdges(DeallocatingVector< EdgeBasedEdge >& outputEdgeList ) {
|
||||||
void EdgeBasedGraphFactory::GetEdgeBasedEdges( std::vector< EdgeBasedEdge >& outputEdgeList ) {
|
|
||||||
|
|
||||||
GUARANTEE(0 == outputEdgeList.size(), "Vector passed to EdgeBasedGraphFactory::GetEdgeBasedEdges(..) is not empty");
|
GUARANTEE(0 == outputEdgeList.size(), "Vector passed to EdgeBasedGraphFactory::GetEdgeBasedEdges(..) is not empty");
|
||||||
GUARANTEE(0 != edgeBasedEdges.size(), "No edges in edge based graph");
|
|
||||||
|
|
||||||
edgeBasedEdges.swap(outputEdgeList);
|
edgeBasedEdges.swap(outputEdgeList);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EdgeBasedGraphFactory::GetEdgeBasedNodes( std::vector< EdgeBasedNode> & nodes) {
|
void EdgeBasedGraphFactory::GetEdgeBasedNodes( DeallocatingVector< EdgeBasedNode> & nodes) {
|
||||||
for(unsigned i = 0; i < edgeBasedNodes.size(); ++i)
|
#ifndef NDEBUG
|
||||||
nodes.push_back(edgeBasedNodes[i]);
|
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::Run() {
|
void EdgeBasedGraphFactory::GetOriginalEdgeData( std::vector< OriginalEdgeData> & oed) {
|
||||||
INFO("Generating Edge based representation of input data");
|
oed.swap(originalEdgeData);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<_Restriction>::iterator restrictionIterator = inputRestrictions.begin();
|
NodeID EdgeBasedGraphFactory::CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const {
|
||||||
Percent p(_nodeBasedGraph->GetNumberOfNodes());
|
std::pair < NodeID, NodeID > restrictionSource = std::make_pair(u, v);
|
||||||
int numberOfResolvedRestrictions(0);
|
RestrictionMap::const_iterator restrIter = _restrictionMap.find(restrictionSource);
|
||||||
int nodeBasedEdgeCounter(0);
|
if (restrIter != _restrictionMap.end()) {
|
||||||
|
unsigned index = restrIter->second;
|
||||||
//Loop over all nodes u. Three nested loop look super-linear, but we are dealing with a number linear in the turns only.
|
BOOST_FOREACH(RestrictionSource restrictionTarget, _restrictionBucketVector.at(index)) {
|
||||||
for(_NodeBasedDynamicGraph::NodeIterator u = 0; u < _nodeBasedGraph->GetNumberOfNodes(); ++u ) {
|
if(restrictionTarget.second) {
|
||||||
//loop over all adjacent edge (u,v)
|
return restrictionTarget.first;
|
||||||
while(restrictionIterator->fromNode < u && inputRestrictions.end() != restrictionIterator) {
|
}
|
||||||
++restrictionIterator;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
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) {
|
for(_NodeBasedDynamicGraph::EdgeIterator e1 = _nodeBasedGraph->BeginEdges(u); e1 < _nodeBasedGraph->EndEdges(u); ++e1) {
|
||||||
++nodeBasedEdgeCounter;
|
++nodeBasedEdgeCounter;
|
||||||
_NodeBasedDynamicGraph::NodeIterator v = _nodeBasedGraph->GetTarget(e1);
|
_NodeBasedDynamicGraph::NodeIterator v = _nodeBasedGraph->GetTarget(e1);
|
||||||
//loop over all reachable edges (v,w)
|
//EdgeWeight heightPenalty = ComputeHeightPenalty(u, v);
|
||||||
|
NodeID onlyToNode = CheckForEmanatingIsOnlyTurn(u, v);
|
||||||
for(_NodeBasedDynamicGraph::EdgeIterator e2 = _nodeBasedGraph->BeginEdges(v); e2 < _nodeBasedGraph->EndEdges(v); ++e2) {
|
for(_NodeBasedDynamicGraph::EdgeIterator e2 = _nodeBasedGraph->BeginEdges(v); e2 < _nodeBasedGraph->EndEdges(v); ++e2) {
|
||||||
_NodeBasedDynamicGraph::NodeIterator w = _nodeBasedGraph->GetTarget(e2);
|
const _NodeBasedDynamicGraph::NodeIterator w = _nodeBasedGraph->GetTarget(e2);
|
||||||
//if (u,v,w) is a forbidden turn, continue
|
|
||||||
bool isTurnProhibited = false;
|
if(onlyToNode != UINT_MAX && w != onlyToNode) { //We are at an only_-restriction but not at the right turn.
|
||||||
if( u != w ) { //only add an edge if turn is not a U-turn
|
++numberOfSkippedTurns;
|
||||||
if(u == restrictionIterator->fromNode) {
|
continue;
|
||||||
std::vector<_Restriction>::iterator secondRestrictionIterator = restrictionIterator;
|
}
|
||||||
do {
|
bool isBollardNode = (_barrierNodes.find(v) != _barrierNodes.end());
|
||||||
if( v == secondRestrictionIterator->viaNode && w == secondRestrictionIterator->toNode) {
|
if(u == w && 1 != _nodeBasedGraph->GetOutDegree(v) ) {
|
||||||
isTurnProhibited = true;
|
continue;
|
||||||
}
|
}
|
||||||
++secondRestrictionIterator;
|
|
||||||
} while(u == secondRestrictionIterator->fromNode);
|
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
|
||||||
if( !isTurnProhibited ) { //only add an edge if turn is not prohibited
|
const _NodeBasedDynamicGraph::EdgeData edgeData1 = _nodeBasedGraph->GetEdgeData(e1);
|
||||||
//new costs for edge based edge (e1, e2) = cost (e1) + tc(e1,e2)
|
const _NodeBasedDynamicGraph::EdgeData edgeData2 = _nodeBasedGraph->GetEdgeData(e2);
|
||||||
const _NodeBasedDynamicGraph::NodeIterator edgeBasedSource = _nodeBasedGraph->GetEdgeData(e1).edgeBasedNodeID;
|
assert(edgeData1.edgeBasedNodeID < _nodeBasedGraph->GetNumberOfEdges());
|
||||||
// INFO("edgeBasedSource: " << edgeBasedSource);
|
assert(edgeData2.edgeBasedNodeID < _nodeBasedGraph->GetNumberOfEdges());
|
||||||
if(edgeBasedSource > _nodeBasedGraph->GetNumberOfEdges()) {
|
|
||||||
ERR("edgeBasedTarget" << edgeBasedSource << ">" << _nodeBasedGraph->GetNumberOfEdges());
|
if(!edgeData1.forward || !edgeData2.forward) {
|
||||||
}
|
continue;
|
||||||
const _NodeBasedDynamicGraph::NodeIterator edgeBasedTarget = _nodeBasedGraph->GetEdgeData(e2).edgeBasedNodeID;
|
|
||||||
// INFO("edgeBasedTarget: " << edgeBasedTarget);
|
|
||||||
if(edgeBasedTarget > _nodeBasedGraph->GetNumberOfEdges()) {
|
|
||||||
ERR("edgeBasedTarget" << edgeBasedTarget << ">" << _nodeBasedGraph->GetNumberOfEdges());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//incorporate turn costs, this is just a simple model and can (read: must) be extended
|
unsigned distance = edgeData1.distance;
|
||||||
double angle = GetAngleBetweenTwoEdges(inputNodeInfoList[u], inputNodeInfoList[v], inputNodeInfoList[w]);
|
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;
|
||||||
|
// }
|
||||||
|
|
||||||
unsigned distance = (int)( _nodeBasedGraph->GetEdgeData(e1).distance *(1+std::abs((angle-180.)/180.)));
|
|
||||||
unsigned nameID = _nodeBasedGraph->GetEdgeData(e2).nameID;
|
|
||||||
short turnInstruction = AnalyzeTurn(u, v, w);
|
|
||||||
|
|
||||||
//create edge-based graph edge
|
//distance += heightPenalty;
|
||||||
//EdgeBasedEdge(NodeID s, NodeID t, NodeID v, unsigned n1, EdgeWeight w, bool f, bool b, short ty)
|
//distance += ComputeTurnPenalty(u, v, w);
|
||||||
EdgeBasedEdge newEdge(edgeBasedSource, edgeBasedTarget, v, nameID, distance, true, false, turnInstruction);
|
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);
|
edgeBasedEdges.push_back(newEdge);
|
||||||
EdgeBasedNode currentNode;
|
|
||||||
|
|
||||||
if(_nodeBasedGraph->GetEdgeData(e1).type != 14) {
|
|
||||||
currentNode.nameID = _nodeBasedGraph->GetEdgeData(e1).nameID;
|
|
||||||
currentNode.lat1 = inputNodeInfoList[u].lat;
|
|
||||||
currentNode.lon1 = inputNodeInfoList[u].lon;
|
|
||||||
currentNode.lat2 = inputNodeInfoList[v].lat;
|
|
||||||
currentNode.lon2 = inputNodeInfoList[v].lon;
|
|
||||||
currentNode.id = edgeBasedSource;
|
|
||||||
currentNode.weight = _nodeBasedGraph->GetEdgeData(e1).distance;
|
|
||||||
edgeBasedNodes.push_back(currentNode);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
++numberOfResolvedRestrictions;
|
++numberOfSkippedTurns;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.printIncrement();
|
p.printIncrement();
|
||||||
}
|
}
|
||||||
std::sort(edgeBasedNodes.begin(), edgeBasedNodes.end());
|
numberOfOriginalEdges += originalEdgeData.size();
|
||||||
edgeBasedNodes.erase( std::unique(edgeBasedNodes.begin(), edgeBasedNodes.end()), edgeBasedNodes.end() );
|
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("Node-based graph contains " << nodeBasedEdgeCounter << " edges");
|
||||||
INFO("Edge-based graph contains " << edgeBasedEdges.size() << " edges, blowup is " << (double)edgeBasedEdges.size()/(double)nodeBasedEdgeCounter);
|
// INFO("Edge-based graph contains " << edgeBasedEdges.size() << " edges, blowup is " << 2*((double)edgeBasedEdges.size()/(double)nodeBasedEdgeCounter));
|
||||||
INFO("Edge-based graph obeys " << numberOfResolvedRestrictions << " turn restrictions, " << (inputRestrictions.size() - numberOfResolvedRestrictions )<< " skipped.");
|
INFO("Edge-based graph skipped " << numberOfSkippedTurns << " turns, defined by " << numberOfTurnRestrictions << " restrictions.");
|
||||||
INFO("Generated " << edgeBasedNodes.size() << " edge based nodes");
|
INFO("Generated " << edgeBasedNodes.size() << " edge based nodes");
|
||||||
}
|
}
|
||||||
|
|
||||||
short EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w) const {
|
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 edge1 = _nodeBasedGraph->FindEdge(u, v);
|
||||||
_NodeBasedDynamicGraph::EdgeIterator edge2 = _nodeBasedGraph->FindEdge(v, w);
|
_NodeBasedDynamicGraph::EdgeIterator edge2 = _nodeBasedGraph->FindEdge(v, w);
|
||||||
|
|
||||||
_NodeBasedDynamicGraph::EdgeData & data1 = _nodeBasedGraph->GetEdgeData(edge1);
|
_NodeBasedDynamicGraph::EdgeData & data1 = _nodeBasedGraph->GetEdgeData(edge1);
|
||||||
_NodeBasedDynamicGraph::EdgeData & data2 = _nodeBasedGraph->GetEdgeData(edge2);
|
_NodeBasedDynamicGraph::EdgeData & data2 = _nodeBasedGraph->GetEdgeData(edge2);
|
||||||
|
|
||||||
double angle = GetAngleBetweenTwoEdges(inputNodeInfoList[u], inputNodeInfoList[v], inputNodeInfoList[w]);
|
|
||||||
|
|
||||||
//roundabouts need to be handled explicitely
|
//roundabouts need to be handled explicitely
|
||||||
if(data1.roundabout && data2.roundabout) {
|
if(data1.roundabout && data2.roundabout) {
|
||||||
//Is a turn possible? If yes, we stay on the roundabout!
|
//Is a turn possible? If yes, we stay on the roundabout!
|
||||||
@@ -200,22 +358,22 @@ short EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u, const NodeID v, const N
|
|||||||
if( (!data1.roundabout) && data2.roundabout)
|
if( (!data1.roundabout) && data2.roundabout)
|
||||||
return TurnInstructions.EnterRoundAbout;
|
return TurnInstructions.EnterRoundAbout;
|
||||||
//We are leaving the roundabout
|
//We are leaving the roundabout
|
||||||
if(data1.roundabout && (!data2.roundabout) )
|
else if(data1.roundabout && (!data2.roundabout) )
|
||||||
return TurnInstructions.LeaveRoundAbout;
|
return TurnInstructions.LeaveRoundAbout;
|
||||||
}
|
}
|
||||||
|
|
||||||
//If street names stay the same and if we are certain that it is not a roundabout, we skip it.
|
//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)
|
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;
|
return TurnInstructions.NoTurn;
|
||||||
|
|
||||||
|
double angle = GetAngleBetweenTwoEdges(inputNodeInfoList[u], inputNodeInfoList[v], inputNodeInfoList[w]);
|
||||||
return TurnInstructions.GetTurnDirectionOfInstruction(angle);
|
return TurnInstructions.GetTurnDirectionOfInstruction(angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned EdgeBasedGraphFactory::GetNumberOfNodes() const {
|
unsigned EdgeBasedGraphFactory::GetNumberOfNodes() const {
|
||||||
return edgeBasedEdges.size();
|
return _nodeBasedGraph->GetNumberOfEdges();
|
||||||
}
|
|
||||||
|
|
||||||
EdgeBasedGraphFactory::~EdgeBasedGraphFactory() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get angle of line segment (A,C)->(C,B), atan2 magic, formerly cosine theorem*/
|
/* Get angle of line segment (A,C)->(C,B), atan2 magic, formerly cosine theorem*/
|
||||||
@@ -229,6 +387,5 @@ double EdgeBasedGraphFactory::GetAngleBetweenTwoEdges(const CoordinateT& A, cons
|
|||||||
double angle = (atan2((double)v2y,v2x) - atan2((double)v1y,v1x) )*180/M_PI;
|
double angle = (atan2((double)v2y,v2x) - atan2((double)v1y,v1x) )*180/M_PI;
|
||||||
while(angle < 0)
|
while(angle < 0)
|
||||||
angle += 360;
|
angle += 360;
|
||||||
|
|
||||||
return angle;
|
return angle;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,28 +25,43 @@
|
|||||||
#ifndef EDGEBASEDGRAPHFACTORY_H_
|
#ifndef EDGEBASEDGRAPHFACTORY_H_
|
||||||
#define EDGEBASEDGRAPHFACTORY_H_
|
#define EDGEBASEDGRAPHFACTORY_H_
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <algorithm>
|
||||||
|
#include <queue>
|
||||||
#include <vector>
|
#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 "../typedefs.h"
|
||||||
|
#include "../DataStructures/DeallocatingVector.h"
|
||||||
#include "../DataStructures/DynamicGraph.h"
|
#include "../DataStructures/DynamicGraph.h"
|
||||||
#include "../DataStructures/ExtractorStructs.h"
|
#include "../Extractor/ExtractorStructs.h"
|
||||||
|
#include "../DataStructures/HashTable.h"
|
||||||
#include "../DataStructures/ImportEdge.h"
|
#include "../DataStructures/ImportEdge.h"
|
||||||
|
#include "../DataStructures/QueryEdge.h"
|
||||||
#include "../DataStructures/Percent.h"
|
#include "../DataStructures/Percent.h"
|
||||||
#include "../DataStructures/TurnInstructions.h"
|
#include "../DataStructures/TurnInstructions.h"
|
||||||
|
#include "../Util/BaseConfiguration.h"
|
||||||
|
|
||||||
class EdgeBasedGraphFactory {
|
class EdgeBasedGraphFactory {
|
||||||
private:
|
private:
|
||||||
struct _NodeBasedEdgeData {
|
struct _NodeBasedEdgeData {
|
||||||
int distance;
|
int distance;
|
||||||
unsigned edgeBasedNodeID;
|
unsigned edgeBasedNodeID;
|
||||||
unsigned nameID;
|
unsigned nameID:31;
|
||||||
bool shortcut:1;
|
bool shortcut:1;
|
||||||
bool forward:1;
|
bool forward:1;
|
||||||
bool backward:1;
|
bool backward:1;
|
||||||
bool roundabout:1;
|
bool roundabout:1;
|
||||||
|
bool ignoreInGrid:1;
|
||||||
short type;
|
short type;
|
||||||
} data;
|
bool isAccessRestricted;
|
||||||
|
};
|
||||||
|
|
||||||
struct _EdgeBasedEdgeData {
|
struct _EdgeBasedEdgeData {
|
||||||
int distance;
|
int distance;
|
||||||
@@ -54,12 +69,13 @@ private:
|
|||||||
unsigned nameID;
|
unsigned nameID;
|
||||||
bool forward;
|
bool forward;
|
||||||
bool backward;
|
bool backward;
|
||||||
short turnInstruction;
|
TurnInstruction turnInstruction;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef DynamicGraph< _NodeBasedEdgeData > _NodeBasedDynamicGraph;
|
typedef DynamicGraph< _NodeBasedEdgeData > _NodeBasedDynamicGraph;
|
||||||
typedef _NodeBasedDynamicGraph::InputEdge _NodeBasedEdge;
|
typedef _NodeBasedDynamicGraph::InputEdge _NodeBasedEdge;
|
||||||
|
std::vector<NodeInfo> inputNodeInfoList;
|
||||||
|
unsigned numberOfTurnRestrictions;
|
||||||
public:
|
public:
|
||||||
struct EdgeBasedNode {
|
struct EdgeBasedNode {
|
||||||
bool operator<(const EdgeBasedNode & other) const {
|
bool operator<(const EdgeBasedNode & other) const {
|
||||||
@@ -68,36 +84,61 @@ public:
|
|||||||
bool operator==(const EdgeBasedNode & other) const {
|
bool operator==(const EdgeBasedNode & other) const {
|
||||||
return id == other.id;
|
return id == other.id;
|
||||||
}
|
}
|
||||||
|
NodeID id;
|
||||||
int lat1;
|
int lat1;
|
||||||
int lat2;
|
int lat2;
|
||||||
int lon1;
|
int lon1;
|
||||||
int lon2;
|
int lon2:31;
|
||||||
NodeID id;
|
bool belongsToTinyComponent:1;
|
||||||
NodeID nameID;
|
NodeID nameID;
|
||||||
unsigned weight;
|
unsigned weight:31;
|
||||||
|
bool ignoreInGrid:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct SpeedProfileProperties{
|
||||||
|
SpeedProfileProperties() : trafficSignalPenalty(0), uTurnPenalty(0) {}
|
||||||
|
int trafficSignalPenalty;
|
||||||
|
int uTurnPenalty;
|
||||||
|
} speedProfile;
|
||||||
private:
|
private:
|
||||||
boost::shared_ptr<_NodeBasedDynamicGraph> _nodeBasedGraph;
|
boost::shared_ptr<_NodeBasedDynamicGraph> _nodeBasedGraph;
|
||||||
|
boost::unordered_map<NodeID, bool> _barrierNodes;
|
||||||
|
boost::unordered_map<NodeID, bool> _trafficLights;
|
||||||
|
|
||||||
std::vector<_Restriction> & inputRestrictions;
|
typedef std::pair<NodeID, NodeID> RestrictionSource;
|
||||||
std::vector<NodeInfo> & inputNodeInfoList;
|
typedef std::pair<NodeID, bool> RestrictionTarget;
|
||||||
|
typedef std::vector<RestrictionTarget> EmanatingRestrictionsVector;
|
||||||
|
typedef boost::unordered_map<RestrictionSource, unsigned > RestrictionMap;
|
||||||
|
std::vector<EmanatingRestrictionsVector> _restrictionBucketVector;
|
||||||
|
RestrictionMap _restrictionMap;
|
||||||
|
|
||||||
std::vector<EdgeBasedEdge> edgeBasedEdges;
|
|
||||||
std::vector<EdgeBasedNode> edgeBasedNodes;
|
|
||||||
|
|
||||||
|
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>
|
template<class CoordinateT>
|
||||||
double GetAngleBetweenTwoEdges(const CoordinateT& A, const CoordinateT& C, const CoordinateT& B) const;
|
double GetAngleBetweenTwoEdges(const CoordinateT& A, const CoordinateT& C, const CoordinateT& B) const;
|
||||||
|
// SRTMLookup srtmLookup;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template< class InputEdgeT >
|
template< class InputEdgeT >
|
||||||
explicit EdgeBasedGraphFactory(int nodes, std::vector<InputEdgeT> & inputEdges, std::vector<_Restriction> & inputRestrictions, std::vector<NodeInfo> & nI);
|
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);
|
||||||
virtual ~EdgeBasedGraphFactory();
|
|
||||||
|
|
||||||
void Run();
|
void Run(const char * originalEdgeDataFilename);
|
||||||
template< class ImportEdgeT >
|
void GetEdgeBasedEdges( DeallocatingVector< EdgeBasedEdge >& edges );
|
||||||
void GetEdgeBasedEdges( std::vector< ImportEdgeT >& edges );
|
void GetEdgeBasedNodes( DeallocatingVector< EdgeBasedNode> & nodes);
|
||||||
void GetEdgeBasedNodes( std::vector< EdgeBasedNode> & nodes);
|
void GetOriginalEdgeData( std::vector< OriginalEdgeData> & originalEdgeData);
|
||||||
short AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w) const;
|
TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w) const;
|
||||||
unsigned GetNumberOfNodes() const;
|
unsigned GetNumberOfNodes() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
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_ */
|
||||||
@@ -28,9 +28,7 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <google/dense_hash_map>
|
#include <boost/unordered_map.hpp>
|
||||||
#include <google/sparse_hash_map>
|
|
||||||
#include <google/sparsetable>
|
|
||||||
|
|
||||||
template< typename NodeID, typename Key >
|
template< typename NodeID, typename Key >
|
||||||
class ArrayStorage {
|
class ArrayStorage {
|
||||||
@@ -58,7 +56,7 @@ template< typename NodeID, typename Key >
|
|||||||
class MapStorage {
|
class MapStorage {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MapStorage( size_t size = 0 ) {}
|
MapStorage( size_t ) {}
|
||||||
|
|
||||||
Key &operator[]( NodeID node ) {
|
Key &operator[]( NodeID node ) {
|
||||||
return nodes[node];
|
return nodes[node];
|
||||||
@@ -74,10 +72,10 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template< typename NodeID, typename Key >
|
template< typename NodeID, typename Key >
|
||||||
class DenseStorage {
|
class UnorderedMapStorage {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DenseStorage( size_t size = 0 ) { nodes.set_empty_key(UINT_MAX); }
|
UnorderedMapStorage( size_t ) { }
|
||||||
|
|
||||||
Key &operator[]( NodeID node ) {
|
Key &operator[]( NodeID node ) {
|
||||||
return nodes[node];
|
return nodes[node];
|
||||||
@@ -88,34 +86,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
google::dense_hash_map< NodeID, Key > nodes;
|
boost::unordered_map< NodeID, Key > nodes;
|
||||||
};
|
|
||||||
|
|
||||||
template< typename NodeID, typename Key >
|
|
||||||
class SparseStorage {
|
|
||||||
public:
|
|
||||||
|
|
||||||
SparseStorage( size_t size = 0 ) { }
|
|
||||||
|
|
||||||
Key &operator[]( NodeID node ) {
|
|
||||||
return nodes[node];
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clear() {
|
|
||||||
nodes.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
google::sparse_hash_map< NodeID, Key > nodes;
|
|
||||||
};
|
|
||||||
|
|
||||||
template< typename NodeID, typename Key >
|
|
||||||
class SparseTableStorage : public google::sparsetable<NodeID> {
|
|
||||||
public:
|
|
||||||
SparseTableStorage(size_t n) : google::sparsetable<NodeID>(n){ }
|
|
||||||
void Clear() {
|
|
||||||
google::sparsetable<NodeID>::clear();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename NodeID = unsigned>
|
template<typename NodeID = unsigned>
|
||||||
@@ -146,14 +117,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Key Size() const {
|
Key Size() const {
|
||||||
return ( Key )( heap.size() - 1 );
|
return static_cast<Key>( heap.size() - 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Insert( NodeID node, Weight weight, const Data &data ) {
|
void Insert( NodeID node, Weight weight, const Data &data ) {
|
||||||
HeapElement element;
|
HeapElement element;
|
||||||
element.index = ( NodeID ) insertedNodes.size();
|
element.index = static_cast<NodeID>(insertedNodes.size());
|
||||||
element.weight = weight;
|
element.weight = weight;
|
||||||
const Key key = ( Key ) heap.size();
|
const Key key = static_cast<Key>(heap.size());
|
||||||
heap.push_back( element );
|
heap.push_back( element );
|
||||||
insertedNodes.push_back( HeapNode( node, key, weight, data ) );
|
insertedNodes.push_back( HeapNode( node, key, weight, data ) );
|
||||||
nodeIndex[node] = element.index;
|
nodeIndex[node] = element.index;
|
||||||
@@ -179,7 +150,7 @@ public:
|
|||||||
|
|
||||||
bool WasInserted( NodeID node ) {
|
bool WasInserted( NodeID node ) {
|
||||||
const Key index = nodeIndex[node];
|
const Key index = nodeIndex[node];
|
||||||
if ( index >= ( Key ) insertedNodes.size() )
|
if ( index >= static_cast<Key> (insertedNodes.size()) )
|
||||||
return false;
|
return false;
|
||||||
return insertedNodes[index].node == node;
|
return insertedNodes[index].node == node;
|
||||||
}
|
}
|
||||||
@@ -247,9 +218,9 @@ private:
|
|||||||
const Key droppingIndex = heap[key].index;
|
const Key droppingIndex = heap[key].index;
|
||||||
const Weight weight = heap[key].weight;
|
const Weight weight = heap[key].weight;
|
||||||
Key nextKey = key << 1;
|
Key nextKey = key << 1;
|
||||||
while ( nextKey < ( Key ) heap.size() ) {
|
while ( nextKey < static_cast<Key>( heap.size() ) ) {
|
||||||
const Key nextKeyOther = nextKey + 1;
|
const Key nextKeyOther = nextKey + 1;
|
||||||
if ( ( nextKeyOther < ( Key ) heap.size() )&& ( heap[nextKey].weight > heap[nextKeyOther].weight) )
|
if ( ( nextKeyOther < static_cast<Key> ( heap.size() ) )&& ( heap[nextKey].weight > heap[nextKeyOther].weight) )
|
||||||
nextKey = nextKeyOther;
|
nextKey = nextKeyOther;
|
||||||
|
|
||||||
if ( weight <= heap[nextKey].weight )
|
if ( weight <= heap[nextKey].weight )
|
||||||
|
|||||||
@@ -21,78 +21,63 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
#ifndef CONCURRENTQUEUE_H_INCLUDED
|
#ifndef CONCURRENTQUEUE_H_INCLUDED
|
||||||
#define CONCURRENTQUEUE_H_INCLUDED
|
#define CONCURRENTQUEUE_H_INCLUDED
|
||||||
|
|
||||||
#include <queue>
|
#include <boost/bind.hpp>
|
||||||
#include <boost/signals2/mutex.hpp>
|
#include <boost/circular_buffer.hpp>
|
||||||
|
#include <boost/thread/condition.hpp>
|
||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
|
||||||
#include "../typedefs.h"
|
#include "../typedefs.h"
|
||||||
|
|
||||||
/*
|
|
||||||
Concurrent Queue written by Anthony Williams:
|
|
||||||
http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html
|
|
||||||
*/
|
|
||||||
template<typename Data>
|
template<typename Data>
|
||||||
class ConcurrentQueue {
|
class ConcurrentQueue {
|
||||||
|
|
||||||
|
typedef typename boost::circular_buffer<Data>::size_type size_t;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConcurrentQueue(const size_t max_size)
|
ConcurrentQueue(const size_t max_size) : internal_queue(max_size) { }
|
||||||
: max_queue_size(max_size) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void push(Data const& data) {
|
inline void push(Data const& data) {
|
||||||
if (size_exceeded()) {
|
boost::mutex::scoped_lock lock(m_mutex);
|
||||||
boost::mutex::scoped_lock qf_lock(queue_full_mutex);
|
m_not_full.wait(lock, boost::bind(&ConcurrentQueue<Data>::is_not_full, this));
|
||||||
queue_full_cv.wait(qf_lock);
|
internal_queue.push_back(data);
|
||||||
}
|
|
||||||
|
|
||||||
boost::mutex::scoped_lock lock(queue_mutex);
|
|
||||||
internal_queue.push(data);
|
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
queue_cv.notify_one();
|
m_not_empty.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const {
|
inline bool empty() const {
|
||||||
return internal_queue.empty();
|
return internal_queue.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool try_pop(Data& popped_value) {
|
inline void wait_and_pop(Data& popped_value) {
|
||||||
boost::mutex::scoped_lock lock(queue_mutex);
|
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()) {
|
if(internal_queue.empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
popped_value=internal_queue.front();
|
popped_value=internal_queue.front();
|
||||||
internal_queue.pop();
|
internal_queue.pop_front();
|
||||||
queue_full_cv.notify_one();
|
lock.unlock();
|
||||||
|
m_not_full.notify_one();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wait_and_pop(Data& popped_value) {
|
|
||||||
boost::mutex::scoped_lock lock(queue_mutex);
|
|
||||||
while(internal_queue.empty()) {
|
|
||||||
queue_cv.wait(lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
popped_value=internal_queue.front();
|
|
||||||
internal_queue.pop();
|
|
||||||
queue_full_cv.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
int size() const {
|
|
||||||
return static_cast<int>(internal_queue.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::queue<Data> internal_queue;
|
boost::circular_buffer<Data> internal_queue;
|
||||||
mutable boost::mutex queue_mutex;
|
boost::mutex m_mutex;
|
||||||
mutable boost::mutex queue_full_mutex;
|
boost::condition m_not_empty;
|
||||||
boost::condition_variable queue_cv;
|
boost::condition m_not_full;
|
||||||
boost::condition_variable queue_full_cv;
|
|
||||||
const size_t max_queue_size;
|
|
||||||
|
|
||||||
bool size_exceeded() const {
|
|
||||||
return internal_queue.size() >= max_queue_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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
|
#endif //#ifndef CONCURRENTQUEUE_H_INCLUDED
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
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_ */
|
||||||
@@ -0,0 +1,307 @@
|
|||||||
|
/*
|
||||||
|
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_ */
|
||||||
@@ -25,6 +25,8 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
|
#include "../DataStructures/DeallocatingVector.h"
|
||||||
|
|
||||||
template< typename EdgeDataT>
|
template< typename EdgeDataT>
|
||||||
class DynamicGraph {
|
class DynamicGraph {
|
||||||
public:
|
public:
|
||||||
@@ -49,10 +51,11 @@ class DynamicGraph {
|
|||||||
m_nodes.reserve( m_numNodes );
|
m_nodes.reserve( m_numNodes );
|
||||||
m_nodes.resize( m_numNodes );
|
m_nodes.resize( m_numNodes );
|
||||||
|
|
||||||
m_edges.reserve( m_numNodes * 1.2 );
|
m_edges.reserve( m_numNodes * 1.1 );
|
||||||
m_edges.resize( m_numNodes );
|
m_edges.resize( m_numNodes );
|
||||||
}
|
}
|
||||||
DynamicGraph( int nodes, const std::vector< InputEdge > &graph )
|
template<class ContainerT>
|
||||||
|
DynamicGraph( const int nodes, const ContainerT &graph )
|
||||||
{
|
{
|
||||||
m_numNodes = nodes;
|
m_numNodes = nodes;
|
||||||
m_numEdges = ( EdgeIterator ) graph.size();
|
m_numEdges = ( EdgeIterator ) graph.size();
|
||||||
@@ -69,7 +72,7 @@ class DynamicGraph {
|
|||||||
m_nodes[node].edges = edge - lastEdge;
|
m_nodes[node].edges = edge - lastEdge;
|
||||||
position += m_nodes[node].edges;
|
position += m_nodes[node].edges;
|
||||||
}
|
}
|
||||||
m_edges.reserve( position * 1.2 );
|
m_edges.reserve( position * 1.1 );
|
||||||
m_edges.resize( position );
|
m_edges.resize( position );
|
||||||
edge = 0;
|
edge = 0;
|
||||||
for ( NodeIterator node = 0; node < m_numNodes; ++node ) {
|
for ( NodeIterator node = 0; node < m_numNodes; ++node ) {
|
||||||
@@ -77,7 +80,7 @@ class DynamicGraph {
|
|||||||
m_edges[i].target = graph[edge].target;
|
m_edges[i].target = graph[edge].target;
|
||||||
m_edges[i].data = graph[edge].data;
|
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);
|
GUARANTEE(graph[edge].data.distance > 0, "edge: " << edge << "(" << graph[edge].source << "," << graph[edge].target << ")=" << graph[edge].data.distance);
|
||||||
edge++;
|
++edge;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,7 +139,7 @@ class DynamicGraph {
|
|||||||
m_edges[node.firstEdge] = m_edges[node.firstEdge + node.edges];
|
m_edges[node.firstEdge] = m_edges[node.firstEdge + node.edges];
|
||||||
} else {
|
} else {
|
||||||
EdgeIterator newFirstEdge = ( EdgeIterator ) m_edges.size();
|
EdgeIterator newFirstEdge = ( EdgeIterator ) m_edges.size();
|
||||||
unsigned newSize = node.edges * 1.2 + 2;
|
unsigned newSize = node.edges * 1.1 + 2;
|
||||||
EdgeIterator requiredCapacity = newSize + m_edges.size();
|
EdgeIterator requiredCapacity = newSize + m_edges.size();
|
||||||
EdgeIterator oldCapacity = m_edges.capacity();
|
EdgeIterator oldCapacity = m_edges.capacity();
|
||||||
if ( requiredCapacity >= oldCapacity ) {
|
if ( requiredCapacity >= oldCapacity ) {
|
||||||
@@ -147,7 +150,7 @@ class DynamicGraph {
|
|||||||
m_edges[newFirstEdge + i ] = m_edges[node.firstEdge + i];
|
m_edges[newFirstEdge + i ] = m_edges[node.firstEdge + i];
|
||||||
makeDummy( node.firstEdge + i );
|
makeDummy( node.firstEdge + i );
|
||||||
}
|
}
|
||||||
for ( EdgeIterator i = node.edges + 1; i < newSize; i++ )
|
for ( EdgeIterator i = node.edges + 1; i < newSize; ++i )
|
||||||
makeDummy( newFirstEdge + i );
|
makeDummy( newFirstEdge + i );
|
||||||
node.firstEdge = newFirstEdge;
|
node.firstEdge = newFirstEdge;
|
||||||
}
|
}
|
||||||
@@ -155,8 +158,8 @@ class DynamicGraph {
|
|||||||
Edge &edge = m_edges[node.firstEdge + node.edges];
|
Edge &edge = m_edges[node.firstEdge + node.edges];
|
||||||
edge.target = to;
|
edge.target = to;
|
||||||
edge.data = data;
|
edge.data = data;
|
||||||
m_numEdges++;
|
++m_numEdges;
|
||||||
node.edges++;
|
++node.edges;
|
||||||
return EdgeIterator( node.firstEdge + node.edges );
|
return EdgeIterator( node.firstEdge + node.edges );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,8 +233,9 @@ class DynamicGraph {
|
|||||||
NodeIterator m_numNodes;
|
NodeIterator m_numNodes;
|
||||||
EdgeIterator m_numEdges;
|
EdgeIterator m_numEdges;
|
||||||
|
|
||||||
std::vector< Node > m_nodes;
|
DeallocatingVector< Node > m_nodes;
|
||||||
std::vector< Edge > m_edges;
|
DeallocatingVector< Edge > m_edges;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DYNAMICGRAPH_H_INCLUDED
|
#endif // DYNAMICGRAPH_H_INCLUDED
|
||||||
|
|||||||
@@ -1,196 +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 <stxxl.h>
|
|
||||||
#include <vector>
|
|
||||||
#include "ExtractorStructs.h"
|
|
||||||
|
|
||||||
typedef stxxl::vector<NodeID> STXXLNodeIDVector;
|
|
||||||
typedef stxxl::vector<_Node> STXXLNodeVector;
|
|
||||||
typedef stxxl::vector<_Edge> STXXLEdgeVector;
|
|
||||||
typedef stxxl::vector<_Address> STXXLAddressVector;
|
|
||||||
typedef stxxl::vector<string> STXXLStringVector;
|
|
||||||
typedef stxxl::vector<_RawRestrictionContainer> STXXLRestrictionsVector;
|
|
||||||
typedef stxxl::vector<_WayIDStartAndEndEdge> STXXLWayIDStartEndVector;
|
|
||||||
|
|
||||||
|
|
||||||
struct STXXLContainers {
|
|
||||||
STXXLNodeIDVector usedNodeIDs;
|
|
||||||
STXXLNodeVector allNodes;
|
|
||||||
STXXLEdgeVector allEdges;
|
|
||||||
STXXLAddressVector adressVector;
|
|
||||||
STXXLStringVector nameVector;
|
|
||||||
STXXLRestrictionsVector restrictionsVector;
|
|
||||||
STXXLWayIDStartEndVector wayStartEndVector;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExtractorCallbacks{
|
|
||||||
private:
|
|
||||||
Settings settings;
|
|
||||||
StringMap * stringMap;
|
|
||||||
STXXLContainers * externalMemory;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ExtractorCallbacks(STXXLContainers * ext, Settings set, StringMap * strMap){
|
|
||||||
externalMemory = ext;
|
|
||||||
settings = set;
|
|
||||||
stringMap = strMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
~ExtractorCallbacks() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** warning: caller needs to take care of synchronization! */
|
|
||||||
inline bool adressFunction(_Node n, HashTable<std::string, std::string> &keyVals) {
|
|
||||||
/*
|
|
||||||
std::string housenumber(keyVals.Find("addr:housenumber"));
|
|
||||||
std::string housename(keyVals.Find("addr:housename"));
|
|
||||||
std::string street(keyVals.Find("addr:street"));
|
|
||||||
std::string state(keyVals.Find("addr:state"));
|
|
||||||
std::string country(keyVals.Find("addr:country"));
|
|
||||||
std::string postcode(keyVals.Find("addr:postcode"));
|
|
||||||
std::string city(keyVals.Find("addr:city"));
|
|
||||||
|
|
||||||
if(housenumber != "" || housename != "" || street != "") {
|
|
||||||
if(housenumber == "")
|
|
||||||
housenumber = housename;
|
|
||||||
addressVector->push_back(_Address(n, housenumber, street, state, country, postcode, city));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** warning: caller needs to take care of synchronization! */
|
|
||||||
inline bool nodeFunction(_Node &n) {
|
|
||||||
externalMemory->allNodes.push_back(n);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool restrictionFunction(_RawRestrictionContainer &r) {
|
|
||||||
externalMemory->restrictionsVector.push_back(r);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** warning: caller needs to take care of synchronization! */
|
|
||||||
inline bool wayFunction(_Way &w) {
|
|
||||||
|
|
||||||
//Get the properties of the way.
|
|
||||||
std::string highway( w.keyVals.Find("highway") );
|
|
||||||
std::string name( w.keyVals.Find("name") );
|
|
||||||
std::string ref( w.keyVals.Find("ref"));
|
|
||||||
std::string oneway( w.keyVals.Find("oneway"));
|
|
||||||
std::string junction( w.keyVals.Find("junction") );
|
|
||||||
std::string route( w.keyVals.Find("route") );
|
|
||||||
double maxspeed( atoi(w.keyVals.Find("maxspeed").c_str()) );
|
|
||||||
std::string access( w.keyVals.Find("access") );
|
|
||||||
std::string accessClass( w.keyVals.Find(settings.accessTag) );
|
|
||||||
std::string man_made( w.keyVals.Find("man_made") );
|
|
||||||
std::string barrier( w.keyVals.Find("barrier") );
|
|
||||||
|
|
||||||
//Save the name of the way if it has one, ref has precedence over name tag.
|
|
||||||
if ( 0 < ref.length() )
|
|
||||||
w.name = ref;
|
|
||||||
else
|
|
||||||
if ( 0 < name.length() )
|
|
||||||
w.name = name;
|
|
||||||
|
|
||||||
if(junction == "roundabout") {
|
|
||||||
w.roundabout = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Is the highway tag listed as usable way?
|
|
||||||
if(0 < settings[highway]) {
|
|
||||||
|
|
||||||
if(0 != maxspeed)
|
|
||||||
w.speed = maxspeed;
|
|
||||||
else
|
|
||||||
w.speed = settings[highway];
|
|
||||||
w.useful = true;
|
|
||||||
|
|
||||||
//Okay, do we have access to that way?
|
|
||||||
if(0 < access.size()) { //fastest way to check for non-empty string
|
|
||||||
//If access is forbidden, we don't want to route there.
|
|
||||||
if(access == "private" || access == "no" || access == "agricultural" || access == "forestry" || access == "delivery") { //Todo: this is still hard coded
|
|
||||||
w.access = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if("yes" == accessClass)
|
|
||||||
w.access = true;
|
|
||||||
else if("no" == accessClass)
|
|
||||||
w.access = false;
|
|
||||||
|
|
||||||
//Let's process oneway property, if speed profile obeys to it
|
|
||||||
if(oneway != "no" && oneway != "false" && oneway != "0" && settings.obeyOneways) {
|
|
||||||
//if oneway tag is in forward direction or if actually roundabout
|
|
||||||
if(junction == "roundabout" || oneway == "yes" || oneway == "true" || oneway == "1") {
|
|
||||||
w.direction = _Way::oneway;
|
|
||||||
} else {
|
|
||||||
if( oneway == "-1")
|
|
||||||
w.direction = _Way::opposite;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//Is the route tag listed as usable way in the profile?
|
|
||||||
if(settings[route] > 0 || settings[man_made] > 0) {
|
|
||||||
w.useful = true;
|
|
||||||
w.direction = _Way::oneway;
|
|
||||||
w.speed = settings[route];
|
|
||||||
w.direction = _Way::bidirectional;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( w.useful && w.access && (1 < w.path.size()) ) { //Only true if the way is specified by the speed profile
|
|
||||||
//TODO: type is not set, perhaps use a bimap'ed speed profile to do set the type correctly?
|
|
||||||
w.type = 1;
|
|
||||||
|
|
||||||
//Get the unique identifier for the street name
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
GUARANTEE(w.id != UINT_MAX, "found way with unknown type");
|
|
||||||
GUARANTEE(-1 != w.speed, "found way with unknown speed");
|
|
||||||
|
|
||||||
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));
|
|
||||||
externalMemory->usedNodeIDs.push_back(w.path[n]);
|
|
||||||
}
|
|
||||||
externalMemory->usedNodeIDs.push_back(w.path[w.path.size()-1]);
|
|
||||||
|
|
||||||
//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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* EXTRACTORCALLBACKS_H_ */
|
|
||||||
@@ -1,359 +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/unordered_map.hpp>
|
|
||||||
#include "../typedefs.h"
|
|
||||||
#include "Util.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;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef boost::unordered_map<std::string, NodeID> StringMap;
|
|
||||||
|
|
||||||
struct _Node : NodeInfo{
|
|
||||||
_Node(int _lat, int _lon, unsigned int _id) : NodeInfo(_lat, _lon, _id) {}
|
|
||||||
_Node() {}
|
|
||||||
|
|
||||||
static _Node min_value() {
|
|
||||||
return _Node(0,0,0);
|
|
||||||
}
|
|
||||||
static _Node max_value() {
|
|
||||||
return _Node((numeric_limits<int>::max)(), (numeric_limits<int>::max)(), (numeric_limits<unsigned int>::max)());
|
|
||||||
}
|
|
||||||
NodeID key() const {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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 ostream & operator<<(ostream & out, const _Coordinate & c){
|
|
||||||
out << "(" << c.lat << "," << c.lon << ")";
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct _Way {
|
|
||||||
_Way() : id(UINT_MAX), nameID(UINT_MAX) {
|
|
||||||
|
|
||||||
direction = _Way::notSure;
|
|
||||||
speed = -1;
|
|
||||||
type = -1;
|
|
||||||
useful = false;
|
|
||||||
access = true;
|
|
||||||
roundabout = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum {
|
|
||||||
notSure = 0, oneway, bidirectional, opposite
|
|
||||||
} direction;
|
|
||||||
unsigned id;
|
|
||||||
unsigned nameID;
|
|
||||||
std::string name;
|
|
||||||
double speed;
|
|
||||||
short type;
|
|
||||||
bool useful;
|
|
||||||
bool access;
|
|
||||||
bool roundabout;
|
|
||||||
std::vector< NodeID > path;
|
|
||||||
HashTable<std::string, std::string> keyVals;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _Address {
|
|
||||||
_Address() {}
|
|
||||||
_Address(_Node n, std::string h, std::string str, std::string sta, std::string p, std::string ci, std::string co) {
|
|
||||||
node = n;
|
|
||||||
housenumber = h;
|
|
||||||
street = str;
|
|
||||||
state = sta;
|
|
||||||
postcode = p;
|
|
||||||
city = ci;
|
|
||||||
country = co;
|
|
||||||
}
|
|
||||||
_Node node;
|
|
||||||
std::string housenumber;
|
|
||||||
std::string street;
|
|
||||||
std::string state;
|
|
||||||
std::string postcode;
|
|
||||||
std::string city;
|
|
||||||
std::string country;
|
|
||||||
};
|
|
||||||
|
|
||||||
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) {};
|
|
||||||
_Edge(NodeID s, NodeID t) : start(s), target(t), type(0), direction(0), speed(0), nameID(0), isRoundabout(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) { }
|
|
||||||
_Edge(NodeID s, NodeID t, short tp, short d, double sp, unsigned nid, bool isra): start(s), target(t), type(tp), direction(d), speed(sp), nameID(nid), isRoundabout(isra) { }
|
|
||||||
NodeID start;
|
|
||||||
NodeID target;
|
|
||||||
short type;
|
|
||||||
short direction;
|
|
||||||
double speed;
|
|
||||||
unsigned nameID;
|
|
||||||
bool isRoundabout;
|
|
||||||
|
|
||||||
_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 _Restriction {
|
|
||||||
NodeID viaNode;
|
|
||||||
NodeID fromNode;
|
|
||||||
NodeID toNode;
|
|
||||||
struct bits { //mostly unused
|
|
||||||
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 viaWay;
|
|
||||||
|
|
||||||
_RawRestrictionContainer(EdgeID f, EdgeID t, NodeID vn, unsigned vw) : fromWay(f), toWay(t), viaWay(vw) { restriction.viaNode = vn;}
|
|
||||||
_RawRestrictionContainer(bool isOnly = false) : fromWay(UINT_MAX), toWay(UINT_MAX), viaWay(UINT_MAX) { restriction.flags.isOnly = isOnly;}
|
|
||||||
|
|
||||||
static _RawRestrictionContainer min_value() {
|
|
||||||
return _RawRestrictionContainer((numeric_limits<unsigned>::min)(), (numeric_limits<unsigned>::min)(), (numeric_limits<unsigned>::min)(), (numeric_limits<unsigned>::min)());
|
|
||||||
}
|
|
||||||
static _RawRestrictionContainer max_value() {
|
|
||||||
return _RawRestrictionContainer((numeric_limits<unsigned>::max)(), (numeric_limits<unsigned>::max)(), (numeric_limits<unsigned>::max)(), (numeric_limits<unsigned>::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();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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 CmpWayStartAndEnd : 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 Settings {
|
|
||||||
Settings() : obeyPollards(true), obeyOneways(true), useRestrictions(true), accessTag("motorcar") {}
|
|
||||||
StringMap speedProfile;
|
|
||||||
int operator[](const string & param) const {
|
|
||||||
if(speedProfile.find(param) == speedProfile.end())
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return speedProfile.at(param);
|
|
||||||
}
|
|
||||||
bool obeyPollards;
|
|
||||||
bool obeyOneways;
|
|
||||||
bool useRestrictions;
|
|
||||||
string accessTag;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
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 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);
|
|
||||||
static const double DEG_TO_RAD = 0.017453292519943295769236907684886;
|
|
||||||
///Earth's quatratic mean radius for WGS-84
|
|
||||||
static const double EARTH_RADIUS_IN_METERS = 6372797.560856;
|
|
||||||
double latitudeArc = ( lat1/100000. - lat2/100000. ) * DEG_TO_RAD;
|
|
||||||
double longitudeArc = ( lon1/100000. - lon2/100000. ) * DEG_TO_RAD;
|
|
||||||
double latitudeH = sin( latitudeArc * 0.5 );
|
|
||||||
latitudeH *= latitudeH;
|
|
||||||
double lontitudeH = sin( longitudeArc * 0.5 );
|
|
||||||
lontitudeH *= lontitudeH;
|
|
||||||
double tmp = cos( lat1/100000. * DEG_TO_RAD ) * cos( lat2/100000. * DEG_TO_RAD );
|
|
||||||
double distanceArc = 2.0 * asin( sqrt( latitudeH + tmp * lontitudeH ) );
|
|
||||||
return EARTH_RADIUS_IN_METERS * distanceArc;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double ApproximateDistance(const _Coordinate &c1, const _Coordinate &c2) {
|
|
||||||
return ApproximateDistance( c1.lat, c1.lon, c2.lat, c2.lon );
|
|
||||||
}
|
|
||||||
|
|
||||||
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_ */
|
|
||||||
@@ -21,14 +21,24 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
#ifndef GRIDEDGE_H_
|
#ifndef GRIDEDGE_H_
|
||||||
#define GRIDEDGE_H_
|
#define GRIDEDGE_H_
|
||||||
|
|
||||||
|
#include "Coordinate.h"
|
||||||
|
|
||||||
struct _GridEdge {
|
struct _GridEdge {
|
||||||
_GridEdge(NodeID n, NodeID na, int w, _Coordinate sc, _Coordinate tc) : edgeBasedNode(n), nameID(na), weight(w), startCoord(sc), targetCoord(tc) {}
|
_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) {}
|
_GridEdge() : edgeBasedNode(UINT_MAX), nameID(UINT_MAX), weight(INT_MAX), belongsToTinyComponent(false) {}
|
||||||
NodeID edgeBasedNode;
|
NodeID edgeBasedNode;
|
||||||
NodeID nameID;
|
NodeID nameID;
|
||||||
int weight;
|
int weight;
|
||||||
_Coordinate startCoord;
|
_Coordinate startCoord;
|
||||||
_Coordinate targetCoord;
|
_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 {
|
struct GridEntry {
|
||||||
@@ -45,30 +55,24 @@ struct GridEntry {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CompareGridEdgeDataByFileIndex
|
struct CompareGridEdgeDataByFileIndex {
|
||||||
{
|
bool operator () (const GridEntry & a, const GridEntry & b) const {
|
||||||
bool operator () (const GridEntry & a, const GridEntry & b) const
|
|
||||||
{
|
|
||||||
return a.fileIndex < b.fileIndex;
|
return a.fileIndex < b.fileIndex;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CompareGridEdgeDataByRamIndex
|
struct CompareGridEdgeDataByRamIndex {
|
||||||
{
|
|
||||||
typedef GridEntry value_type;
|
typedef GridEntry value_type;
|
||||||
|
|
||||||
bool operator () (const GridEntry & a, const GridEntry & b) const
|
bool operator () (const GridEntry & a, const GridEntry & b) const {
|
||||||
{
|
|
||||||
return a.ramIndex < b.ramIndex;
|
return a.ramIndex < b.ramIndex;
|
||||||
}
|
}
|
||||||
value_type max_value()
|
value_type max_value() {
|
||||||
{
|
|
||||||
GridEntry e;
|
GridEntry e;
|
||||||
e.ramIndex = (1024*1024) - 1;
|
e.ramIndex = (1024*1024) - 1;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
value_type min_value()
|
value_type min_value() {
|
||||||
{
|
|
||||||
GridEntry e;
|
GridEntry e;
|
||||||
e.ramIndex = 0;
|
e.ramIndex = 0;
|
||||||
return e;
|
return e;
|
||||||
|
|||||||
@@ -36,19 +36,19 @@ public:
|
|||||||
HashTable(const unsigned size) {
|
HashTable(const unsigned size) {
|
||||||
table.resize(size);
|
table.resize(size);
|
||||||
}
|
}
|
||||||
void Add(const keyT& key, const valueT& value){
|
inline void Add(const keyT& key, const valueT& value){
|
||||||
table[key] = value;
|
table[key] = value;
|
||||||
}
|
}
|
||||||
void Set(const keyT& key, const valueT& value){
|
inline void Set(const keyT& key, const valueT& value){
|
||||||
table[key] = value;
|
table[key] = value;
|
||||||
}
|
}
|
||||||
valueT Find(const keyT& key) {
|
inline valueT Find(const keyT& key) const {
|
||||||
if(table.find(key) == table.end())
|
if(table.find(key) == table.end())
|
||||||
return valueT();
|
return valueT();
|
||||||
return table.find(key)->second;
|
return table.find(key)->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Holds(const keyT& key) {
|
inline bool Holds(const keyT& key) const {
|
||||||
if(table.find(key) == table.end())
|
if(table.find(key) == table.end())
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
@@ -58,11 +58,12 @@ public:
|
|||||||
table.clear();
|
table.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline valueT operator[] (keyT key) const {
|
||||||
valueT & operator[] (keyT key) {
|
if(table.find(key) == table.end())
|
||||||
return table[key];
|
return valueT();
|
||||||
|
return table.find(key)->second;
|
||||||
}
|
}
|
||||||
unsigned Size() const {
|
inline unsigned Size() const {
|
||||||
return table.size();
|
return table.size();
|
||||||
}
|
}
|
||||||
MyIterator begin() const {
|
MyIterator begin() const {
|
||||||
|
|||||||
@@ -42,10 +42,10 @@ public:
|
|||||||
|
|
||||||
/** Default constructor. target and weight are set to 0.*/
|
/** Default constructor. target and weight are set to 0.*/
|
||||||
NodeBasedEdge() :
|
NodeBasedEdge() :
|
||||||
_source(0), _target(0), _name(0), _weight(0), forward(0), backward(0), _type(0), _roundabout(false) { assert(false); } //shall not be used.
|
_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) :
|
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) { assert(ty >= 0); }
|
_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 target() const {return _target; }
|
||||||
NodeID source() const {return _source; }
|
NodeID source() const {return _source; }
|
||||||
@@ -57,6 +57,8 @@ public:
|
|||||||
bool isForward() const { return forward; }
|
bool isForward() const { return forward; }
|
||||||
bool isLocatable() const { return _type != 14; }
|
bool isLocatable() const { return _type != 14; }
|
||||||
bool isRoundabout() const { return _roundabout; }
|
bool isRoundabout() const { return _roundabout; }
|
||||||
|
bool ignoreInGrid() const { return _ignoreInGrid; }
|
||||||
|
bool isAccessRestricted() const { return _accessRestricted; }
|
||||||
|
|
||||||
NodeID _source;
|
NodeID _source;
|
||||||
NodeID _target;
|
NodeID _target;
|
||||||
@@ -66,6 +68,8 @@ public:
|
|||||||
bool backward;
|
bool backward;
|
||||||
short _type;
|
short _type;
|
||||||
bool _roundabout;
|
bool _roundabout;
|
||||||
|
bool _ignoreInGrid;
|
||||||
|
bool _accessRestricted;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EdgeBasedEdge {
|
class EdgeBasedEdge {
|
||||||
@@ -89,39 +93,34 @@ public:
|
|||||||
EdgeBasedEdge(const EdgeT & myEdge ) :
|
EdgeBasedEdge(const EdgeT & myEdge ) :
|
||||||
_source(myEdge.source),
|
_source(myEdge.source),
|
||||||
_target(myEdge.target),
|
_target(myEdge.target),
|
||||||
_via(myEdge.data.via),
|
_edgeID(myEdge.data.via),
|
||||||
_nameID1(myEdge.data.nameID),
|
// _nameID1(myEdge.data.nameID),
|
||||||
_weight(myEdge.data.distance),
|
_weight(myEdge.data.distance),
|
||||||
_forward(myEdge.data.forward),
|
_forward(myEdge.data.forward),
|
||||||
_backward(myEdge.data.backward),
|
_backward(myEdge.data.backward)//,
|
||||||
_turnInstruction(myEdge.data.turnInstruction) { }
|
// _turnInstruction(myEdge.data.turnInstruction)
|
||||||
|
{ }
|
||||||
|
|
||||||
/** Default constructor. target and weight are set to 0.*/
|
/** Default constructor. target and weight are set to 0.*/
|
||||||
EdgeBasedEdge() :
|
EdgeBasedEdge() :
|
||||||
_source(0), _target(0), _via(0), _nameID1(0), _weight(0), _forward(0), _backward(0), _turnInstruction(0) { assert(false); } //shall not be used.
|
_source(0), _target(0), _edgeID(0), _weight(0), _forward(false), _backward(false) { }
|
||||||
|
|
||||||
explicit EdgeBasedEdge(NodeID s, NodeID t, NodeID v, unsigned n1, EdgeWeight w, bool f, bool b, short ty) :
|
explicit EdgeBasedEdge(NodeID s, NodeID t, NodeID v, EdgeWeight w, bool f, bool b) :
|
||||||
_source(s), _target(t), _via(v), _nameID1(n1), _weight(w), _forward(f), _backward(b), _turnInstruction(ty) { assert(ty >= 0); }
|
_source(s), _target(t), _edgeID(v), _weight(w), _forward(f), _backward(b){}
|
||||||
|
|
||||||
NodeID target() const {return _target; }
|
NodeID target() const {return _target; }
|
||||||
NodeID source() const {return _source; }
|
NodeID source() const {return _source; }
|
||||||
EdgeWeight weight() const {return _weight; }
|
EdgeWeight weight() const {return _weight; }
|
||||||
NodeID via() const { return _via; }
|
NodeID id() const { return _edgeID; }
|
||||||
short turnInstruction() const { assert(_turnInstruction >= 0); return _turnInstruction; }
|
|
||||||
bool isBackward() const { return _backward; }
|
bool isBackward() const { return _backward; }
|
||||||
bool isForward() const { return _forward; }
|
bool isForward() const { return _forward; }
|
||||||
|
|
||||||
unsigned getNameIDOfTurnTarget() const { return _nameID1; }
|
|
||||||
|
|
||||||
NodeID _source;
|
NodeID _source;
|
||||||
NodeID _target;
|
NodeID _target;
|
||||||
NodeID _via;
|
NodeID _edgeID;
|
||||||
unsigned _nameID1;
|
EdgeWeight _weight:30;
|
||||||
EdgeWeight _weight;
|
bool _forward:1;
|
||||||
bool _forward;
|
bool _backward:1;
|
||||||
bool _backward;
|
|
||||||
short _turnInstruction;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MinimalEdgeData {
|
struct MinimalEdgeData {
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
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,128 +1,82 @@
|
|||||||
#include <climits>
|
/*
|
||||||
#include <google/sparse_hash_map>
|
open source routing machine
|
||||||
#include <iostream>
|
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 <list>
|
||||||
#include <vector>
|
#include <boost/unordered_map.hpp>
|
||||||
|
|
||||||
template < class T >
|
|
||||||
struct Countfn {
|
|
||||||
unsigned long operator()( const T &x ) { return 1; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template< class Key, class Data, class Sizefn = Countfn< Data > > class LRUCache {
|
|
||||||
public:
|
|
||||||
typedef std::list< std::pair< Key, Data > > List; ///< Main cache storage typedef
|
|
||||||
typedef typename List::iterator List_Iter; ///< Main cache iterator
|
|
||||||
typedef typename List::const_iterator List_cIter; ///< Main cache iterator (const)
|
|
||||||
typedef std::vector< Key > Key_List; ///< List of keys
|
|
||||||
typedef typename Key_List::iterator Key_List_Iter; ///< Main cache iterator
|
|
||||||
typedef typename Key_List::const_iterator Key_List_cIter; ///< Main cache iterator (const)
|
|
||||||
typedef google::sparse_hash_map< Key, List_Iter > Map; ///< Index typedef
|
|
||||||
typedef std::pair< Key, List_Iter > Pair; ///< Pair of Map elements
|
|
||||||
typedef typename Map::iterator Map_Iter; ///< Index iterator
|
|
||||||
typedef typename Map::const_iterator Map_cIter; ///< Index iterator (const)
|
|
||||||
|
|
||||||
|
template<typename KeyT, typename ValueT>
|
||||||
|
class LRUCache {
|
||||||
private:
|
private:
|
||||||
List _list; ///< Main cache storage
|
struct CacheEntry {
|
||||||
Map _index; ///< Cache storage index
|
CacheEntry(KeyT k, ValueT v) : key(k), value(v) {}
|
||||||
unsigned long _max_size; ///< Maximum abstract size of the cache
|
KeyT key;
|
||||||
unsigned long _curr_size; ///< Current abstract size of the cache
|
ValueT value;
|
||||||
|
|
||||||
public:
|
|
||||||
LRUCache( const unsigned long Size ) : _max_size( Size ), _curr_size( 0 ) {
|
|
||||||
_index.set_deleted_key(UINT_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
~LRUCache() { clear(); }
|
|
||||||
|
|
||||||
inline const unsigned long size( void ) const { return _curr_size; }
|
|
||||||
|
|
||||||
inline const unsigned long max_size( void ) const { return _max_size; }
|
|
||||||
|
|
||||||
/// Clears all storage and indices.
|
|
||||||
void clear( void ) {
|
|
||||||
_list.clear();
|
|
||||||
_index.clear();
|
|
||||||
};
|
};
|
||||||
|
unsigned capacity;
|
||||||
|
std::list<CacheEntry> itemsInCache;
|
||||||
|
boost::unordered_map<KeyT, typename std::list<CacheEntry>::iterator > positionMap;
|
||||||
|
public:
|
||||||
|
LRUCache(unsigned c) : capacity(c) {}
|
||||||
|
|
||||||
inline bool exists( const Key &key ) const {
|
bool Holds(KeyT key) {
|
||||||
return _index.find( key ) != _index.end();
|
if(positionMap.find(key) != positionMap.end()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void remove( const Key &key ) {
|
void Insert(const KeyT key, ValueT &value) {
|
||||||
Map_Iter miter = _index.find( key );
|
itemsInCache.push_front(CacheEntry(key, value));
|
||||||
if( miter == _index.end() ) return;
|
positionMap.insert(std::make_pair(key, itemsInCache.begin()));
|
||||||
_remove( miter );
|
if(itemsInCache.size() > capacity) {
|
||||||
}
|
positionMap.erase(itemsInCache.back().key);
|
||||||
|
itemsInCache.pop_back();
|
||||||
inline void touch( const Key &key ) {
|
|
||||||
_touch( key );
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Data *fetch_ptr( const Key &key, bool touch = true ) {
|
|
||||||
Map_Iter miter = _index.find( key );
|
|
||||||
if( miter == _index.end() ) return NULL;
|
|
||||||
_touch( key );
|
|
||||||
return &(miter->second->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool fetch( const Key &key, Data &data, bool touch_data = true ) {
|
|
||||||
Map_Iter miter = _index.find( key );
|
|
||||||
if( miter == _index.end() ) return false;
|
|
||||||
if( touch_data )
|
|
||||||
_touch( key );
|
|
||||||
data = miter->second->second;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void insert( const Key &key, const Data data ) {
|
|
||||||
// Touch the key, if it exists, then replace the content.
|
|
||||||
Map_Iter miter = _touch( key );
|
|
||||||
if( miter != _index.end() )
|
|
||||||
_remove( miter );
|
|
||||||
|
|
||||||
// Ok, do the actual insert at the head of the list
|
|
||||||
_list.push_front( std::make_pair( key, data ) );
|
|
||||||
List_Iter liter = _list.begin();
|
|
||||||
|
|
||||||
// Store the index
|
|
||||||
_index.insert( std::make_pair( key, liter ) );
|
|
||||||
_curr_size += Sizefn()( data );
|
|
||||||
|
|
||||||
// Check to see if we need to remove an element due to exceeding max_size
|
|
||||||
while( _curr_size > _max_size ) {
|
|
||||||
std::cout << "removing element " << std::endl;
|
|
||||||
// Remove the last element.
|
|
||||||
liter = _list.end();
|
|
||||||
--liter;
|
|
||||||
_remove( liter->first );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const Key_List get_all_keys( void ) {
|
void Insert(const KeyT key, ValueT value) {
|
||||||
Key_List ret;
|
itemsInCache.push_front(CacheEntry(key, value));
|
||||||
for( List_cIter liter = _list.begin(); liter != _list.end(); liter++ )
|
positionMap.insert(std::make_pair(key, itemsInCache.begin()));
|
||||||
ret.push_back( liter->first );
|
if(itemsInCache.size() > capacity) {
|
||||||
return ret;
|
positionMap.erase(itemsInCache.back().key);
|
||||||
|
itemsInCache.pop_back();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
bool Fetch(const KeyT key, ValueT& result) {
|
||||||
inline Map_Iter _touch( const Key &key ) {
|
if(Holds(key)) {
|
||||||
Map_Iter miter = _index.find( key );
|
CacheEntry e = *(positionMap.find(key)->second);
|
||||||
if( miter == _index.end() ) return miter;
|
result = e.value;
|
||||||
// Move the found node to the head of the list.
|
|
||||||
_list.splice( _list.begin(), _list, miter->second );
|
|
||||||
return miter;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void _remove( const Map_Iter &miter ) {
|
//move to front
|
||||||
_curr_size -= Sizefn()( miter->second->second );
|
itemsInCache.splice(positionMap.find(key)->second, itemsInCache, itemsInCache.begin());
|
||||||
_list.erase( miter->second );
|
positionMap.find(key)->second = itemsInCache.begin();
|
||||||
_index.erase( miter );
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
unsigned Size() const {
|
||||||
inline void _remove( const Key &key ) {
|
return itemsInCache.size();
|
||||||
Map_Iter miter = _index.find( key );
|
|
||||||
_remove( miter );
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
#endif //LRUCACHE_H
|
||||||
|
|||||||
@@ -23,13 +23,14 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cfloat>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#ifndef ROUTED
|
||||||
#include <stxxl.h>
|
#include <stxxl.h>
|
||||||
#ifdef _OPENMP
|
|
||||||
#include <omp.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -38,114 +39,18 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
|
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
#include <google/dense_hash_map>
|
#include <boost/unordered_map.hpp>
|
||||||
|
|
||||||
#include "ExtractorStructs.h"
|
#include "DeallocatingVector.h"
|
||||||
|
//#include "ExtractorStructs.h"
|
||||||
#include "GridEdge.h"
|
#include "GridEdge.h"
|
||||||
#include "LRUCache.h"
|
|
||||||
#include "Percent.h"
|
#include "Percent.h"
|
||||||
#include "PhantomNodes.h"
|
#include "PhantomNodes.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include "StaticGraph.h"
|
#include "StaticGraph.h"
|
||||||
|
#include "../Algorithms/Bresenham.h"
|
||||||
static const unsigned MAX_CACHE_ELEMENTS = 1000;
|
|
||||||
|
|
||||||
namespace NNGrid{
|
namespace NNGrid{
|
||||||
static 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;
|
|
||||||
|
|
||||||
assert( x<=1.0 && x >= 0);
|
|
||||||
assert( y<=1.0 && y >= 0);
|
|
||||||
|
|
||||||
unsigned line = 1073741824.0*y;
|
|
||||||
line = line - (line % 32768);
|
|
||||||
assert(line % 32768 == 0);
|
|
||||||
unsigned column = 32768.*x;
|
|
||||||
unsigned fileIndex = line+column;
|
|
||||||
return fileIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned GetRAMIndexFromFileIndex(const int fileIndex) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int signum(int x){
|
|
||||||
return (x > 0) ? 1 : (x < 0) ? -1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void GetIndicesByBresenhamsAlgorithm(int xstart,int ystart,int xend,int yend, std::vector<std::pair<unsigned, unsigned> > &indexList) {
|
|
||||||
int x, y, t, dx, dy, incx, incy, pdx, pdy, ddx, ddy, es, el, err;
|
|
||||||
|
|
||||||
dx = xend - xstart;
|
|
||||||
dy = yend - ystart;
|
|
||||||
|
|
||||||
incx = signum(dx);
|
|
||||||
incy = signum(dy);
|
|
||||||
if(dx<0) dx = -dx;
|
|
||||||
if(dy<0) dy = -dy;
|
|
||||||
|
|
||||||
if (dx>dy) {
|
|
||||||
pdx=incx; pdy=0;
|
|
||||||
ddx=incx; ddy=incy;
|
|
||||||
es =dy; el =dx;
|
|
||||||
} else {
|
|
||||||
pdx=0; pdy=incy;
|
|
||||||
ddx=incx; ddy=incy;
|
|
||||||
es =dx; el =dy;
|
|
||||||
}
|
|
||||||
x = xstart;
|
|
||||||
y = ystart;
|
|
||||||
err = el/2;
|
|
||||||
{
|
|
||||||
int fileIndex = (y-1)*32768 + x;
|
|
||||||
int ramIndex = GetRAMIndexFromFileIndex(fileIndex);
|
|
||||||
indexList.push_back(std::make_pair(fileIndex, ramIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
for(t=0; t<el; ++t) {
|
|
||||||
err -= es;
|
|
||||||
if(err<0) {
|
|
||||||
err += el;
|
|
||||||
x += ddx;
|
|
||||||
y += ddy;
|
|
||||||
} else {
|
|
||||||
x += pdx;
|
|
||||||
y += pdy;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
int fileIndex = (y-1)*32768 + x;
|
|
||||||
int ramIndex = GetRAMIndexFromFileIndex(fileIndex);
|
|
||||||
indexList.push_back(std::make_pair(fileIndex, ramIndex));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void GetListOfIndexesForEdgeAndGridSize(_Coordinate& start, _Coordinate& target, std::vector<std::pair<unsigned, unsigned> > &indexList) {
|
|
||||||
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;
|
|
||||||
|
|
||||||
GetIndicesByBresenhamsAlgorithm(x1*32768, y1*32768, x2*32768, y2*32768, indexList);
|
|
||||||
}
|
|
||||||
|
|
||||||
static boost::thread_specific_ptr<std::ifstream> localStream;
|
static boost::thread_specific_ptr<std::ifstream> localStream;
|
||||||
|
|
||||||
@@ -153,28 +58,28 @@ template<bool WriteAccess = false>
|
|||||||
class NNGrid {
|
class NNGrid {
|
||||||
public:
|
public:
|
||||||
NNGrid() /*: cellCache(500), fileCache(500)*/ {
|
NNGrid() /*: cellCache(500), fileCache(500)*/ {
|
||||||
ramIndexTable.resize((1024*1024), UINT_MAX);
|
ramIndexTable.resize((1024*1024), ULONG_MAX);
|
||||||
if( WriteAccess) {
|
|
||||||
entries = new stxxl::vector<GridEntry>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NNGrid(const char* rif, const char* _i, unsigned numberOfThreads = omp_get_num_procs()) /*: cellCache(500), fileCache(500) */{
|
NNGrid(const char* rif, const char* _i) {
|
||||||
if(WriteAccess) {
|
if(WriteAccess) {
|
||||||
ERR("Not available in Write mode");
|
ERR("Not available in Write mode");
|
||||||
}
|
}
|
||||||
iif = std::string(_i);
|
iif = std::string(_i);
|
||||||
ramIndexTable.resize((1024*1024), UINT_MAX);
|
ramIndexTable.resize((1024*1024), ULONG_MAX);
|
||||||
ramInFile.open(rif, std::ios::in | std::ios::binary);
|
ramInFile.open(rif, std::ios::in | std::ios::binary);
|
||||||
entries = NULL;
|
if(!ramInFile) { ERR(rif << " not found"); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~NNGrid() {
|
~NNGrid() {
|
||||||
if(ramInFile.is_open()) ramInFile.close();
|
if(ramInFile.is_open()) ramInFile.close();
|
||||||
|
|
||||||
|
#ifndef ROUTED
|
||||||
if (WriteAccess) {
|
if (WriteAccess) {
|
||||||
delete entries;
|
entries.clear();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if(localStream.get() && localStream->is_open()) {
|
if(localStream.get() && localStream->is_open()) {
|
||||||
localStream->close();
|
localStream->close();
|
||||||
}
|
}
|
||||||
@@ -182,205 +87,168 @@ public:
|
|||||||
|
|
||||||
void OpenIndexFiles() {
|
void OpenIndexFiles() {
|
||||||
assert(ramInFile.is_open());
|
assert(ramInFile.is_open());
|
||||||
|
ramInFile.read(static_cast<char*>(static_cast<void*>(&ramIndexTable[0]) ), sizeof(unsigned long)*1024*1024);
|
||||||
for(int i = 0; i < 1024*1024; ++i) {
|
|
||||||
unsigned temp;
|
|
||||||
ramInFile.read((char*)&temp, sizeof(unsigned));
|
|
||||||
ramIndexTable[i] = temp;
|
|
||||||
}
|
|
||||||
ramInFile.close();
|
ramInFile.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename EdgeT, typename NodeInfoT>
|
#ifndef ROUTED
|
||||||
void ConstructGrid(std::vector<EdgeT> & edgeList, vector<NodeInfoT> * int2ExtNodeMap, char * ramIndexOut, char * fileIndexOut) {
|
template<typename EdgeT>
|
||||||
|
inline void ConstructGrid(DeallocatingVector<EdgeT> & edgeList, char * ramIndexOut, char * fileIndexOut) {
|
||||||
|
//TODO: Implement this using STXXL-Streams
|
||||||
Percent p(edgeList.size());
|
Percent p(edgeList.size());
|
||||||
for(NodeID i = 0; i < edgeList.size(); ++i) {
|
BOOST_FOREACH(EdgeT & edge, edgeList) {
|
||||||
p.printIncrement();
|
p.printIncrement();
|
||||||
EdgeT & edge = edgeList[i];
|
if(edge.ignoreInGrid)
|
||||||
|
continue;
|
||||||
int slat = 100000*lat2y(edge.lat1/100000.);
|
int slat = 100000*lat2y(edge.lat1/100000.);
|
||||||
int slon = edge.lon1;
|
int slon = edge.lon1;
|
||||||
int tlat = 100000*lat2y(edge.lat2/100000.);
|
int tlat = 100000*lat2y(edge.lat2/100000.);
|
||||||
int tlon = edge.lon2;
|
int tlon = edge.lon2;
|
||||||
AddEdge( _GridEdge(
|
AddEdge( _GridEdge( edge.id, edge.nameID, edge.weight, _Coordinate(slat, slon), _Coordinate(tlat, tlon), edge.belongsToTinyComponent ) );
|
||||||
edge.id, edge.nameID, edge.weight,
|
|
||||||
_Coordinate(slat, slon),
|
|
||||||
_Coordinate(tlat, tlon) )
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
double timestamp = get_timestamp();
|
double timestamp = get_timestamp();
|
||||||
//create index file on disk, old one is over written
|
//create index file on disk, old one is over written
|
||||||
indexOutFile.open(fileIndexOut, std::ios::out | std::ios::binary | std::ios::trunc);
|
indexOutFile.open(fileIndexOut, std::ios::out | std::ios::binary | std::ios::trunc);
|
||||||
cout << "sorting grid data consisting of " << entries->size() << " edges..." << flush;
|
|
||||||
//sort entries
|
//sort entries
|
||||||
stxxl::sort(entries->begin(), entries->end(), CompareGridEdgeDataByRamIndex(), 1024*1024*1024);
|
stxxl::sort(entries.begin(), entries.end(), CompareGridEdgeDataByRamIndex(), 1024*1024*1024);
|
||||||
cout << "ok in " << (get_timestamp() - timestamp) << "s" << endl;
|
INFO("finished sorting after " << (get_timestamp() - timestamp) << "s");
|
||||||
std::vector<GridEntry> entriesInFileWithRAMSameIndex;
|
std::vector<GridEntry> entriesInFileWithRAMSameIndex;
|
||||||
unsigned indexInRamTable = entries->begin()->ramIndex;
|
unsigned indexInRamTable = entries.begin()->ramIndex;
|
||||||
unsigned lastPositionInIndexFile = 0;
|
unsigned long lastPositionInIndexFile = 0;
|
||||||
unsigned numberOfUsedCells = 0;
|
|
||||||
unsigned maxNumberOfRAMCellElements = 0;
|
|
||||||
cout << "writing data ..." << flush;
|
cout << "writing data ..." << flush;
|
||||||
p.reinit(entries->size());
|
p.reinit(entries.size());
|
||||||
for(stxxl::vector<GridEntry>::iterator vt = entries->begin(); vt != entries->end(); ++vt) {
|
boost::unordered_map< unsigned, unsigned > cellMap(1024);
|
||||||
|
BOOST_FOREACH(GridEntry & gridEntry, entries) {
|
||||||
p.printIncrement();
|
p.printIncrement();
|
||||||
if(vt->ramIndex != indexInRamTable) {
|
if(gridEntry.ramIndex != indexInRamTable) {
|
||||||
unsigned numberOfBytesInCell = FillCell(entriesInFileWithRAMSameIndex, lastPositionInIndexFile);
|
cellMap.clear();
|
||||||
if(entriesInFileWithRAMSameIndex.size() > maxNumberOfRAMCellElements)
|
BuildCellIndexToFileIndexMap(indexInRamTable, cellMap);
|
||||||
maxNumberOfRAMCellElements = entriesInFileWithRAMSameIndex.size();
|
|
||||||
|
|
||||||
|
unsigned numberOfBytesInCell = FillCell(entriesInFileWithRAMSameIndex, lastPositionInIndexFile, cellMap);
|
||||||
ramIndexTable[indexInRamTable] = lastPositionInIndexFile;
|
ramIndexTable[indexInRamTable] = lastPositionInIndexFile;
|
||||||
lastPositionInIndexFile += numberOfBytesInCell;
|
lastPositionInIndexFile += numberOfBytesInCell;
|
||||||
entriesInFileWithRAMSameIndex.clear();
|
entriesInFileWithRAMSameIndex.clear();
|
||||||
indexInRamTable = vt->ramIndex;
|
indexInRamTable = gridEntry.ramIndex;
|
||||||
numberOfUsedCells++;
|
|
||||||
}
|
}
|
||||||
entriesInFileWithRAMSameIndex.push_back(*vt);
|
entriesInFileWithRAMSameIndex.push_back(gridEntry);
|
||||||
}
|
}
|
||||||
/*unsigned numberOfBytesInCell = */FillCell(entriesInFileWithRAMSameIndex, lastPositionInIndexFile);
|
cellMap.clear();
|
||||||
|
BuildCellIndexToFileIndexMap(indexInRamTable, cellMap);
|
||||||
|
/*unsigned numberOfBytesInCell = */FillCell(entriesInFileWithRAMSameIndex, lastPositionInIndexFile, cellMap);
|
||||||
ramIndexTable[indexInRamTable] = lastPositionInIndexFile;
|
ramIndexTable[indexInRamTable] = lastPositionInIndexFile;
|
||||||
numberOfUsedCells++;
|
|
||||||
entriesInFileWithRAMSameIndex.clear();
|
entriesInFileWithRAMSameIndex.clear();
|
||||||
|
std::vector<GridEntry>().swap(entriesInFileWithRAMSameIndex);
|
||||||
assert(entriesInFileWithRAMSameIndex.size() == 0);
|
assert(entriesInFileWithRAMSameIndex.size() == 0);
|
||||||
|
|
||||||
for(int i = 0; i < 1024*1024; ++i) {
|
|
||||||
if(ramIndexTable[i] != UINT_MAX) {
|
|
||||||
numberOfUsedCells--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(numberOfUsedCells == 0);
|
|
||||||
|
|
||||||
//close index file
|
//close index file
|
||||||
indexOutFile.close();
|
indexOutFile.close();
|
||||||
|
|
||||||
//Serialize RAM Index
|
//Serialize RAM Index
|
||||||
ofstream ramFile(ramIndexOut, std::ios::out | std::ios::binary | std::ios::trunc);
|
ofstream ramFile(ramIndexOut, std::ios::out | std::ios::binary | std::ios::trunc);
|
||||||
//write 4 MB of index Table in RAM
|
//write 4 MB of index Table in RAM
|
||||||
for(int i = 0; i < 1024*1024; ++i)
|
ramFile.write((char *)&ramIndexTable[0], sizeof(unsigned long)*1024*1024 );
|
||||||
ramFile.write((char *)&ramIndexTable[i], sizeof(unsigned) );
|
|
||||||
//close ram index file
|
//close ram index file
|
||||||
ramFile.close();
|
ramFile.close();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
bool GetEdgeBasedStartNode(const _Coordinate& coord, NodesOfEdge& nodesOfEdge) {
|
inline bool CoordinatesAreEquivalent(const _Coordinate & a, const _Coordinate & b, const _Coordinate & c, const _Coordinate & d) const {
|
||||||
_Coordinate startCoord(100000*(lat2y(static_cast<double>(coord.lat)/100000.)), coord.lon);
|
return (a == b && c == d) || (a == c && b == d) || (a == d && b == c);
|
||||||
/** search for point on edge next to source */
|
|
||||||
unsigned fileIndex = GetFileIndexForLatLon(startCoord.lat, startCoord.lon);
|
|
||||||
std::vector<_GridEdge> candidates;
|
|
||||||
|
|
||||||
for(int j = -32768; j < (32768+1); j+=32768) {
|
|
||||||
for(int i = -1; i < 2; i++){
|
|
||||||
GetContentsOfFileBucket(fileIndex+i+j, candidates);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_Coordinate tmp;
|
|
||||||
double dist = 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) {
|
|
||||||
nodesOfEdge.edgeBasedNode = candidate.edgeBasedNode;
|
|
||||||
nodesOfEdge.ratio = r;
|
|
||||||
dist = tmpDist;
|
|
||||||
nodesOfEdge.projectedPoint.lat = round(100000*(y2lat(static_cast<double>(tmp.lat)/100000.)));
|
|
||||||
nodesOfEdge.projectedPoint.lon = tmp.lon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(dist != (numeric_limits<double>::max)()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FindPhantomNodeForCoordinate( const _Coordinate & location, PhantomNode & resultNode) {
|
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;
|
bool foundNode = false;
|
||||||
_Coordinate startCoord(100000*(lat2y(static_cast<double>(location.lat)/100000.)), location.lon);
|
const _Coordinate startCoord(100000*(lat2y(static_cast<double>(location.lat)/100000.)), location.lon);
|
||||||
/** search for point on edge close to source */
|
/** search for point on edge close to source */
|
||||||
unsigned fileIndex = GetFileIndexForLatLon(startCoord.lat, startCoord.lon);
|
const unsigned fileIndex = GetFileIndexForLatLon(startCoord.lat, startCoord.lon);
|
||||||
std::vector<_GridEdge> candidates;
|
std::vector<_GridEdge> candidates;
|
||||||
|
const int lowerBoundForLoop = (fileIndex < 32768 ? 0 : -32768);
|
||||||
for(int j = -32768; j < (32768+1); j+=32768) {
|
for(int j = lowerBoundForLoop; (j < (32768+1)) && (fileIndex != UINT_MAX); j+=32768) {
|
||||||
for(int i = -1; i < 2; i++){
|
for(int i = -1; i < 2; ++i){
|
||||||
GetContentsOfFileBucket(fileIndex+i+j, candidates);
|
// 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;
|
_GridEdge smallestEdge;
|
||||||
_Coordinate tmp, newEndpoint;
|
_Coordinate tmp, edgeStartCoord, edgeEndCoord;
|
||||||
double dist = (numeric_limits<double>::max)();
|
double dist = numeric_limits<double>::max();
|
||||||
|
double r, tmpDist;
|
||||||
|
|
||||||
BOOST_FOREACH(_GridEdge candidate, candidates) {
|
BOOST_FOREACH(_GridEdge candidate, candidates) {
|
||||||
double r = 0.;
|
if(candidate.belongsToTinyComponent && ignoreTinyComponents)
|
||||||
double tmpDist = ComputeDistance(startCoord, candidate.startCoord, candidate.targetCoord, tmp, &r);
|
continue;
|
||||||
if(DoubleEpsilonCompare(dist, tmpDist) && 1 == std::abs((int)candidate.edgeBasedNode-(int)resultNode.edgeBasedNode)) {
|
r = 0.;
|
||||||
resultNode.weight2 = candidate.weight;
|
tmpDist = ComputeDistance(startCoord, candidate.startCoord, candidate.targetCoord, tmp, &r);
|
||||||
/* if(resultNode.weight1 != resultNode.weight2) {
|
// INFO("dist " << startCoord << "->[" << candidate.startCoord << "-" << candidate.targetCoord << "]=" << tmpDist );
|
||||||
ERR("w1: " << resultNode.weight1 << ", w2: " << resultNode.weight2);
|
// INFO("Looking at edge " << candidate.edgeBasedNode << " at distance " << tmpDist);
|
||||||
assert(false);
|
if(tmpDist < dist && !DoubleEpsilonCompare(dist, tmpDist)) {
|
||||||
}*/
|
// INFO("a) " << candidate.edgeBasedNode << ", dist: " << tmpDist << ", tinyCC: " << (candidate.belongsToTinyComponent ? "yes" : "no"));
|
||||||
if(candidate.edgeBasedNode < resultNode.edgeBasedNode) {
|
dist = tmpDist;
|
||||||
resultNode.edgeBasedNode = candidate.edgeBasedNode;
|
|
||||||
std::swap(resultNode.weight1, resultNode.weight2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(tmpDist < dist) {
|
|
||||||
resultNode.Reset();
|
|
||||||
resultNode.edgeBasedNode = candidate.edgeBasedNode;
|
resultNode.edgeBasedNode = candidate.edgeBasedNode;
|
||||||
resultNode.nodeBasedEdgeNameID = candidate.nameID;
|
resultNode.nodeBasedEdgeNameID = candidate.nameID;
|
||||||
resultNode.weight1 = candidate.weight;
|
resultNode.weight1 = candidate.weight;
|
||||||
dist = tmpDist;
|
resultNode.weight2 = INT_MAX;
|
||||||
resultNode.location.lat = round(100000*(y2lat(static_cast<double>(tmp.lat)/100000.)));
|
resultNode.location.lat = tmp.lat;
|
||||||
resultNode.location.lon = tmp.lon;
|
resultNode.location.lon = tmp.lon;
|
||||||
|
edgeStartCoord = candidate.startCoord;
|
||||||
|
edgeEndCoord = candidate.targetCoord;
|
||||||
foundNode = true;
|
foundNode = true;
|
||||||
smallestEdge = candidate;
|
smallestEdge = candidate;
|
||||||
newEndpoint = tmp;
|
//} 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("startcoord: " << smallestEdge.startCoord << ", tgtcoord" << smallestEdge.targetCoord << "result: " << newEndpoint);
|
||||||
// INFO("length of old edge: " << LengthOfVector(smallestEdge.startCoord, smallestEdge.targetCoord));
|
// INFO("length of old edge: " << ApproximateDistance(smallestEdge.startCoord, smallestEdge.targetCoord));
|
||||||
// INFO("Length of new edge: " << LengthOfVector(smallestEdge.startCoord, newEndpoint));
|
// INFO("Length of new edge: " << ApproximateDistance(smallestEdge.startCoord, newEndpoint));
|
||||||
// assert(!resultNode.isBidirected || (resultNode.weight1 == resultNode.weight2));
|
// assert(!resultNode.isBidirected() || (resultNode.weight1 == resultNode.weight2));
|
||||||
// if(resultNode.weight1 != resultNode.weight2) {
|
// if(resultNode.weight1 != resultNode.weight2) {
|
||||||
// INFO("-> Weight1: " << resultNode.weight1 << ", weight2: " << resultNode.weight2);
|
// INFO("-> Weight1: " << resultNode.weight1 << ", weight2: " << resultNode.weight2);
|
||||||
// INFO("-> node: " << resultNode.edgeBasedNode << ", bidir: " << (resultNode.isBidirected ? "yes" : "no"));
|
// INFO("-> node: " << resultNode.edgeBasedNode << ", bidir: " << (resultNode.isBidirected() ? "yes" : "no"));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
double ratio = std::min(1., LengthOfVector(smallestEdge.startCoord, newEndpoint)/LengthOfVector(smallestEdge.startCoord, smallestEdge.targetCoord) );
|
// INFO("startCoord: " << smallestEdge.startCoord << "; targetCoord: " << smallestEdge.targetCoord << "; newEndpoint: " << resultNode.location);
|
||||||
assert(ratio >= 0 && ratio <=1);
|
double ratio = (foundNode ? std::min(1., ApproximateDistance(smallestEdge.startCoord, resultNode.location)/ApproximateDistance(smallestEdge.startCoord, smallestEdge.targetCoord)) : 0);
|
||||||
// INFO("Old weight1: " << resultNode.weight1 << ", old weight2: " << resultNode.weight2);
|
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;
|
resultNode.weight1 *= ratio;
|
||||||
if(INT_MAX != resultNode.weight2) {
|
if(INT_MAX != resultNode.weight2) {
|
||||||
resultNode.weight2 *= (1-ratio);
|
resultNode.weight2 -= resultNode.weight1;
|
||||||
// INFO("New weight1: " << resultNode.weight1 << ", new weight2: " << resultNode.weight2);
|
|
||||||
}
|
}
|
||||||
|
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;
|
return foundNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FindRoutingStarts(const _Coordinate& start, const _Coordinate& target, PhantomNodes & routingStarts) {
|
bool FindRoutingStarts(const _Coordinate& start, const _Coordinate& target, PhantomNodes & routingStarts, unsigned zoomLevel) {
|
||||||
routingStarts.Reset();
|
routingStarts.Reset();
|
||||||
return (FindPhantomNodeForCoordinate( start, routingStarts.startPhantom) &&
|
return (FindPhantomNodeForCoordinate( start, routingStarts.startPhantom, zoomLevel) &&
|
||||||
FindPhantomNodeForCoordinate( target, routingStarts.targetPhantom) );
|
FindPhantomNodeForCoordinate( target, routingStarts.targetPhantom, zoomLevel) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void FindNearestCoordinateOnEdgeInNodeBasedGraph(const _Coordinate& inputCoordinate, _Coordinate& outputCoordinate) {
|
bool FindNearestCoordinateOnEdgeInNodeBasedGraph(const _Coordinate& inputCoordinate, _Coordinate& outputCoordinate, unsigned zoomLevel = 18) {
|
||||||
unsigned fileIndex = GetFileIndexForLatLon(100000*(lat2y(static_cast<double>(inputCoordinate.lat)/100000.)), inputCoordinate.lon);
|
PhantomNode resultNode;
|
||||||
std::vector<_GridEdge> candidates;
|
bool foundNode = FindPhantomNodeForCoordinate(inputCoordinate, resultNode, zoomLevel);
|
||||||
for(int j = -32768; j < (32768+1); j+=32768) {
|
outputCoordinate = resultNode.location;
|
||||||
for(int i = -1; i < 2; i++) {
|
return foundNode;
|
||||||
GetContentsOfFileBucket(fileIndex+i+j, candidates);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_Coordinate tmp;
|
|
||||||
double dist = (numeric_limits<double>::max)();
|
|
||||||
BOOST_FOREACH(_GridEdge candidate, candidates) {
|
|
||||||
double r = 0.;
|
|
||||||
double tmpDist = ComputeDistance(inputCoordinate, candidate.startCoord, candidate.targetCoord, tmp, &r);
|
|
||||||
if(tmpDist < dist) {
|
|
||||||
dist = tmpDist;
|
|
||||||
outputCoordinate = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outputCoordinate.lat = 100000*(y2lat(static_cast<double>(outputCoordinate.lat)/100000.));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FindNearestPointOnEdge(const _Coordinate& inputCoordinate, _Coordinate& outputCoordinate) {
|
void FindNearestPointOnEdge(const _Coordinate& inputCoordinate, _Coordinate& outputCoordinate) {
|
||||||
@@ -388,13 +256,14 @@ public:
|
|||||||
unsigned fileIndex = GetFileIndexForLatLon(startCoord.lat, startCoord.lon);
|
unsigned fileIndex = GetFileIndexForLatLon(startCoord.lat, startCoord.lon);
|
||||||
|
|
||||||
std::vector<_GridEdge> candidates;
|
std::vector<_GridEdge> candidates;
|
||||||
|
boost::unordered_map< unsigned, unsigned > cellMap;
|
||||||
for(int j = -32768; j < (32768+1); j+=32768) {
|
for(int j = -32768; j < (32768+1); j+=32768) {
|
||||||
for(int i = -1; i < 2; i++) {
|
for(int i = -1; i < 2; ++i) {
|
||||||
GetContentsOfFileBucket(fileIndex+i+j, candidates);
|
GetContentsOfFileBucket(fileIndex+i+j, candidates, cellMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_Coordinate tmp;
|
_Coordinate tmp;
|
||||||
double dist = (numeric_limits<double>::max)();
|
double dist = (std::numeric_limits<double>::max)();
|
||||||
BOOST_FOREACH(_GridEdge candidate, candidates) {
|
BOOST_FOREACH(_GridEdge candidate, candidates) {
|
||||||
double r = 0.;
|
double r = 0.;
|
||||||
double tmpDist = ComputeDistance(startCoord, candidate.startCoord, candidate.targetCoord, tmp, &r);
|
double tmpDist = ComputeDistance(startCoord, candidate.startCoord, candidate.targetCoord, tmp, &r);
|
||||||
@@ -408,41 +277,50 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline double LengthOfVector(const _Coordinate & c1, const _Coordinate & c2) {
|
inline unsigned GetCellIndexFromRAMAndFileIndex(const unsigned ramIndex, const unsigned fileIndex) const {
|
||||||
double length1 = std::sqrt(c1.lat/100000.*c1.lat/100000. + c1.lon/100000.*c1.lon/100000.);
|
|
||||||
double length2 = std::sqrt(c2.lat/100000.*c2.lat/100000. + c2.lon/100000.*c2.lon/100000.);
|
|
||||||
return std::fabs(length1-length2);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool DoubleEpsilonCompare(const double d1, const double d2) {
|
|
||||||
return (std::fabs(d1 - d2) < 0.000000001);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned FillCell(std::vector<GridEntry>& entriesWithSameRAMIndex, unsigned fileOffset ) {
|
|
||||||
vector<char> * tmpBuffer = new vector<char>();
|
|
||||||
tmpBuffer->resize(32*32*4096,0);
|
|
||||||
unsigned indexIntoTmpBuffer = 0;
|
|
||||||
unsigned numberOfWrittenBytes = 0;
|
|
||||||
assert(indexOutFile.is_open());
|
|
||||||
|
|
||||||
vector<unsigned> cellIndex;
|
|
||||||
cellIndex.resize(32*32,UINT_MAX);
|
|
||||||
google::dense_hash_map< unsigned, unsigned > * cellMap = new google::dense_hash_map< unsigned, unsigned >(1024);
|
|
||||||
cellMap->set_empty_key(UINT_MAX);
|
|
||||||
|
|
||||||
unsigned ramIndex = entriesWithSameRAMIndex.begin()->ramIndex;
|
|
||||||
unsigned lineBase = ramIndex/1024;
|
unsigned lineBase = ramIndex/1024;
|
||||||
lineBase = lineBase*32*32768;
|
lineBase = lineBase*32*32768;
|
||||||
unsigned columnBase = ramIndex%1024;
|
unsigned columnBase = ramIndex%1024;
|
||||||
columnBase=columnBase*32;
|
columnBase=columnBase*32;
|
||||||
|
for (int i = 0;i < 32;++i) {
|
||||||
for(int i = 0; i < 32; i++) {
|
for (int j = 0;j < 32;++j) {
|
||||||
for(int j = 0; j < 32; j++) {
|
const unsigned localFileIndex = lineBase + i * 32768 + columnBase + j;
|
||||||
unsigned fileIndex = lineBase + i*32768 + columnBase+j;
|
if(localFileIndex == fileIndex) {
|
||||||
unsigned cellIndex = i*32+j;
|
unsigned cellIndex = i * 32 + j;
|
||||||
cellMap->insert(std::make_pair(fileIndex, cellIndex));
|
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) {
|
for(unsigned i = 0; i < entriesWithSameRAMIndex.size() -1; ++i) {
|
||||||
assert(entriesWithSameRAMIndex[i].ramIndex== entriesWithSameRAMIndex[i+1].ramIndex);
|
assert(entriesWithSameRAMIndex[i].ramIndex== entriesWithSameRAMIndex[i+1].ramIndex);
|
||||||
@@ -450,149 +328,163 @@ private:
|
|||||||
|
|
||||||
//sort & unique
|
//sort & unique
|
||||||
std::sort(entriesWithSameRAMIndex.begin(), entriesWithSameRAMIndex.end(), CompareGridEdgeDataByFileIndex());
|
std::sort(entriesWithSameRAMIndex.begin(), entriesWithSameRAMIndex.end(), CompareGridEdgeDataByFileIndex());
|
||||||
std::vector<GridEntry>::iterator uniqueEnd = std::unique(entriesWithSameRAMIndex.begin(), entriesWithSameRAMIndex.end());
|
// entriesWithSameRAMIndex.erase(std::unique(entriesWithSameRAMIndex.begin(), entriesWithSameRAMIndex.end()), entriesWithSameRAMIndex.end());
|
||||||
|
|
||||||
//traverse each file bucket and write its contents to disk
|
//traverse each file bucket and write its contents to disk
|
||||||
std::vector<GridEntry> entriesWithSameFileIndex;
|
std::vector<GridEntry> entriesWithSameFileIndex;
|
||||||
unsigned fileIndex = entriesWithSameRAMIndex.begin()->fileIndex;
|
unsigned fileIndex = entriesWithSameRAMIndex.begin()->fileIndex;
|
||||||
|
|
||||||
for(std::vector<GridEntry>::iterator it = entriesWithSameRAMIndex.begin(); it != uniqueEnd; it++) {
|
BOOST_FOREACH(GridEntry & gridEntry, entriesWithSameRAMIndex) {
|
||||||
assert(cellMap->find(it->fileIndex) != cellMap->end() ); //asserting that file index belongs to cell index
|
assert(cellMap.find(gridEntry.fileIndex) != cellMap.end() ); //asserting that file index belongs to cell index
|
||||||
if(it->fileIndex != fileIndex) {
|
if(gridEntry.fileIndex != fileIndex) {
|
||||||
// start in cellIndex vermerken
|
// start in cellIndex vermerken
|
||||||
int localFileIndex = entriesWithSameFileIndex.begin()->fileIndex;
|
int localFileIndex = entriesWithSameFileIndex.begin()->fileIndex;
|
||||||
int localCellIndex = cellMap->find(localFileIndex)->second;
|
int localCellIndex = cellMap.find(localFileIndex)->second;
|
||||||
/*int localRamIndex = */GetRAMIndexFromFileIndex(localFileIndex);
|
assert(cellMap.find(entriesWithSameFileIndex.begin()->fileIndex) != cellMap.end());
|
||||||
assert(cellMap->find(entriesWithSameFileIndex.begin()->fileIndex) != cellMap->end());
|
|
||||||
|
|
||||||
cellIndex[localCellIndex] = indexIntoTmpBuffer + fileOffset;
|
cellIndex[localCellIndex] = indexIntoTmpBuffer + fileOffset;
|
||||||
indexIntoTmpBuffer += FlushEntriesWithSameFileIndexToBuffer(entriesWithSameFileIndex, tmpBuffer, indexIntoTmpBuffer);
|
indexIntoTmpBuffer += FlushEntriesWithSameFileIndexToBuffer(entriesWithSameFileIndex, tmpBuffer, indexIntoTmpBuffer);
|
||||||
|
fileIndex = gridEntry.fileIndex;
|
||||||
}
|
}
|
||||||
GridEntry data = *it;
|
entriesWithSameFileIndex.push_back(gridEntry);
|
||||||
entriesWithSameFileIndex.push_back(data);
|
|
||||||
fileIndex = it->fileIndex;
|
|
||||||
}
|
}
|
||||||
assert(cellMap->find(entriesWithSameFileIndex.begin()->fileIndex) != cellMap->end());
|
assert(cellMap.find(entriesWithSameFileIndex.begin()->fileIndex) != cellMap.end());
|
||||||
int localFileIndex = entriesWithSameFileIndex.begin()->fileIndex;
|
int localFileIndex = entriesWithSameFileIndex.begin()->fileIndex;
|
||||||
int localCellIndex = cellMap->find(localFileIndex)->second;
|
int localCellIndex = cellMap.find(localFileIndex)->second;
|
||||||
/*int localRamIndex = */GetRAMIndexFromFileIndex(localFileIndex);
|
|
||||||
|
|
||||||
cellIndex[localCellIndex] = indexIntoTmpBuffer + fileOffset;
|
cellIndex[localCellIndex] = indexIntoTmpBuffer + fileOffset;
|
||||||
indexIntoTmpBuffer += FlushEntriesWithSameFileIndexToBuffer(entriesWithSameFileIndex, tmpBuffer, indexIntoTmpBuffer);
|
indexIntoTmpBuffer += FlushEntriesWithSameFileIndexToBuffer(entriesWithSameFileIndex, tmpBuffer, indexIntoTmpBuffer);
|
||||||
|
|
||||||
assert(entriesWithSameFileIndex.size() == 0);
|
assert(entriesWithSameFileIndex.size() == 0);
|
||||||
|
indexOutFile.write(static_cast<char*>(static_cast<void*>(&cellIndex[0])),32*32*sizeof(unsigned long));
|
||||||
for(int i = 0; i < 32*32; i++) {
|
numberOfWrittenBytes += 32*32*sizeof(unsigned long);
|
||||||
indexOutFile.write((char *)&cellIndex[i], sizeof(unsigned));
|
|
||||||
numberOfWrittenBytes += sizeof(unsigned);
|
|
||||||
}
|
|
||||||
|
|
||||||
//write contents of tmpbuffer to disk
|
//write contents of tmpbuffer to disk
|
||||||
for(unsigned i = 0; i < indexIntoTmpBuffer; i++) {
|
indexOutFile.write(&tmpBuffer[0], indexIntoTmpBuffer*sizeof(char));
|
||||||
indexOutFile.write(&(tmpBuffer->at(i)), sizeof(char));
|
numberOfWrittenBytes += indexIntoTmpBuffer*sizeof(char);
|
||||||
numberOfWrittenBytes += sizeof(char);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete tmpBuffer;
|
|
||||||
delete cellMap;
|
|
||||||
return numberOfWrittenBytes;
|
return numberOfWrittenBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned FlushEntriesWithSameFileIndexToBuffer( std::vector<GridEntry> &vectorWithSameFileIndex, vector<char> * tmpBuffer, const unsigned index) {
|
inline unsigned FlushEntriesWithSameFileIndexToBuffer( std::vector<GridEntry> &vectorWithSameFileIndex, std::vector<char> & tmpBuffer, const unsigned long index) const {
|
||||||
tmpBuffer->resize(tmpBuffer->size()+(sizeof(_GridEdge)*vectorWithSameFileIndex.size()) );
|
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;
|
unsigned counter = 0;
|
||||||
unsigned max = UINT_MAX;
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < vectorWithSameFileIndex.size()-1; i++) {
|
for(unsigned i = 0; i < vectorWithSameFileIndex.size()-1; ++i) {
|
||||||
assert( vectorWithSameFileIndex[i].fileIndex == vectorWithSameFileIndex[i+1].fileIndex );
|
assert( vectorWithSameFileIndex[i].fileIndex == vectorWithSameFileIndex[i+1].fileIndex );
|
||||||
assert( vectorWithSameFileIndex[i].ramIndex == vectorWithSameFileIndex[i+1].ramIndex );
|
assert( vectorWithSameFileIndex[i].ramIndex == vectorWithSameFileIndex[i+1].ramIndex );
|
||||||
}
|
}
|
||||||
|
|
||||||
sort( vectorWithSameFileIndex.begin(), vectorWithSameFileIndex.end() );
|
//write length of bucket
|
||||||
vectorWithSameFileIndex.erase(unique(vectorWithSameFileIndex.begin(), vectorWithSameFileIndex.end()), vectorWithSameFileIndex.end());
|
memcpy((char*)&(tmpBuffer[index+counter]), (char*)&lengthOfBucket, sizeof(lengthOfBucket));
|
||||||
BOOST_FOREACH(GridEntry entry, vectorWithSameFileIndex) {
|
counter += sizeof(lengthOfBucket);
|
||||||
char * data = (char *)&(entry.edge);
|
|
||||||
for(unsigned i = 0; i < sizeof(_GridEdge); ++i) {
|
BOOST_FOREACH(const GridEntry & entry, vectorWithSameFileIndex) {
|
||||||
tmpBuffer->at(index+counter) = data[i];
|
char * data = (char*)&(entry.edge);
|
||||||
++counter;
|
memcpy(static_cast<char*>(static_cast<void*>(&(tmpBuffer[index+counter]) )), data, sizeof(entry.edge));
|
||||||
}
|
counter += sizeof(entry.edge);
|
||||||
}
|
|
||||||
char * umax = (char *) &max;
|
|
||||||
for(unsigned i = 0; i < sizeof(unsigned); i++) {
|
|
||||||
tmpBuffer->at(index+counter) = umax[i];
|
|
||||||
counter++;
|
|
||||||
}
|
}
|
||||||
|
//Freeing data
|
||||||
vectorWithSameFileIndex.clear();
|
vectorWithSameFileIndex.clear();
|
||||||
std::vector<GridEntry>().swap(vectorWithSameFileIndex);
|
|
||||||
return counter;
|
return counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetContentsOfFileBucket(const unsigned fileIndex, std::vector<_GridEdge>& result) {
|
inline void GetContentsOfFileBucketEnumerated(const unsigned fileIndex, std::vector<_GridEdge>& result) const {
|
||||||
unsigned ramIndex = GetRAMIndexFromFileIndex(fileIndex);
|
unsigned ramIndex = GetRAMIndexFromFileIndex(fileIndex);
|
||||||
unsigned startIndexInFile = ramIndexTable[ramIndex];
|
unsigned long startIndexInFile = ramIndexTable[ramIndex];
|
||||||
if(startIndexInFile == UINT_MAX) {
|
if(startIndexInFile == ULONG_MAX) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
unsigned enumeratedIndex = GetCellIndexFromRAMAndFileIndex(ramIndex, fileIndex);
|
||||||
|
|
||||||
std::vector<unsigned> cellIndex;
|
|
||||||
cellIndex.resize(32*32);
|
|
||||||
google::dense_hash_map< unsigned, unsigned > cellMap(1024);
|
|
||||||
cellMap.set_empty_key(UINT_MAX);
|
|
||||||
|
|
||||||
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++) {
|
|
||||||
unsigned fileIndex = lineBase + i*32768 + columnBase+j;
|
|
||||||
unsigned cellIndex = i*32+j;
|
|
||||||
cellMap.insert(std::make_pair(fileIndex, cellIndex));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!localStream.get() || !localStream->is_open()) {
|
if(!localStream.get() || !localStream->is_open()) {
|
||||||
localStream.reset(new std::ifstream(iif.c_str(), std::ios::in | std::ios::binary));
|
localStream.reset(new std::ifstream(iif.c_str(), std::ios::in | std::ios::binary));
|
||||||
}
|
}
|
||||||
localStream->seekg(startIndexInFile);
|
if(!localStream->good()) {
|
||||||
localStream->read((char*) &cellIndex[0], 32*32*sizeof(unsigned));
|
localStream->clear(std::ios::goodbit);
|
||||||
assert(cellMap.find(fileIndex) != cellMap.end());
|
DEBUG("Resetting stale filestream");
|
||||||
if(cellIndex[cellMap.find(fileIndex)->second] == UINT_MAX) {
|
}
|
||||||
|
|
||||||
|
//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;
|
return;
|
||||||
}
|
}
|
||||||
const unsigned position = cellIndex[cellMap.find(fileIndex)->second] + 32*32*sizeof(unsigned) ;
|
const unsigned long position = fetchedIndex + 32*32*sizeof(unsigned long) ;
|
||||||
|
|
||||||
|
unsigned lengthOfBucket;
|
||||||
|
unsigned currentSizeOfResult = result.size();
|
||||||
localStream->seekg(position);
|
localStream->seekg(position);
|
||||||
_GridEdge gridEdge;
|
localStream->read(static_cast<char*>( static_cast<void*>(&(lengthOfBucket))), sizeof(unsigned));
|
||||||
do {
|
result.resize(currentSizeOfResult+lengthOfBucket);
|
||||||
localStream->read((char *)&(gridEdge), sizeof(_GridEdge));
|
localStream->read(static_cast<char*>( static_cast<void*>(&result[currentSizeOfResult])), lengthOfBucket*sizeof(_GridEdge));
|
||||||
if(localStream->eof() || gridEdge.edgeBasedNode == UINT_MAX)
|
|
||||||
break;
|
|
||||||
result.push_back(gridEdge);
|
|
||||||
} while(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddEdge(_GridEdge edge) {
|
inline void GetContentsOfFileBucket(const unsigned fileIndex, std::vector<_GridEdge>& result, boost::unordered_map< unsigned, unsigned> & cellMap) {
|
||||||
std::vector<std::pair<unsigned, unsigned> > indexList;
|
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);
|
GetListOfIndexesForEdgeAndGridSize(edge.startCoord, edge.targetCoord, indexList);
|
||||||
for(unsigned i = 0; i < indexList.size(); ++i) {
|
for(unsigned i = 0; i < indexList.size(); ++i) {
|
||||||
entries->push_back(GridEntry(edge, indexList[i].first, indexList[i].second));
|
entries.push_back(GridEntry(edge, indexList[i].first, indexList[i].second));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
double ComputeDistance(const _Coordinate& inputPoint, const _Coordinate& source, const _Coordinate& target, _Coordinate& nearest, double *r) {
|
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 = (double)inputPoint.lat;
|
const double x = static_cast<double>(inputPoint.lat);
|
||||||
const double y = (double)inputPoint.lon;
|
const double y = static_cast<double>(inputPoint.lon);
|
||||||
const double a = (double)source.lat;
|
const double a = static_cast<double>(source.lat);
|
||||||
const double b = (double)source.lon;
|
const double b = static_cast<double>(source.lon);
|
||||||
const double c = (double)target.lat;
|
const double c = static_cast<double>(target.lat);
|
||||||
const double d = (double)target.lon;
|
const double d = static_cast<double>(target.lon);
|
||||||
double p,q,mX,nY;
|
double p,q,mX,nY;
|
||||||
if(c != a){
|
// 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
|
const double m = (d-b)/(c-a); // slope
|
||||||
// Projection of (x,y) on line joining (a,b) and (c,d)
|
// Projection of (x,y) on line joining (a,b) and (c,d)
|
||||||
p = ((x + (m*y)) + (m*m*a - m*b))/(1 + m*m);
|
p = ((x + (m*y)) + (m*m*a - m*b))/(1. + m*m);
|
||||||
q = b + m*(p - a);
|
q = b + m*(p - a);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
@@ -601,31 +493,98 @@ private:
|
|||||||
}
|
}
|
||||||
nY = (d*p - c*q)/(a*d - b*c);
|
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
|
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
|
||||||
*r = mX;
|
// INFO("p=" << p << ", q=" << q << ", nY=" << nY << ", mX=" << mX);
|
||||||
if(*r<=0){
|
if(std::isnan(mX)) {
|
||||||
|
*r = (target == inputPoint) ? 1. : 0.;
|
||||||
|
} else {
|
||||||
|
*r = mX;
|
||||||
|
}
|
||||||
|
// INFO("r=" << *r);
|
||||||
|
if(*r<=0.){
|
||||||
nearest.lat = source.lat;
|
nearest.lat = source.lat;
|
||||||
nearest.lon = source.lon;
|
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));
|
return ((b - y)*(b - y) + (a - x)*(a - x));
|
||||||
}
|
}
|
||||||
else if(*r >= 1){
|
else if(*r >= 1.){
|
||||||
nearest.lat = target.lat;
|
nearest.lat = target.lat;
|
||||||
nearest.lon = target.lon;
|
nearest.lon = target.lon;
|
||||||
return ((d - y)*(d - y) + (c - x)*(c - x));
|
// 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
|
// point lies in between
|
||||||
nearest.lat = p;
|
nearest.lat = p;
|
||||||
nearest.lon = q;
|
nearest.lon = q;
|
||||||
|
// INFO("c returning distance " << (p-x)*(p-x) + (q-y)*(q-y))
|
||||||
|
|
||||||
return (p-x)*(p-x) + (q-y)*(q-y);
|
return (p-x)*(p-x) + (q-y)*(q-y);
|
||||||
}
|
}
|
||||||
|
|
||||||
ofstream indexOutFile;
|
inline void GetListOfIndexesForEdgeAndGridSize(const _Coordinate& start, const _Coordinate& target, std::vector<BresenhamPixel> &indexList) const {
|
||||||
ifstream ramInFile;
|
double lat1 = start.lat/100000.;
|
||||||
stxxl::vector<GridEntry> * entries;
|
double lon1 = start.lon/100000.;
|
||||||
std::vector<unsigned> ramIndexTable; //4 MB for first level index in RAM
|
|
||||||
|
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;
|
std::string iif;
|
||||||
// LRUCache<int,std::vector<unsigned> > cellCache;
|
// LRUCache<int,std::vector<unsigned> > cellCache;
|
||||||
// LRUCache<int,std::vector<_Edge> > fileCache;
|
// LRUCache<int,std::vector<_Edge> > fileCache;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,45 +24,46 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "../typedefs.h"
|
#include "../typedefs.h"
|
||||||
|
|
||||||
template<typename NodeT>
|
template<typename NodeT>
|
||||||
struct NodeCoords {
|
struct NodeCoords {
|
||||||
typedef unsigned key_type; //type of NodeID
|
typedef unsigned key_type; //type of NodeID
|
||||||
typedef int value_type; //type of lat,lons
|
typedef int value_type; //type of lat,lons
|
||||||
|
|
||||||
NodeCoords(int _lat, int _lon, NodeT _id) : lat(_lat), lon(_lon), id(_id) {}
|
NodeCoords(int _lat, int _lon, NodeT _id) : lat(_lat), lon(_lon), id(_id) {}
|
||||||
NodeCoords() : lat(INT_MAX), lon(INT_MAX), id(UINT_MAX) {}
|
NodeCoords() : lat(INT_MAX), lon(INT_MAX), id(UINT_MAX) {}
|
||||||
int lat;
|
int lat;
|
||||||
int lon;
|
int lon;
|
||||||
NodeT id;
|
NodeT id;
|
||||||
|
|
||||||
static NodeCoords<NodeT> min_value()
|
static NodeCoords<NodeT> min_value() {
|
||||||
{
|
return NodeCoords<NodeT>(-90*100000,-180*100000,std::numeric_limits<NodeT>::min());
|
||||||
return NodeCoords<NodeT>(-90*100000,-180*100000,numeric_limits<NodeT>::min());
|
}
|
||||||
}
|
static NodeCoords<NodeT> max_value() {
|
||||||
static NodeCoords<NodeT> max_value()
|
return NodeCoords<NodeT>(90*100000, 180*100000, std::numeric_limits<NodeT>::max());
|
||||||
{
|
}
|
||||||
return NodeCoords<NodeT>(90*100000, 180*100000, numeric_limits<NodeT>::max());
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type operator[](size_t n) const {
|
value_type operator[](std::size_t n) const {
|
||||||
switch(n) {
|
switch(n) {
|
||||||
case 1:
|
case 1:
|
||||||
return lat;
|
return lat;
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
return lon;
|
return lon;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
return UINT_MAX;
|
return UINT_MAX;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
assert(false);
|
assert(false);
|
||||||
return UINT_MAX;
|
return UINT_MAX;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef NodeCoords<NodeID> NodeInfo;
|
||||||
|
|
||||||
#endif //_NODE_COORDS_H
|
#endif //_NODE_COORDS_H
|
||||||
|
|||||||
@@ -26,65 +26,99 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "../typedefs.h"
|
#include "../typedefs.h"
|
||||||
|
#include "../DataStructures/QueryEdge.h"
|
||||||
#include "NNGrid.h"
|
#include "NNGrid.h"
|
||||||
#include "PhantomNodes.h"
|
#include "PhantomNodes.h"
|
||||||
|
#include "NodeCoords.h"
|
||||||
|
|
||||||
class NodeInformationHelpDesk{
|
class NodeInformationHelpDesk{
|
||||||
public:
|
public:
|
||||||
NodeInformationHelpDesk(const char* ramIndexInput, const char* fileIndexInput, unsigned _numberOfNodes) : numberOfNodes(_numberOfNodes) {
|
NodeInformationHelpDesk(const char* ramIndexInput, const char* fileIndexInput, const unsigned _numberOfNodes, const unsigned crc) : numberOfNodes(_numberOfNodes), checkSum(crc) {
|
||||||
readOnlyGrid = new ReadOnlyGrid(ramIndexInput,fileIndexInput);
|
readOnlyGrid = new ReadOnlyGrid(ramIndexInput,fileIndexInput);
|
||||||
int2ExtNodeMap = new vector<_Coordinate>();
|
assert(0 == coordinateVector.size());
|
||||||
int2ExtNodeMap->reserve(numberOfNodes);
|
}
|
||||||
assert(0 == int2ExtNodeMap->size());
|
|
||||||
}
|
//Todo: Shared memory mechanism
|
||||||
|
// NodeInformationHelpDesk(const char* ramIndexInput, const char* fileIndexInput, const unsigned crc) : checkSum(crc) {
|
||||||
|
// readOnlyGrid = new ReadOnlyGrid(ramIndexInput,fileIndexInput);
|
||||||
|
// }
|
||||||
|
|
||||||
~NodeInformationHelpDesk() {
|
~NodeInformationHelpDesk() {
|
||||||
delete int2ExtNodeMap;
|
|
||||||
delete readOnlyGrid;
|
delete readOnlyGrid;
|
||||||
}
|
}
|
||||||
void initNNGrid(ifstream& in) {
|
void initNNGrid(std::ifstream& nodesInstream, std::ifstream& edgesInStream) {
|
||||||
while(!in.eof()) {
|
DEBUG("Loading node data");
|
||||||
NodeInfo b;
|
NodeInfo b;
|
||||||
in.read((char *)&b, sizeof(b));
|
while(!nodesInstream.eof()) {
|
||||||
int2ExtNodeMap->push_back(_Coordinate(b.lat, b.lon));
|
nodesInstream.read((char *)&b, sizeof(NodeInfo));
|
||||||
|
coordinateVector.push_back(_Coordinate(b.lat, b.lon));
|
||||||
}
|
}
|
||||||
in.close();
|
std::vector<_Coordinate>(coordinateVector).swap(coordinateVector);
|
||||||
readOnlyGrid->OpenIndexFiles();
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int getLatitudeOfNode(const NodeID node) const {
|
void initNNGrid() {
|
||||||
return int2ExtNodeMap->at(node).lat;
|
readOnlyGrid->OpenIndexFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int getLongitudeOfNode(const NodeID node) const { return int2ExtNodeMap->at(node).lon; }
|
inline int getLatitudeOfNode(const unsigned id) const {
|
||||||
|
const NodeID node = origEdgeData.at(id).viaNode;
|
||||||
NodeID getNumberOfNodes() const { return numberOfNodes; }
|
return coordinateVector.at(node).lat;
|
||||||
NodeID getNumberOfNodes2() const { return int2ExtNodeMap->size(); }
|
|
||||||
|
|
||||||
inline void FindNearestNodeCoordForLatLon(const _Coordinate& coord, _Coordinate& result) {
|
|
||||||
readOnlyGrid->FindNearestCoordinateOnEdgeInNodeBasedGraph(coord, result);
|
|
||||||
}
|
|
||||||
bool FindPhantomNodeForCoordinate( const _Coordinate & location, PhantomNode & resultNode) {
|
|
||||||
return readOnlyGrid->FindPhantomNodeForCoordinate(location, resultNode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool FindRoutingStarts(const _Coordinate &start, const _Coordinate &target, PhantomNodes & phantomNodes) {
|
inline int getLongitudeOfNode(const unsigned id) const {
|
||||||
readOnlyGrid->FindRoutingStarts(start, target, phantomNodes);
|
const NodeID node = origEdgeData.at(id).viaNode;
|
||||||
return true;
|
return coordinateVector.at(node).lon;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool GetStartAndDestNodesOfEdge(const _Coordinate& coord, NodesOfEdge& nodesOfEdge) {
|
inline unsigned getNameIndexFromEdgeID(const unsigned id) const {
|
||||||
return readOnlyGrid->GetEdgeBasedStartNode(coord, nodesOfEdge);
|
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){
|
inline void FindNearestPointOnEdge(const _Coordinate & input, _Coordinate& output){
|
||||||
readOnlyGrid->FindNearestPointOnEdge(input, output);
|
readOnlyGrid->FindNearestPointOnEdge(input, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline unsigned GetCheckSum() const {
|
||||||
|
return checkSum;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vector<_Coordinate> * int2ExtNodeMap;
|
std::vector<_Coordinate> coordinateVector;
|
||||||
|
std::vector<OriginalEdgeData> origEdgeData;
|
||||||
|
|
||||||
ReadOnlyGrid * readOnlyGrid;
|
ReadOnlyGrid * readOnlyGrid;
|
||||||
unsigned numberOfNodes;
|
const unsigned numberOfNodes;
|
||||||
|
const unsigned checkSum;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /*NODEINFORMATIONHELPDESK_H_*/
|
#endif /*NODEINFORMATIONHELPDESK_H_*/
|
||||||
|
|||||||
@@ -22,9 +22,7 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
#define PERCENT_H
|
#define PERCENT_H
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#ifdef _OPENMP
|
|
||||||
#include <omp.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class Percent
|
class Percent
|
||||||
{
|
{
|
||||||
@@ -61,7 +59,13 @@ public:
|
|||||||
void printIncrement()
|
void printIncrement()
|
||||||
{
|
{
|
||||||
#pragma omp atomic
|
#pragma omp atomic
|
||||||
_current_value++;
|
++_current_value;
|
||||||
|
printStatus(_current_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printAddition(const unsigned addition) {
|
||||||
|
#pragma omp atomic
|
||||||
|
_current_value += addition;
|
||||||
printStatus(_current_value);
|
printStatus(_current_value);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -21,25 +21,34 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
#ifndef PHANTOMNODES_H_
|
#ifndef PHANTOMNODES_H_
|
||||||
#define PHANTOMNODES_H_
|
#define PHANTOMNODES_H_
|
||||||
|
|
||||||
#include "ExtractorStructs.h"
|
#include "Coordinate.h"
|
||||||
|
|
||||||
struct PhantomNode {
|
struct PhantomNode {
|
||||||
PhantomNode() : edgeBasedNode(UINT_MAX), nodeBasedEdgeNameID(UINT_MAX), weight1(INT_MAX), weight2(INT_MAX) {}
|
PhantomNode() : edgeBasedNode(UINT_MAX), nodeBasedEdgeNameID(UINT_MAX), weight1(INT_MAX), weight2(INT_MAX), ratio(0.) {}
|
||||||
NodeID edgeBasedNode;
|
NodeID edgeBasedNode;
|
||||||
unsigned nodeBasedEdgeNameID;
|
unsigned nodeBasedEdgeNameID;
|
||||||
int weight1;
|
int weight1;
|
||||||
int weight2;
|
int weight2;
|
||||||
|
double ratio;
|
||||||
_Coordinate location;
|
_Coordinate location;
|
||||||
void Reset() {
|
void Reset() {
|
||||||
edgeBasedNode = UINT_MAX;
|
edgeBasedNode = UINT_MAX;
|
||||||
nodeBasedEdgeNameID = UINT_MAX;
|
nodeBasedEdgeNameID = UINT_MAX;
|
||||||
weight1 = INT_MAX;
|
weight1 = INT_MAX;
|
||||||
weight2 = INT_MAX;
|
weight2 = INT_MAX;
|
||||||
|
ratio = 0.;
|
||||||
location.Reset();
|
location.Reset();
|
||||||
}
|
}
|
||||||
bool isBidirected() const {
|
bool isBidirected() const {
|
||||||
return weight2 != INT_MAX;
|
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 {
|
struct PhantomNodes {
|
||||||
@@ -57,6 +66,10 @@ struct PhantomNodes {
|
|||||||
bool AtLeastOnePhantomNodeIsUINTMAX() const {
|
bool AtLeastOnePhantomNodeIsUINTMAX() const {
|
||||||
return !(startPhantom.edgeBasedNode == UINT_MAX || targetPhantom.edgeBasedNode == UINT_MAX);
|
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){
|
inline std::ostream& operator<<(std::ostream &out, const PhantomNodes & pn){
|
||||||
@@ -67,6 +80,11 @@ inline std::ostream& operator<<(std::ostream &out, const PhantomNodes & pn){
|
|||||||
return out;
|
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 {
|
struct NodesOfEdge {
|
||||||
NodeID edgeBasedNode;
|
NodeID edgeBasedNode;
|
||||||
double ratio;
|
double ratio;
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
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_ */
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
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_ */
|
||||||
@@ -23,245 +23,149 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
|
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include "SimpleStack.h"
|
||||||
|
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
|
|
||||||
#include "BinaryHeap.h"
|
#include "BinaryHeap.h"
|
||||||
|
#include "NodeInformationHelpDesk.h"
|
||||||
#include "PhantomNodes.h"
|
#include "PhantomNodes.h"
|
||||||
|
#include "../RoutingAlgorithms/AlternativePathRouting.h"
|
||||||
|
#include "../RoutingAlgorithms/BasicRoutingInterface.h"
|
||||||
|
#include "../RoutingAlgorithms/ShortestPathRouting.h"
|
||||||
|
|
||||||
#include "../Util/StringUtil.h"
|
#include "../Util/StringUtil.h"
|
||||||
#include "../typedefs.h"
|
#include "../typedefs.h"
|
||||||
|
|
||||||
struct _HeapData {
|
struct _HeapData {
|
||||||
NodeID parent;
|
NodeID parent;
|
||||||
_HeapData( NodeID p ) : parent(p) { }
|
_HeapData( NodeID p ) : parent(p) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef boost::thread_specific_ptr<BinaryHeap< NodeID, NodeID, int, _HeapData > > HeapPtr;
|
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>
|
template<class EdgeData, class GraphT>
|
||||||
class SearchEngine {
|
class SearchEngine {
|
||||||
private:
|
private:
|
||||||
const GraphT * _graph;
|
typedef SearchEngineData<EdgeData, GraphT> SearchEngineDataT;
|
||||||
NodeInformationHelpDesk * nodeHelpDesk;
|
SearchEngineDataT _queryData;
|
||||||
std::vector<string> * _names;
|
|
||||||
static HeapPtr _forwardHeap;
|
inline double absDouble(double input) { if(input < 0) return input*(-1); else return input;}
|
||||||
static HeapPtr _backwardHeap;
|
|
||||||
inline double absDouble(double input) { if(input < 0) return input*(-1); else return input;}
|
|
||||||
public:
|
public:
|
||||||
SearchEngine(GraphT * g, NodeInformationHelpDesk * nh, std::vector<string> * n = new std::vector<string>()) : _graph(g), nodeHelpDesk(nh), _names(n) {}
|
ShortestPathRouting<SearchEngineDataT> shortestPath;
|
||||||
~SearchEngine() {}
|
AlternativeRouting<SearchEngineDataT> alternativePaths;
|
||||||
|
|
||||||
inline const void GetCoordinatesForNodeID(NodeID id, _Coordinate& result) const {
|
SearchEngine(GraphT * g, NodeInformationHelpDesk * nh, std::vector<string> & n) :
|
||||||
result.lat = nodeHelpDesk->getLatitudeOfNode(id);
|
_queryData(g, nh, n),
|
||||||
result.lon = nodeHelpDesk->getLongitudeOfNode(id);
|
shortestPath(_queryData),
|
||||||
}
|
alternativePaths(_queryData)
|
||||||
|
{}
|
||||||
|
~SearchEngine() {}
|
||||||
|
|
||||||
inline void InitializeThreadLocalStorageIfNecessary() {
|
inline void GetCoordinatesForNodeID(NodeID id, _Coordinate& result) const {
|
||||||
if(!_forwardHeap.get())
|
result.lat = _queryData.nodeHelpDesk->getLatitudeOfNode(id);
|
||||||
_forwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData >(nodeHelpDesk->getNumberOfNodes()));
|
result.lon = _queryData.nodeHelpDesk->getLongitudeOfNode(id);
|
||||||
else
|
}
|
||||||
_forwardHeap->Clear();
|
|
||||||
|
|
||||||
if(!_backwardHeap.get())
|
inline void FindRoutingStarts(const _Coordinate & start, const _Coordinate & target, PhantomNodes & routingStarts) const {
|
||||||
_backwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData >(nodeHelpDesk->getNumberOfNodes()));
|
_queryData.nodeHelpDesk->FindRoutingStarts(start, target, routingStarts);
|
||||||
else
|
}
|
||||||
_backwardHeap->Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
int ComputeRoute(PhantomNodes & phantomNodes, std::vector<_PathData> & path) {
|
inline void FindPhantomNodeForCoordinate(const _Coordinate & location, PhantomNode & result, unsigned zoomLevel) const {
|
||||||
int _upperbound = INT_MAX;
|
_queryData.nodeHelpDesk->FindPhantomNodeForCoordinate(location, result, zoomLevel);
|
||||||
if(!phantomNodes.AtLeastOnePhantomNodeIsUINTMAX())
|
}
|
||||||
return _upperbound;
|
|
||||||
|
|
||||||
InitializeThreadLocalStorageIfNecessary();
|
inline NodeID GetNameIDForOriginDestinationNodeID(const NodeID s, const NodeID t) const {
|
||||||
NodeID middle = ( NodeID ) UINT_MAX;
|
if(s == t)
|
||||||
bool stOnSameEdge = false;
|
return 0;
|
||||||
//Handling the special case that origin and destination are on same edge and that the order is correct.
|
|
||||||
if(phantomNodes.PhantomsAreOnSameNodeBasedEdge()){
|
|
||||||
if(phantomNodes.startPhantom.isBidirected() && phantomNodes.targetPhantom.isBidirected()) {
|
|
||||||
int weight = std::abs(phantomNodes.startPhantom.weight1 - phantomNodes.targetPhantom.weight1);
|
|
||||||
return weight;
|
|
||||||
} else if(phantomNodes.startPhantom.weight1 <= phantomNodes.targetPhantom.weight1){
|
|
||||||
int weight = std::abs(phantomNodes.startPhantom.weight1 - phantomNodes.targetPhantom.weight1);
|
|
||||||
return weight;
|
|
||||||
} else {
|
|
||||||
stOnSameEdge = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//insert start and/or target node of start edge
|
EdgeID e = _queryData.graph->FindEdge(s, t);
|
||||||
_forwardHeap->Insert(phantomNodes.startPhantom.edgeBasedNode, -phantomNodes.startPhantom.weight1, phantomNodes.startPhantom.edgeBasedNode);
|
if(e == UINT_MAX)
|
||||||
if(phantomNodes.startPhantom.isBidirected() ) {
|
e = _queryData.graph->FindEdge( t, s );
|
||||||
_forwardHeap->Insert(phantomNodes.startPhantom.edgeBasedNode+1, -phantomNodes.startPhantom.weight2, phantomNodes.startPhantom.edgeBasedNode+1);
|
if(UINT_MAX == e) {
|
||||||
}
|
return 0;
|
||||||
//insert start and/or target node of target edge id
|
}
|
||||||
_backwardHeap->Insert(phantomNodes.targetPhantom.edgeBasedNode, -phantomNodes.targetPhantom.weight1, phantomNodes.targetPhantom.edgeBasedNode);
|
assert(e != UINT_MAX);
|
||||||
if(phantomNodes.targetPhantom.isBidirected() ) {
|
const EdgeData ed = _queryData.graph->GetEdgeData(e);
|
||||||
_backwardHeap->Insert(phantomNodes.targetPhantom.edgeBasedNode+1, -phantomNodes.targetPhantom.weight2, phantomNodes.targetPhantom.edgeBasedNode+1);
|
return ed.via;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(_forwardHeap->Size() + _backwardHeap->Size() > 0){
|
inline std::string GetEscapedNameForNameID(const unsigned nameID) const {
|
||||||
if(_forwardHeap->Size() > 0){
|
return ((nameID >= _queryData.names.size() || nameID == 0) ? std::string("") : HTMLEntitize(_queryData.names.at(nameID)));
|
||||||
_RoutingStep(_forwardHeap, _backwardHeap, true, &middle, &_upperbound, stOnSameEdge);
|
}
|
||||||
}
|
|
||||||
if(_backwardHeap->Size() > 0){
|
|
||||||
_RoutingStep(_backwardHeap, _forwardHeap, false, &middle, &_upperbound, stOnSameEdge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( _upperbound == INT_MAX ) {
|
|
||||||
return _upperbound;
|
|
||||||
}
|
|
||||||
NodeID pathNode = middle;
|
|
||||||
deque<NodeID> packedPath;
|
|
||||||
while(phantomNodes.startPhantom.edgeBasedNode != pathNode && (!phantomNodes.startPhantom.isBidirected() || phantomNodes.startPhantom.edgeBasedNode+1 != pathNode) ) {
|
|
||||||
pathNode = _forwardHeap->GetData(pathNode).parent;
|
|
||||||
packedPath.push_front(pathNode);
|
|
||||||
}
|
|
||||||
packedPath.push_back(middle);
|
|
||||||
pathNode = middle;
|
|
||||||
while(phantomNodes.targetPhantom.edgeBasedNode != pathNode && (!phantomNodes.targetPhantom.isBidirected() || phantomNodes.targetPhantom.edgeBasedNode+1 != pathNode)) {
|
|
||||||
pathNode = _backwardHeap->GetData(pathNode).parent;
|
|
||||||
packedPath.push_back(pathNode);
|
|
||||||
}
|
|
||||||
for(deque<NodeID>::size_type i = 0;i < packedPath.size() - 1;i++){
|
|
||||||
_UnpackEdge(packedPath[i], packedPath[i + 1], path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _upperbound;
|
inline std::string GetEscapedNameForEdgeBasedEdgeID(const unsigned edgeID) const {
|
||||||
}
|
const unsigned nameID = _queryData.graph->GetEdgeData(edgeID).nameID1;
|
||||||
|
return GetEscapedNameForNameID(nameID);
|
||||||
|
}
|
||||||
|
|
||||||
inline bool FindRoutingStarts(const _Coordinate & start, const _Coordinate & target, PhantomNodes & routingStarts) const {
|
|
||||||
nodeHelpDesk->FindRoutingStarts(start, target, routingStarts);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool FindPhantomNodeForCoordinate(const _Coordinate & location, PhantomNode & result) const {
|
|
||||||
return nodeHelpDesk->FindPhantomNodeForCoordinate(location, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline NodeID GetNameIDForOriginDestinationNodeID(NodeID s, NodeID t) const {
|
|
||||||
if(s == t)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
EdgeID e = _graph->FindEdge(s, t);
|
|
||||||
if(e == UINT_MAX)
|
|
||||||
e = _graph->FindEdge( t, s );
|
|
||||||
if(UINT_MAX == e) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
assert(e != UINT_MAX);
|
|
||||||
const EdgeData ed = _graph->GetEdgeData(e);
|
|
||||||
return ed.via;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string GetEscapedNameForNameID(const NodeID nameID) const {
|
|
||||||
return ((nameID >= _names->size() || nameID == 0) ? std::string("") : HTMLEntitize(_names->at(nameID)));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string GetEscapedNameForEdgeBasedEdgeID(const unsigned edgeID) const {
|
|
||||||
|
|
||||||
const unsigned nameID = _graph->GetEdgeData(edgeID).nameID1;
|
|
||||||
return GetEscapedNameForNameID(nameID);
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
inline void _RoutingStep(HeapPtr & _forwardHeap, HeapPtr & _backwardHeap, const bool & forwardDirection, NodeID *middle, int *_upperbound, const bool stOnSameEdge) const {
|
|
||||||
const NodeID node = _forwardHeap->DeleteMin();
|
|
||||||
const int distance = _forwardHeap->GetKey(node);
|
|
||||||
if(_backwardHeap->WasInserted(node) && (!stOnSameEdge || distance > 0) ){
|
|
||||||
const int newDistance = _backwardHeap->GetKey(node) + distance;
|
|
||||||
if(newDistance < *_upperbound){
|
|
||||||
*middle = node;
|
|
||||||
*_upperbound = newDistance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(distance > *_upperbound){
|
|
||||||
_forwardHeap->DeleteAll();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( typename GraphT::EdgeIterator edge = _graph->BeginEdges( node ); edge < _graph->EndEdges(node); edge++ ) {
|
|
||||||
const EdgeData & data = _graph->GetEdgeData(edge);
|
|
||||||
bool backwardDirectionFlag = (!forwardDirection) ? data.forward : data.backward;
|
|
||||||
if(backwardDirectionFlag) {
|
|
||||||
const NodeID to = _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 GraphT::EdgeIterator edge = _graph->BeginEdges( node ); edge < _graph->EndEdges(node); edge++ ) {
|
|
||||||
const EdgeData & data = _graph->GetEdgeData(edge);
|
|
||||||
bool forwardDirectionFlag = (forwardDirection ? data.forward : data.backward );
|
|
||||||
if(forwardDirectionFlag) {
|
|
||||||
|
|
||||||
const NodeID to = _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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool _UnpackEdge(const NodeID source, const NodeID target, std::vector<_PathData> & path) const {
|
|
||||||
assert(source != target);
|
|
||||||
//find edge first.
|
|
||||||
typename GraphT::EdgeIterator smallestEdge = SPECIAL_EDGEID;
|
|
||||||
int smallestWeight = INT_MAX;
|
|
||||||
for(typename GraphT::EdgeIterator eit = _graph->BeginEdges(source);eit < _graph->EndEdges(source);eit++){
|
|
||||||
const int weight = _graph->GetEdgeData(eit).distance;
|
|
||||||
if(_graph->GetTarget(eit) == target && weight < smallestWeight && _graph->GetEdgeData(eit).forward){
|
|
||||||
smallestEdge = eit;
|
|
||||||
smallestWeight = weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(smallestEdge == SPECIAL_EDGEID){
|
|
||||||
for(typename GraphT::EdgeIterator eit = _graph->BeginEdges(target);eit < _graph->EndEdges(target);eit++){
|
|
||||||
const int weight = _graph->GetEdgeData(eit).distance;
|
|
||||||
if(_graph->GetTarget(eit) == source && weight < smallestWeight && _graph->GetEdgeData(eit).backward){
|
|
||||||
smallestEdge = eit;
|
|
||||||
smallestWeight = weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(smallestWeight != INT_MAX);
|
|
||||||
|
|
||||||
const EdgeData& ed = _graph->GetEdgeData(smallestEdge);
|
|
||||||
if(ed.shortcut) {//unpack
|
|
||||||
const NodeID middle = ed.via;
|
|
||||||
_UnpackEdge(source, middle, path);
|
|
||||||
_UnpackEdge(middle, target, path);
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
assert(!ed.shortcut);
|
|
||||||
path.push_back(_PathData(ed.via, ed.nameID1, ed.turnInstruction, ed.distance) );
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
template<class EdgeData, class GraphT> HeapPtr SearchEngine<EdgeData, GraphT>::_forwardHeap;
|
|
||||||
template<class EdgeData, class GraphT> HeapPtr SearchEngine<EdgeData, GraphT>::_backwardHeap;
|
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_ */
|
#endif /* SEARCHENGINE_H_ */
|
||||||
|
|||||||
@@ -23,17 +23,20 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
|
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
|
||||||
|
#include "TurnInstructions.h"
|
||||||
|
|
||||||
struct SegmentInformation {
|
struct SegmentInformation {
|
||||||
_Coordinate location;
|
_Coordinate location;
|
||||||
NodeID nameID;
|
NodeID nameID;
|
||||||
unsigned length;
|
double length;
|
||||||
unsigned duration;
|
unsigned duration;
|
||||||
short turnInstruction;
|
double bearing;
|
||||||
|
TurnInstruction turnInstruction;
|
||||||
bool necessary;
|
bool necessary;
|
||||||
SegmentInformation(const _Coordinate & loc, const NodeID nam, const unsigned len, const unsigned dur, const short tInstr, const bool nec) :
|
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), turnInstruction(tInstr), necessary(nec) {}
|
location(loc), nameID(nam), length(len), duration(dur), bearing(0.), turnInstruction(tInstr), necessary(nec) {}
|
||||||
SegmentInformation(const _Coordinate & loc, const NodeID nam, const unsigned len, const unsigned dur, const short tInstr) :
|
SegmentInformation(const _Coordinate & loc, const NodeID nam, const double len, const unsigned dur, const TurnInstruction tInstr) :
|
||||||
location(loc), nameID(nam), length(len), duration(dur), turnInstruction(tInstr), necessary(tInstr != 0) {}
|
location(loc), nameID(nam), length(len), duration(dur), bearing(0.), turnInstruction(tInstr), necessary(tInstr != 0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* SEGMENTINFORMATION_H_ */
|
#endif /* SEGMENTINFORMATION_H_ */
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
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_ */
|
||||||
@@ -22,11 +22,7 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
#define STATICGRAPH_H_INCLUDED
|
#define STATICGRAPH_H_INCLUDED
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#ifdef _GLIBCXX_PARALLEL
|
|
||||||
#include <parallel/algorithm>
|
|
||||||
#else
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "../typedefs.h"
|
#include "../typedefs.h"
|
||||||
#include "ImportEdge.h"
|
#include "ImportEdge.h"
|
||||||
@@ -49,12 +45,18 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _StrNode {
|
||||||
|
//index of the first edge
|
||||||
|
EdgeIterator firstEdge;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _StrEdge {
|
||||||
|
NodeID target;
|
||||||
|
EdgeDataT data;
|
||||||
|
};
|
||||||
|
|
||||||
StaticGraph( const int nodes, std::vector< InputEdge > &graph ) {
|
StaticGraph( const int nodes, std::vector< InputEdge > &graph ) {
|
||||||
#ifdef _GLIBCXX_PARALLEL
|
|
||||||
__gnu_parallel::sort( graph.begin(), graph.end() );
|
|
||||||
#else
|
|
||||||
std::sort( graph.begin(), graph.end() );
|
std::sort( graph.begin(), graph.end() );
|
||||||
#endif
|
|
||||||
_numNodes = nodes;
|
_numNodes = nodes;
|
||||||
_numEdges = ( EdgeIterator ) graph.size();
|
_numEdges = ( EdgeIterator ) graph.size();
|
||||||
_nodes.resize( _numNodes + 1);
|
_nodes.resize( _numNodes + 1);
|
||||||
@@ -79,6 +81,40 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
unsigned GetNumberOfNodes() const {
|
||||||
return _numNodes;
|
return _numNodes;
|
||||||
}
|
}
|
||||||
@@ -142,16 +178,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct _StrNode {
|
|
||||||
//index of the first edge
|
|
||||||
EdgeIterator firstEdge;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _StrEdge {
|
|
||||||
NodeID target;
|
|
||||||
EdgeDataT data;
|
|
||||||
};
|
|
||||||
|
|
||||||
NodeIterator _numNodes;
|
NodeIterator _numNodes;
|
||||||
EdgeIterator _numEdges;
|
EdgeIterator _numEdges;
|
||||||
|
|
||||||
|
|||||||
@@ -23,12 +23,9 @@ KD Tree coded by Christian Vetter, Monav Project
|
|||||||
#ifndef STATICKDTREE_H_INCLUDED
|
#ifndef STATICKDTREE_H_INCLUDED
|
||||||
#define STATICKDTREE_H_INCLUDED
|
#define STATICKDTREE_H_INCLUDED
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#ifdef _GLIBCXX_PARALLEL
|
|
||||||
#include <parallel/algorithm>
|
|
||||||
#else
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#endif
|
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
@@ -119,11 +116,7 @@ public:
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
Iterator middle = tree.left + ( tree.right - tree.left ) / 2;
|
Iterator middle = tree.left + ( tree.right - tree.left ) / 2;
|
||||||
#ifdef _GLIBCXX_PARALLEL
|
|
||||||
__gnu_parallel::nth_element( kdtree + tree.left, kdtree + middle, kdtree + tree.right, Less( tree.dimension ) );
|
|
||||||
#else
|
|
||||||
std::nth_element( kdtree + tree.left, kdtree + middle, kdtree + tree.right, Less( tree.dimension ) );
|
std::nth_element( kdtree + tree.left, kdtree + middle, kdtree + tree.right, Less( tree.dimension ) );
|
||||||
#endif
|
|
||||||
s.push( Tree( tree.left, middle, ( tree.dimension + 1 ) % k ) );
|
s.push( Tree( tree.left, middle, ( tree.dimension + 1 ) % k ) );
|
||||||
s.push( Tree( middle + 1, tree.right, ( tree.dimension + 1 ) % k ) );
|
s.push( Tree( middle + 1, tree.right, ( tree.dimension + 1 ) % k ) );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,58 +23,70 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
typedef unsigned char TurnInstruction;
|
||||||
|
|
||||||
//This is a hack until c++0x is available enough to use scoped enums
|
//This is a hack until c++0x is available enough to use scoped enums
|
||||||
struct TurnInstructionsClass {
|
struct TurnInstructionsClass {
|
||||||
|
|
||||||
const static short NoTurn = 0; //Give no instruction at all
|
const static TurnInstruction NoTurn = 0; //Give no instruction at all
|
||||||
const static short GoStraight = 1; //Tell user to go straight!
|
const static TurnInstruction GoStraight = 1; //Tell user to go straight!
|
||||||
const static short TurnSlightRight = 2;
|
const static TurnInstruction TurnSlightRight = 2;
|
||||||
const static short TurnRight = 3;
|
const static TurnInstruction TurnRight = 3;
|
||||||
const static short TurnSharpRight = 4;
|
const static TurnInstruction TurnSharpRight = 4;
|
||||||
const static short UTurn = 5;
|
const static TurnInstruction UTurn = 5;
|
||||||
const static short TurnSharpLeft = 6;
|
const static TurnInstruction TurnSharpLeft = 6;
|
||||||
const static short TurnLeft = 7;
|
const static TurnInstruction TurnLeft = 7;
|
||||||
const static short TurnSlightLeft = 8;
|
const static TurnInstruction TurnSlightLeft = 8;
|
||||||
const static short ReachViaPoint = 9;
|
const static TurnInstruction ReachViaPoint = 9;
|
||||||
const static short HeadOn = 10;
|
const static TurnInstruction HeadOn = 10;
|
||||||
const static short EnterRoundAbout = 11;
|
const static TurnInstruction EnterRoundAbout = 11;
|
||||||
const static short LeaveRoundAbout = 12;
|
const static TurnInstruction LeaveRoundAbout = 12;
|
||||||
const static short StayOnRoundAbout = 13;
|
const static TurnInstruction StayOnRoundAbout = 13;
|
||||||
|
const static TurnInstruction StartAtEndOfStreet = 14;
|
||||||
|
const static TurnInstruction ReachedYourDestination = 15;
|
||||||
|
|
||||||
std::string TurnStrings[14];
|
const static TurnInstruction AccessRestrictionFlag = 128;
|
||||||
std::string Ordinals[11];
|
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.
|
//This is a hack until c++0x is available enough to use initializer lists.
|
||||||
TurnInstructionsClass(){
|
// TurnInstructionsClass(){
|
||||||
TurnStrings [0] = "";
|
// TurnStrings [0] = "";
|
||||||
TurnStrings [1] = "Continue";
|
// TurnStrings [1] = "Continue";
|
||||||
TurnStrings [2] = "Turn slight right";
|
// TurnStrings [2] = "Turn slight right";
|
||||||
TurnStrings [3] = "Turn right";
|
// TurnStrings [3] = "Turn right";
|
||||||
TurnStrings [4] = "Turn sharp right";
|
// TurnStrings [4] = "Turn sharp right";
|
||||||
TurnStrings [5] = "U-Turn";
|
// TurnStrings [5] = "U-Turn";
|
||||||
TurnStrings [6] = "Turn sharp left";
|
// TurnStrings [6] = "Turn sharp left";
|
||||||
TurnStrings [7] = "Turn left";
|
// TurnStrings [7] = "Turn left";
|
||||||
TurnStrings [8] = "Turn slight left";
|
// TurnStrings [8] = "Turn slight left";
|
||||||
TurnStrings [9] = "Reach via point";
|
// TurnStrings [9] = "Reach via point";
|
||||||
TurnStrings[10] = "Head";
|
// TurnStrings[10] = "Head";
|
||||||
TurnStrings[11] = "Enter round-about";
|
// TurnStrings[11] = "Enter roundabout";
|
||||||
TurnStrings[12] = "Leave round-about";
|
// TurnStrings[12] = "Leave roundabout";
|
||||||
TurnStrings[13] = "Stay on round-about";
|
// 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";
|
||||||
|
// };
|
||||||
|
|
||||||
Ordinals[0] = "zeroth";
|
static inline TurnInstruction GetTurnDirectionOfInstruction( const double angle ) {
|
||||||
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";
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline double GetTurnDirectionOfInstruction( const double angle ) {
|
|
||||||
if(angle >= 23 && angle < 67) {
|
if(angle >= 23 && angle < 67) {
|
||||||
return TurnSharpRight;
|
return TurnSharpRight;
|
||||||
}
|
}
|
||||||
@@ -96,7 +108,7 @@ struct TurnInstructionsClass {
|
|||||||
if (angle >= 292 && angle < 336) {
|
if (angle >= 292 && angle < 336) {
|
||||||
return TurnSharpLeft;
|
return TurnSharpLeft;
|
||||||
}
|
}
|
||||||
return 5;
|
return UTurn;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool TurnIsNecessary ( const short turnInstruction ) {
|
static inline bool TurnIsNecessary ( const short turnInstruction ) {
|
||||||
@@ -105,48 +117,6 @@ struct TurnInstructionsClass {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// static inline void getDirectionOfInstruction(double angle, DirectionOfInstruction & dirInst) {
|
|
||||||
// if(angle >= 23 && angle < 67) {
|
|
||||||
// dirInst.direction = "southeast";
|
|
||||||
// dirInst.shortDirection = "SE";
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// if(angle >= 67 && angle < 113) {
|
|
||||||
// dirInst.direction = "south";
|
|
||||||
// dirInst.shortDirection = "S";
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// if(angle >= 113 && angle < 158) {
|
|
||||||
// dirInst.direction = "southwest";
|
|
||||||
// dirInst.shortDirection = "SW";
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// if(angle >= 158 && angle < 202) {
|
|
||||||
// dirInst.direction = "west";
|
|
||||||
// dirInst.shortDirection = "W";
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// if(angle >= 202 && angle < 248) {
|
|
||||||
// dirInst.direction = "northwest";
|
|
||||||
// dirInst.shortDirection = "NW";
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// if(angle >= 248 && angle < 292) {
|
|
||||||
// dirInst.direction = "north";
|
|
||||||
// dirInst.shortDirection = "N";
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// if(angle >= 292 && angle < 336) {
|
|
||||||
// dirInst.direction = "northeast";
|
|
||||||
// dirInst.shortDirection = "NE";
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// dirInst.direction = "East";
|
|
||||||
// dirInst.shortDirection = "E";
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static TurnInstructionsClass TurnInstructions;
|
static TurnInstructionsClass TurnInstructions;
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
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_ */
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
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,53 +0,0 @@
|
|||||||
/** Copyright (c) 2010 Scott A. Crosby. <scott@sacrosby.com>
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Lesser 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
option java_package = "crosby.binary";
|
|
||||||
package OSMPBF;
|
|
||||||
|
|
||||||
//protoc --java_out=../.. fileformat.proto
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// STORAGE LAYER: Storing primitives.
|
|
||||||
//
|
|
||||||
|
|
||||||
message Blob {
|
|
||||||
optional bytes raw = 1; // No compression
|
|
||||||
optional int32 raw_size = 2; // When compressed, the uncompressed size
|
|
||||||
|
|
||||||
// Possible compressed versions of the data.
|
|
||||||
optional bytes zlib_data = 3;
|
|
||||||
|
|
||||||
// PROPOSED feature for LZMA compressed data. SUPPORT IS NOT REQUIRED.
|
|
||||||
optional bytes lzma_data = 4;
|
|
||||||
|
|
||||||
// Formerly used for bzip2 compressed data. Depreciated in 2010.
|
|
||||||
optional bytes OBSOLETE_bzip2_data = 5 [deprecated=true]; // Don't reuse this tag number.
|
|
||||||
}
|
|
||||||
|
|
||||||
/* A file contains an sequence of fileblock headers, each prefixed by
|
|
||||||
their length in network byte order, followed by a data block
|
|
||||||
containing the actual data. types staring with a "_" are reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
message BlobHeader {
|
|
||||||
required string type = 1;
|
|
||||||
optional bytes indexdata = 2;
|
|
||||||
required int32 datasize = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,226 +0,0 @@
|
|||||||
/** Copyright (c) 2010 Scott A. Crosby. <scott@sacrosby.com>
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Lesser 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
option java_package = "crosby.binary";
|
|
||||||
package OSMPBF;
|
|
||||||
|
|
||||||
/* OSM Binary file format
|
|
||||||
|
|
||||||
This is the master schema file of the OSM binary file format. This
|
|
||||||
file is designed to support limited random-access and future
|
|
||||||
extendability.
|
|
||||||
|
|
||||||
A binary OSM file consists of a sequence of FileBlocks (please see
|
|
||||||
fileformat.proto). The first fileblock contains a serialized instance
|
|
||||||
of HeaderBlock, followed by a sequence of PrimitiveBlock blocks that
|
|
||||||
contain the primitives.
|
|
||||||
|
|
||||||
Each primitiveblock is designed to be independently parsable. It
|
|
||||||
contains a string table storing all strings in that block (keys and
|
|
||||||
values in tags, roles in relations, usernames, etc.) as well as
|
|
||||||
metadata containing the precision of coordinates or timestamps in that
|
|
||||||
block.
|
|
||||||
|
|
||||||
A primitiveblock contains a sequence of primitive groups, each
|
|
||||||
containing primitives of the same type (nodes, densenodes, ways,
|
|
||||||
relations). Coordinates are stored in signed 64-bit integers. Lat&lon
|
|
||||||
are measured in units <granularity> nanodegrees. The default of
|
|
||||||
granularity of 100 nanodegrees corresponds to about 1cm on the ground,
|
|
||||||
and a full lat or lon fits into 32 bits.
|
|
||||||
|
|
||||||
Converting an integer to a lattitude or longitude uses the formula:
|
|
||||||
$OUT = IN * granularity / 10**9$. Many encoding schemes use delta
|
|
||||||
coding when representing nodes and relations.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/* Contains the file header. */
|
|
||||||
|
|
||||||
message HeaderBlock {
|
|
||||||
optional HeaderBBox bbox = 1;
|
|
||||||
/* Additional tags to aid in parsing this dataset */
|
|
||||||
repeated string required_features = 4;
|
|
||||||
repeated string optional_features = 5;
|
|
||||||
|
|
||||||
optional string writingprogram = 16;
|
|
||||||
optional string source = 17; // From the bbox field.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** The bounding box field in the OSM header. BBOX, as used in the OSM
|
|
||||||
header. Units are always in nanodegrees -- they do not obey
|
|
||||||
granularity rules. */
|
|
||||||
|
|
||||||
message HeaderBBox {
|
|
||||||
required sint64 left = 1;
|
|
||||||
required sint64 right = 2;
|
|
||||||
required sint64 top = 3;
|
|
||||||
required sint64 bottom = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
message PrimitiveBlock {
|
|
||||||
required StringTable stringtable = 1;
|
|
||||||
repeated PrimitiveGroup primitivegroup = 2;
|
|
||||||
|
|
||||||
// Granularity, units of nanodegrees, used to store coordinates in this block
|
|
||||||
optional int32 granularity = 17 [default=100];
|
|
||||||
// Offset value between the output coordinates coordinates and the granularity grid in unites of nanodegrees.
|
|
||||||
optional int64 lat_offset = 19 [default=0];
|
|
||||||
optional int64 lon_offset = 20 [default=0];
|
|
||||||
|
|
||||||
// Granularity of dates, normally represented in units of milliseconds since the 1970 epoch.
|
|
||||||
optional int32 date_granularity = 18 [default=1000];
|
|
||||||
|
|
||||||
|
|
||||||
// Proposed extension:
|
|
||||||
//optional BBox bbox = XX;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Group of OSMPrimitives. All primitives in a group must be the same type.
|
|
||||||
message PrimitiveGroup {
|
|
||||||
repeated Node nodes = 1;
|
|
||||||
optional DenseNodes dense = 2;
|
|
||||||
repeated Way ways = 3;
|
|
||||||
repeated Relation relations = 4;
|
|
||||||
repeated ChangeSet changesets = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** String table, contains the common strings in each block.
|
|
||||||
|
|
||||||
Note that we reserve index '0' as a delimiter, so the entry at that
|
|
||||||
index in the table is ALWAYS blank and unused.
|
|
||||||
|
|
||||||
*/
|
|
||||||
message StringTable {
|
|
||||||
repeated bytes s = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Optional metadata that may be included into each primitive. */
|
|
||||||
message Info {
|
|
||||||
optional int32 version = 1 [default = -1];
|
|
||||||
optional int64 timestamp = 2;
|
|
||||||
optional int64 changeset = 3;
|
|
||||||
optional int32 uid = 4;
|
|
||||||
optional uint32 user_sid = 5; // String IDs
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Optional metadata that may be included into each primitive. Special dense format used in DenseNodes. */
|
|
||||||
message DenseInfo {
|
|
||||||
repeated int32 version = 1 [packed = true];
|
|
||||||
repeated sint64 timestamp = 2 [packed = true]; // DELTA coded
|
|
||||||
repeated sint64 changeset = 3 [packed = true]; // DELTA coded
|
|
||||||
repeated sint32 uid = 4 [packed = true]; // DELTA coded
|
|
||||||
repeated sint32 user_sid = 5 [packed = true]; // String IDs for usernames. DELTA coded
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// THIS IS STUB DESIGN FOR CHANGESETS. NOT USED RIGHT NOW.
|
|
||||||
// TODO: REMOVE THIS?
|
|
||||||
message ChangeSet {
|
|
||||||
required int64 id = 1;
|
|
||||||
//
|
|
||||||
// // Parallel arrays.
|
|
||||||
// repeated uint32 keys = 2 [packed = true]; // String IDs.
|
|
||||||
// repeated uint32 vals = 3 [packed = true]; // String IDs.
|
|
||||||
//
|
|
||||||
// optional Info info = 4;
|
|
||||||
|
|
||||||
// optional int64 created_at = 8;
|
|
||||||
// optional int64 closetime_delta = 9;
|
|
||||||
// optional bool open = 10;
|
|
||||||
// optional HeaderBBox bbox = 11;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
message Node {
|
|
||||||
required sint64 id = 1;
|
|
||||||
// Parallel arrays.
|
|
||||||
repeated uint32 keys = 2 [packed = true]; // String IDs.
|
|
||||||
repeated uint32 vals = 3 [packed = true]; // String IDs.
|
|
||||||
|
|
||||||
optional Info info = 4; // May be omitted in omitmeta
|
|
||||||
|
|
||||||
required sint64 lat = 8;
|
|
||||||
required sint64 lon = 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Used to densly represent a sequence of nodes that do not have any tags.
|
|
||||||
|
|
||||||
We represent these nodes columnwise as five columns: ID's, lats, and
|
|
||||||
lons, all delta coded. When metadata is not omitted,
|
|
||||||
|
|
||||||
We encode keys & vals for all nodes as a single array of integers
|
|
||||||
containing key-stringid and val-stringid, using a stringid of 0 as a
|
|
||||||
delimiter between nodes.
|
|
||||||
|
|
||||||
( (<keyid> <valid>)* '0' )*
|
|
||||||
*/
|
|
||||||
|
|
||||||
message DenseNodes {
|
|
||||||
repeated sint64 id = 1 [packed = true]; // DELTA coded
|
|
||||||
|
|
||||||
//repeated Info info = 4;
|
|
||||||
optional DenseInfo denseinfo = 5;
|
|
||||||
|
|
||||||
repeated sint64 lat = 8 [packed = true]; // DELTA coded
|
|
||||||
repeated sint64 lon = 9 [packed = true]; // DELTA coded
|
|
||||||
|
|
||||||
// Special packing of keys and vals into one array. May be empty if all nodes in this block are tagless.
|
|
||||||
repeated int32 keys_vals = 10 [packed = true];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
message Way {
|
|
||||||
required int64 id = 1;
|
|
||||||
// Parallel arrays.
|
|
||||||
repeated uint32 keys = 2 [packed = true];
|
|
||||||
repeated uint32 vals = 3 [packed = true];
|
|
||||||
|
|
||||||
optional Info info = 4;
|
|
||||||
|
|
||||||
repeated sint64 refs = 8 [packed = true]; // DELTA coded
|
|
||||||
}
|
|
||||||
|
|
||||||
message Relation {
|
|
||||||
enum MemberType {
|
|
||||||
NODE = 0;
|
|
||||||
WAY = 1;
|
|
||||||
RELATION = 2;
|
|
||||||
}
|
|
||||||
required int64 id = 1;
|
|
||||||
|
|
||||||
// Parallel arrays.
|
|
||||||
repeated uint32 keys = 2 [packed = true];
|
|
||||||
repeated uint32 vals = 3 [packed = true];
|
|
||||||
|
|
||||||
optional Info info = 4;
|
|
||||||
|
|
||||||
// Parallel arrays
|
|
||||||
repeated int32 roles_sid = 8 [packed = true];
|
|
||||||
repeated sint64 memids = 9 [packed = true]; // DELTA encoded
|
|
||||||
repeated MemberType types = 10 [packed = true];
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -28,32 +28,14 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "../typedefs.h"
|
#include "../typedefs.h"
|
||||||
#include "../DataStructures/ExtractorStructs.h"
|
#include "../DataStructures/PhantomNodes.h"
|
||||||
#include "../DataStructures/HashTable.h"
|
#include "../DataStructures/HashTable.h"
|
||||||
#include "../Util/StringUtil.h"
|
#include "../Util/StringUtil.h"
|
||||||
|
|
||||||
#include "../Plugins/RawRouteData.h"
|
#include "../Plugins/RawRouteData.h"
|
||||||
|
|
||||||
struct _RouteSummary {
|
|
||||||
std::string lengthString;
|
|
||||||
std::string durationString;
|
|
||||||
std::string startName;
|
|
||||||
std::string destName;
|
|
||||||
_RouteSummary() : lengthString("0"), durationString("0"), startName("unknown street"), destName("unknown street") {}
|
|
||||||
void BuildDurationAndLengthStrings(unsigned distance, unsigned time) {
|
|
||||||
//compute distance/duration for route summary
|
|
||||||
std::ostringstream s;
|
|
||||||
s << 10*(round(distance/10.));
|
|
||||||
lengthString = s.str();
|
|
||||||
int travelTime = time/10 + 1;
|
|
||||||
s.str("");
|
|
||||||
s << travelTime;
|
|
||||||
durationString = s.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _DescriptorConfig {
|
struct _DescriptorConfig {
|
||||||
_DescriptorConfig() : instructions(true), geometry(true), encodeGeometry(false), z(18) {}
|
_DescriptorConfig() : instructions(true), geometry(true), encodeGeometry(true), z(18) {}
|
||||||
bool instructions;
|
bool instructions;
|
||||||
bool geometry;
|
bool geometry;
|
||||||
bool encodeGeometry;
|
bool encodeGeometry;
|
||||||
@@ -66,7 +48,7 @@ public:
|
|||||||
BaseDescriptor() { }
|
BaseDescriptor() { }
|
||||||
//Maybe someone can explain the pure virtual destructor thing to me (dennis)
|
//Maybe someone can explain the pure virtual destructor thing to me (dennis)
|
||||||
virtual ~BaseDescriptor() { }
|
virtual ~BaseDescriptor() { }
|
||||||
virtual void Run(http::Reply & reply, RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine, unsigned distance) = 0;
|
virtual void Run(http::Reply & reply, const RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine) = 0;
|
||||||
virtual void SetConfig(const _DescriptorConfig & config) = 0;
|
virtual void SetConfig(const _DescriptorConfig & config) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,12 +20,33 @@
|
|||||||
|
|
||||||
#include "DescriptionFactory.h"
|
#include "DescriptionFactory.h"
|
||||||
|
|
||||||
DescriptionFactory::DescriptionFactory() { }
|
DescriptionFactory::DescriptionFactory() : entireLength(0) { }
|
||||||
|
|
||||||
DescriptionFactory::~DescriptionFactory() { }
|
DescriptionFactory::~DescriptionFactory() { }
|
||||||
|
|
||||||
double DescriptionFactory::GetAngleBetweenCoordinates() const {
|
inline double DescriptionFactory::DegreeToRadian(const double degree) const {
|
||||||
return 0.;//GetAngleBetweenTwoEdges(previousCoordinate, currentCoordinate, nextCoordinate);
|
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) {
|
void DescriptionFactory::SetStartSegment(const PhantomNode & _startPhantom) {
|
||||||
@@ -39,7 +60,11 @@ void DescriptionFactory::SetEndSegment(const PhantomNode & _targetPhantom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DescriptionFactory::AppendSegment(const _Coordinate & coordinate, const _PathData & data ) {
|
void DescriptionFactory::AppendSegment(const _Coordinate & coordinate, const _PathData & data ) {
|
||||||
pathDescription.push_back(SegmentInformation(coordinate, data.nameID, 0, data.durationOfSegment, data.turnInstruction) );
|
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) {
|
void DescriptionFactory::AppendEncodedPolylineString(std::string & output, bool isEncoded) {
|
||||||
@@ -57,28 +82,77 @@ void DescriptionFactory::AppendUnencodedPolylineString(std::string &output) {
|
|||||||
pc.printUnencodedString(pathDescription, output);
|
pc.printUnencodedString(pathDescription, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned DescriptionFactory::Run(const unsigned zoomLevel) {
|
void DescriptionFactory::Run(const SearchEngineT &sEngine, const unsigned zoomLevel) {
|
||||||
if(0 == pathDescription.size())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
unsigned entireLength = 0;
|
if(0 == pathDescription.size())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// unsigned entireLength = 0;
|
||||||
/** starts at index 1 */
|
/** starts at index 1 */
|
||||||
pathDescription[0].length = 0;
|
pathDescription[0].length = 0;
|
||||||
for(unsigned i = 1; i < pathDescription.size(); ++i) {
|
for(unsigned i = 1; i < pathDescription.size(); ++i) {
|
||||||
pathDescription[i].length = ApproximateDistance(pathDescription[i-1].location, pathDescription[i].location);
|
pathDescription[i].length = ApproximateDistanceByEuclid(pathDescription[i-1].location, pathDescription[i].location);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned lengthOfSegment = 0;
|
double lengthOfSegment = 0;
|
||||||
unsigned durationOfSegment = 0;
|
unsigned durationOfSegment = 0;
|
||||||
unsigned indexOfSegmentBegin = 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) {
|
for(unsigned i = 1; i < pathDescription.size(); ++i) {
|
||||||
entireLength += pathDescription[i].length;
|
entireLength += pathDescription[i].length;
|
||||||
lengthOfSegment += pathDescription[i].length;
|
lengthOfSegment += pathDescription[i].length;
|
||||||
durationOfSegment += pathDescription[i].duration;
|
durationOfSegment += pathDescription[i].duration;
|
||||||
pathDescription[indexOfSegmentBegin].length = lengthOfSegment;
|
pathDescription[indexOfSegmentBegin].length = lengthOfSegment;
|
||||||
pathDescription[indexOfSegmentBegin].duration = durationOfSegment;
|
pathDescription[indexOfSegmentBegin].duration = durationOfSegment;
|
||||||
if(pathDescription[i].turnInstruction != 0) {
|
|
||||||
|
|
||||||
|
if(TurnInstructionsClass::NoTurn != pathDescription[i].turnInstruction) {
|
||||||
//INFO("Turn after " << lengthOfSegment << "m into way with name id " << segment.nameID);
|
//INFO("Turn after " << lengthOfSegment << "m into way with name id " << segment.nameID);
|
||||||
assert(pathDescription[i].necessary);
|
assert(pathDescription[i].necessary);
|
||||||
lengthOfSegment = 0;
|
lengthOfSegment = 0;
|
||||||
@@ -86,10 +160,51 @@ unsigned DescriptionFactory::Run(const unsigned zoomLevel) {
|
|||||||
indexOfSegmentBegin = i;
|
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
|
//Generalize poly line
|
||||||
dp.Run(pathDescription, zoomLevel);
|
dp.Run(pathDescription, zoomLevel);
|
||||||
|
|
||||||
//fix what needs to be fixed else
|
//fix what needs to be fixed else
|
||||||
return entireLength;
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,8 +26,11 @@
|
|||||||
#include "../typedefs.h"
|
#include "../typedefs.h"
|
||||||
#include "../Algorithms/DouglasPeucker.h"
|
#include "../Algorithms/DouglasPeucker.h"
|
||||||
#include "../Algorithms/PolylineCompressor.h"
|
#include "../Algorithms/PolylineCompressor.h"
|
||||||
#include "../DataStructures/ExtractorStructs.h"
|
#include "../DataStructures/Coordinate.h"
|
||||||
|
#include "../DataStructures/QueryEdge.h"
|
||||||
|
#include "../DataStructures/SearchEngine.h"
|
||||||
#include "../DataStructures/SegmentInformation.h"
|
#include "../DataStructures/SegmentInformation.h"
|
||||||
|
#include "../DataStructures/TurnInstructions.h"
|
||||||
|
|
||||||
/* This class is fed with all way segments in consecutive order
|
/* This class is fed with all way segments in consecutive order
|
||||||
* and produces the description plus the encoded polyline */
|
* and produces the description plus the encoded polyline */
|
||||||
@@ -36,63 +39,45 @@ class DescriptionFactory {
|
|||||||
DouglasPeucker<SegmentInformation> dp;
|
DouglasPeucker<SegmentInformation> dp;
|
||||||
PolylineCompressor pc;
|
PolylineCompressor pc;
|
||||||
PhantomNode startPhantom, targetPhantom;
|
PhantomNode startPhantom, targetPhantom;
|
||||||
|
|
||||||
|
typedef SearchEngine<QueryEdge::EdgeData, StaticGraph<QueryEdge::EdgeData> > SearchEngineT;
|
||||||
|
|
||||||
|
double DegreeToRadian(const double degree) const;
|
||||||
|
double RadianToDegree(const double degree) const;
|
||||||
public:
|
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
|
//I know, declaring this public is considered bad. I'm lazy
|
||||||
std::vector <SegmentInformation> pathDescription;
|
std::vector <SegmentInformation> pathDescription;
|
||||||
DescriptionFactory();
|
DescriptionFactory();
|
||||||
virtual ~DescriptionFactory();
|
virtual ~DescriptionFactory();
|
||||||
double GetAngleBetweenCoordinates() const;
|
double GetBearing(const _Coordinate& C, const _Coordinate& B) const;
|
||||||
void AppendEncodedPolylineString(std::string &output);
|
void AppendEncodedPolylineString(std::string &output);
|
||||||
void AppendUnencodedPolylineString(std::string &output);
|
void AppendUnencodedPolylineString(std::string &output);
|
||||||
void AppendSegment(const _Coordinate & coordinate, const _PathData & data);
|
void AppendSegment(const _Coordinate & coordinate, const _PathData & data);
|
||||||
|
void BuildRouteSummary(const double distance, const unsigned time);
|
||||||
void SetStartSegment(const PhantomNode & startPhantom);
|
void SetStartSegment(const PhantomNode & startPhantom);
|
||||||
void SetEndSegment(const PhantomNode & startPhantom);
|
void SetEndSegment(const PhantomNode & startPhantom);
|
||||||
void AppendEncodedPolylineString(std::string & output, bool isEncoded);
|
void AppendEncodedPolylineString(std::string & output, bool isEncoded);
|
||||||
unsigned Run(const unsigned zoomLevel);
|
void Run(const SearchEngineT &sEngine, const unsigned zoomLevel);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* DESCRIPTIONFACTORY_H_ */
|
#endif /* DESCRIPTIONFACTORY_H_ */
|
||||||
|
|
||||||
//private:
|
|
||||||
// void appendInstructionNameToString(const std::string & nameOfStreet, const std::string & instructionOrDirection, std::string &output, bool firstAdvice = false) {
|
|
||||||
// output += "[";
|
|
||||||
// if(config.instructions) {
|
|
||||||
// output += "\"";
|
|
||||||
// if(firstAdvice) {
|
|
||||||
// output += "Head ";
|
|
||||||
// }
|
|
||||||
// output += instructionOrDirection;
|
|
||||||
// output += "\",\"";
|
|
||||||
// output += nameOfStreet;
|
|
||||||
// output += "\",";
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// void appendInstructionLengthToString(unsigned length, std::string &output) {
|
|
||||||
// if(config.instructions){
|
|
||||||
// std::string tmpDistance;
|
|
||||||
// intToString(10*(round(length/10.)), tmpDistance);
|
|
||||||
// output += tmpDistance;
|
|
||||||
// output += ",";
|
|
||||||
// intToString(descriptionFactory.startIndexOfGeometry, tmp);
|
|
||||||
// output += tmp;
|
|
||||||
// output += ",";
|
|
||||||
// intToString(descriptionFactory.durationOfInstruction, tmp);
|
|
||||||
// output += tmp;
|
|
||||||
// output += ",";
|
|
||||||
// output += "\"";
|
|
||||||
// output += tmpDistance;
|
|
||||||
// output += "\",";
|
|
||||||
// double angle = descriptionFactory.GetAngleBetweenCoordinates();
|
|
||||||
// DirectionOfInstruction direction;
|
|
||||||
// getDirectionOfInstruction(angle, direction);
|
|
||||||
// output += "\"";
|
|
||||||
// output += direction.shortDirection;
|
|
||||||
// output += "\",";
|
|
||||||
// std::stringstream numberString;
|
|
||||||
// numberString << fixed << setprecision(2) << angle;
|
|
||||||
// output += numberString.str();
|
|
||||||
// }
|
|
||||||
// output += "]";
|
|
||||||
// }
|
|
||||||
|
|||||||
@@ -33,28 +33,26 @@ private:
|
|||||||
std::string tmp;
|
std::string tmp;
|
||||||
public:
|
public:
|
||||||
void SetConfig(const _DescriptorConfig& c) { config = c; }
|
void SetConfig(const _DescriptorConfig& c) { config = c; }
|
||||||
void Run(http::Reply & reply, RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine, unsigned distance) {
|
void Run(http::Reply & reply, const RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine) {
|
||||||
reply.content += ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
reply.content += ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||||
reply.content += "<gpx xmlns=\"http://www.topografix.com/GPX/1/1\" "
|
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\" "
|
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
||||||
"xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd"
|
"xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd"
|
||||||
"\">";
|
"\">";
|
||||||
reply.content += "<rte>";
|
reply.content += "<rte>";
|
||||||
if(distance != UINT_MAX && rawRoute.routeSegments.size()) {
|
if(rawRoute.lengthOfShortestPath != INT_MAX && rawRoute.computedShortestPath.size()) {
|
||||||
convertInternalLatLonToString(phantomNodes.startPhantom.location.lat, tmp);
|
convertInternalLatLonToString(phantomNodes.startPhantom.location.lat, tmp);
|
||||||
reply.content += "<rtept lat=\"" + tmp + "\" ";
|
reply.content += "<rtept lat=\"" + tmp + "\" ";
|
||||||
convertInternalLatLonToString(phantomNodes.startPhantom.location.lon, tmp);
|
convertInternalLatLonToString(phantomNodes.startPhantom.location.lon, tmp);
|
||||||
reply.content += "lon=\"" + tmp + "\"></rtept>";
|
reply.content += "lon=\"" + tmp + "\"></rtept>";
|
||||||
|
|
||||||
for(unsigned segmentIdx = 0; segmentIdx < rawRoute.routeSegments.size(); segmentIdx++) {
|
BOOST_FOREACH(_PathData pathData, rawRoute.computedShortestPath) {
|
||||||
BOOST_FOREACH(_PathData pathData, rawRoute.routeSegments[segmentIdx]) {
|
sEngine.GetCoordinatesForNodeID(pathData.node, current);
|
||||||
sEngine.GetCoordinatesForNodeID(pathData.node, current);
|
|
||||||
|
|
||||||
convertInternalLatLonToString(current.lat, tmp);
|
convertInternalLatLonToString(current.lat, tmp);
|
||||||
reply.content += "<rtept lat=\"" + tmp + "\" ";
|
reply.content += "<rtept lat=\"" + tmp + "\" ";
|
||||||
convertInternalLatLonToString(current.lon, tmp);
|
convertInternalLatLonToString(current.lon, tmp);
|
||||||
reply.content += "lon=\"" + tmp + "\"></rtept>";
|
reply.content += "lon=\"" + tmp + "\"></rtept>";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
convertInternalLatLonToString(phantomNodes.targetPhantom.location.lat, tmp);
|
convertInternalLatLonToString(phantomNodes.targetPhantom.location.lat, tmp);
|
||||||
reply.content += "<rtept lat=\"" + tmp + "\" ";
|
reply.content += "<rtept lat=\"" + tmp + "\" ";
|
||||||
|
|||||||
@@ -21,47 +21,66 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
|||||||
#ifndef JSON_DESCRIPTOR_H_
|
#ifndef JSON_DESCRIPTOR_H_
|
||||||
#define JSON_DESCRIPTOR_H_
|
#define JSON_DESCRIPTOR_H_
|
||||||
|
|
||||||
#include <boost/foreach.hpp>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <boost/lambda/lambda.hpp>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
#include "BaseDescriptor.h"
|
#include "BaseDescriptor.h"
|
||||||
#include "DescriptionFactory.h"
|
#include "DescriptionFactory.h"
|
||||||
|
#include "../Algorithms/ObjectToBase64.h"
|
||||||
#include "../DataStructures/SegmentInformation.h"
|
#include "../DataStructures/SegmentInformation.h"
|
||||||
#include "../DataStructures/TurnInstructions.h"
|
#include "../DataStructures/TurnInstructions.h"
|
||||||
|
#include "../Util/Azimuth.h"
|
||||||
#include "../Util/StringUtil.h"
|
#include "../Util/StringUtil.h"
|
||||||
|
|
||||||
template<class SearchEngineT>
|
template<class SearchEngineT>
|
||||||
class JSONDescriptor : public BaseDescriptor<SearchEngineT>{
|
class JSONDescriptor : public BaseDescriptor<SearchEngineT>{
|
||||||
private:
|
private:
|
||||||
_DescriptorConfig config;
|
_DescriptorConfig config;
|
||||||
_RouteSummary summary;
|
|
||||||
DescriptionFactory descriptionFactory;
|
DescriptionFactory descriptionFactory;
|
||||||
std::string tmp;
|
DescriptionFactory alternateDescriptionFactory;
|
||||||
_Coordinate current;
|
_Coordinate current;
|
||||||
|
unsigned numberOfEnteredRestrictedAreas;
|
||||||
struct {
|
struct {
|
||||||
int startIndex;
|
int startIndex;
|
||||||
int nameID;
|
int nameID;
|
||||||
int leaveAtExit;
|
int leaveAtExit;
|
||||||
} roundAbout;
|
} 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:
|
public:
|
||||||
JSONDescriptor() {}
|
JSONDescriptor() : numberOfEnteredRestrictedAreas(0) {}
|
||||||
void SetConfig(const _DescriptorConfig & c) { config = c; }
|
void SetConfig(const _DescriptorConfig & c) { config = c; }
|
||||||
|
|
||||||
void Run(http::Reply & reply, RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine, unsigned durationOfTrip) {
|
void Run(http::Reply & reply, const RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine) {
|
||||||
|
|
||||||
WriteHeaderToOutput(reply.content);
|
WriteHeaderToOutput(reply.content);
|
||||||
if(durationOfTrip != INT_MAX && rawRoute.routeSegments.size() > 0) {
|
|
||||||
summary.startName = sEngine.GetEscapedNameForNameID(phantomNodes.startPhantom.nodeBasedEdgeNameID);
|
if(rawRoute.lengthOfShortestPath != INT_MAX) {
|
||||||
descriptionFactory.SetStartSegment(phantomNodes.startPhantom);
|
descriptionFactory.SetStartSegment(phantomNodes.startPhantom);
|
||||||
summary.destName = sEngine.GetEscapedNameForNameID(phantomNodes.targetPhantom.nodeBasedEdgeNameID);
|
|
||||||
reply.content += "0,"
|
reply.content += "0,"
|
||||||
"\"status_message\": \"Found route between points\",";
|
"\"status_message\": \"Found route between points\",";
|
||||||
for(unsigned segmentIdx = 0; segmentIdx < rawRoute.routeSegments.size(); segmentIdx++) {
|
|
||||||
const std::vector< _PathData > & path = rawRoute.routeSegments[segmentIdx];
|
//Get all the coordinates for the computed route
|
||||||
BOOST_FOREACH(_PathData pathData, path) {
|
BOOST_FOREACH(const _PathData & pathData, rawRoute.computedShortestPath) {
|
||||||
sEngine.GetCoordinatesForNodeID(pathData.node, current);
|
sEngine.GetCoordinatesForNodeID(pathData.node, current);
|
||||||
descriptionFactory.AppendSegment(current, pathData );
|
descriptionFactory.AppendSegment(current, pathData );
|
||||||
}
|
|
||||||
//TODO: Add via points
|
|
||||||
}
|
}
|
||||||
descriptionFactory.SetEndSegment(phantomNodes.targetPhantom);
|
descriptionFactory.SetEndSegment(phantomNodes.targetPhantom);
|
||||||
} else {
|
} else {
|
||||||
@@ -70,107 +89,303 @@ public:
|
|||||||
"\"status_message\": \"Cannot find route between points\",";
|
"\"status_message\": \"Cannot find route between points\",";
|
||||||
}
|
}
|
||||||
|
|
||||||
summary.BuildDurationAndLengthStrings(descriptionFactory.Run(config.z), durationOfTrip);
|
descriptionFactory.Run(sEngine, config.z);
|
||||||
|
|
||||||
reply.content += "\"route_summary\": {"
|
|
||||||
"\"total_distance\":";
|
|
||||||
reply.content += summary.lengthString;
|
|
||||||
reply.content += ","
|
|
||||||
"\"total_time\":";
|
|
||||||
reply.content += summary.durationString;
|
|
||||||
reply.content += ","
|
|
||||||
"\"start_point\":\"";
|
|
||||||
reply.content += summary.startName;
|
|
||||||
reply.content += "\","
|
|
||||||
"\"end_point\":\"";
|
|
||||||
reply.content += summary.destName;
|
|
||||||
reply.content += "\"";
|
|
||||||
reply.content += "},";
|
|
||||||
reply.content += "\"route_geometry\": ";
|
reply.content += "\"route_geometry\": ";
|
||||||
if(config.geometry) {
|
if(config.geometry) {
|
||||||
if(config.encodeGeometry)
|
descriptionFactory.AppendEncodedPolylineString(reply.content, config.encodeGeometry);
|
||||||
descriptionFactory.AppendEncodedPolylineString(reply.content, config.encodeGeometry);
|
|
||||||
} else {
|
} else {
|
||||||
reply.content += "[]";
|
reply.content += "[]";
|
||||||
}
|
}
|
||||||
|
|
||||||
reply.content += ","
|
reply.content += ","
|
||||||
"\"route_instructions\": [";
|
"\"route_instructions\": [";
|
||||||
|
numberOfEnteredRestrictedAreas = 0;
|
||||||
if(config.instructions) {
|
if(config.instructions) {
|
||||||
//Segment information has following format:
|
BuildTextualDescription(descriptionFactory, reply, rawRoute.lengthOfShortestPath, sEngine, shortestSegments);
|
||||||
//["instruction","streetname",length,position,time,"length","earth_direction",azimuth]
|
} else {
|
||||||
//Example: ["Turn left","High Street",200,4,10,"200m","NE",22.5]
|
BOOST_FOREACH(const SegmentInformation & segment, descriptionFactory.pathDescription) {
|
||||||
//See also: http://developers.cloudmade.com/wiki/navengine/JSON_format
|
TurnInstruction currentInstruction = segment.turnInstruction & TurnInstructions.InverseAccessRestrictionFlag;
|
||||||
unsigned prefixSumOfNecessarySegments = 0;
|
numberOfEnteredRestrictedAreas += (currentInstruction != segment.turnInstruction);
|
||||||
roundAbout.leaveAtExit = 0;
|
|
||||||
roundAbout.nameID = 0;
|
|
||||||
std::string tmpDist, tmpLength, tmp;
|
|
||||||
//Fetch data from Factory and generate a string from it.
|
|
||||||
BOOST_FOREACH(SegmentInformation segment, descriptionFactory.pathDescription) {
|
|
||||||
if(TurnInstructions.TurnIsNecessary( segment.turnInstruction) ) {
|
|
||||||
if(TurnInstructions.EnterRoundAbout == segment.turnInstruction) {
|
|
||||||
roundAbout.nameID = segment.nameID;
|
|
||||||
roundAbout.startIndex = prefixSumOfNecessarySegments;
|
|
||||||
} else {
|
|
||||||
if(0 != prefixSumOfNecessarySegments)
|
|
||||||
reply.content += ",";
|
|
||||||
|
|
||||||
reply.content += "[\"";
|
|
||||||
if(TurnInstructions.LeaveRoundAbout == segment.turnInstruction) {
|
|
||||||
reply.content += TurnInstructions.TurnStrings[TurnInstructions.EnterRoundAbout];
|
|
||||||
reply.content += " and leave at ";
|
|
||||||
reply.content += TurnInstructions.Ordinals[roundAbout.leaveAtExit+1];
|
|
||||||
reply.content += " exit";
|
|
||||||
roundAbout.leaveAtExit = 0;
|
|
||||||
} else {
|
|
||||||
reply.content += TurnInstructions.TurnStrings[segment.turnInstruction];
|
|
||||||
}
|
|
||||||
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, tmp);
|
|
||||||
reply.content += ",\"";
|
|
||||||
reply.content += tmpLength;
|
|
||||||
//TODO: fix heading
|
|
||||||
reply.content += "\",\"NE\",22.5";
|
|
||||||
reply.content += "]";
|
|
||||||
}
|
|
||||||
} else if(TurnInstructions.StayOnRoundAbout == segment.turnInstruction) {
|
|
||||||
++roundAbout.leaveAtExit;
|
|
||||||
}
|
|
||||||
if(segment.necessary)
|
|
||||||
++prefixSumOfNecessarySegments;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reply.content += "],";
|
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
|
//list all viapoints so that the client may display it
|
||||||
reply.content += "\"via_points\":[";
|
reply.content += "\"via_points\":[";
|
||||||
for(unsigned segmentIdx = 1; (true == config.geometry) && (segmentIdx < rawRoute.segmentEndCoordinates.size()); segmentIdx++) {
|
std::string tmp;
|
||||||
if(segmentIdx > 1)
|
if(config.geometry && INT_MAX != rawRoute.lengthOfShortestPath) {
|
||||||
reply.content += ",";
|
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 += "[";
|
reply.content += "[";
|
||||||
if(rawRoute.segmentEndCoordinates[segmentIdx].startPhantom.location.isSet())
|
if(rawRoute.segmentEndCoordinates.back().startPhantom.location.isSet())
|
||||||
convertInternalReversedCoordinateToString(rawRoute.segmentEndCoordinates[segmentIdx].startPhantom.location, tmp);
|
convertInternalReversedCoordinateToString(rawRoute.segmentEndCoordinates.back().targetPhantom.location, tmp);
|
||||||
else
|
else
|
||||||
convertInternalReversedCoordinateToString(rawRoute.rawViaNodeCoordinates[segmentIdx], tmp);
|
convertInternalReversedCoordinateToString(rawRoute.rawViaNodeCoordinates.back(), tmp);
|
||||||
reply.content += tmp;
|
reply.content += tmp;
|
||||||
reply.content += "]";
|
reply.content += "]";
|
||||||
}
|
}
|
||||||
reply.content += "],"
|
reply.content += "],";
|
||||||
"\"transactionId\": \"OSRM Routing Engine JSON Descriptor (v0.2)\"";
|
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 += "}";
|
reply.content += "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteHeaderToOutput(std::string & output) {
|
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 += "{"
|
output += "{"
|
||||||
"\"version\": 0.3,"
|
"\"version\": 0.3,"
|
||||||
"\"status\":";
|
"\"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_ */
|
#endif /* JSON_DESCRIPTOR_H_ */
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
Third Party Libraries:
|
|
||||||
|
|
||||||
Scons 1.3+
|
|
||||||
Boost 1.37+
|
|
||||||
sparsehash 1.4+
|
|
||||||
stxxl 1.3.1+
|
|
||||||
libz2-dev 1.0.5+
|
|
||||||
protobuffer 2.3.0+
|
|
||||||
zlib 1.2.3.4+
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
FAQ
|
|
||||||
---
|
|
||||||
|
|
||||||
Q: What platforms does OSMR run on?
|
|
||||||
A: Virtually any Unix-like platform with g++ installed. It has been developed
|
|
||||||
under Linux and tested on MacOS X 10.6. It should run under Windows as well
|
|
||||||
though the code will need some adjustments.
|
|
||||||
|
|
||||||
Q: What is the workflow to get the engine up and running
|
|
||||||
A: Road network extraction->Preprocessing->Startup
|
|
||||||
|
|
||||||
Q: What does OSRM stand for?
|
|
||||||
A: It is an abbreviation for Open Source Routing Machine.
|
|
||||||
|
|
||||||
Q: What does HSGR stand for?
|
|
||||||
A: It is an abbreviation for Hierarchy Search GRaph.
|
|
||||||
|
|
||||||
Q: What is the .nodes file?
|
|
||||||
A: It is a map that translates between internal and external Node IDs. Remember
|
|
||||||
that external NodeIDs can be arbitrary and non-contigous. Internally the
|
|
||||||
nodes are numbered from 0 to n-1.
|
|
||||||
|
|
||||||
Q: The routing engine crashes with a seg-fault
|
|
||||||
A: Check the startup parameters.
|
|
||||||
|
|
||||||
Q: Something about the route is odd. I know that there is a better path
|
|
||||||
A: Most probably it is missing data in the OSM file.
|
|
||||||
|
|
||||||
Q: I work for this company that would like to use the code, but we are hesistant
|
|
||||||
because of the license.
|
|
||||||
A: Contact me. Probably, we can work something out.
|
|
||||||
|
|
||||||
Q: How fast is this thing?
|
|
||||||
A: Good question. Here is a number. The engine was able to handle more than
|
|
||||||
2800 requests per Minute on the German road network with the travel time
|
|
||||||
metric on a Core 2 Duo. This also includes transfer of data across a
|
|
||||||
switched 100MBit/s LAN. So, I guess it's fair to say it's fast.
|
|
||||||
|
|
||||||
Q: What is the difference between extractNetwork and extractLargeNetwork?
|
|
||||||
A: extractNetwork does all of its magic in RAM, while extractLargeNetwork uses the
|
|
||||||
stxxl library to store the data in external memory. Use the first one for small
|
|
||||||
networks, but beware of running out of RAM. Swapping is the kiss of death. For
|
|
||||||
larger networks use extractLargeNetwork. It will be somewhat slower on the
|
|
||||||
smaller files, but way faster with large ones like the planet file.
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
- extractorLargeNetwork finishes with:
|
|
||||||
terminate called after throwing an instance of 'stxxl::resource_error'
|
|
||||||
what(): Error in function void stxxl::mutex::lock() pthread_mutex_lock(&_mutex) Invalid argument
|
|
||||||
|
|
||||||
This ist a known, albeit odd behavior that is caused by a bug in stxxl. It can be ignored. Upgrade
|
|
||||||
to version 1.3.1 of stxxl.
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
/*
|
|
||||||
* Open Source Routing Machine (OSRM) - Web (GUI) Interface
|
|
||||||
* Copyright (C) Pascal Neis, 2011
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Title: Geocode.js
|
|
||||||
* Description: JS file for geocoding
|
|
||||||
*
|
|
||||||
* @author Pascal Neis, pascal@neis-one.org
|
|
||||||
* @version 0.1 2011-05-15
|
|
||||||
*/
|
|
||||||
|
|
||||||
//======================
|
|
||||||
// OBJECTS
|
|
||||||
var HOST_GEOCODE_URL = 'http://open.mapquestapi.com';
|
|
||||||
var GEOCODE_POST = HOST_GEOCODE_URL + '/nominatim/v1/search?format=json&json_callback=showResultsGeocode';
|
|
||||||
var searchType = 'search';
|
|
||||||
|
|
||||||
var isStartPointSet = false;
|
|
||||||
var isEndPointSet = false;
|
|
||||||
|
|
||||||
//======================
|
|
||||||
// FUNCTIONS
|
|
||||||
/*
|
|
||||||
* geocodeAddress()-Function to read out textfield and send request to a OSM nominatim geocoder
|
|
||||||
*/
|
|
||||||
function geocodeAddress(tf){
|
|
||||||
var freeform;
|
|
||||||
|
|
||||||
if(tf == 'start'){
|
|
||||||
freeform = document.getElementById('tfStartSearch').value;
|
|
||||||
}
|
|
||||||
if(tf == 'end'){
|
|
||||||
freeform = document.getElementById('tfEndSearch').value;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('information').style.visibility = 'visible';
|
|
||||||
document.getElementById('information').innerHTML = '<p class="infoHL">One moment please ...</p>';
|
|
||||||
|
|
||||||
|
|
||||||
var newURL = GEOCODE_POST + "&q="+freeform;
|
|
||||||
var script = document.createElement('script');
|
|
||||||
script.type = 'text/javascript';
|
|
||||||
script.src = newURL;
|
|
||||||
document.body.appendChild(script);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* showResultsGeocode()-Function to show the geocode result in a div
|
|
||||||
*/
|
|
||||||
function showResultsGeocode(response) {
|
|
||||||
var html = '';
|
|
||||||
var lonlat = '';
|
|
||||||
|
|
||||||
if(response){
|
|
||||||
html += '<p class="infoHL">Search Results:</p>';
|
|
||||||
html += '<table>'
|
|
||||||
var markername;
|
|
||||||
if(getStatus()=='start'){
|
|
||||||
markername = 'start'; isStartPointSet = true;
|
|
||||||
}
|
|
||||||
else if(getStatus()=='end'){
|
|
||||||
markername = 'end'; isEndPointSet = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(var i=0; i < response.length; i++){
|
|
||||||
var result = response[i]; var resultNum = i+1;
|
|
||||||
//odd or even ?
|
|
||||||
var rowstyle='geocodeResultOdd';
|
|
||||||
if(i%2==0){ rowstyle='geocodeResultEven'; }
|
|
||||||
|
|
||||||
html += '<tr class="'+rowstyle+'">';
|
|
||||||
html += '<td align="right" valign="top"><span class="routeSummarybold">'+resultNum+'</span></td>';
|
|
||||||
html += '<td class="'+rowstyle+'">';
|
|
||||||
if(result.display_name){
|
|
||||||
var new_display_name = result.display_name;//.replace(/,/g, ",<br />")
|
|
||||||
html += '<a href="#" onclick="javascript:setMarkerAndZoom(\''+markername+'\', new OpenLayers.LonLat('+result.lon+','+result.lat+'));">'+new_display_name.trim()+'</a>';
|
|
||||||
}
|
|
||||||
html += "</td></tr>";
|
|
||||||
|
|
||||||
//alert(result.lat + ", " + result.lon);
|
|
||||||
if(lonlat == ''){
|
|
||||||
lonlat = new OpenLayers.LonLat(result.lon,result.lat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
html += '</table>';
|
|
||||||
|
|
||||||
setMarkerAndZoom(markername, lonlat);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
switch (searchType) {
|
|
||||||
case "search":
|
|
||||||
document.getElementById('information').style.display = "";
|
|
||||||
document.getElementById('information').innerHTML = html;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* setMarkerAndZoom()-Function to set a marker on the map and zoom
|
|
||||||
*/
|
|
||||||
function setMarkerAndZoom(markername,lonlat){
|
|
||||||
setMarker(markername,lonlat);
|
|
||||||
|
|
||||||
//Hack - FIXME !
|
|
||||||
lonlat.lon -= 500;
|
|
||||||
//Set Center
|
|
||||||
map.setCenter(lonlat, 15);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* setMarker()-Function to set a marker on the map
|
|
||||||
*/
|
|
||||||
function setMarker(markername,lonlat){
|
|
||||||
lonlat.transform(EPSG_4326, EPSG_900913);
|
|
||||||
for(var i= 0; i<dragLayer.features.length; i++){
|
|
||||||
if(dragLayer.features[i].name == markername){ dragLayer.removeFeatures([dragLayer.features[i]]); }
|
|
||||||
}
|
|
||||||
var point = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat));
|
|
||||||
point.attributes = { icon: "img/start.png" };
|
|
||||||
|
|
||||||
if(markername == 'start'){
|
|
||||||
point.attributes = { icon: "img/start.png" };
|
|
||||||
}
|
|
||||||
else if(markername == 'end'){
|
|
||||||
point.attributes = { icon: "img/end.png" };
|
|
||||||
}
|
|
||||||
|
|
||||||
point.name = markername;
|
|
||||||
dragLayer.addFeatures([point]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* getMarkerByName()-Function to return the marker-object by a name
|
|
||||||
*/
|
|
||||||
function getMarkerByName(markerName){
|
|
||||||
for(var i= 0; i<dragLayer.features.length; i++){
|
|
||||||
if(dragLayer.features[i].name == markerName){
|
|
||||||
return dragLayer.features[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,354 +0,0 @@
|
|||||||
/*
|
|
||||||
* Open Source Routing Machine (OSRM) - Web (GUI) Interface
|
|
||||||
* Copyright (C) Pascal Neis, 2011
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Title: Map.js
|
|
||||||
* Description: JS file to show a map, for markers, left slide div, ...
|
|
||||||
*
|
|
||||||
* @author Pascal Neis, pascal@neis-one.org
|
|
||||||
* @version 0.1.1 2011-06-09
|
|
||||||
*/
|
|
||||||
|
|
||||||
//======================
|
|
||||||
// OBJECTS
|
|
||||||
//Map
|
|
||||||
var map;
|
|
||||||
|
|
||||||
//Status object for what position actually a coordinate is searched
|
|
||||||
var status = ''; //possible values [start,end]
|
|
||||||
function getStatus(){ return status; }
|
|
||||||
function setStatus(stat){ status = stat; }
|
|
||||||
|
|
||||||
//Indicator
|
|
||||||
var ISDRAGGING = false;
|
|
||||||
|
|
||||||
//Layer
|
|
||||||
var dragLayer;
|
|
||||||
var vectorLayerRoute;
|
|
||||||
var vectorLayerViaRoute;
|
|
||||||
var markersLayer;
|
|
||||||
|
|
||||||
var selectFeature;
|
|
||||||
//======================
|
|
||||||
// FUNCTIONS
|
|
||||||
/*
|
|
||||||
* init()-Function to create the map div
|
|
||||||
*/
|
|
||||||
function init(){
|
|
||||||
//Create Map
|
|
||||||
map = new OpenLayers.Map ("map", {
|
|
||||||
controls:[
|
|
||||||
new OpenLayers.Control.Navigation(),
|
|
||||||
new OpenLayers.Control.Permalink(),
|
|
||||||
new OpenLayers.Control.LayerSwitcher()],
|
|
||||||
maxExtent: new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34),
|
|
||||||
maxResolution: 156543.0399,
|
|
||||||
numZoomLevels: 19,
|
|
||||||
units: 'm',
|
|
||||||
projection: new OpenLayers.Projection("EPSG:900913"),
|
|
||||||
displayProjection: new OpenLayers.Projection("EPSG:4326")
|
|
||||||
} );
|
|
||||||
//Add the base layers.
|
|
||||||
|
|
||||||
var coverageLayer = new OpenLayers.Layer.Vector("Coverage", {
|
|
||||||
style: {
|
|
||||||
strokeColor: "#000000",
|
|
||||||
strokeTransparency: 0.5,
|
|
||||||
strokeWidth: 4
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if("map.project-osrm.org" == location.host) {
|
|
||||||
var coveragePointList = [
|
|
||||||
new OpenLayers.Geometry.Point(-11.99, 58.80),
|
|
||||||
new OpenLayers.Geometry.Point(-11.99, 35.30),
|
|
||||||
new OpenLayers.Geometry.Point(-7.57, 35.30),
|
|
||||||
new OpenLayers.Geometry.Point(9.22, 38.24),
|
|
||||||
new OpenLayers.Geometry.Point(15.38, 35.39),
|
|
||||||
new OpenLayers.Geometry.Point(18.92, 40.02),
|
|
||||||
new OpenLayers.Geometry.Point(15.70, 42.25),
|
|
||||||
new OpenLayers.Geometry.Point(15.70, 55.40),
|
|
||||||
new OpenLayers.Geometry.Point(30.31, 60.29),
|
|
||||||
new OpenLayers.Geometry.Point(30.31, 71.27),
|
|
||||||
new OpenLayers.Geometry.Point(21.01, 71.27),
|
|
||||||
new OpenLayers.Geometry.Point(-11.99, 58.80)
|
|
||||||
];
|
|
||||||
|
|
||||||
var line_string = new OpenLayers.Geometry.LineString(coveragePointList).transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913"));
|
|
||||||
coverageLayer.addFeatures([new OpenLayers.Feature.Vector(line_string)]);
|
|
||||||
|
|
||||||
map.addLayer(coverageLayer);
|
|
||||||
}
|
|
||||||
|
|
||||||
map.addLayer(new OpenLayers.Layer.OSM.Mapnik("Mapnik"));
|
|
||||||
map.addLayer(new OpenLayers.Layer.OSM.MapQuest("MapQuest"));
|
|
||||||
map.addLayer(new OpenLayers.Layer.OSM.Osmarender("Osmarender"));
|
|
||||||
|
|
||||||
//Add layer for the route
|
|
||||||
vectorLayerRoute = new OpenLayers.Layer.Vector("Route",{maxResolution: 156543.0339});
|
|
||||||
map.addLayer(vectorLayerRoute);
|
|
||||||
|
|
||||||
//Add layer for temporary via route
|
|
||||||
vectorLayerViaRoute = new OpenLayers.Layer.Vector("ViaRoute",{maxResolution: 156543.0339});
|
|
||||||
map.addLayer(vectorLayerViaRoute);
|
|
||||||
|
|
||||||
//Add Layerswitcher
|
|
||||||
map.addControl(new OpenLayers.Control.LayerSwitcher());
|
|
||||||
|
|
||||||
//Add Panzoombar
|
|
||||||
var panZoomBar = new OpenLayers.Control.PanZoomBar({id:'panzoombar',displayClass:'olControlPanZoomBar'})
|
|
||||||
map.addControl(panZoomBar);
|
|
||||||
//Customize the position of the panzoombar
|
|
||||||
document.getElementById('panzoombar').style.left="400px";
|
|
||||||
document.getElementById('panzoombar').style.top="25px";
|
|
||||||
|
|
||||||
//Create drag vector layer
|
|
||||||
dragLayer = new OpenLayers.Layer.Vector(
|
|
||||||
"Start/End Marker",{
|
|
||||||
styleMap: new OpenLayers.StyleMap({
|
|
||||||
// Set the external graphic and background graphic images.
|
|
||||||
externalGraphic: '${icon}',
|
|
||||||
// Makes sure the background graphic is placed correctly relative
|
|
||||||
// to the external graphic.
|
|
||||||
backgroundXOffset: -11,
|
|
||||||
backgroundYOffset: -40,
|
|
||||||
graphicXOffset: -11,
|
|
||||||
graphicYOffset: -40,
|
|
||||||
|
|
||||||
// Set the z-indexes of both graphics to make sure the background
|
|
||||||
// graphics stay in the background (shadows on top of markers looks
|
|
||||||
// odd; let's not do that).
|
|
||||||
graphicZIndex: 10,
|
|
||||||
backgroundGraphicZIndex: 11,
|
|
||||||
|
|
||||||
pointRadius: 10,
|
|
||||||
graphicWidth: 22,
|
|
||||||
graphicHeight: 40
|
|
||||||
}),
|
|
||||||
rendererOptions: {zIndexing: true}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
// Add a drag feature control to move features around.
|
|
||||||
var dragFeatures = new OpenLayers.Control.DragFeature(dragLayer,
|
|
||||||
{ onDrag: function(feature, pixel){
|
|
||||||
ISDRAGGING = true;
|
|
||||||
if(feature.name == "start" || feature.name == "end") {
|
|
||||||
feature.move(map.getLonLatFromPixel(pixel));
|
|
||||||
if(!ISCALCULATING){ routing(true); }
|
|
||||||
}
|
|
||||||
if(feature.name == "via") {
|
|
||||||
computeViaRoute(pixel, true);
|
|
||||||
}
|
|
||||||
if(feature.name == "viapoint" && feature.popup) {
|
|
||||||
map.removePopup(feature.popup);
|
|
||||||
computeViaRoute(pixel, true, feature.viaIndex);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onComplete: function(feature, pixel){
|
|
||||||
ISDRAGGING = false;
|
|
||||||
if(feature.name == "start" || feature.name == "end") {
|
|
||||||
feature.move(map.getLonLatFromPixel(pixel));
|
|
||||||
routing(false);
|
|
||||||
} else if(feature.name == "via") {
|
|
||||||
console.log('finished via');
|
|
||||||
//Erase temporary point from draglayer
|
|
||||||
dragLayer.renderer.eraseFeatures([feature]);
|
|
||||||
//delete temporary route from via route Layer
|
|
||||||
vectorLayerViaRoute.removeFeatures(vectorLayerViaRoute.features);
|
|
||||||
//compute via route
|
|
||||||
computeViaRoute(pixel, false);
|
|
||||||
feature.destroy();
|
|
||||||
} else if(feature.name == "viapoint") {
|
|
||||||
//Erase temporary point from draglayer
|
|
||||||
dragLayer.renderer.eraseFeatures([feature]);
|
|
||||||
//delete via point from vector
|
|
||||||
viaPointsVector.splice(feature.viaIndex,1);
|
|
||||||
//delete temporary route from via route Layer
|
|
||||||
vectorLayerViaRoute.removeFeatures(vectorLayerViaRoute.features);
|
|
||||||
//compute via route
|
|
||||||
computeViaRoute(pixel, false);
|
|
||||||
feature.destroy();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onLeave: function(f){
|
|
||||||
if(!ISCALCULATING){ routing(false); }}
|
|
||||||
});
|
|
||||||
map.addControl(dragFeatures);
|
|
||||||
dragFeatures.activate();
|
|
||||||
map.addLayers([dragLayer]);
|
|
||||||
|
|
||||||
//Add a marker layer
|
|
||||||
markersLayer = new OpenLayers.Layer.Markers("Markers");
|
|
||||||
map.addLayer(markersLayer);
|
|
||||||
|
|
||||||
//Add zoom event for rerouting
|
|
||||||
map.events.on({zoomend: function(e) {reroute();distanceToRoute(null);}});
|
|
||||||
|
|
||||||
// Register Callback to evaluate distance to from mouse location to route on Mousemove
|
|
||||||
map.events.on({mousemove: function(e) {distanceToRoute(e.xy);}});
|
|
||||||
|
|
||||||
// Set center of the map
|
|
||||||
if (!map.getCenter()){
|
|
||||||
map.setCenter(new OpenLayers.LonLat(600000, 6600000),6);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check if the URL contains some GET parameter, e.g. for the route
|
|
||||||
checkURL();
|
|
||||||
|
|
||||||
for(var i = 0; i < map.layers.length; i++) {
|
|
||||||
map.layers[i].transitionEffect = 'resize';
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('map').oncontextmenu = function(e){
|
|
||||||
e = e?e:window.event;
|
|
||||||
if (e.preventDefault) e.preventDefault(); // For non-IE browsers.
|
|
||||||
else return false; // For IE browsers.
|
|
||||||
};
|
|
||||||
|
|
||||||
// A control class for capturing click events...
|
|
||||||
OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, {
|
|
||||||
|
|
||||||
defaultHandlerOptions: {
|
|
||||||
'single': true,
|
|
||||||
'double': true,
|
|
||||||
'pixelTolerance': 0,
|
|
||||||
'stopSingle': false,
|
|
||||||
'stopDouble': false
|
|
||||||
},
|
|
||||||
handleRightClicks:true,
|
|
||||||
initialize: function(options) {
|
|
||||||
this.handlerOptions = OpenLayers.Util.extend(
|
|
||||||
{}, this.defaultHandlerOptions
|
|
||||||
);
|
|
||||||
OpenLayers.Control.prototype.initialize.apply(
|
|
||||||
this, arguments
|
|
||||||
);
|
|
||||||
this.handler = new OpenLayers.Handler.Click(
|
|
||||||
this, this.eventMethods, this.handlerOptions
|
|
||||||
);
|
|
||||||
},
|
|
||||||
CLASS_NAME: "OpenLayers.Control.Click"
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add an instance of the Click control that listens to various click events:
|
|
||||||
var oClick = new OpenLayers.Control.Click({eventMethods:{
|
|
||||||
'rightclick': function(e) {
|
|
||||||
rightClick(e);
|
|
||||||
},
|
|
||||||
'click': function(e) {
|
|
||||||
leftClick(e);
|
|
||||||
},
|
|
||||||
'dblclick': function(e) {
|
|
||||||
dblClick(e);
|
|
||||||
},
|
|
||||||
'dblrightclick': function(e) {
|
|
||||||
dblRightClick(e);
|
|
||||||
}
|
|
||||||
}});
|
|
||||||
map.addControl(oClick);
|
|
||||||
oClick.activate();
|
|
||||||
|
|
||||||
|
|
||||||
selectFeature = new OpenLayers.Control.SelectFeature(
|
|
||||||
[dragLayer],
|
|
||||||
{
|
|
||||||
clickout: true, toggle: false,
|
|
||||||
multiple: false, hover: true,
|
|
||||||
toggleKey: "ctrlKey", // ctrl key removes from selection
|
|
||||||
multipleKey: "shiftKey", // shift key adds to selection
|
|
||||||
onSelect: createPopup,
|
|
||||||
onUnselect: destroyPopup
|
|
||||||
|
|
||||||
}
|
|
||||||
);
|
|
||||||
map.addControl(selectFeature);
|
|
||||||
dragLayer.events.on({
|
|
||||||
"featureselected": function(e) {
|
|
||||||
featureSelected(e);
|
|
||||||
},
|
|
||||||
"featureunselected": function(e) {
|
|
||||||
featureUnselected(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
selectFeature.activate();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Helper Functions
|
|
||||||
function checkReturn(textfieldname,e){
|
|
||||||
var evt = e || window.event;
|
|
||||||
if(!evt){ return; }
|
|
||||||
|
|
||||||
var key = 0;
|
|
||||||
if (evt.keyCode) { key = evt.keyCode; }
|
|
||||||
else if (typeof(evt.which)!= 'undefined') { key = evt.which; }
|
|
||||||
if( key == 13 && textfieldname=='start'){ setStatus('start'); geocodeAddress('start'); return; }
|
|
||||||
if( key == 13 && textfieldname=='end'){ setStatus('end'); geocodeAddress('end'); return; }
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeOpenDiv(name){
|
|
||||||
if(document.getElementById(name).style.display == 'none'){ document.getElementById(name).style.display = ''; }
|
|
||||||
else{ document.getElementById(name).style.display = 'none'; }
|
|
||||||
}
|
|
||||||
|
|
||||||
//URL Functions
|
|
||||||
function checkURL(){
|
|
||||||
var getObjs = new Array();
|
|
||||||
var getString = document.location.search.substr(1,document.location.search.length);
|
|
||||||
if(getString != ''){
|
|
||||||
var getArray=getString.split('&');
|
|
||||||
console.log(getArray);
|
|
||||||
for(i=0 ; i<getArray.length ; ++i){
|
|
||||||
var v='';
|
|
||||||
var vArr = getArray[i].split('=');
|
|
||||||
if(vArr.length>1){ v = vArr[1]; }
|
|
||||||
if("via" == vArr[0]) {
|
|
||||||
var via_loc = unescape(v).split(',');
|
|
||||||
for(var j=0; j<via_loc.length; j++) { via_loc[j] = parseFloat(via_loc[j]); }
|
|
||||||
viaPointsVector.push(via_loc);
|
|
||||||
} else {
|
|
||||||
getObjs[unescape(vArr[0])]=unescape(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var fr = getObjectOfArray(getObjs, "fr");
|
|
||||||
var to = getObjectOfArray(getObjs, "to");
|
|
||||||
|
|
||||||
if(fr != 'undefined' && to != 'undefined'){
|
|
||||||
//From
|
|
||||||
var fr_pos = fr.split(',');
|
|
||||||
var fr_lonlat = new OpenLayers.LonLat(fr_pos[1],fr_pos[0]);
|
|
||||||
setMarkerAndZoom('start', fr_lonlat);
|
|
||||||
isStartPointSet = true;
|
|
||||||
//To
|
|
||||||
var to_pos = to.split(',');
|
|
||||||
var to_lonlat = new OpenLayers.LonLat(to_pos[1],to_pos[0]);
|
|
||||||
setMarker('end', to_lonlat);
|
|
||||||
isEndPointSet = true;
|
|
||||||
//Calculate the route
|
|
||||||
routing(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getObjectOfArray(objects, elementName){
|
|
||||||
if(!objects[elementName]){ return 'undefined'; }
|
|
||||||
return objects[elementName];
|
|
||||||
}
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
var selectedFeature = null;
|
|
||||||
var popupCloseTimer = null;
|
|
||||||
var popupToRemove = null;
|
|
||||||
|
|
||||||
function rightClick(e) {
|
|
||||||
console.log("right click1");
|
|
||||||
if(null == selectedFeature)
|
|
||||||
return;
|
|
||||||
//alert('rightclick at '+e.xy.x+','+e.xy.y);
|
|
||||||
console.log("right click2");
|
|
||||||
}
|
|
||||||
|
|
||||||
function dblClick(e) {
|
|
||||||
//alert('dblclick at '+e.xy.x+','+e.xy.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
function dblRightClick(e) {
|
|
||||||
//alert('dblrightclick at '+e.xy.x+','+e.xy.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
function leftClick(e) {
|
|
||||||
//set start and target via clicks
|
|
||||||
var lonlat = map.getLonLatFromViewPortPx(e.xy);
|
|
||||||
var markername = "";
|
|
||||||
|
|
||||||
/* //routing shall not be done by left clicks
|
|
||||||
* if (e.ctrlKey || e.altKey) {
|
|
||||||
markername = "end";
|
|
||||||
isEndPointSet = true;
|
|
||||||
} else if(e.shiftKey) {
|
|
||||||
markername = "start";
|
|
||||||
isStartPointSet = true;
|
|
||||||
}
|
|
||||||
for(var i= 0; i<dragLayer.features.length; i++){
|
|
||||||
if(dragLayer.features[i].name == markername){ dragLayer.removeFeatures([dragLayer.features[i]]); }
|
|
||||||
}
|
|
||||||
|
|
||||||
var point = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat));
|
|
||||||
point.attributes = { icon: "img/start.png" };
|
|
||||||
|
|
||||||
if(markername == 'start'){
|
|
||||||
point.attributes = { icon: "img/start.png" };
|
|
||||||
}
|
|
||||||
else if(markername == 'end'){
|
|
||||||
point.attributes = { icon: "img/end.png" };
|
|
||||||
}
|
|
||||||
|
|
||||||
point.name = markername;
|
|
||||||
dragLayer.addFeatures([point]);
|
|
||||||
reroute();
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
function featureSelected(f) {
|
|
||||||
if("viapoint" == f.feature.name) {
|
|
||||||
// console.log('selected ' + f.feature.name);
|
|
||||||
selectedFeature = f.feature;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function featureUnselected(f) {
|
|
||||||
if("viapoint" == f.feature.name) {
|
|
||||||
// console.log('unselected ' + f.feature.name);
|
|
||||||
selectedFeature = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createPopup(feature) {
|
|
||||||
if("viapoint" != feature.name || ISDRAGGING)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(popupCloseTimer != null) {
|
|
||||||
clearInterval(popupCloseTimer);
|
|
||||||
popupCloseTimer = null;
|
|
||||||
map.removePopup(popupToRemove);
|
|
||||||
popupToRemove = null;
|
|
||||||
}
|
|
||||||
var location = feature.geometry.getBounds().getCenterLonLat().clone();
|
|
||||||
location.lon; location.lat;
|
|
||||||
feature.popup = new OpenLayers.Popup.Anchored("ViaPointInfo",
|
|
||||||
location,
|
|
||||||
new OpenLayers.Size(16,16),
|
|
||||||
'<div><a href="javascript:removeViaPoint('+ feature.viaIndex +')"><img src="img/cancel_small.png"/></a></div>',
|
|
||||||
null,
|
|
||||||
false,
|
|
||||||
destroyPopup );
|
|
||||||
feature.popup.backgroundColor = 'transparent';
|
|
||||||
feature.popup.fixedRelativePosition = true;
|
|
||||||
feature.popup.relativePosition = "tr";
|
|
||||||
map.addPopup(feature.popup, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function destroyPopup(feature) {
|
|
||||||
if(feature.popup) {
|
|
||||||
popupToRemove = feature.popup;
|
|
||||||
popupCloseTimer = setTimeout("removePopup()",2000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function removePopup() {
|
|
||||||
if(null == popupToRemove)
|
|
||||||
return;
|
|
||||||
|
|
||||||
map.removePopup(popupToRemove);
|
|
||||||
popupToRemove = null;
|
|
||||||
popupCloseTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeViaPoint(index) {
|
|
||||||
for(var i = 0; i < map.popups.length; i++) {
|
|
||||||
map.removePopup(map.popups[i]);
|
|
||||||
}
|
|
||||||
viaPointsVector.splice(index, 1);
|
|
||||||
reroute();
|
|
||||||
}
|
|
||||||
@@ -1,366 +0,0 @@
|
|||||||
/*
|
|
||||||
* Open Source Routing Machine (OSRM) - Web (GUI) Interface
|
|
||||||
* Copyright (C) Pascal Neis, 2011
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Title: Route.js
|
|
||||||
* Description: JS file for routing
|
|
||||||
*
|
|
||||||
* @author Pascal Neis, pascal@neis-one.org
|
|
||||||
* @version 0.2 2011-06-23
|
|
||||||
*/
|
|
||||||
|
|
||||||
//======================
|
|
||||||
// OBJECTS
|
|
||||||
//Map
|
|
||||||
//var HOST_ROUTING_URL = 'http://localhost:5000/viaroute';
|
|
||||||
var HOST_ROUTING_URL = 'http://routingdemo.geofabrik.de/route-via/';
|
|
||||||
var HOST_WEBSITE = 'http://map.project-osrm.org/';//location.host
|
|
||||||
|
|
||||||
var ISCALCULATING = false;
|
|
||||||
var EPSG_4326 = new OpenLayers.Projection("EPSG:4326");
|
|
||||||
var EPSG_900913 = new OpenLayers.Projection("EPSG:900913");
|
|
||||||
var allRoutePoints = [];
|
|
||||||
//======================
|
|
||||||
// FUNCTIONS
|
|
||||||
/*
|
|
||||||
* routing()-Function to create and send route request
|
|
||||||
*/
|
|
||||||
function routing(isDragRoute){
|
|
||||||
//Check if startpoint is set
|
|
||||||
if(!isStartPointSet){
|
|
||||||
//alert("Please set your Start location first!");
|
|
||||||
document.getElementById('information').innerHTML = '<p class="infoHLRed">Please set your Start location first!</p>';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//Check if endpoint is set
|
|
||||||
if(!isEndPointSet){
|
|
||||||
//alert("Please set your Destination first!");
|
|
||||||
document.getElementById('information').innerHTML = '<p class="infoHLRed">Please set your Destination first!</p>';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check if already a route is planning
|
|
||||||
if(!isDragRoute){ ISCALCULATING = false; }
|
|
||||||
if(ISCALCULATING){ return; }
|
|
||||||
else{ ISCALCULATING = true; }
|
|
||||||
|
|
||||||
//Get Coordinates of the Start and Endpoint
|
|
||||||
var startFeat = getMarkerByName('start');
|
|
||||||
var endFeat = getMarkerByName('end');
|
|
||||||
var from = new OpenLayers.LonLat(startFeat.geometry.x,startFeat.geometry.y).transform(new OpenLayers.Projection("EPSG:900913"), new OpenLayers.Projection("EPSG:4326"));
|
|
||||||
var to = new OpenLayers.LonLat(endFeat.geometry.x,endFeat.geometry.y).transform(new OpenLayers.Projection("EPSG:900913"), new OpenLayers.Projection("EPSG:4326"));
|
|
||||||
|
|
||||||
//Send Request
|
|
||||||
var script = document.createElement('script');
|
|
||||||
script.type = 'text/javascript';
|
|
||||||
|
|
||||||
var callBackFunction = 'showResultsRoute';
|
|
||||||
var instructions = '&geomformat=cmp&instructions=true';
|
|
||||||
if(isDragRoute){
|
|
||||||
callBackFunction = 'showResultsDragRoute';
|
|
||||||
instructions = '&geomformat=cmp&instructions=false';
|
|
||||||
document.getElementById('information').innerHTML = '<p class="infoHL">Release mouse button to get Route Information!</p>(If no Route Summary is diplayed, press the Route!-button)';
|
|
||||||
}
|
|
||||||
|
|
||||||
script.src = HOST_ROUTING_URL + "&start="+from.lat + ',' + from.lon + '&dest=' + to.lat + ',' + to.lon;
|
|
||||||
for(var i = 0; i < viaPointsVector.length; i++) {
|
|
||||||
script.src += ('&via=' + viaPointsVector[i][0] + ',' + viaPointsVector[i][1]);
|
|
||||||
}
|
|
||||||
script.src +='&z='+this.map.getZoom()+'&output=json&jsonp='+callBackFunction+instructions;
|
|
||||||
document.body.appendChild(script);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* reroute()-Function
|
|
||||||
*/
|
|
||||||
function reroute() {
|
|
||||||
if(!isStartPointSet || !isEndPointSet){ return; }
|
|
||||||
routing(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* showResultsDragRoute()-Function to show route result for drag-route
|
|
||||||
*/
|
|
||||||
function showResultsDragRoute(response) {
|
|
||||||
if (response) {
|
|
||||||
//Display Route
|
|
||||||
showRouteGeometry(response);
|
|
||||||
}
|
|
||||||
markersLayer.clearMarkers();
|
|
||||||
ISCALCULATING = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* showResultsRoute()-Function to show route result
|
|
||||||
*/
|
|
||||||
function showResultsRoute(response) {
|
|
||||||
if (response) {
|
|
||||||
//Display Route
|
|
||||||
if(document.getElementById("cbNoNames").checked == true){
|
|
||||||
showNoNameStreets(response);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
showRouteGeometry(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Save Via Points that come with route
|
|
||||||
var lengthOfArray = response.via_points.length;
|
|
||||||
var i = 0;
|
|
||||||
viaPointsVector.length = 0;
|
|
||||||
viaPointsVector = response.via_points.slice(0);
|
|
||||||
paintViaPoints();
|
|
||||||
|
|
||||||
//Create Link of the route
|
|
||||||
var startFeat = getMarkerByName('start');
|
|
||||||
var endFeat = getMarkerByName('end');
|
|
||||||
var from = new OpenLayers.LonLat(startFeat.geometry.x,startFeat.geometry.y).transform(EPSG_900913,EPSG_4326);
|
|
||||||
var to = new OpenLayers.LonLat(endFeat.geometry.x,endFeat.geometry.y).transform(EPSG_900913,EPSG_4326);
|
|
||||||
var routelink = '<div id="routelink"><input name="routelink" type="submit" title="Get Link" onClick="createShortLink(\''+HOST_WEBSITE+'?fr='+from.lat.toFixed(6)+','+from.lon.toFixed(6)+'&to='+to.lat.toFixed(6)+','+to.lon.toFixed(6);
|
|
||||||
for(i = 0; i < viaPointsVector.length; i++) {
|
|
||||||
routelink += "&via=" + viaPointsVector[i][0] + "," + viaPointsVector[i][1];
|
|
||||||
}
|
|
||||||
routelink += '\');" value="Get Link"></div>';
|
|
||||||
|
|
||||||
//Link for the GPX Download
|
|
||||||
var gpxLink = '(<a href="'+HOST_ROUTING_URL+'&start='+from.lat.toFixed(6)+','+from.lon.toFixed(6)+'&dest='+to.lat.toFixed(6)+','+to.lon.toFixed(6)+'&z='+this.map.getZoom();
|
|
||||||
for(i = 0; i < viaPointsVector.length; i++) {
|
|
||||||
gpxLink += "&via=" + viaPointsVector[i][0] + "," + viaPointsVector[i][1];
|
|
||||||
}
|
|
||||||
gpxLink += '&output=gpx">Get GPX File</a>)';;
|
|
||||||
|
|
||||||
//Show Route Summary
|
|
||||||
var output = '<p class="routeSummaryHL">Some information about your Way <br> from \'<span class="routeSummaryHLlight">'+response.route_summary.start_point+'</span>\' to \'<span class="routeSummaryHLlight">'+response.route_summary.end_point+'</span>\'</p>';
|
|
||||||
output += '<p class="routeSummary">Distance: <span class="routeSummarybold">'+response.route_summary.total_distance/1000+' km</span> - Duration: <span class="routeSummarybold">'+secondsToTime(response.route_summary.total_time)+'</span></p><p>'+routelink+'</p><p><span class="routeInstructionsHL">The Route-Instructions:</span> '+gpxLink+'</p>';
|
|
||||||
//Show Route Instructions
|
|
||||||
output += '<table>';
|
|
||||||
lengthOfArray = response.route_instructions.length;
|
|
||||||
for (i = 0; i < lengthOfArray; i++) {
|
|
||||||
//console.log(response.route_instructions[i]);
|
|
||||||
//odd or even ?
|
|
||||||
var rowstyle='routeInstructionsOdd';
|
|
||||||
if(i%2==0){ rowstyle='routeInstructionsEven'; }
|
|
||||||
|
|
||||||
var indexPos = response.route_instructions[i][3];
|
|
||||||
//console.log('setting : ' + response.route_instructions[i] + ' at ' + allRoutePoints[indexPos]);
|
|
||||||
var point = allRoutePoints[indexPos];
|
|
||||||
|
|
||||||
output += '<tr class="'+rowstyle+'"><td align="right" valign="top"><span class="routeSummarybold">'+(i+1)+'.</span></td><td class="'+rowstyle+'"><a href="#" class="nolinkStyle" onclick="setMapCenter(new OpenLayers.LonLat('+point.x+','+point.y+'));">'+response.route_instructions[i][0]+' on '+response.route_instructions[i][1]+' for '+getDistanceWithUnit(response.route_instructions[i][2])+'</a></td></tr>';
|
|
||||||
}
|
|
||||||
var rowstyle='routeInstructionsOdd';
|
|
||||||
if(i%2==0){ rowstyle='routeInstructionsEven'; }
|
|
||||||
if( lengthOfArray > 0) {
|
|
||||||
var point = allRoutePoints[allRoutePoints.length-1];
|
|
||||||
output += '<tr class="'+rowstyle+'"><td align="right" valign="top"><span class="routeSummarybold">'+(i+1)+'.</span></td><td class="'+rowstyle+'"><a href="#" class="nolinkStyle" onclick="setMapCenter(new OpenLayers.LonLat('+point.x+','+point.y+'));">You have reached your destination</a></td></tr>';
|
|
||||||
}
|
|
||||||
output += '</table>';
|
|
||||||
//alert(vectorLayerRoute.features[0].geometry.getVertices());
|
|
||||||
|
|
||||||
document.getElementById('information').innerHTML = output;
|
|
||||||
ISCALCULATING = false;
|
|
||||||
ISCALCULATINGVIA = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* showRouteGeometry()-Function to show route result
|
|
||||||
*/
|
|
||||||
function showRouteGeometry(response) {
|
|
||||||
if (response) {
|
|
||||||
allRoutePoints.length = 0;
|
|
||||||
// now with compression of the route geometry
|
|
||||||
var geometry = decodeRouteGeometry(response.route_geometry, 5);
|
|
||||||
var lengthOfArray = geometry.length;
|
|
||||||
var points = [];
|
|
||||||
points.length = lengthOfArray;
|
|
||||||
var points = [];
|
|
||||||
//delete any previously displayed via route
|
|
||||||
vectorLayerViaRoute.removeFeatures(vectorLayerViaRoute.features);
|
|
||||||
vectorLayerRoute.removeAllFeatures();
|
|
||||||
|
|
||||||
//Create Route Layer for Display
|
|
||||||
for (var i = 0; i < lengthOfArray; i++) {
|
|
||||||
var point = new OpenLayers.Geometry.Point(geometry[i][1], geometry[i][0]).transform(EPSG_4326, EPSG_900913);
|
|
||||||
allRoutePoints.push(point);
|
|
||||||
points.push(point);
|
|
||||||
|
|
||||||
if(i % 1024 == 0 && i>0 || i==lengthOfArray-1){
|
|
||||||
/* var feature2 = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(points), null, {
|
|
||||||
strokeColor: "#000066",
|
|
||||||
strokeOpacity: 1,
|
|
||||||
strokeWidth: 9
|
|
||||||
});
|
|
||||||
|
|
||||||
var feature1 = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(points), null, {
|
|
||||||
strokeColor: "#ffffff",
|
|
||||||
strokeOpacity: 0.75,
|
|
||||||
strokeWidth: 7
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
|
|
||||||
var feature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(points), null, {
|
|
||||||
strokeColor: "#0033ff",
|
|
||||||
strokeOpacity: 0.7,
|
|
||||||
strokeWidth: 5
|
|
||||||
});
|
|
||||||
// vectorLayerRoute.addFeatures([feature2]);
|
|
||||||
// vectorLayerRoute.addFeatures([feature1]);
|
|
||||||
vectorLayerRoute.addFeatures([feature]);
|
|
||||||
points = [];
|
|
||||||
points.push(point);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* showNoNameStreets()-Function to show route result
|
|
||||||
*/
|
|
||||||
function showNoNameStreets(response) {
|
|
||||||
if (response) {
|
|
||||||
allRoutePoints.length = 0;
|
|
||||||
vectorLayerRoute.removeFeatures(vectorLayerRoute.features);
|
|
||||||
// now with compression of the route geometry
|
|
||||||
var geometry = decodeRouteGeometry(response.route_geometry, 5);
|
|
||||||
var lengthOfArray = geometry.length;
|
|
||||||
var points = [];
|
|
||||||
points.length = lengthOfArray;
|
|
||||||
|
|
||||||
//Check if a instruction has no name !
|
|
||||||
var colors = [];
|
|
||||||
if(true){
|
|
||||||
var instrucLength = response.route_instructions.length;
|
|
||||||
for (var i = 0; i < instrucLength; i++) {
|
|
||||||
var indexPos = response.route_instructions[i][3];
|
|
||||||
var streetName = response.route_instructions[i][1];
|
|
||||||
if(streetName == ''){ colors[indexPos] = "#FF00FF"; }
|
|
||||||
else{ colors[indexPos] = "#0033ff"; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//delete any previously displayed via route
|
|
||||||
vectorLayerViaRoute.removeFeatures(vectorLayerViaRoute.features);
|
|
||||||
vectorLayerRoute.removeAllFeatures();
|
|
||||||
|
|
||||||
//Create Route Layer for Display
|
|
||||||
var color = "#0033ff";
|
|
||||||
var changeColor = false;
|
|
||||||
for (var i = 0; i < lengthOfArray; i++) {
|
|
||||||
var point = new OpenLayers.Geometry.Point(geometry[i][1], geometry[i][0]).transform(EPSG_4326, EPSG_900913);
|
|
||||||
points.push(point);
|
|
||||||
allRoutePoints.push(point);
|
|
||||||
|
|
||||||
if(colors[i] != undefined){ changeColor=true;}
|
|
||||||
|
|
||||||
if(i % 1024 == 0 && i>0 || i==lengthOfArray-1 || changeColor){
|
|
||||||
var feature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(points), null, {
|
|
||||||
strokeColor: color,
|
|
||||||
strokeOpacity: 0.7,
|
|
||||||
strokeWidth: 5
|
|
||||||
});
|
|
||||||
vectorLayerRoute.addFeatures([feature]);
|
|
||||||
points = [];
|
|
||||||
points.push(point);
|
|
||||||
|
|
||||||
if(colors[i] != undefined){ color = colors[i]; }
|
|
||||||
changeColor=false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* secondsToTime()-Function to transform seconds to a time string
|
|
||||||
*/
|
|
||||||
function secondsToTime(seconds){
|
|
||||||
seconds = parseInt(seconds);
|
|
||||||
minutes = parseInt(seconds/60);
|
|
||||||
seconds = seconds%60;
|
|
||||||
hours = parseInt(minutes/60);
|
|
||||||
minutes = minutes%60;
|
|
||||||
//return stunden+':'+minuten+':'+seconds;
|
|
||||||
if(hours==0){
|
|
||||||
return minutes+' min(s)';
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
return hours+' h '+minutes+' min(s)';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* getDistanceWithUnit()-Function to return a distance with units
|
|
||||||
*/
|
|
||||||
function getDistanceWithUnit(distance){
|
|
||||||
distance = parseInt(distance);
|
|
||||||
if(distance >= 1000){ return (parseInt(distance/1000))+' km'; }
|
|
||||||
else{ return distance+' m'; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* setMapCenter()-Function to add a marker and center the map
|
|
||||||
*/
|
|
||||||
function setMapCenter(lonlat){
|
|
||||||
//lonlat.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913"));
|
|
||||||
//console.log('zooming to :' + lonlat);
|
|
||||||
|
|
||||||
//Add Marker
|
|
||||||
markersLayer.clearMarkers();
|
|
||||||
var size = new OpenLayers.Size(21,25);
|
|
||||||
var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
|
|
||||||
var icon = new OpenLayers.Icon('img/marker.png',size,offset);
|
|
||||||
markersLayer.addMarker(new OpenLayers.Marker(lonlat,icon));
|
|
||||||
|
|
||||||
//Hack - FIXME !
|
|
||||||
map.setCenter(new OpenLayers.LonLat(lonlat.lon-200, lonlat.lat), 17);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* decodeRouteGeometry()-Function to decode encoded Route Geometry
|
|
||||||
*/
|
|
||||||
function decodeRouteGeometry(encoded, precision) {
|
|
||||||
precision = Math.pow(10, -precision);
|
|
||||||
var len = encoded.length, index=0, lat=0, lng = 0, array = [];
|
|
||||||
while (index < len) {
|
|
||||||
var b, shift = 0, result = 0;
|
|
||||||
do {
|
|
||||||
b = encoded.charCodeAt(index++) - 63;
|
|
||||||
result |= (b & 0x1f) << shift;
|
|
||||||
shift += 5;
|
|
||||||
} while (b >= 0x20);
|
|
||||||
var dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
|
|
||||||
lat += dlat;
|
|
||||||
shift = 0;
|
|
||||||
result = 0;
|
|
||||||
do {
|
|
||||||
b = encoded.charCodeAt(index++) - 63;
|
|
||||||
result |= (b & 0x1f) << shift;
|
|
||||||
shift += 5;
|
|
||||||
} while (b >= 0x20);
|
|
||||||
var dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
|
|
||||||
lng += dlng;
|
|
||||||
array.push([lat * precision, lng * precision]);
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* createShortLink()-Function to "create" shortlink of a route
|
|
||||||
*/
|
|
||||||
function createShortLink(str){
|
|
||||||
var script = document.createElement('script');
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
/*
|
|
||||||
* Open Source Routing Machine (OSRM) - Web (GUI) Interface
|
|
||||||
* Copyright (C) Pascal Neis, 2011
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Title: Slide.js
|
|
||||||
* Description: Fixme
|
|
||||||
*
|
|
||||||
* @author Pascal Neis, pascal@neis-one.org
|
|
||||||
* @version 0.1 2011-05-15
|
|
||||||
*/
|
|
||||||
|
|
||||||
var timerlen = 5;
|
|
||||||
var slideAniLen = 250;
|
|
||||||
|
|
||||||
var timerID = new Array();
|
|
||||||
var startTime = new Array();
|
|
||||||
var obj = new Array();
|
|
||||||
var endWidth = new Array();
|
|
||||||
var moving = new Array();
|
|
||||||
var dir = new Array();
|
|
||||||
|
|
||||||
function toggleSlide(objname){
|
|
||||||
document.getElementById('panzoombar').style.top="25px";
|
|
||||||
document.getElementById('panzoombar').style.display = "none";
|
|
||||||
document.getElementById('slide').style.display = "none";
|
|
||||||
if(document.getElementById(objname).style.display == "none"){
|
|
||||||
// div is hidden, so let's slide right
|
|
||||||
slide_right(objname);
|
|
||||||
}else{
|
|
||||||
// div is not hidden, so slide left
|
|
||||||
slide_left(objname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function slide_right(objname){
|
|
||||||
if(moving[objname]){ return; }
|
|
||||||
if(document.getElementById(objname).style.display != "none"){
|
|
||||||
return; // cannot slide right something that is already visible
|
|
||||||
}
|
|
||||||
moving[objname] = true; dir[objname] = "right"; startslide(objname);
|
|
||||||
}
|
|
||||||
|
|
||||||
function slide_left(objname){
|
|
||||||
if(moving[objname]){ return; }
|
|
||||||
if(document.getElementById(objname).style.display == "none"){
|
|
||||||
return; // cannot slide left something that is already hidden
|
|
||||||
}
|
|
||||||
moving[objname] = true; dir[objname] = "left"; startslide(objname);
|
|
||||||
}
|
|
||||||
|
|
||||||
function startslide(objname){
|
|
||||||
obj[objname] = document.getElementById(objname);
|
|
||||||
endWidth[objname] = parseInt(obj[objname].style.width);
|
|
||||||
startTime[objname] = (new Date()).getTime();
|
|
||||||
if(dir[objname] == "right"){ obj[objname].style.width = "1px"; }
|
|
||||||
obj[objname].style.display = "block";
|
|
||||||
timerID[objname] = setInterval('slidetick(\'' + objname + '\');',timerlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
function slidetick(objname){
|
|
||||||
var elapsed = (new Date()).getTime() - startTime[objname];
|
|
||||||
if (elapsed > slideAniLen){ endSlide(objname); }
|
|
||||||
else {
|
|
||||||
var d = Math.round(elapsed / slideAniLen * endWidth[objname]);
|
|
||||||
if(dir[objname] == "left"){ d = endWidth[objname] - d; }
|
|
||||||
obj[objname].style.width = d + "px";
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
function endSlide(objname){
|
|
||||||
clearInterval(timerID[objname]);
|
|
||||||
|
|
||||||
if(dir[objname] == "left"){
|
|
||||||
obj[objname].style.display = "none";
|
|
||||||
document.getElementById('panzoombar').style.left="25px";
|
|
||||||
document.getElementById('panzoombar').style.display = "";
|
|
||||||
document.getElementById('slide').style.left="5px";
|
|
||||||
document.getElementById('slide').innerHTML = "<a class=\"btn-slide\" href=\"javascript:;\" onmousedown=\"toggleSlide('data');\">>></a>";
|
|
||||||
document.getElementById('slide').style.display = "";
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
document.getElementById('panzoombar').style.left="400px";
|
|
||||||
document.getElementById('panzoombar').style.display = "";document.getElementById('slide').style.left="365px";
|
|
||||||
document.getElementById('slide').innerHTML = "<a class=\"btn-slide\" href=\"javascript:;\" onmousedown=\"toggleSlide('data');\"><<</a>";
|
|
||||||
document.getElementById('slide').style.display = "";
|
|
||||||
}
|
|
||||||
obj[objname].style.width = endWidth[objname] + "px";
|
|
||||||
|
|
||||||
delete(moving[objname]);
|
|
||||||
delete(timerID[objname]);
|
|
||||||
delete(startTime[objname]);
|
|
||||||
delete(endWidth[objname]);
|
|
||||||
delete(obj[objname]);
|
|
||||||
delete(dir[objname]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
@@ -1,340 +0,0 @@
|
|||||||
/*
|
|
||||||
* Open Source Routing Machine (OSRM) - Web (GUI) Interface
|
|
||||||
* Copyright (C) Dennis Luxen, 2011
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Title: ViaRoute.js
|
|
||||||
* Description: JS file for routing with via points
|
|
||||||
*
|
|
||||||
* @author Dennis Luxen, luxen@kit.edu
|
|
||||||
* @version 0.1 June 2011
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
//======================
|
|
||||||
// OBJECTS
|
|
||||||
|
|
||||||
//global timestamp to control frequency of mouse->route distance computations
|
|
||||||
var timestamp = (new Date()).getTime();
|
|
||||||
var ISCOMPUTINGDISTANCE = false;
|
|
||||||
var ISCALCULATINGVIA = false;
|
|
||||||
//var HASDELETEDTEMPORARYVIAROUTE = false;
|
|
||||||
var nearestPoint = new OpenLayers.Geometry.Point(1,1);
|
|
||||||
var nearestSegmentIndex = null;
|
|
||||||
var viaPointsVector = [];
|
|
||||||
var p0;
|
|
||||||
|
|
||||||
var temporaryViaStyle = {
|
|
||||||
fillColor: "#ffffff",
|
|
||||||
strokeColor: "#33ff33",
|
|
||||||
strokeOpacity: 0.6,
|
|
||||||
strokeWidth: 2,
|
|
||||||
pointRadius: 4,
|
|
||||||
pointerEvents: "visiblePainted"
|
|
||||||
};
|
|
||||||
|
|
||||||
var permanentViaStyle = {
|
|
||||||
fillColor: "#ffffff",
|
|
||||||
strokeColor: "#0033ff",
|
|
||||||
strokeOpacity: 0.6,
|
|
||||||
strokeWidth: 2,
|
|
||||||
pointRadius: 4,
|
|
||||||
pointerEvents: "visiblePainted"
|
|
||||||
};
|
|
||||||
|
|
||||||
//======================
|
|
||||||
//FUNCTIONS
|
|
||||||
function distanceBetweenPoint(x1, y1, x2, y2) {
|
|
||||||
var a = x1 - x2;
|
|
||||||
var b = y1 - y2;
|
|
||||||
return Math.sqrt(a*a + b*b);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Distance from a point to a line or segment.
|
|
||||||
x point's x coord
|
|
||||||
y point's y coord
|
|
||||||
x0 x coord of the line's A point
|
|
||||||
y0 y coord of the line's A point
|
|
||||||
x1 x coord of the line's B point
|
|
||||||
y1 y coord of the line's B point
|
|
||||||
o specifies if the distance should respect the limits of the segment
|
|
||||||
(overLine = true) or if it should consider the segment as an infinite
|
|
||||||
line (overLine = false), if false returns the distance from the point
|
|
||||||
to the line, otherwise the distance from the point to the segment
|
|
||||||
*/
|
|
||||||
function dotLineLength(x, y, x0, y0, x1, y1, o){
|
|
||||||
function lineLength(x, y, x0, y0){
|
|
||||||
return Math.sqrt((x -= x0) * x + (y -= y0) * y);
|
|
||||||
}
|
|
||||||
if(o && !(o = function(x, y, x0, y0, x1, y1){
|
|
||||||
if(!(x1 - x0)) return {x: x0, y: y};
|
|
||||||
else if(!(y1 - y0)) return {x: x, y: y0};
|
|
||||||
var left, tg = -1 / ((y1 - y0) / (x1 - x0));
|
|
||||||
return {x: left = (x1 * (x * tg - y + y0) + x0 * (x * - tg + y - y1)) / (tg * (x1 - x0) + y0 - y1), y: tg * left - tg * x + y};
|
|
||||||
}(x, y, x0, y0, x1, y1), o.x >= Math.min(x0, x1) && o.x <= Math.max(x0, x1) && o.y >= Math.min(y0, y1) && o.y <= Math.max(y0, y1))){
|
|
||||||
var l1 = lineLength(x, y, x0, y0), l2 = lineLength(x, y, x1, y1);
|
|
||||||
return l1 > l2 ? l2 : l1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var a = y0 - y1, b = x1 - x0, c = x0 * y1 - y0 * x1;
|
|
||||||
return Math.abs(a * x + b * y + c) / Math.sqrt(a * a + b * b);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function distanceToRoute(pixel) {
|
|
||||||
if(!isStartPointSet || !isEndPointSet){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(ISDRAGGING) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ISCOMPUTINGDISTANCE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var tempTime = (new Date()).getTime()
|
|
||||||
if( tempTime - timestamp < 25) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
timestamp = tempTime;
|
|
||||||
if(ISCALCULATING) {
|
|
||||||
var viaPointFeature = dragLayer.getFeatureBy("name", 'via');
|
|
||||||
if(viaPointFeature != null) {
|
|
||||||
dragLayer.removeFeatures(viaPointFeature);
|
|
||||||
viaPointFeature.destroy;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pixel == null) {
|
|
||||||
pixel.x = window.event.clientX;
|
|
||||||
pixel.y = window.event.clientY;
|
|
||||||
}
|
|
||||||
|
|
||||||
var newLonLat = map.getLonLatFromPixel(pixel);
|
|
||||||
var minimumDist = 20*Math.pow(2,(19- this.map.getZoom()));
|
|
||||||
var minimumDistToVia = 20*Math.pow(2,(19- this.map.getZoom()));
|
|
||||||
var indexToInsertViaPoint = 0;
|
|
||||||
|
|
||||||
var startFeat = getMarkerByName('start');
|
|
||||||
var endFeat = getMarkerByName('end');
|
|
||||||
var from = new OpenLayers.LonLat(startFeat.geometry.x,startFeat.geometry.y).transform(EPSG_900913, EPSG_4326);
|
|
||||||
var to = new OpenLayers.LonLat(endFeat.geometry.x,endFeat.geometry.y).transform(EPSG_900913, EPSG_4326);
|
|
||||||
|
|
||||||
var mapExtent = map.getExtent();
|
|
||||||
for(var i = 0; i < allRoutePoints.length-1; i++) {
|
|
||||||
var p1 = allRoutePoints[i];
|
|
||||||
var p2 = allRoutePoints[i+1];
|
|
||||||
if(p1.x < mapExtent.left || p1.x > mapExtent.right || p1.y < mapExtent.bottom || p1.y > mapExtent.top) {
|
|
||||||
if(p2.x < mapExtent.left || p2.x > mapExtent.right || p2.y < mapExtent.bottom || p2.y > mapExtent.top) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//check if previous segment is closest to via point
|
|
||||||
//if yes, then we have passed a via point.
|
|
||||||
if(viaPointsVector.length > indexToInsertViaPoint && p0) {
|
|
||||||
var viaPoint = new OpenLayers.LonLat(viaPointsVector[indexToInsertViaPoint][1],viaPointsVector[indexToInsertViaPoint][0]).transform(EPSG_4326, EPSG_900913);
|
|
||||||
var dist2 = dotLineLength(viaPoint.lon, viaPoint.lat, p1.x, p1.y, p0.x, p0.y, true)
|
|
||||||
if( 0 == dist2 ) {
|
|
||||||
indexToInsertViaPoint++;
|
|
||||||
}
|
|
||||||
var tmpDist = distanceBetweenPoint(viaPoint.lat, viaPoint.lon, newLonLat.lat, newLonLat.lon);
|
|
||||||
if(tmpDist < minimumDistToVia) {
|
|
||||||
minimumDistToVia = tmpDist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//continue if point out of view
|
|
||||||
dist = dotLineLength(newLonLat.lon, newLonLat.lat, p1.x, p1.y, p2.x, p2.y, true);
|
|
||||||
if(dist <= minimumDist) {
|
|
||||||
nearestSegmentIndex = indexToInsertViaPoint;
|
|
||||||
minimumDist = dist;
|
|
||||||
var lonDiff = (p2.x - p1.x)
|
|
||||||
var m = (p2.y - p1.y) / lonDiff;
|
|
||||||
|
|
||||||
var b = p1.y - (m * p1.x);
|
|
||||||
var m2 = m*m;
|
|
||||||
var x = (m * newLonLat.lat + newLonLat.lon - m * b) / (m2 + 1);
|
|
||||||
var y = (m2 * newLonLat.lat + m * newLonLat.lon + b) / (m2 + 1);
|
|
||||||
var r = (x - p1.x) / lonDiff;
|
|
||||||
if ( r <= 1 && r >= 0 ) {
|
|
||||||
nearestPoint.x = x;
|
|
||||||
nearestPoint.y = y;
|
|
||||||
} else {
|
|
||||||
if( r < 0 ) {
|
|
||||||
nearestPoint.x = p1.x;
|
|
||||||
nearestPoint.y = p1.y;
|
|
||||||
} if ( r > 1 ) {
|
|
||||||
nearestPoint.x = p2.x;
|
|
||||||
nearestPoint.y = p2.y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(p2.x == p1.x) {
|
|
||||||
nearestPoint.x = p1.x;
|
|
||||||
nearestPoint.y = newLonLat.lat;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var zoomFactor = Math.pow(2,(19- this.map.getZoom()));
|
|
||||||
var viaPointFeature = dragLayer.getFeatureBy("name", 'via');
|
|
||||||
if(viaPointFeature != null) {
|
|
||||||
dragLayer.removeFeatures(viaPointFeature);
|
|
||||||
viaPointFeature.destroy;
|
|
||||||
}
|
|
||||||
|
|
||||||
//too close to start or destination?
|
|
||||||
if(Math.min(distanceBetweenPoint(startFeat.geometry.x, startFeat.geometry.y, newLonLat.lon, newLonLat.lat),
|
|
||||||
distanceBetweenPoint(endFeat.geometry.x, endFeat.geometry.y, newLonLat.lon, newLonLat.lat)) < 10*zoomFactor) {
|
|
||||||
ISCOMPUTINGDISTANCE = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Are we close to the route but sufficiently far away from any existing via point?
|
|
||||||
if(minimumDist < 10*zoomFactor && minimumDistToVia > 5*zoomFactor) {
|
|
||||||
viaPointFeature = new OpenLayers.Feature.Vector( OpenLayers.Geometry.Polygon.createRegularPolygon( nearestPoint, (1.5*zoomFactor), 15, 0 ), null, temporaryViaStyle );
|
|
||||||
viaPointFeature.name = "via";
|
|
||||||
dragLayer.addFeatures( viaPointFeature );
|
|
||||||
//console.log('nearestSegmentIndex: ' + nearestSegmentIndex);
|
|
||||||
}
|
|
||||||
ISCOMPUTINGDISTANCE = false;
|
|
||||||
p0 = p1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function computeViaRoute(pixel, isTemporary, skipViaPointsIndex) {
|
|
||||||
if(ISCALCULATINGVIA && isTemporary)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if( nearestSegmentIndex == null ) {
|
|
||||||
//console.log('nearestSegmentIndex: ' + nearestSegmentIndex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isTemporary == null) {
|
|
||||||
isTemporary = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//So, we jumped all fences
|
|
||||||
ISCALCULATINGVIA = true;
|
|
||||||
|
|
||||||
var startFeat = getMarkerByName('start');
|
|
||||||
var endFeat = getMarkerByName('end');
|
|
||||||
var from = new OpenLayers.LonLat(startFeat.geometry.x,startFeat.geometry.y).transform(EPSG_900913, EPSG_4326);
|
|
||||||
var to = new OpenLayers.LonLat(endFeat.geometry.x,endFeat.geometry.y).transform(EPSG_900913, EPSG_4326);
|
|
||||||
|
|
||||||
var coordinate = map.getLonLatFromPixel(pixel);
|
|
||||||
var via = coordinate.transform(EPSG_900913, EPSG_4326);
|
|
||||||
var viaNodeInserted = false;
|
|
||||||
var newURL = HOST_ROUTING_URL + "&start="+from.lat + ',' + from.lon + '&dest=' + to.lat + ',' + to.lon;
|
|
||||||
newURL += '&geomformat=cmp';
|
|
||||||
for(var i = 0; i < viaPointsVector.length; i++) {
|
|
||||||
if(i == nearestSegmentIndex) { //insert new via node here
|
|
||||||
newURL += '&via=' + via.lat + ',' + via.lon;
|
|
||||||
viaNodeInserted = true;
|
|
||||||
}
|
|
||||||
if(skipViaPointsIndex == i)
|
|
||||||
continue;
|
|
||||||
newURL += '&via=' + viaPointsVector[i][0] + ',' + viaPointsVector[i][1];
|
|
||||||
}
|
|
||||||
if(false == viaNodeInserted) {
|
|
||||||
newURL += '&via=' + via.lat + ',' + via.lon;
|
|
||||||
}
|
|
||||||
newURL += '&output=json' + '&z=' + this.map.getZoom();
|
|
||||||
if(!isTemporary) {
|
|
||||||
newURL += '&instructions=true&jsonp=showResultsRoute';
|
|
||||||
} else {
|
|
||||||
newURL += '&instructions=false&jsonp=showResultsViaRoute';
|
|
||||||
}
|
|
||||||
//console.log(newURL);
|
|
||||||
var script = document.createElement('script');
|
|
||||||
script.id = 'JSONP';
|
|
||||||
script.type = 'application/javascript';
|
|
||||||
script.src = newURL;
|
|
||||||
|
|
||||||
document.body.appendChild(script);
|
|
||||||
}
|
|
||||||
|
|
||||||
function showResultsViaRoute(response) {
|
|
||||||
if (response) {
|
|
||||||
var viaRouteVector = [];
|
|
||||||
// now with compression of the route geometry
|
|
||||||
var geometry = decodeRouteGeometry(response.route_geometry, 5);
|
|
||||||
var lengthOfArray = geometry.length;
|
|
||||||
var points = [];
|
|
||||||
points.length = lengthOfArray;
|
|
||||||
|
|
||||||
//Create Route Layer for Display
|
|
||||||
for (var i = 0; i < lengthOfArray; i++) {
|
|
||||||
var point = new OpenLayers.Geometry.Point(geometry[i][1], geometry[i][0]).transform(EPSG_4326, EPSG_900913);
|
|
||||||
allRoutePoints.push(point);
|
|
||||||
points.push(point);
|
|
||||||
|
|
||||||
if(i % 1024 == 0 && i>0 || i==lengthOfArray-1){
|
|
||||||
/* var feature1 = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(points), null, {
|
|
||||||
strokeColor: "#006600",
|
|
||||||
strokeOpacity: 1,
|
|
||||||
strokeWidth: 9
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
var feature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(points), null, {
|
|
||||||
strokeColor: "#aaffaa",
|
|
||||||
strokeOpacity: 0.8,
|
|
||||||
strokeWidth: 7
|
|
||||||
});
|
|
||||||
// viaRouteVector.push(feature1);
|
|
||||||
viaRouteVector.push(feature);
|
|
||||||
points = [];
|
|
||||||
points.push(point);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vectorLayerViaRoute.removeFeatures(vectorLayerViaRoute.features);
|
|
||||||
|
|
||||||
for(var i = 0; i< viaRouteVector.length; i++) {
|
|
||||||
vectorLayerViaRoute.addFeatures(viaRouteVector[i]);
|
|
||||||
}
|
|
||||||
viaRouteVector.length = 0;
|
|
||||||
ISCALCULATINGVIA = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function paintViaPoints() {
|
|
||||||
//remove all previous via points
|
|
||||||
var featuresToRemove = [];
|
|
||||||
for(var i = 0; i < dragLayer.features.length; i++) {
|
|
||||||
if(dragLayer.features[i].name == "viapoint" || "via" == dragLayer.features[i].name ) {
|
|
||||||
featuresToRemove.push(dragLayer.features[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dragLayer.removeFeatures(featuresToRemove);
|
|
||||||
featuresToRemove.length = 0;
|
|
||||||
|
|
||||||
//paint all via points
|
|
||||||
var zoomFactor = Math.pow(2,(19- this.map.getZoom()));
|
|
||||||
//console.log('painting ' + viaPointsVector.length + ' via points');
|
|
||||||
for(var i = 0; i < viaPointsVector.length; i++) {
|
|
||||||
//console.log(viaPointsVector[i]);
|
|
||||||
var viapoint = new OpenLayers.Geometry.Point(
|
|
||||||
viaPointsVector[i][1],
|
|
||||||
viaPointsVector[i][0]);
|
|
||||||
viapoint.transform(EPSG_4326, EPSG_900913);
|
|
||||||
var viaPointFeature = new OpenLayers.Feature.Vector( OpenLayers.Geometry.Polygon.createRegularPolygon( viapoint, (1.5*zoomFactor), 20, 0 ), null, permanentViaStyle );
|
|
||||||
viaPointFeature.name = "viapoint";
|
|
||||||
viaPointFeature.viaIndex = i;
|
|
||||||
dragLayer.addFeatures( viaPointFeature )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 934 B |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 831 B |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
@@ -1,70 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
|
||||||
<title>OSRM Web(GUI)Interface</title>
|
|
||||||
<meta name="description" content="OSRM Web(GUI)Interface"/>
|
|
||||||
<meta name="language" content="en" />
|
|
||||||
<meta name="robots" content="index,follow" />
|
|
||||||
<meta name="author" content="Pascal Neis" />
|
|
||||||
<meta name="revisit-After" content="7 days" />
|
|
||||||
<meta name="distribution" content="global" />
|
|
||||||
|
|
||||||
<script src="ol/OpenLayers.js"></script>
|
|
||||||
<script src="ol/OpenStreetMap.js"></script>
|
|
||||||
<script src="Slides.js"></script>
|
|
||||||
<script src="Map.js"></script>
|
|
||||||
<script src="Route.js"></script>
|
|
||||||
<script src="ViaRoute.js"></script>
|
|
||||||
<script src="Geocode.js"></script>
|
|
||||||
<script src="MouseClick.js"></script>
|
|
||||||
<!-- <script src="osrm.js"></script> -->
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="style.css" type="text/css" media="all" />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body onload="init();">
|
|
||||||
|
|
||||||
<div id="slide" class="slide"><a class="btn-slide" href="javascript:;" onmousedown="toggleSlide('data');"><<</a></div>
|
|
||||||
<div id="data" style="width:350px;overflow:hidden;" class="data">
|
|
||||||
<div id="inner" style="width:350px;overflow:hidden;">
|
|
||||||
<div id="routing">
|
|
||||||
<!-- http://map.project-osrm.org/osrm3_small.png - http://project-osrm.org/osrm3.png -->
|
|
||||||
<img src="http://map.project-osrm.org/osrm3_small.png" style="margin-left:auto; margin-right:auto; width:200px; display:block; padding: 5px;" alt="">
|
|
||||||
|
|
||||||
<table width="100%">
|
|
||||||
<tr id="StartPoint">
|
|
||||||
<td><div class="textLabel"><img src="img/arrow-start.png" class="radioIcons" width="12" height="16" alt=""><span class="text"></span></div></td>
|
|
||||||
<td><input name="tfStartSearch" style="width:220px" type="text" id="tfStartSearch" class="tfPoints" value="Berlin" title="Search your start point!" onKeyPress="checkReturn('start',event);" >
|
|
||||||
<button name="enterStart" onclick="setStatus('start'); geocodeAddress('start');">Search</button></td>
|
|
||||||
<td rowspan="2" valign="middle">
|
|
||||||
<!-- <button name="switchStartEnd" disabled="true" id="switchStartEnd" type="button"
|
|
||||||
value="Change Start and Endpoint"onClick="changeStartEnd();"><img src="img/changePos.gif" width="9" height="22" alt="Tausche Start- und Endpunkt"><br> --></button></td>
|
|
||||||
</tr>
|
|
||||||
<tr id="EndPoint">
|
|
||||||
<td nowrap>
|
|
||||||
<div class="textLabel"><img src="img/arrow-finish.png" class="radioIcons" width="12" height="16" alt=""><span class="text"></span></div>
|
|
||||||
</td>
|
|
||||||
<td id="tdEnd">
|
|
||||||
<input name="tfEndSearch" style="width:220px" type="text" id="tfEndSearch" class="tfPoints" value="München, Altstadt" title="Search your end point!" onKeyPress="checkReturn('end',event);">
|
|
||||||
<button name="enterEnd" onclick="setStatus('end'); geocodeAddress('end');">Search</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="calc_route" class="calc_route"><span class="options"><a href="#" onclick="closeOpenDiv('options');">Options</a></span>
|
|
||||||
<select name="selectRoutePref" id="selectRoutePref" title="Select the route preference ..."><option value="Fastest" selected>Car (travel time)</option></select>
|
|
||||||
<input name="Submit5" type="submit" class="calculate_button" id="Calculate" title="Route!" onClick="markersLayer.clearMarkers(); routing(false);" value="Route!"></div>
|
|
||||||
|
|
||||||
<div id="options" class="options_div" style="display:none"><input class="checkbox" type="checkbox" name="cbNoNames" id="cbNoNames" value="checkbox">Highlight No Name Streets in my Route</div>
|
|
||||||
<div id="information" class="information"> <p class="infoHL">Demo Website for the <br><a target="_blank" href="http://project-osrm.org/">Open Source Routing Machine Project</a></p> </div>
|
|
||||||
<div id="thx" class="thx">GUI v0.3 110722 - OSRM hosting by <a target="_blank" href="http://www.geofabrik.de/">Geofabrik</a> - Geocoder by <a target="_blank" href="http://developer.mapquest.com/web/products/open/nominatim/">MapQuest</a></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="map" class="map"></div>
|
|
||||||
|
|
||||||
<div class="copyright">© 2011 <a target="_blank" href="http://project-osrm.org/">Project OSRM</a> - Map data <a target="_blank" href="http://creativecommons.org/licenses/by-sa/2.0/">CC-By-SA</a> <a target="_blank" href="http://www.openstreetmap.org">by OpenStreetMap</a></div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
/**
|
|
||||||
* Namespace: Util.OSM
|
|
||||||
*/
|
|
||||||
OpenLayers.Util.OSM = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constant: MISSING_TILE_URL
|
|
||||||
* {String} URL of image to display for missing tiles
|
|
||||||
*/
|
|
||||||
OpenLayers.Util.OSM.MISSING_TILE_URL = "http://www.openstreetmap.org/openlayers/img/404.png";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Property: originalOnImageLoadError
|
|
||||||
* {Function} Original onImageLoadError function.
|
|
||||||
*/
|
|
||||||
OpenLayers.Util.OSM.originalOnImageLoadError = OpenLayers.Util.onImageLoadError;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function: onImageLoadError
|
|
||||||
*/
|
|
||||||
OpenLayers.Util.onImageLoadError = function() {
|
|
||||||
if (this.src.match(/^http:\/\/[abc]\.[a-z]+\.openstreetmap\.org\//)) {
|
|
||||||
this.src = OpenLayers.Util.OSM.MISSING_TILE_URL;
|
|
||||||
} else if (this.src.match(/^http:\/\/[def]\.tah\.openstreetmap\.org\//)) {
|
|
||||||
// do nothing - this layer is transparent
|
|
||||||
} else {
|
|
||||||
OpenLayers.Util.OSM.originalOnImageLoadError;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class: OpenLayers.Layer.OSM.Mapnik
|
|
||||||
*
|
|
||||||
* Inherits from:
|
|
||||||
* - <OpenLayers.Layer.OSM>
|
|
||||||
*/
|
|
||||||
OpenLayers.Layer.OSM.Mapnik = OpenLayers.Class(OpenLayers.Layer.OSM, {
|
|
||||||
/**
|
|
||||||
* Constructor: OpenLayers.Layer.OSM.Mapnik
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* name - {String}
|
|
||||||
* options - {Object} Hashtable of extra options to tag onto the layer
|
|
||||||
*/
|
|
||||||
initialize: function(name, options) {
|
|
||||||
var url = [
|
|
||||||
"http://a.tile.openstreetmap.org/${z}/${x}/${y}.png",
|
|
||||||
"http://b.tile.openstreetmap.org/${z}/${x}/${y}.png",
|
|
||||||
"http://c.tile.openstreetmap.org/${z}/${x}/${y}.png"
|
|
||||||
];
|
|
||||||
options = OpenLayers.Util.extend({ numZoomLevels: 19, buffer: 0 }, options);
|
|
||||||
var newArguments = [name, url, options];
|
|
||||||
OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
|
|
||||||
},
|
|
||||||
|
|
||||||
CLASS_NAME: "OpenLayers.Layer.OSM.Mapnik"
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class: OpenLayers.Layer.OSM.Osmarender
|
|
||||||
*
|
|
||||||
* Inherits from:
|
|
||||||
* - <OpenLayers.Layer.OSM>
|
|
||||||
*/
|
|
||||||
OpenLayers.Layer.OSM.Osmarender = OpenLayers.Class(OpenLayers.Layer.OSM, {
|
|
||||||
/**
|
|
||||||
* Constructor: OpenLayers.Layer.OSM.Osmarender
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* name - {String}
|
|
||||||
* options - {Object} Hashtable of extra options to tag onto the layer
|
|
||||||
*/
|
|
||||||
initialize: function(name, options) {
|
|
||||||
var url = [
|
|
||||||
"http://a.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png",
|
|
||||||
"http://b.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png",
|
|
||||||
"http://c.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png"
|
|
||||||
];
|
|
||||||
options = OpenLayers.Util.extend({ numZoomLevels: 18, buffer: 0 }, options);
|
|
||||||
var newArguments = [name, url, options];
|
|
||||||
OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
|
|
||||||
},
|
|
||||||
|
|
||||||
CLASS_NAME: "OpenLayers.Layer.OSM.Osmarender"
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class: OpenLayers.Layer.OSM.CycleMap
|
|
||||||
*
|
|
||||||
* Inherits from:
|
|
||||||
* - <OpenLayers.Layer.OSM>
|
|
||||||
*/
|
|
||||||
OpenLayers.Layer.OSM.CycleMap = OpenLayers.Class(OpenLayers.Layer.OSM, {
|
|
||||||
/**
|
|
||||||
* Constructor: OpenLayers.Layer.OSM.CycleMap
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* name - {String}
|
|
||||||
* options - {Object} Hashtable of extra options to tag onto the layer
|
|
||||||
*/
|
|
||||||
initialize: function(name, options) {
|
|
||||||
var url = [
|
|
||||||
"http://a.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png",
|
|
||||||
"http://b.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png",
|
|
||||||
"http://c.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png"
|
|
||||||
];
|
|
||||||
options = OpenLayers.Util.extend({ numZoomLevels: 19, buffer: 0 }, options);
|
|
||||||
var newArguments = [name, url, options];
|
|
||||||
OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
|
|
||||||
},
|
|
||||||
|
|
||||||
CLASS_NAME: "OpenLayers.Layer.OSM.CycleMap"
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class: OpenLayers.Layer.OSM.MapQuest
|
|
||||||
*
|
|
||||||
* Inherits from:
|
|
||||||
* - <OpenLayers.Layer.OSM>
|
|
||||||
*/
|
|
||||||
OpenLayers.Layer.OSM.MapQuest = OpenLayers.Class(OpenLayers.Layer.OSM, {
|
|
||||||
/**
|
|
||||||
* Constructor: OpenLayers.Layer.OSM.MapQuest
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* name - {String}
|
|
||||||
* options - {Object} Hashtable of extra options to tag onto the layer
|
|
||||||
*/
|
|
||||||
initialize: function(name, options) {
|
|
||||||
var url = [
|
|
||||||
"http://otile1.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png",
|
|
||||||
"http://otile2.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png",
|
|
||||||
"http://otile3.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png"
|
|
||||||
];
|
|
||||||
options = OpenLayers.Util.extend({ numZoomLevels: 19, buffer: 0 }, options);
|
|
||||||
var newArguments = [name, url, options];
|
|
||||||
OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
|
|
||||||
},
|
|
||||||
|
|
||||||
CLASS_NAME: "OpenLayers.Layer.OSM.MapQuest"
|
|
||||||
});
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
This is the OpenLayers Version 2.10
|
|
||||||
|
Before Width: | Height: | Size: 42 B |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 451 B |
|
Before Width: | Height: | Size: 451 B |
|
Before Width: | Height: | Size: 249 B |
|
Before Width: | Height: | Size: 992 B |
|
Before Width: | Height: | Size: 831 B |
|
Before Width: | Height: | Size: 967 B |
|
Before Width: | Height: | Size: 606 B |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 484 B |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 285 B |
|
Before Width: | Height: | Size: 481 B |
|
Before Width: | Height: | Size: 453 B |
|
Before Width: | Height: | Size: 359 B |
|
Before Width: | Height: | Size: 489 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 463 B |
@@ -1,10 +0,0 @@
|
|||||||
.olLayerGoogleCopyright {
|
|
||||||
right: 3px;
|
|
||||||
bottom: 2px;
|
|
||||||
left: auto;
|
|
||||||
}
|
|
||||||
.olLayerGooglePoweredBy {
|
|
||||||
left: 2px;
|
|
||||||
bottom: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
.olControlZoomPanel div {
|
|
||||||
background-image: url(img/zoom-panel-NOALPHA.png);
|
|
||||||
}
|
|
||||||
.olControlPanPanel div {
|
|
||||||
background-image: url(img/pan-panel-NOALPHA.png);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 1.6 KiB |